Прежде, чем вы сможете развернуть синтаксический разбор, ко-
торый вычисляет выражения, вы должны для облегчения выделить эле-
менты выражения. Например, в данном выражении
А*В-(w+10)
вы должны быть способны выделить операнды A,B,W и 10, скобки и
операторы *, + и -. В данном случае вам нужна процедура, которая
возвращает каждый элемент выражения в отдельности. Данная проце-
дура также должна пропускать пробелы и табуляции и обнаруживать
конец выражения. Формально каждый элемент выражения называется
лексемой (lcken). Следовательно, функция, которая возвращает оче-
редную лексему выражения, называется CetToken. Для хранения выра-
жения нужна глобальная переменная. Данная символьная переменная
называется prog. Переменная prog является глобальной, так как она
должна устанавливаться между вызовами CetToken и должна позволять
другим функциям использовать ее. В дополнении к prog используется
глобальная целая переменная t в качестве индекса по prog, позво-
ляя CetToken продвигаться по выражению по одной лексеме за раз.
CetToken предполагает, что prog заканчивается символом $. Вы
должны убедиться и в данном случае, что это так в виду того, что
символ $ сигнализирует о конце выражения.
Помимо получения лексемы вам необходимо также знать ее тип.
Для синтаксического разбора, рассматриваемого в данной главе,
достаточно трех типов: VARIABLE (переменная),NUMDER (число) и
DELIMITER (разделитель), где тип DELIMITER используется для опе-
раторов и скобок. Далее показана функция CetToken с необходимыми
глобальными переменными и функциями поддержки:
type
str80 = string[80];
TType = (DELIMITER,VARIABLE,NUMBER);
var
token, prog: str80;
TokType: TType;
code, t: integer;
result: real;
{данная функция возвращает TRUE, если ch является буквой
алфавита}
function IsAlpha(ch: char): boolean;
begin
IsAlpha:= (UpCase(ch)>='A') and (UpCase(ch)<='Z');
end; {IsAlpha}
{данная функция возвращает TRUE, если ch является
символом новой строки, табуляции или пробелом }
function IsWhite(ch: char): boolean;
begin
IsWhite: = (ch=' ') or (ch=chr(9)) or (ch=chr(13));
end; {IsWhite}
{данная функция возвращает TRUE, если ch является
разделителем}
function IsDelim(ch: char): boolean;
begin
if pos(ch, ' +-/*%^=()S')<>0 then IsDelim: = TRUE
end; {IsDelim}
{данная функция возвращает TRUE, если ch - цифра от 0 до 9}
function IsDigit(ch: char): boolean;
begin
IsDigit: = (ch>='0') and (ch<='9');
end; {IsDigit}
{GotToken считывает следующую лексему из входного потока}
procedure GetToken;
var
temp: str80;
begin
token: = ''; {пустая строка }
while(IsWhite(prog[t])) do t:=t+1; {пропустить
предшествующие пробелы}
if prog[t]='S' then token: = 'S';
if pos(prog[t], '+-*/%^=()')<>0 then
begin
TokType: = DELIMITER;
token: = prog[t]; {является оператором }
t: = t+1;
end else if IsAlpha(prog[t]) then
begin
While(not IsDelim(prog[t])) do
begin
token: = concat(token, prog[t]); { построить лексемы }
t: = t+1;
end;
TokType: = VARIABLE;
end
else if IsDigit(prog[t]) then
begin
while(not IsDelim[t])) do
begin
token: = concat(token,prog[t]); { построить число }
t: = t+1;
TokType: = NUMBER;
end;
end;
end;{GetToken}
Прежде, чем данная процедура может быть использована, гло-
бальная переменная t должна быть установлена в 1. Помните, что
эта переменная используется для индексирования по строке prog,
которая содержит входное выражение. При входе в CetToken процеду-
ра проверяет, не равен ли очередной символ $, который указывает
на конец строки выражения. Предваряющие пробелы пропускаются. Хо-
тя пробелы могут быть добавлены в выражение для читабельности,
при синтаксическом разборе они игнорируются.
После пропуска пробелов prog(t) указывает на число, перемен-
ную, оператор или $, если хвостовые пробелы завершают выражение.
Если следующий символ является оператором, то этот символ возвра-
щается как строка в глобальной переменной token и тип DELIMITER
помещается в TokType. Если этот следующий символ является буквой,
то считается, что это переменная; символ возвращается, как строка
в token; TokType принимает значение VARIABLE. Если следующий сим-
вол является числом, то целое число возвращается как строка в
token с типом NUMBER. Наконец, если следующий символ отсутствует,
вы можете считать, что это найден конец выражения, и token прини-
мает значение $.
Чтобы сохранить логическую ясность данной функции, опреде-
ленное количество проверок на ошибки опущено и сделан ряд допуще-
ний. Например, некоторые неопознанные символы отбрасываются. Кро-
ме того, в данной версии переменные могут быть любой длины, но
первым символом должна быть буква. Однако, вы легко можете моди-
фицировать CelToken, чтобы допустить применение символьных строк,
чисел с плавающей запятой или чего-либо еще.
Для того, чтобы понять, как работает CetToken, рассмотрим,
что она возвращает на каждом шаге для выражения А+100-(В*С)/2.
Лексема Тип лексемы
A VARIABLE переменная
+ DELIMITER ограничитель
100 NUMBER число
- DELIMITER ограничитель
( DELIMITER ограничитель
B VARIABLE переменная
* DELIMITER ограничитель
C VARIABLE переменная
) DELIMITER ограничитель
/ DELIMITER ограничитель
2 NUMBER число
$ $