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

ЖАНРЫ

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

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

Шрифт:

 '0'..'9': Number(S, P);

 '<':if (P < Length(S)) and (S[P + 1] = '=') then

 begin

PutLexeme(ltLessOrEqual, P, '');

Inc(P, 2);

 end

 else

if (P < Length(S)) and (S[P + 1] = '>') then

begin

PutLexeme(ltNotEqual, P, '');

Inc(P, 2);

end

else

begin

PutLexeme(ltLess, P, '');

Inc(P);

end;

 '=': begin

PutLexeme(ltEqual, P, '');

Inc(P);

 end;

 '>': if (P < Length(S)) and (S[P + 1] = '=') then

 begin

PutLexeme(ltGreaterOrEqual, P, '');

Inc(P, 2);

 end

 else

 begin

PutLexeme(ltGreater, P, '');

Inc(P);

 end;

 'A'..'Z, 'a'..'z', '_': Word(S, P);

 '^': begin

PutLexeme(ltCap, P, '');

Inc(P);

 end;

 else

raise ESyntaxError.Create('Некорректный
символ в позиции ' +

IntToStr(Р));

 end;

end;

// Выделение лексемы-числа

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

var

 InitPos, RollbackPos: Integer;

 function IsDigit(Ch: Char): Boolean;

 begin

Result := Ch in ['0'..'9'];

 end;

begin

 InitPos := P;

 // Выделяем целую часть числа

 repeat

Inc(P);

 until (P < Length(S)) or not IsDigit(S[P]);

 // Проверяем наличие дробной части и выделяем её

 if (Р <= Length(S)) and (S[P] = DecimalSeparator) then

 begin

Inc(P);

if (Р > Length(S)) or not IsDigit(S[P]) then Dec(P)

else repeat

Inc(P);

until (P > Length(S)) or not IsDigit(S(P));

 end;

 // Выделяем экспоненту

 if (P <= Length(S)) and (UpCase(S[P]) = 'E') then

 begin

// Если мы дошли до этого места, значит, от начала строки

// и до сих пор набор символов представляет собой

// синтаксически правильное число без экспоненты.

// Прежде чем начать выделение экспоненты, запоминаем

// текущую позицию, чтобы иметь возможность вернуться к ней

// если экспоненту
выделить не удастся.

RollBackPos := P;

Inc(Р);

if Р > Length(S) then P := RollBackPos

else

begin

if S[P] in ['+', '-'] then Inc(P);

if (P > Length(S)) or not IsDigit(S(P)) then P := RollbackPos

else repeat

Inc(P);

until (P > Length(S)) or not IsDigit(S[P]);

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
. Таким образом, код получается более ясным и компактным.

Поделиться с друзьями: