Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2241 / 912 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 5:

Лексический анализ

< Лекция 4 || Лекция 5: 123456 || Лекция 6 >

Lex

Существует целый ряд инструментов для создания лексических анализаторов; большинство этих инструментов основывается на регулярных выражениях. Одним из традиционных средств подобного рода является Lex, состоящий из Lex-языка и Lex-компилятора. На самом деле запись спецификаций на языке Lex полезна даже тогда, когда Lex компилятор не доступен, поскольку эти спецификации могут быть без особого труда преобразованы в программу вручную. На данный момент, компиляторы Lex существуют на многих платформах и, несомненно, в ближайшее время появятся и на платформе .NET.

Процесс использования Lex'а выглядит следующим образом: cпецификации лексического анализатора на языке Lex подготавливаются в виде программы lex.l. Затем этот файл обрабатывается Lex компилятором, в результате чего создается программа на языке программирования. Большинство существующих реализаций генерируют программы на С и потому в дальнейшем рассмотрении средства Lex мы будем подразумевать использование С, хотя с тем же успехом можно было бы использовать и любой другой язык, например, C#.

Сгенерированная программа состоит из табличного представления диаграмм переходов, построенных по регулярным выражениям, и стандартных подпрограмм, которые используют эти таблицы для разбора лексем. Действия, связанные с реакцией на встреченные регулярные выражения, пишутся непосредственно на С и обычно помещаются сразу же за самими правилами. Затем эта программа обрабатывается компилятором С, в результате чего создается объектная программа, которая и является лексическим анализатором.


Структура Lex-программы

Lex-программа состоит из трех частей: описаний, правил трансляции и процедур. Каждая часть отделяется от следующей строкой, содержащей два символа %%.

Секция описаний включает описания переменных, констант и регулярных определений. Раздел описаний содержит определения макросимволов (метасимволов) в виде:

ИМЯ ВЫРАЖЕНИЕ

Если в последующем тексте в регулярном выражении встречается {ИМЯ}, то оно заменяется на ВЫРАЖЕНИЕ. Если строка описаний начинается с пробелов или заключена в скобки %{ ... }%, то она просто копируется в выходной файл.

Регулярные определения - это последовательность определений вида

d1 r1 
… 
dn rn,

где каждое di - некоторое имя, а каждое ri - регулярное выражение над алфавитом

\Sigma \cup \{d_1 ,...,d_n \}

Правила трансляции - это операторы вида

p1 {action1}
…
pn{actionn}

где pi - регулярное выражение, actioni - фрагмент программы, описывающий, какие действия должен выполнять лексический анализатор для лексемы, определяемой pi.

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

Способы записи регулярных выражений в Lex-программе

Рассмотрим способы записи регулярных выражений во входном языке Lex'а. Символ из входного алфавита, естественно, представляет регулярное выражение из одного символа. Специальные символы (в том числе +-*?()[]{}|/\^$.<> ) записываются после префикса \. Символы и цепочки можно брать в кавычки, например допустимы следующие три способа кодирования символа а: а, "а" и .

Имеется возможность задания класса символов:

[0-9] или [0123456789] - любая цифра
     [A-Za-z]             - любая буква
     [^0-7]                 - любая литера, кроме цифр от 0 до 7
     .                          - любая литера, кроме \n

Грамматика для записи регулярных выражений (в порядке убывания приоритета):

<р>*           - повторение 0 или более раз
    <р>+           - повторение 1 или более раз
    <р>?            - необязательный фрагмент
    <р><р>       - конкатенация
    <р>{m,n}    - повторение от m до n раз
    <р>{m}       - повторение m раз
    <р>{m,}      - повторение m или более раз
    ^<р>            - фрагмент в начале строки
    <р>$            - фрагмент в конце  строки
    <р>|<р>       - любое из выражений
    <р>/<р>       - первое выражение, если за ним следует второе
    (р)                - скобки, используются для группировки

Пример. Регулярное выражение ^[^aeiou]*$ означает любую строку, не содержащую букв a, e, i, o .

< Лекция 4 || Лекция 5: 123456 || Лекция 6 >