Inc(P);
while (P <-=Length(S)) and (S[P) <> '}') do Inc(P);
if P > Length(S) then
raise ESyntaxError.Create('Незавершенный комментарий');
Inc(P);
end
else Inc(P);
end;
// Функция выделяет одну лексему и помещает ее в список
procedure TLexicalAnalyzer.ExtractLexeme(const S: string; var P: Integer);
begin
if P > Length(S) then Exit;
case S[P] of
'(': begin
PutLexeme(ltLeftBracket, P, '');
Inc(P);
end;
')': begin
PutLexeme(ltRightBracket, P, '');
Inc(P);
end;
'*': begin
PutLexeme(ltAsterisk, P, '');
Inc(P);
end;
'+': begin
PutLexeme(ltPlus, P, '');
Inc(P);
end;
'-': begin
PutLexeme(ltMinus, P, '');
Inc(P);
end;
'/': begin
PutLexeme(ltSlash, P, '');
Inc(P);
end;
'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
. Таким образом, код получается более ясным и компактным.
Читать дальше
Конец ознакомительного отрывка
Купить книгу