Пишем интерпретатор на PascalABC.NET. Лексический анализатор. Часть 1
Общие термины
Компилятор или интерпретатор языка программирования состоит из нескольких подсистем.
Лексический анализатор (лексер) разбивает текст программы на так называемые лексемы или токены - неделимые элементы языка. К ним относятся ключевые слова, числовые и строковые константы, знаки препинания, знаки операций (которые могут быть односимвольными или многосимвольными как например := в Паскале или != в языке C). На этапе лексического анализа также пропускаются комментарии языка, которые могут быть либо однострочными (как правило до конца строки), либо многострочными (начинающимися и заканчивающимися как правило разными лексемами).
Синтаксический анализатор (другое название парсер)строит из лексем правильные языковые конструкции: операторы, выражения, списки и т.п. Синтаксические конструкции описываются грамматикой языка, которая представляет набор правил - по нескольку правил на каждую синтаксическую конструкцию. Грамматика языка обычно рекурсивна: например, условный оператор является разновидностью оператора и по каждой ветке (then и else) также содержит оператор.
Семантический анализатор проверяет правильную синтаксически программу на наличие так называемых семантических ошибок. К числу таких ошибок относятся ошибки, связанные с одинаковыми именами (в одном блоке нельзя описать две переменные с одним именем), а также ошибки, связанные с неверной типизацией (целой переменной нельзя присвоить строковое значение). Часто семантический анализатор называют Type Checkerом, подчеркивая, что проверка типов до выполнения программы - важнейшая задача.
В скриптовых языках программирования, к которым в частности относится язык Питон, фаза семантического анализа отсутствует, что приводит к появлению многочисленных ошибок прямо в момент выполнения программы, а также к существенному замедлению скорости выполнения программы за счет парадигмы динамической типизации.
Следующие фазы компиляции - это собственно интерпретация программы, генерация кода программы для целевой архитектуры компьютера, генерация кода для некоторой виртуальной машины и оптимизация кода.
Мы будем нацелены в итоге на создание эффективного интерпретатора для языка со статической типизацией, то есть языка, в котором тип переменной не меняется после её первичного описания или инициализации.
Лексический анализатор. Основная программа
Создадим лексический анализатор для некоторого простого языка, содержащего несколько ключевых слов, типичные разделители и знаки операций и блоки.
Приведем пример итоговой программы:
Как мы видим, программа написана на одной строке - этой строкой инициализируется конструктор класса Lexer. Важнейшей функцией лексера является метод NextToken, возвращающий следующую лексему. Мы перебираем таким образом все лексемы в цикле и выводим их пока не будет достигнута лексема TokenType.Eof, обозначающая конец программы.
На скриншоте видно, что лексер разбирает все лексемы и выводит их, разделяя одним пробелом. Лексема в конце - это Eof - признак конца программы.
Полный код модуля LexUnit и класса Lexer будет приведен в следующей статье.