Страница 33 из 37
Разбор выражения Прежде, чем вы сможете развернуть синтаксический разбор, ко- торый вычисляет выражения, вы должны для облегчения выделить эле- менты выражения. Например, в данном выражении
А*В-(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 число $ $
|