Язык Си в примерах/Калькулятор выражений в обратной польской нотации на Bison

Материал из Викиучебника — открытых книг для открытого мира
Перейти к навигации Перейти к поиску

Язык Си в примерах


  1. Компиляция программ
  2. Простейшая программа «Hello World»
  3. Учимся складывать
  4. Максимум
  5. Таблица умножения
  6. ASCII-коды символов
  7. Верхний регистр
  8. Скобочки
  9. Факториал
  10. Степень числа
  11. Треугольник Паскаля
  12. Корень уравнения
  13. Система счисления
  14. Сортировка
  15. Библиотека complex
  16. Сортировка на основе qsort
  17. RPN-калькулятор
  18. RPN-калькулятор на Bison
  19. Простая грамматика
  20. Задача «Расчёт сопротивления схемы»
  21. Простая реализация конечного автомата
  22. Использование аргументов командной строки
  23. Чтение и печать без использования stdio
  24. Декодирование звукозаписи в формате ADX

Калькулятор на Bison[править]

GNU Bison

Файл с правилами bison[править]

/*  
  file:  rpn.yy
  title: Reverse polish notation calculator rules. 
*/

%{
     #define YYSTYPE double
     #include <math.h>
     #include <stdio.h>
%}

%token NUM 

%% /* Grammar rules and actions follow */


     input:    /* empty */
             | input line
     ; 

     line:     '\n'
             | exp '\n'  { printf ("\t%.10g\n", $1); }
     ;

     exp:      NUM             { $$ = $1;         }
             | exp exp '+'     { $$ = $1 + $2;    }
             | exp exp '-'     { $$ = $1 - $2;    }
             | exp exp '*'     { $$ = $1 * $2;    }
             | exp exp '/'     { $$ = $1 / $2;    }
           /* Exponentiation */
             | exp exp '^'     { $$ = pow ($1, $2); }
           /* Unary minus    */
             | exp 'n'         { $$ = -$1;        }
     ;
%%

Примечание: Пример реально удалось запустить... НО... при выполнении этого примера в VM-Linux под SuSe-11.1 относительно оригинала статьи пришлось сделать следующие изменения:

1. В данный файл описания грамматики(сразу после "#include <stdio.h>" и до "%}") пришлось добавить прототипы ф-ий "yylex", "yyerror" (определенных в «main»):

         int yylex (void);
         int yyerror (const char *s);

2. Вместо команды «cpp» - трансляцию-сборку всего примера пришлось выполнять при помощи команды «c++».

Файл на языке Си с функциями main и yylex[править]

 /*  
   file:  rpn.cc
   title: Tokenizer functions 
           yylex   -- функция разбиения входного потока на токены. 
           yyerror -- функция обработки ошибок
           main    -- главная функция
 */
 #include <stdio.h>
 #include <ctype.h>
 #include "rpn.tab.hh"
 int yyparse(void); 
 
 int yyerror (const char *s)  /* Called by yyparse on error */
 {
     printf ("%s\n", s);
 }
 
 /* Lexical analyzer returns a double floating point
     number on the stack and the token NUM, or the ASCII
     character read if not a number.  Skips all blanks
     and tabs, returns 0 for EOF. */
 int yylex (void)
 {
     int c;
 
     /* skip white space  */
     while ((c = getchar ()) == ' ' || c == '\t')
       ;
     /* process numbers   */
     if (c == '.' || isdigit (c))
     {
         ungetc (c, stdin);
         scanf ("%lf", &yylval);
         return NUM;
      }
      /* return end-of-file  */
      if (c == EOF)
         return 0;
      /* return single chars */
      return c;
 }
 
 int main (void)
 {
     return yyparse ();
 }

Команды компиляции[править]

$ bison -d rpn.yy      # -> produce files rpn.tab.cc  and rpn.tab.hh
$ gcc rpn.tab.cc rpn.cc -lm -o rpn #  produce executable file rpn


Пример использования калькулятора:[править]

$
./rpn
1 2 +
        3
1 2 3 * + 100 +
        107
<Ctrl+D>
$