Здравствуйте! Записался на ваш курс, но не понимаю как произвести оплату. Надо ли писать заявление и, если да, то куда отправлять? как я получу диплом о профессиональной переподготовке? |
Компиляция функциональных программ
Компилятор и требования к коду программы
Описанная в предыдущей лекции специальная абстрактная машина SECD удобна для спецификации машинно-зависимых аспектов семантики Лиспа. Такой подход позволяет не загромождать определение компилятора, добиться его прозрачности, но главное, такое определение может быть машинно-независимым и переносимым [ 3 ] .
Для функционального стиля в программировании характерно стремление снять непринципиальные ограничения на применение и построение функций. Для этого приходится сдерживать привычные для многих областей применения разграничения, а также смягчать стандартные границы при организации процессов в системах программирования. В этом отношении следует отметить:
- единое пространство функций, их аргументов и всех обозначений, роль которых определяется по контексту при интерпретации форм;
- разрешение функциональных переменных, значение которых конструируется (вычисляется) в процессе их интерпретации. Это позволяет вводить частичные определения, уточняемые по мере необходимости;
- самоопределение основных механизмов символьной обработки и, следовательно, открытый характер системы программирования, поддерживающей функциональное программирование;
- мягкость пространственно-временных ограничений, без точных численных оценок по отдельным параметрам;
- поощрение рекурсивных определений;
- предельная уточняемость и детализируемость определений, управление временем их существования и выполнения.
Лисп-компилятор — это программа, написанная на Лисп, которая транслирует S-выражения, определяющие функции, в машинные подпрограммы. Это средство оптимизации, позволяющее ускорить работу программ от двух до ста раз, чем было бы при простой интерпретации.
Когда компилятор вызывается для компиляции функций, он находит определение функции в списке свойств названия функции. Компилятор транслирует найденное исходное S-выражение в объектное S-выражение, которое представляет подпрограмму на языке ассемблера. Ассемблер после этого ассемблирует код программы. Затем в списке свойств функции размещается ссылка на код программы.
Опыт показывает, что скомпилированная программа может работать намного раз быстрее, чем интерпретируемая программа, в зависимости от ее природы. Скомпилированные программы могут быть и экономичнее с точки зрения расхода памяти, требуя 50–80% от полного объема.
Основная часть компилятора — транслятор или функция, отображающая S-выражения, которые обозначают функции, на язык ассемблера. Единственное основание для того, чтобы рассматривать компилятор как псевдо-функцию, состоит в том, что он изменяет свойства названий функций по завершении компиляции.
Лисп-компилятор имеет уникальную историю. Он развивался пошаговым образом ( метод раскрутки ) [ 1 ] .
- Компилятор был написан и отлажен как Лисп-программа, состоящая из набора определений функций в виде S-выражений. Это позволило компилировать любые Лисп-программы и строить специализированные расширения Лисп-интерпретатора.
- Компилятору была дана команда скомпилировать себя самого. Данная операция называется раскруткой ( bootstrapping ). На это потребовалось более 5 минут на IBM 7090, поскольку значительная часть компилятора в основном интерпретировалась. В результате было создано эффективное расширение Лисп-системы, способное компилировать Лисп-программы и строить расширения Лисп-интерпретатора.
- Чтобы исключить повторение медленной раскрутки при дальнейших шагах установки системы, весь код компилятора заново был введен на языке ассемблера.
- Была создана системная лента, и компилятор стал загружаемым на уровне ассемблера.
- Процесс раскрутки был повторен до полного формирования кода Лисп-системы.
Компилятор вызывается псевдо-функцией COMPILE. Аргумент COMPILE — список названий функций, которые следует компилировать. Каждый атом в списке должен иметь определение функции в своем списке свойств до компиляции.
Обработка каждой функции происходит в три шага. Во-первых, S-выражение, задающее функцию, транслируется в текст на уровень ассемблера. При отсутствии S-выражения, компилятор сообщает об этом и переходит к другой функции. Во-вторых, текст программы на уровне ассемблера транслируется в код программы. И, наконец, если никаких ошибок не обнаружено, то S-выражение функции может быть удалено из списка свойств. Когда некоторые ошибки указывают на появление необъявленной переменной, компилятор предупреждает об этом и продолжает работу. Такая диагностика будет дополнительно уточнена при анализе значений переменной.
При написании большой Лисп-программы лучше отлаживать отдельные функции, используя интерпретатор, а компилировать только те из них, которые уже хорошо изучены.
Программист, планирующий применять компилятор, должен обратить внимание на следующие моменты.
- Нет необходимости компилировать все функции, которые используются лишь эпизодически. Интерпретатору доступны скомпилированные функции. Компилированные функции, использующие интерпретируемые функции, могут вычислять их непосредственно при счете.
- Порядок выполнения компиляции не имеет значения. Даже нет необходимости определять все функции до тех пор, пока они не понадобятся при счете. (Исключение из этого правила — специальные формы. Они должны быть определены до того, как компилируется их вызов.)
- При динамическом использовании LABEL результирующая функция не может быть скомпилирована полностью.
- Свободные переменные в компилируемых функциях должны объявляться до компиляции функций (См. лекцию 7).
Последнее требование проясняет роль типового контроля в стандартных, ориентированных на компиляцию без интерпретации, системах программирования.Компиляция всех объектов осуществляется без анализа фактических данных, а это и означает, что на момент компиляции переменные, как правило, являются свободными. Интерпретация располагает более полной информацией, связывающей необходимые для вычислений переменные с конкретными значениями, тип которых определен.
Компилятор и ассемблер могут быть удалены из комплекта Лисп-системы. В целом существует механизм пакетов, позволяющий управлять составом функций и объектов, включаемых в комплект. При удалении части системы освободившаяся память может быть присоединена к списку свободной памяти. Имеются реализации, в которых выделено минимальное ядро системы, все остальные функции загружаются по мере необходимости, а мусорщик может рассматривать память от неиспользуемых функций как свободную.