w72er

Калькулятор

w72er | 18 Январь, 2010 08:56

Код калькулятора, приведенный в главе 6, применяется повсеместно в книге Бьерна Страуструпа "Язык программирования c++". 

/*
program:
  END                         //это конец ввода
  expr_list
expr_list:                      //список выражений
  expression PRINT            //PRINT - это точка с запятой
  expression PRINT expr_list
expression:                     //выражение
  expression + term
  expression - term
  term
term:                           //терм
  term / primary
  term * primary
  primary
primary:                        //первичное выражение
  NUMBER                      //число
  NAME                        //имя
  NAME = expression
  -primary
  (expression)

Терминальные символы распознаются лексическим анализатором,
get_token(); Нетерминальные символы распознаются синтаксическим
анализатором, expr(), term(), prim(); Как только оба (под)выражения
определены вычисляется значение выражения.
*/


#include <iostream>
#include <string>
#include <map>
#include <cctype>

using namespace std;


enum Token_value {
  NAME, NUMBER, END,
  PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
  PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};

Token_value curr_tok = PRINT;
double number_value;  //численное значение
string string_value;  //строковое значение
map<string, double> table;
int no_of_errors;

 

int error(const string& s)
{
  no_of_errors++;
  cerr << "ошибка: " << s << '\n';
  return 1;
}


Token_value get_token()
{
  char ch = 0;
  cin >> ch;

  switch (ch) {
  case 0:
    return curr_tok = END;
  case ';':
  case '*':
  case '/':
  case '+':
  case '-':
  case '(':
  case ')':
  case '=':
    return curr_tok = Token_value(ch);
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
  case '.':
    cin.putback(ch);
    cin >> number_value;
    return curr_tok = NUMBER;
  default:
    if (isalpha(ch)) {
      cin.putback(ch);
      cin >> string_value;
      return curr_tok = NAME;
    }
    error("неправильная лексема");
    return curr_tok = PRINT;
  }
}


double expr(bool);


double prim(bool get)  //первичные выражения
{
  if (get) get_token();

  switch (curr_tok) {
  case NUMBER:
  {
    double v = number_value;
    get_token();
    return v;
  }
  case NAME:
  {
    double& v = table[string_value];
    if (get_token() == ASSIGN) v = expr(true);
    return v;
  }
  case MINUS:
    return -prim(true);
  case LP:
  {
    double e = expr(true);
    if (curr_tok != RP) return error("ожидалась )");
    get_token(); //пропустить ")"
    return e;
  }
  default:
    return error("ожидалось первичное выражение");
  }
}

 

double term(bool get) //умножение и деление
{
  double left = prim(get);

  for (;;)
    switch (curr_tok) {
    case MUL:
      left *= prim(true);
      break;
    case DIV:
      if (double d = prim(true)) {
        left /= prim(true);
        break;
      }
      return error("деление на 0");
    default:
      return left;

    }
}


double expr(bool get)
{
  double left = term(get);
  for (;;)
    switch (curr_tok) {
    case PLUS:
      left += term(true);
      break;
    case MINUS:
      left -= term(true);
      break;
    default:
      return left;
    }
}

 

int main()
{
  table["pi"] = 3.14;
  table["e"] = 2.72;
  while (cin) {
    get_token();
    if (curr_tok == END) break;
    if (curr_tok == PRINT) continue;
    cout << expr(false) << '\n';
  }

  return no_of_errors;
}

 
Бесплатный хостинг блогов - blogbin.net