Сущность и задачи лексического анализа

Лексический анализ (ЛА) - это первый этап процесса трансляции. Основная задача лексического анализа – разбить входной текст, состоящий из последовательности символов алфавита, на минимально значимые части языка, называемые лексемами. Лексемами естественных языков являются слова. В языках программирования встречаются лексемы различных типов (рис.3.1), состав которых определяется синтаксисом конкретного языка программирования.

 
 

Рис.3.1 Типы лексем языков программирования

Все символы входной последовательности можно разделить на символы, принадлежащие каким-либо лексемам, и символы, разделяющие лексемы (терминальные символы). В некоторых случаях между лексемами может и не быть разделителей (например: между числами и знаками операций). В некоторых языках символы разделители могут блокироваться специальными символами (например: в Си в строке "ааа\"ббб" – вторая кавычка не заканчивает строку, потому что блокируется ‘\’).

Таким образом, лексический анализатор (сканер) - это транслятор, входом которого служит цепочка символов, представляющих исходную программу, а выходом - последовательность лексем. При этом каждой лексеме сопоставляется пара (тип_лексемы, указатель_на_информацию_о_ней). Выбор конструкций, которые будут выделяться как отдельные лексемы, зависит от языка программирования и от точки зрения разработчиков транслятора.

Теоретически лексический анализатор не является обязательной частью транслятора, так как все его функции могут выполняться синтаксическим анализатором. На практике существует ряд причин, по которым лексический анализатор включают в состав почти всех компиляторов как самостоятельный элемент:

- замена в программе идентификаторов, констант, знаков операций, ограничителей и служебных слов лексемами делает представление программы более удобным для дальнейшей обработки;

- лексический анализ уменьшает длину программы, устраняя из ее исходного представления несущественные пробелы и комментарии;

- для решения задач лексического анализа возможно применять простую и эффективную технику анализа, в то время как для синтаксического разбора используются достаточно сложные алгоритмы;

- при изменении версии входного языка достаточно будет перестроить относительно простой лексический анализатор, не затрагивая сложный по конструкции синтаксический анализатор.

Функционирование сканера и синтаксического анализатора тесно взаимосвязано, поскольку результаты работы сканера представляют собой исходные данные для синтаксического разбора; кроме того, в некоторых языках смысл лексемы зависит от ее контекста, поэтому невозможно провести лексический анализ в отрыве от синтаксического.

Существует два метода организации взаимодействия лексического и синтаксического анализаторов – последовательный и параллельный.

При реализации последовательного варианта взаимодействия (рис. 3.2., а) сканер просматривает весь текст исходной программы один раз от начала до конца и преобразует его в таблицы лексем, где выделенные лексемы заменяются соответствующими кодами.

В случае параллельного взаимодействия (рис. 3.2., б) синтаксический анализатор после разбора очередной конструкции языка обращается к сканеру за следующей лексемой. При этом сканер может получать дополнительную информацию от лексического анализатора о типе лексемы, которая ожидается. С точки зрения обработки значений лексем, сканер может либо просто выдавать значение каждой лексемы, и в этом случае построение таблиц лексем переносится на более поздние фазы, либо он может самостоятельно строить таблицы лексем. В этом случае в качестве значения лексемы выдается индекс (указатель) в соответствующей таблице. В процессе разбора при возникновении ошибки может происходить «откат назад», чтобы проанализировать синтаксическую конструкцию (оператор языка программирования) на другой основе.


 
 


а) Последовательное взаимодействие


б) Параллельное взаимодействие

Рис. 3.2. Варианты схемы взаимодействия сканера и синтаксического анализатора

Последовательный метод взаимодействия лексического и синтаксического анализаторов более прост и эффективен, но подходит не для всех языков. Возможность его применения определяется синтаксическими правилами языка, то есть грамматикой. В некоторых языках (например, Fortran) ключевые слова могут использоваться как обычные идентификаторы – в этом случае работа сканера не может идти независимо от синтаксического анализатора. Большинство распространенных в настоящее время языков (например, С и Pascal) позволяют применить последовательный вариант реализации.

В качестве примера таблицы лексем рассмотрим некоторый фрагмент кода на языке Си и соответствующую ему таблицу лексем, представленную в таблице 3.1:

for(int i=0; i<N; i++) ss *= 0.5;

Таблица 3.1

Лексема Тип лексемы Код лексемы
for Ключевое слово Х1
( Открывающая скобка (ограничитель) (
int Ключевое слово Х2
i Идентификатор i: 1
= Знак операции присваивания =
  Целая константа  
; Точка с запятой (ограничитель) ;
i Идентификатор i: 1
< Знак операции сравнения <
N Идентификатор N: 2
; Точка с запятой (ограничитель) ;
i Идентификатор i: 1
++ Знак операции инкремента ++
) Закрывающая скобка (ограничитель) )
ss Идентификатор ss: 3
*= Знак операции умножения с присваиванием *=
0.5 Вещественная константа 0.5
; Точка с запятой (ограничитель) ;

В качестве кодов лексем использованы условные значения (конкретные коды определяются реализацией компилятора). Кодовые значения лексем помещаются в итоговую таблицу лексем. Для идентификаторов строится еще одна таблица – таблица идентификаторов (или несколько таблиц). Таблица лексем связывается с таблицей идентификаторов с помощью ссылок на индексы строк или указанием конкретных адресов идентификаторов. Таблица идентификаторов является важным элементом процесса трансляции, и способ ее организации существенно влияет на эффективность этого процесса, поскольку транслятор неоднократно обращается к таблице идентификаторов в ходе своей работы. Существуют различные методы организации таблиц идентификаторов, некоторые из них рассматриваются в п. 3. 2.

Анализ ключевых слов представляет отдельную проблему. Здесь возможны два основных способа. Первый способ: очередная лексема диагностируется на совпадение с каким-либо ключевым словом по мере поступления литер на вход сканера, а в случае неуспеха делается попытка выделить лексему из какого-либо другого класса; в этом случае все ключевые слова непосредственно встраиваются в программу-сканер. Второй способ: после выборки лексемы идентификатора происходит обращение к таблице ключевых слов на предмет сравнения; в данном случае лексический анализатор содержит только разбор идентификаторов.

Обобщенный алгоритм работы простейшего лексического анализатора в компиляторе можно описать следующим образом:

(1) из входного потока выбирается очередной символ (символ может быть также проигнорирован либо признан ошибочным); в зависимости от текущего символа запускается тот или иной сканер (сканеров может быть несколько, каждый из которых соответствует определенному типу лексем);

(2) запущенный сканер просматривает входной поток символов программы на исходном языке, выделяя символы, входящие в требуемую лексему, до обнаружения очередного символа, который может ограничить лексему, либо до обнаружения ошибочного символа;

(3) при успешном распознавании информация о выделенной лексеме заносится в таблицу лексем и таблицу идентификаторов, сканер возвращается к первому шагу алгоритма и продолжает рассматривать входной поток символов с того места, на котором остановился сканер;

(4) при неуспешном распознавании выдается сообщение об ошибке, а дальнейшие действия зависят от реализации сканера – либо его выполнение прекращается, либо делается попытка распознать следующею лексему (идет возврат к первому шагу алгоритма).

Язык лексем, с которыми работает сканер, можно описать с помощью регулярных грамматик.

Например,

идентификатор (I): I ® a|b|...|z|Ia|Ib|...|Iz|I0|I1|...|I9

целое без знака (N): N® 0|1|...|9|N0|N1|...|N9

...

Для регулярных грамматик существует простой и эффективный алгоритм анализа того, принадлежит ли заданная цепочка языку, порождаемому этой грамматикой (п. 3.3).


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: