
- •1.1.1.2.Определение компилятора. Отличие компилятора от транслятора
- •1.1.1.3.Определение интерпретатора. Разница между интерпретаторами и трансляторами
- •1.1.1.4.Назначение трансляторов, компиляторов и интерпретаторов. Примеры реализации
- •1.1.2Этапы трансляции. Общая схема работы транслятора
- •1.1.3Понятие прохода. Многопроходные и однопроходные компиляторы
- •1.1.4Интерпретаторы. Особенности построения интерпретаторов
- •1.2Таблицы идентификаторов. Организация таблиц идентификаторов
- •1.2.1Назначение и особенности построения таблиц идентификаторов
- •1.2.2Простейшие методы построения таблиц идентификаторов
- •1.2.3Хэш-функции и хэш-адресация
- •1.2.3.1.Принципы работы хэш-функций
- •1.2.3.2.Построение таблиц идентификаторов на основе хэш-функции
- •1.2.4Комбинированные способы построения таблиц идентификаторов
- •1.3Лексические анализаторы (сканеры). Принципы построения сканеров
- •1.3.1Назначение лексического анализатора
- •1.3.2Принципы построения лексических анализаторов
- •1.3.2.1.Определение границ лексем
- •1.3.2.2.Выполнение действий, связанных с лексемами
- •1.3.3Построение лексических анализаторов
1.3.2.2.Выполнение действий, связанных с лексемами
Выполнение действий в процессе распознавания лексем представляет для сканера гораздо меньшую проблему. Фактически КА, который лежит в основе распознавателя лексем, должен иметь не только входной язык, но и выходной. Он должен не только уметь распознать правильную лексему на входе, но и породить связанную с ней последовательность символов на выходе. В такой конфигурации КА преобразуется в конечный преобразователь.
Для сканера действия по обнаружению лексемы могут трактоваться несколько шире, чем только порождение цепочки символов выходного языка. Сканер должен уметь выполнять такие действия, как запись найденной лексемы в таблицу лексем, поиск ее в таблице символов и запись новой лексемы в таблицу символов. Набор действий определяется реализацией компилятора. Обычно эти действия выполняются сразу же по обнаружению конца распознаваемой лексемы.
В КА сканера эти действия можно отобразить сравнительно просто — достаточно иметь возможность с каждым переходом на графе автомата (или в функции переходов автомата) связать выполнение некоторой произвольной функции f(q,a), где q — текущее состояние автомата, а — текущий входной символ. Функция может выполнять произвольные действия, доступные сканеру, в том числе работать с хранилищами данных, имеющимися в компиляторе (функция может быть и пустой — не выполнять никаких действий). Такую функцию, если она есть, обычно записывают на графе переходов КА под дугами, соединяющими состояния КА.
1.3.3Построение лексических анализаторов
Теперь можно рассмотреть практическую реализацию сканеров. В принципе компилятор может иметь в своем составе не один, а несколько лексических анализаторов, каждый из которых предназначен для выборки и проверки определенного типа лексем.
Таким образом, обобщенный алгоритм работы простейшего лексического анализатора в компиляторе можно описать следующим образом:
из входного потока выбирается очередной символ, в зависимости от которого запускается тот или иной сканер (символ может быть также проигнорирован либо признан ошибочным);
запущенный сканер просматривает входной поток символов программы на исходном языке, выделяя символы, входящие в требуемую лексему, до обнаружения очередного символа, который может ограничивать лексему, либо до обнаружения ошибочного символа;
при успешном распознавании информация о выделенной лексеме заносится в таблицу лексем и таблицу идентификаторов, алгоритм возвращается к первому этапу и продолжает рассматривать входной поток символов с того места, на котором остановился сканер;
при неуспешном распознавании выдается сообщение об ошибке, а дальнейшие действия зависят от реализации сканера — либо его выполнение прекращается, либо делается попытка распознать следующую лексему (идет возврат к первому этапу алгоритма).
В целом техника построения сканеров основывается на моделировании работы детерминированных и недетерминированных конечных автоматов с дополнением функций распознавателя вызовами функций обработки ошибок, а также заполнением таблиц символов и таблиц идентификаторов. Такая техника не требует сложной мат. обработки и принципиально важных преобразований входных грамматик. Для разработчика сканера важно решить, где заканчиваются функции сканера и начинаются функции синтаксического разбора.