Новости           

Программы

Turbo Pascal

Игры

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

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

FAQ

Ссылки

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

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

От автора

Добавление переменных к синтаксическому анализатору 

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

              varsi array[0..25] of real; { 26 переменных }

              Однако, перед тем,  как начать использовать эти  переменные,
         вам следует установить их в 0.
              Вам также нужна процедура для нахождения значения данной пе-
         ременной.  Так как вы используете буквы от А до Z в качестве имен
         переменных,  вы можете легко индексировать по матрице vars на ос-
         нове имени переменной. Далее представлена функция FindVar:

              function FinVar(s: str80): real;
              var
                t: integer;
              begin
                FinVar:=vars[ord(Upcase(s[1]))-ord('A')];
              end; {FindVar}

         Как вы видите,  данная функция может принимать  имена  переменных
         любой длины, но значащей в имени является только первая буква. Вы
         можете модифицировать данную функцию, чтобы она удовлетворяла ва-
         шим нуждам.
              Вы должны также модифицировать функция primitive,  чтобы она
         трактовала и числа и переменные,  как примитив, следующим образом
              procedure Primitive;
              begin
                if TokType=NUMBER then
                 val(token, result, code)
                else if TokType=VARIABLE then
                 result:=FindVar(token)
                else
                 Serror(1);
                GetToken;
              end.
              Все это необходимо, чтобы синтаксический анализатор мог пра-
         вильно использовать переменные;  однако, отсутствует способ прис-
         ваивания значений переменным.  Вы можете назначить значения пере-
         менным   вне  синтаксического  анализатора,  но,  так  как  можно
         трактовать=,  как оператор присваивания,  вы  имеете  возможность
         сделать его частью синтаксического анализатора различными метода-
         ми.  Один из них состоит в том, чтобы добавить level1 к синтакси-
         ческому анализатору, как показано далее:
              { процесс предложения присваивания }
              procedure Level1;
              var
                hold: real;
                temp: Type;
                slot: integer;
                TempToken: str80;

              begin
                if TokType=VARIABLE then
                begin
                 {сохранить  старую лексему}
                 TempToken:=token;
                 temp:=TokType;
                 slot:=ord(Upcase(token[1]))-ord)'A');
                 GetToken; {проверить,существует ли = для присваивания }
                  if token[1]<>'"' then
                 begin
                   PutBack; {заменить лексему }
                   {восстановить старую лексему}
                   token := TempToken;
                   TokType := temp;
                   Level2(result);
                 end else
                 begin
                   GetToken;
                   Level2(result);
                   vars[slot] := result;
                 end;
                end {if}
                else Level2(result);
              end; {Level1}

              Когда переменная встречается как первая лексема в выражении,
         она может быть либо целью выражения, как в
              А=В*10
         либо просто частью выражения
              А-123
              В level1,
         чтобы знать,  что из себя представляет переменная,  должен выпол-
         няться просмотр вперед.  Просмотр вперед - это процесс, сохраняю-
         щий  текущую лексему и затем получающий следующую для анализа.  В
         данном случае,  если существующая лексема - это =,  то вы знаете,
         что будет выполняться присваивание, и выполняются соответствующие
         процедуры.  Если это не =,  то лексема будет возвращена  назад  в
         строку выражения, а предыдущая лексема должна быть восстановлена.
         Вы можете сделать это с помощью процедуры Putbacl, которая просто
         уменьшает индекс t.  Как вы можете видеть, "просмотр вперед" тре-
         бует определенного времени и его следует в общем случае избегать,
         исключая случаи, когда он абсолютно необходим.
              Далее представлены целиком расширенный синтаксический анали-
         затор, вспомогательные функции и главная программа:
              {данная программа демонстрирует синтаксический анализатор
               который допускает применение переменных  }
              program parser2;

              type
                str80 = string[80];
                TType = (DELIMITER, VARIABLE, NUMBER);
              var
                token, prog: str80;
                TokType: TType;
                code, t: integer;
                result: real;
                vars: array[0..25] of real; {26 переменных}

             {данная функция возвращает 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}

              { PutBack возвращает лексему во входной поток }
              procedure PutBack;
              begin
                t := t-length(token);
              end; {PutBack}

              {отображение  сообщений  об  ошибках }
              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}

              {FindVar возвращает значение переменной}
              function FindVar(s: str80): real;
              var
                t: integer;
              begin
                FindVar:=vars[ord(Upcase(s[1]))-ord('A')];
              end; {FindVar}


          {********** синтаксический анализатор выражений  *************}
              {**** with variables and assignment *******}
              procedure Level2(var result: real); forward;
              procedure Level1(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
                 Level1(result)
                else
                 Serror(3);
              end; {GetExp}

              { процесс предложения присваивания }
              procedure Level1;
              var
                hold: real;
                temp: Type;
                slot: integer;
                TempToken: str80;

              begin
                if TokType=VARIABLE then
                begin
                 {сохранить  старую лексему}
                 TempToken:=token;
                 temp:=TokType;
                 slot:=ord(Upcase(token[1]))-ord)'A');
                 GetToken; {проверить,существует ли = для присваивания }
                  if token[1]<>'"' then
                 begin
                   PutBack; {заменить лексему }
                   {восстановить старую лексему}
                   token := TempToken;
                   TokType := temp;
                   Level2(result);
                 end else
                 begin
                   GetToken;
                   Level2(result);
                   vars[slot] := result;
                 end;
                end {if}
                else Level2(result);
              end; {Level1}

             {процесс + или - }
              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);
                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 if TokType=VARIABLE then
                   result := FindVar(token)
                else
                   Serror(1);
                GetToken;
              end;

              begin {главная}
                for t:=0 to 25 do vars[t]:=0; {инициализировать
                                 переменные}

                repeat
                 t := 1;
                 Write('Введите выражение: '); 38
                 ReadLn(prog);
                 prog := concat(prog, '$');
                 if(prog<>'quit$') then
                 begin
                   GetExp(result);
                   writeLn(result);
                 end;
                until prog='quit$';
              end.

              Теперь при  расширенном синтаксическом анализаторе вы можете
         ввести такие выражения, как
              А=10/4
              А-В
              С=А*(Р-21)
         и они будут вычислены правильно.

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

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

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