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

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
Строка 49: Строка 49:
НО... при выполнении этого примера в VM-Linux под SuSe-11.1 относительно оригинала статьи пришлось сделать следующие изменения:
НО... при выполнении этого примера в VM-Linux под SuSe-11.1 относительно оригинала статьи пришлось сделать следующие изменения:


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

Версия от 12:15, 15 мая 2012

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


  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
  25. Другие примеры

Калькулятор на 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>
$