Новости           

Программы

Turbo Pascal

Игры

Документация

"Странности"

FAQ

Ссылки

Благодарности

Гостевая книга

От автора

ПРОСТАЯ ПРОГРАММА СИНТАКСИЧЕСКОГО РАЗБОРА ВЫРАЖЕНИЙ

              В оставшейся части данной главы рассматриваются две програм-
         мы  синтаксического  разбора.  Первая осуществляет синтаксический
         разбор и вычисление  константных  выражений.  Это  синтаксический
         разбор  самого  простого  вида.  Второй синтаксический анализатор
         принимает до 26 задаваемых пользователем переменных от А до Z.
              Далее целиком  приводится простая версия программы рекурсив-
         ного нисходящего синтаксического разбора для целых выражений. Она
         принимает   те  же  самые  глобальные  данные,  что  и  процедура
         GetToken, показанная ранее.

          {********** синтаксический анализатор выражений  *************}
             procedure Level2(var result: real); forward;
             procedure Level3(var result: real); forward;
             procedure Level4(var result: real); forward;
             procedure Level5(var result: real); forvard;
             procedure Level6(var result: real); forward;
             procedure Primitve(var result: real); forward;

             {это точка входа в синтаксический анализатор }
             procedure GetExp(var result: real);
             begin
               GetToken;
               if length(token)<>0 then
                Level2(result)
               else
                Serror(3);
             end; {GetExp}

             {процесс + или - }
             procedure Level2;
             var
               op: char;
               hold: real;

             begin
               Level3(result);
               op: = token[1];
               while((op='+') or (op='-') do
               begin
                GetToken;
                Level3(hold);
                arith(op, result, hold);
                op: = token[1]
               end;
             end; {Level2}

             {процесс * или \ }
             procedure Level3;
             var
               op: char;
               hold: real;

             begin
               Level4(result);
               op: = token[1];
               while ((op '*') or (op='/')) do
               begin
                GetToken;
                Level4(hold);
                arith(op, result, hold);
                op: = token[1];
               end;
             end; {Level3}

              {процесс ^ (возведение в степень)}
              procedure Level4;
              var
                hold: real;

              begin
                Level5(result);
                if token[1]='^' then
                begin
                 GetToken;
                 Level4(hold);
                 arith('^', result, hold); {exponents}
                end;
              end; {Level4}

              {процесс унарного оператора}
              procedure Level5;
              var
                op: char;

              begin
                op: = ' ';
                if((TokType=DELIMITER) and ((token[1]='+') or
                (token[1]='-')))
                then begin {unary plus or minus}
                 op:= token[1];
                 GetToken;
                end;
                Level6(result);
                if op='-' then result: = -result;
              end; {Level5}

              {процесс скобок }
              procedure Level6;
              begin
              if(token[1]='(') and (TokType=DELIMITER) then
              begin {Parenthesized expression}
                GetToken;
                Level2(result);
                if token[1]<>')'then Serror(2);{скобки не сбалансированы}
                GetToken;
               end
               else Primitive(result);
              end; {Level6}

              { найти значение числа}
              procedure Primitive;
              begin
                if TokType=DELIMITER then
                 val(token, result, code)
                else Serror(1);
                GetToken;
              end.

              Программа, как показано,  может принимать операторы +,-,*  и
         /,  а также возведение в степень (^), унарный минус и скобки. Она
         имеет шесть уровней, а также функцию Primilive, которая возвраща-
         ет значение целого числа. Команда foevard необходима, так как не-
         которые из этих процедур взаимно  рекурсивны,  следовательно,  не
         возможно определить все процедуры до обращения к ним.
              В дополнение к синтаксическому анализатору  существует  нес-
         колько процедур для специальных целей: Serror, которая сообщает о
         синтаксических ошибках,  Pwr и Arith, которые выполняют различные
         арифметические операции. Эти подпрограммы показаны далее:

              {отображение  сообщений  об  ошибках }
              Procedure Serror(i: integer);
              begin
                case i of
                 1: WriteLn('синтаксическая ошибка    ');
                 2: WriteLn('несбалансированные скобки');
                 3: WriteLn('выражение  отсутствует   ');
                end;
              end; {Serror}

              {возведение в степень }
              function Pwr(a, b: real): real;
              var
                t: integer;
                temp: real;
              begin
                if a=0 then Pwr: = 1 else
                begin
                 temp: = a;
                 for t: = trunc(b) cownto 2 do a: = a*temp;
                 Pwr: = a;
                end;
              end;

              {данная функция выполняет заданные арифметические операции}
              procedure Arith(op: char; var result, operand: real);
              begin
                case op of
                 '+': result: = result+operand;
                 '-': result: = result-operand;
                 '*': result: = result*operand;
                 '/': result: = result/operand;
                 '^': result: = result^operand;
                end;
              end; {Arith}

              Как показано ранее,  в двух глобальных  переменных  token  и
         TokType  возвращаются  очередная лексема и ее тип,  а строка prog
         содержит выражение.
              Далее представлен  синтаксический  анализатор  с процедурами
         поддержки,  а также простые программы, которые могут быть исполь-
         зованы для демонстрации синтаксического анализатора.
              { Данная программа демонстрирует работу синтаксического
               анализатора. Она не принимает  переменных  и  поддерживает
                    числа только типа real (действительные)}

              program parser;

              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}

              {отображение  сообщений  об  ошибках }
              Procedure Serror(i: integer);
              begin
                case i of
                 1: WriteLn('синтаксическая ошибка    ');
                 2: WriteLn('несбалансированные скобки');
                 3: WriteLn('выражение  отсутствует   ');
                end;
              end; {Serror}

              {возведение в степень }
              function Pwr(a, b: real): real;
              var
                t: integer;
                temp: real;
              begin
                if a=0 then Pwr: = 1 else
                begin
                 temp: = a;
                 for t: = trunc(b) cownto 2 do a: = a*temp;
                 Pwr: = a;
                end;
              end;

              {данная функция выполняет заданные арифметические операции}
              procedure Arith(op: char; var result, operand: real);
              begin
                case op of
                 '+': result: = result+operand;
                 '-': result: = result-operand;
                 '*': result: = result*operand;
                 '/': result: = result/operand;
                 '^': result: = result^operand;
                end;
              end; {Arith}


          {********** синтаксический анализатор выражений  *************}
              procedure Level2(var result: real); forward;
              procedure Level3(var result: real); forward;
              procedure Level4(var result: real); forward;
              procedure Level5(var result: real); forward;
              procedure Level6(var result: real); forward;
              procedure Primitive(var result: real); forward;

             {это точка входа в синтаксический анализатор }
              procedure GetExp(var result: real);
              begin
                GetToken;
                if Length(token)<>0 then
                 Level2(result)
                else
                 Serror(3);
              end; {GetExp}

             {процесс + или - }
              procedure Level2;
              var
                op: char;
                hold: real;

              begin
                Level3(result);
                op:= token[1];
                while(op='+') or (op='-') do
                begin
                 GetToken;
                 Level3(hold);
                 arith(op, result, hold);
                 op: = token[1];
                end;
              end; {Level2}


             {процесс * или \ }
              procedure Level3;
              var
                op: char;
                hold: real;

              begin
                Level4(result);
                op: = token[1];
                while (op='*') or (op='/') do
                begin
                 GetToken;
                 Level4(hold);
                 arith(op,result,hold);
                 op: = token[1];
                end;
              end; {Level3}

              {процесс ^ (возведение в степень)}
              procedure Level4;
              var
                hold: real;

              begin
                Level5(result);
                if token[1]='^' then
                begin
                 GetToken;
                 Level4(hold);
                 arith('^',result,hold); {exponents}
                end;
              end; {Level4}

              {процесс унарного оператора}
              procedure Level5;
              var
                op: char;

              begin
                op: = ' ';
                if((TokType=DELIMITER) and ((token[1]='+') or
                                      (token[1]='-')))
                then begin

                 op: = token[1],
                 GetToken;
                end;
                Level6(result);
                if op='-' then result: = -result;
              end; {Level5}

              {процесс скобок }
              procedure Level6;
              begin
                if(token[1]='(') and (TokType=DELIMITER) then
                begin {заключенное в скобки  выражение }
                  GetToken;
                  Level2(result);
                if token[1]<>')'then Serror(2);{несбалансированные
                                   скобки}

                  GetToken;
                end
                else Primitive(result);

              end; {Level6}

              { найти значение числа }
              procedure Primitive;
              begin
                if TokType=NUMBER then
                 val(token, result, code)
                else Serror(1);
                GetToken;
              end;

              begin {nain}
                repeat
                 t:=1; {инициализировать счетчик лексем }
                 Write('Введите выражение: ');
                 ReadLn(prog);
                 prog:=concat(prog, '$');
                 if(prog<>'quit$') then
                 begin
                   GetExp(result);
                   writeLn(result);
                 end;
                until prog='quit$'
              end.

              Программа позволяет вам ввести численное выражение,  для ко-
         торого  она  вычислит ответ.  Для выхода из программы напечатайте
         QUIT.
              Для понимания того,  как синтаксический анализатор вычисляет
         выражение,  поработайте  со  следующим выражением,  которое после
         приема содержится в prog:

                                10-3*2

              Когда вызывается  GetExp  (начальная  процедура  в синтакси-
         ческом анализаторе),  она берет первую лексему и,  если она явля-
         ется пустой,  печатает сообщение no expression present (выражение
         отсутствует) перед возвратом. Если лексема присутствует, то вызы-
         вается  level2 (level1 будет добавлена к синтаксическому анализа-
         тору позднее,  когда будет добавлен оператор назначения, а сейчас
         она не нужна).
              Лексема теперь содержит число 10.  level2 вызывает level3, а
         level3  вызывает level4,  которая в свою очередь вызывает level5.
         level5 проверяет, является ли лексема унарным оператором + или -;
         в данном случае это не так и,  поэтому, вызывается level6. level6
         рекурсивно вызывает level2 в случае заключенного в скобки выраже-
         ния или вызывает Primitive для нахождения целого значения.  Нако-
         нец,  когда Primitive  выполнится  и  значение  10  поместится  в
         reselt, процедура GetToken получит следующую лексему. Затем функ-
         ции начнут возвращать управление назад по цепочке. Теперь лексема
         - это оператор "-" и функции возвратятся до level2.
              Следующий шаг очень важен.  Так как лексемой является опера-
         тор  "-",  она  сохраняется  и GetToken получает новую лексему 3;
         нисходящая  вниз  цепочка  начинается  вновь.  Снова   вызывается
         Primitive, целое число 3 возвращается в result и считывается лек-
         сема *.  В данном случае управление возвращается  к  Level3,  где
         считывается финальная лексема 2.  В этой точке совершается первая
         арифметическая операция умножения 2 на 3.  Этот  результат  затем
         возвращается  к level2 и выполняется вычитание,  которое дает ре-
         зультат 4.
              Хотя процесс сначала может показаться запутанным,  вы должны
         проработать другие примеры для самопроверки.
              Вы могли бы использовать этот синтаксический анализатор, как
         настольный калькулятор.  Вы также могли бы использовать его в ба-
         зах данных и других не сложных случаях. Прежде, чем можно было бы
         применить его в языках и  сложных  калькуляторах,  синтаксический
         анализатор  должен быть способен поддерживать переменные, которые
         являются предметом следующего раздела.
         

(с)Все права защищены

По всем интересующим вопросампрошу писать на электронный адрес

    Rambler's Top100 PROext: Top 1000
    Rambler's Top100 Яндекс цитирования
Hosted by uCoz