Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

В качестве примера рассмотрим реализацию следующей грамматики (листинг 4.10).

Листинг 4.10. Грамматика калькулятора с лексическим анализатором

<Expr> ::= <MathExpr> [<Comparison> <MathExpr>]

<Comparison> ::= '=' | '>' | '<' | '>=' | '<=' | '<>'

<MathExpr> ::= <Term> {<Operator1> <Term>}

<Operator1> ::= '+' | '-' | 'or' | 'xor'

<Term> ::= <Factor> {<Operator2> <Factor>}

<Operator2> ::= '*' | '/' | 'div' | 'mod' | 'and'

<Factor> ::= <UnaryOp> <Factor> | <Base> ['^' <Factor>]

<UnaryOp> ::= '+' | '-' | 'not'

<Base> ::= <Variable> | <Function> | <Number> | '(' <MathExpr> ')'

<Function> ::= <FuncName> '(' <MathExpr> ')'

<FuncName> ::= 'sin' | 'cos' | 'ln'

<Variable> ::= <Letter> {<Letter> | <Digit>}

<Letter> ::= 'A' | ... | 'Z' | 'a' | ... | 'z' | '_'

<Digit> ::= '0' | ... | '9'

<Number> ::= <Digit> {<Digit>} [<DecimalSeparator> <Digit> {<Digit>}]

 (('E' | 'e') ['+' | '-'] <Digit> {<Digit>)]

Примечание

Здесь

используется нетерминальный символ
<DecimalSeparator>
, который мы не определили. Он полагается равным точке или запятой в зависимости от системных настроек.

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

<DecimalSeparator>
) нетерминальных символов. Определение символа
<Number>
несколько изменено, но это касается только формы его представления — синтаксис числа остался без изменения. То, что раньше обозначалось как
<Expr>
, теперь называется
<MathExpr>
, а выражение
<Expr>
состоит из одного
<MathExpr>
, с которым, возможно, сравнивается другое
<MathExpr>
. Семантика
<Expr>
такова: если в выражении присутствует только обязательная часть, результатом будет число, которое получилось при вычислении
<MathExpr>
. Если же имеется необязательное сравнение с другим
<MathExpr>
, то результатом будет "
True
" или "
False
" в зависимости от результатов сравнения.

В новой грамматике также расширен набор операторов. Операторы

or
,
xor
,
and
и
not
здесь арифметические, т.е. применяются к числовым, а не к логическим выражениям. Все операторы, которые применимы только к целым числам (т.е. вышеперечисленные, а также
div
и
mod
), игнорируют дробную часть своих аргументов.

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

1. Все знаки операций, которые используются в определении символов

<Comparison>
,
<Operator1>
,
<Operator2>
,
<UnaryOp>
, а также символ "
^
".

2. Открывающую и закрывающую скобки.

3. Имена функций.

4. Идентификаторы (т.е. переменные).

5. Числовые константы.

Напомним, что лексический анализатор не должен определять допустимость появления

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

Из нашей грамматики следует, что имена функций являются зарезервированными словами, т.е. объявить переменные с именами

sin
,
cos
и
ln
в отличие от предыдущего примера, нельзя. Это само по себе не упрощает и не усложняет задачу, а сделано только в качестве демонстрации возможной альтернативы (просто если именами служат зарезервированные слова, то их распознает лексический анализатор, а если идентификаторы, то синтаксический).

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

В зависимости от типа лексем разделители между ними могут быть обязательными или необязательными. Например, в выражении "2+3" разделители между лексемами "2", "+" и "5" не нужны, потому что они могут быть отделены друг от друга и без этого. А в выражении

6 div 3
разделитель между "div" и "3" необходим, потому что в противном случае эти лексемы будут восприняты как идентификатор div3. А вот разделитель между "6" и "div" не обязателен, т.к.
6div
не является допустимым идентификатором, и анализатор сможет отделить эти лексемы друг от друга и без разделителя. Вообще, если подстрока, получающаяся в результате слияния двух лексем, может быть целиком интерпретирована как какая-либо другая лексема, разделитель между ними необходим, в противном случае — необязателен. Разделитель внутри отдельной лексемы не допускается (т.е. подстрока "a 1" будет интерпретироваться как последовательность лексем "а" и "1", а не как лексема "а1").

Чтобы продемонстрировать возможности лексического анализатора, добавим поддержку комментариев. Комментарий — это последовательность символов, начинающаяся с "{" и заканчивающаяся "}", которая может содержать внутри себя любые символы, кроме "}". Комментарий считается разделителем, он допустим в любом месте, где возможно появление других разделителей, т.е. в начале и в конце строки и между лексемами.

Пример калькулятора с лексическим анализатором также находится на компакт-диске и называется LexicalSample.

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

Листинг 4.11. Тип
TLexeme
для хранения информации об одной лексеме

TLexemeType = (

 ltEqual, ltLess, ltGreater, ltLessOrEqual,

 ltGreaterOrEqual, ltNotEqual, ltPlus, ltMinus,

 ltOr, ltXor, ltAsterisk, ltSlash, ltDiv, ltMod,

Поделиться:
Популярные книги

Архил...? 4

Кожевников Павел
4. Архил...?
Фантастика:
фэнтези
попаданцы
альтернативная история
5.50
рейтинг книги
Архил...? 4

Мятежник

Прокофьев Роман Юрьевич
4. Стеллар
Фантастика:
боевая фантастика
7.39
рейтинг книги
Мятежник

Дурашка в столичной академии

Свободина Виктория
Фантастика:
фэнтези
7.80
рейтинг книги
Дурашка в столичной академии

Котенок. Книга 3

Федин Андрей Анатольевич
3. Котенок
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Котенок. Книга 3

Аристократ из прошлого тысячелетия

Еслер Андрей
3. Соприкосновение миров
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Аристократ из прошлого тысячелетия

Печать мастера

Лисина Александра
6. Гибрид
Фантастика:
попаданцы
технофэнтези
аниме
фэнтези
6.00
рейтинг книги
Печать мастера

Господин следователь. Книга 3

Шалашов Евгений Васильевич
3. Господин следователь
Детективы:
исторические детективы
5.00
рейтинг книги
Господин следователь. Книга 3

Вернуть невесту. Ловушка для попаданки 2

Ардова Алиса
2. Вернуть невесту
Любовные романы:
любовно-фантастические романы
7.88
рейтинг книги
Вернуть невесту. Ловушка для попаданки 2

Командир Красной Армии

Поселягин Владимир Геннадьевич
1. Командир Красной Армии
Фантастика:
попаданцы
8.72
рейтинг книги
Командир Красной Армии

Рота Его Величества

Дроздов Анатолий Федорович
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Рота Его Величества

Босс Мэн

Киланд Ви
Любовные романы:
современные любовные романы
8.97
рейтинг книги
Босс Мэн

Два лика Ирэн

Ром Полина
Любовные романы:
любовно-фантастические романы
6.08
рейтинг книги
Два лика Ирэн

Не грози Дубровскому! Том III

Панарин Антон
3. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том III

Идеальный мир для Лекаря 27

Сапфир Олег
27. Лекарь
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 27