Таким образом, при наличии в условиях определенных значений, компилятор или интерпретатор могут и должны отсекать лишние проверки. Это не относится к случаю, если вместо значения «4» было бы, к примеру, записано … and (a > c div 2) – тут уже все зависит от переменной С, которая может изменяться в ходе программы. Вообще же, это довольно сложная тема, связанная с оптимизацией работы компиляторов, и популярным объяснением тут не отделаешься. Делающие могут найти несколько интересных статей, вроде статьи Д. Креншоу «Давайте создадим компилятор» или приложения к учебникам по SmallC – там такие проблемы расписаны не в пример лучше.
Собственно, основные направления создания простейшего интерпретатора Бейсика мы уже рассмотрели. Что-то упомянули явно, о чем-то рассказали мельком, но ведь главная задача статьи – заинтересовать, пробудить мысль, а не давать читателю готовый код? Попробуйте-ка реализовать его сами, это очень интересно! А самое интересное, в данном случае, сводится к последнему этапу – генерации кода, который, собственно, и будет выполняться. Возможны следующие основные варианты:
- Исполнение программы средствами самого интерпретатора, написанного на языке высокого уровня. Работать будет не очень быстро, зато не требуется создавать никакие EXE/COM файлы. Кроме того, легко вычислять математические функции вроде синусов, косинусов, взятия корней выражений. В общем, не нужно явно программировать математический сопроцессор или эмулировать его работу, заново изобретая вычислительные таблицы Фортрана.
- Генерация COM-файла, имеющего, как известно, простую структуру на диске и в памяти. Размер образа ограничен 64 Кб, но для данного применения этого хватает. Зато программа будет «как настоящая».
- Генерация выходного листинга на ассемблере. Вариант хорош тем, что можно наглядно видеть ошибки в генерируемом коде, применять оптимизирующие приемы. Кроме того, впоследствии нетрудно будет создавать объектные файлы для объединения с другими, написанными на других языках программирования. Как говорится, в единстве – сила. Нужно только предусмотреть множество тонкостей, связанных, к примеру, с наименованием секций программ и данных, к способам организации стека и т.д.
- Генерация EXE программ. Это уже довольно высокий уровень – программа может иметь огромные размеры, использовать оверлеи. К сожалению, и COM, и EXE программы в эпоху Windows безнадежно устарели, так что работать в этом плане эффективно лишь в тех случаях, если программы делают действительно полезные вещи. Или, например, оптимизированы для разработки системных приложений, драйверов.
- Можно создавать и NE/PE программы. А почему бы и нет, собственно? Будет у вас собственная среда визуальной разработки Windows-программ, а в дальнейшем и Delphi обгоните.
- Генерация кода под платформы JVM, .NET. Современный подход, причем оригинальный. Пусть ваш Бейсик создает байт-код для этих платформ. Помните, что тот же Android использует аналог JVM для запуска программ? Так что можно запросто писать программы для Андроида, но только на своем собственном языке и интерпретаторе.
- А можно генерировать код совсем для других процессоров, которые к Intel не имеют никакого отношения: для Синклеров, Правецов, БК, ДВК, PowerPC и т.д. Такой подход называется кросс-программированием, и применяется в том случае, если на целевой машине разработку программ вести неудобно (как, например, неудобно программировать телефон на самом телефоне).
Что касается применения ассемблера в разработке – помните, что даже корифеи в разработке компиляторов не применяют все его команды, так что советуем действовать так же: определите минимальный набор операций и не выходите за него. Экзотические операции не помогут сделать код слишком эффективным, лишь чуть-чуть красивым.
В заключительной статье мы подберем вам набор интересных ссылок для чтения, посвященных разработке собственных компиляторов и интерпретаторов, где многие вопросы разработки освещены лучше, чем в наших статьях. |