Энциклопедия Turbo Pascal. Главы 5-8
Страница 33. Разбор выражения


Разбор выражения

     Прежде, чем вы сможете развернуть синтаксический разбор, ко-
торый вычисляет выражения, вы должны для облегчения выделить эле-
менты выражения. Например, в данном выражении

                     А*В-(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    число
      $      $

 
« Предыдущая статья   Следующая статья »