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

на главную

Жанры

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

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

Шрифт:

end;

 end;

 PutLexeme(ltNumber, InitPos, Copy(S, InitPos, P- InitPos));

end;

// Выделение слова из строки и проверка его на совпадение

// с зарезервированными словами языка

procedure TLexicalAnalyzer.Word(const S: string; var P: Integer);

var

 InitPos: Integer;

 ID: string;

begin

 InitPos := P;

 Inc(P);

 while (P <= Length(S)) and

(S[P] in ['0'..'9', 'A'..'Z', 'a'..'z', '_']) do

Inc(P);

 ID := Copy(S, InitPos, P - InitPos);

 if AnsiCompareText(ID, 'or') = 0 then

PutLexeme(ltOr, InitPos, '')

 else if AnsiCompareText(ID, 'xor') = 0 than

PutLexeme(ltXor, InitPos, '')

 else if AnsiCompareText(ID, 'div') = 0 then

PutLexeme(ltDiv, InitPos, '')

 else if AnsiCompareText(ID, 'mod') = 0 then

PutLexeme(ltMod, InitPos, '')

 else if AnsiCompareText(ID, 'and') = 0 then

PutLexeme(ltAnd, InitPos, '')

 else if AnsiCompareText(ID, 'not') = 0 then

PutLexeme(ltNot, InitPos, '')

 else if AnsiCompareText(ID, 'sin') = 0 then

PutLexeme(ltSin, InitPos, '')

 else if AnsiCompareText(ID, 'cos') = 0 then

PutLexeme(ltCos, InitPos, '')

 else if AnsiCompareText(ID, 'ln') = 0 then

PutLexeme(ltLn, InitPos, '')

 else PutLexeme(ltIdentifier, InitPos, ID);

end;

В

конец списка лексем помещается специальная лексема типа
ltEnd
. В предыдущих примерах приходилось постоянно сравнивать указатель позиции
P
с длиной строки
S
, чтобы не допустить выход за пределы диапазона. Если бы не было лексемы
ltEnd
, точно так же пришлось бы проверять, не вышел ли указатель за пределы списка. Но лексема
ltEnd
не рассматривается как допустимая ни одной из функций синтаксического анализатора, поэтому, встретив ее, каждая из них возвращает управление вызвавшей ее функции, и заканчивается эта цепочка только на функции
Expr
. Таким образом, код получается более ясным и компактным.

Примечание

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

#1
), и проверять в функции
Expr
или
Calculate
, что разбор выражения остановился именно на этом символе.

Лексический анализ выражения заключается в чередовании вызовов функций

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

Обратите внимание, как в лексическом анализаторе реализован метод

Number
. Рассмотрим выражение "1е*5". В калькуляторе без лексического анализатора функция
Number
, дойдя до символа "*" выдавала исключение, т.к. ожидала увидеть здесь знак "+", или число. Но лексический анализатор не должен брать на себя такую ответственность — поиск синтаксических ошибок. Поэтому в данном случае он должен, дойдя до непонятного символа в конструкции, которую он счел за экспоненту, откатиться назад, выделить из строки лексему "1" и продолжить выделение лексем с символа "е". В результате список лексем будет выглядеть так: "1, "е", "*", "5". И уже синтаксический анализатор должен потом разобраться,
допустима ли такая последовательность лексем или нет.

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

Number
вызывается из
ExtractLexeme
только в том случае, когда в начале лексемы встречается цифра, а с цифры может начинаться только лексема
ltNumber
. Таким образом, сам факт вызова функции
Number
говорит о том, что в строке гарантированно обнаружена подстрока (состоящая, по крайней мере, из одного символа), которая является числом. Функции синтаксического анализатора очень похожи на аналогичные функции из предыдущих примеров, за исключением того, что работают не со строкой, а со списком лексем. Поэтому мы приведем здесь только одну из них — функцию
Term
(листинг 4.13).

Листинг 4.13. Пример функции, использующей лексический анализатор

const

 Operator2 = (ltAsterisk, ltSlash, ltDiv, ltMod, ltAnd);

function Term(LexicalAnalyzer: TLexicalAnalyzer): Extended;

var

 Operator: TLexemeType;

begin

 Result := Factor(LexicalAnalyzer);

 while LexicalAnalyzer.Lexeme.LexemeType in Operator2 do

 begin

Operator := LexicalAnalyzer.Lexeme.LexemeType;

LexicalAnalyzer.Next;

case Operator of

ltAsterisk: Result := Result * Factor(LexicalAnalyzer);

ltSlash: Result := Result / Factor(LexicalAnalyzer);

ltDiv: Result := Trunc(Result) div Trunc(Factor(LexicalAnalyzer));

ltMod: Result := Trunc(Result) mod Trunc(Factor(LexicalAnalyzer));

ltAnd: Result := Trunc(Result) and Trunc(Factor(LexicalAnalyzer));

end;

 end;

end;

Если сравнить этот вариант

Term
с аналогичной функцией из листинга 42, легко заметить их сходство.

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

TLexeme
нужно добавить поле
Number
типа
Extended
и модифицировать метод
Number
таким образом, чтобы он сразу преобразовывал выделенную подстроку в число. Тогда дорогостоящий вызов функции
StrToFloat
будет перенесен из многократно повторяющейся функции
Base
в однократно выполняемый метод
TLexicalAnalyzer.Number
. Но самое радикальное средство повышения производительности — переделка синтаксического анализатора таким образом, чтобы он не вычислял выражение самостоятельно, а формировал машинный код для его вычисления. Однако написание компилятора математических выражений выходит за рамки данной книги.

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

На границе тучи ходят хмуро...

Кулаков Алексей Иванович
1. Александр Агренев
Фантастика:
альтернативная история
9.28
рейтинг книги
На границе тучи ходят хмуро...

Кодекс Охотника. Книга III

Винокуров Юрий
3. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Кодекс Охотника. Книга III

Последний попаданец 11. Финал. Часть 1

Зубов Константин
11. Последний попаданец
Фантастика:
фэнтези
юмористическое фэнтези
рпг
5.00
рейтинг книги
Последний попаданец 11. Финал. Часть 1

Книга пяти колец

Зайцев Константин
1. Книга пяти колец
Фантастика:
фэнтези
6.00
рейтинг книги
Книга пяти колец

Поступь Империи

Ланцов Михаил Алексеевич
7. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Поступь Империи

Купидон с топором

Юнина Наталья
Любовные романы:
современные любовные романы
7.67
рейтинг книги
Купидон с топором

Наследник в Зеркальной Маске

Тарс Элиан
8. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник в Зеркальной Маске

Совок 5

Агарев Вадим
5. Совок
Фантастика:
детективная фантастика
попаданцы
альтернативная история
6.20
рейтинг книги
Совок 5

Аномальный наследник. Том 1 и Том 2

Тарс Элиан
1. Аномальный наследник
Фантастика:
боевая фантастика
альтернативная история
8.50
рейтинг книги
Аномальный наследник. Том 1 и Том 2

Теневой путь. Шаг в тень

Мазуров Дмитрий
1. Теневой путь
Фантастика:
фэнтези
6.71
рейтинг книги
Теневой путь. Шаг в тень

Попаданка в академии драконов 2

Свадьбина Любовь
2. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
6.95
рейтинг книги
Попаданка в академии драконов 2

Гром над Империей. Часть 2

Машуков Тимур
6. Гром над миром
Фантастика:
фэнтези
попаданцы
5.25
рейтинг книги
Гром над Империей. Часть 2

Ритуал для призыва профессора

Лунёва Мария
Любовные романы:
любовно-фантастические романы
7.00
рейтинг книги
Ритуал для призыва профессора

Измена. Осколки чувств

Верди Алиса
2. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Осколки чувств