2016-12-04 6 views
0

Я пишу калькулятор, который относительно близок к калькулятору Stroustrup. У меня есть два вопроса. Самый большой из них: как вы можете правильно вычислить калькулятор рядом с круглыми скобками? Если I физически, добавьте символ умножения между числом и скобками, которые он правильно оценивает. Однако я не думаю, что это правильный способ сделать это. В настоящее время (9 + 5) 3 = 14 = 3 ... (9 + 5) * 3 = 42 Вот мой текущий код:Выполнение калькулятора C++, который правильно оценивает (9 + 8) 7

#include "Calculator.h" 

Calculator::Calculator(){ 

} 

Calculator::~Calculator(){ 

} 

void Calculator::Token_stream::putback(Calculator::Token t){ 
    if(full) error("putback() into a full buffer"); 
    buffer = t; 
    full = true; 
} 

Calculator::Token Calculator::Token_stream::get(){ 
    if(full){full = false;return buffer;} 

    char ch; 
    cin>>ch; 

    switch(ch){ 
    case'(': 
    case ')': 
     case '+': 
     case '-': 
     case '*': 
     case '/': 
    case print: 
    case '=': 
       return Token{ch};  // let each character represent itself 
     case '.': 
     case '0': 
     case '1': 
     case '2': 
     case '3': 
     case '4': 
     case '5': 
     case '6': 
     case '7': 
     case '8': 
     case '9': 
    { 
       cin.unget();   // put digit back into the input stream 
       double val; 
       cin >> val;    // read a floating-point number 
       return Token(number,val); // let '8' represent "a number" 
     } 
     default: 
     if (isalpha(ch)){ 
      string s; 
      s += ch; 
      while(cin.get(ch) && (isalpha(ch) || isdigit(ch))) s=ch; 
      cin.unget(); 
      if (s == "let"); return Token(let); 
      if (s == "quit") return Token(name); 
      return Token(name,s); 
     } 
       error("Bad token"); 
     } 
} 

void Calculator::Token_stream::ignore(char c){ 
    if(full && c == buffer.kind){ 
     full = false; 
     return; 
    } 
    full = false; 

    char ch; 
    while (cin>>ch) 
     if (ch == c) return; 
} 

double Calculator::get_value(string s){ 
    for(int i = 0; i < names.size(); ++i) 
     if (names[i].name == s) return names[i].value; 
    error("get: undefined name ", s); 
} 

void Calculator::set_value(string s, double d){ 
    for(int i = 0; i<=names.size();++i){ 
     if (names[i].name == s) { 
      names[i].value = d; 
      return; 
     } 
    } 
    error("set: undefined name ",s); 
} 

bool Calculator::is_declared(string s){ 
    for(int i = 0; i<names.size(); ++i) 
     if (names[i].name == s) return true; 
    return false; 
} 

Calculator::Token Calculator::get_token(){ 
    char ch; 
    cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.) 

    switch (ch) { 
//not yet case ';': // for "print" 
//not yet case 'q': // for "quit" 
    case '(': 
    case ')': 
    case '+': 
    case '-': 
    case '*': 
    case '/': 
      return Token(ch);  // let each character represent itself 
    case '.': 
    case '0': 
    case '1': 
    case '2': 
    case '3': 
    case '4': 
    case '5': 
    case '6': 
    case '7': 
    case '8': 
    case '9': 
     {  
     cin.putback(ch);   // put digit back into the input stream 
     double val; 
     cin >> val;    // read a floating-point number 
     return Token('8',val); // let '8' represent "a number" 
     } 
    default: 
      error("Bad token"); 
     } 
} 

double Calculator::statement(){ 
    Token t = ts.get(); 
    switch(t.kind){ 
    case let: 
     return declaration(); 
    default: 
     ts.unget(t); 
     return expression(); 
    } 
} 

double Calculator::declaration(){ 
    Token t = ts.get(); 
    if(t.kind != name) error ("name expected in declaration"); 
    string a_name = t.name; 
    if (is_declared(a_name)) error(a_name, "declared twice"); 
    Token t2 = ts.get(); 
    if (t2.kind != '=') error("= missing in declaration of " ,a_name); 
    double d = expression(); 
    names.push_back(Variable(a_name,d)); 
    return d; 
} 

double Calculator::expression(){ 
    double left = term(); 
    while (true){ 
     Token t = ts.get(); 
     switch(t.kind){ 
     case '+': 
      left += term(); 
      break; 
     case '-': 
      left -= term(); 
      break; 
     default: 
      ts.unget(t); 
      return left; 
     } 
    } 
} 

double Calculator::term() { 
    double left = primary(); 
    while(true){ 
     Token t = ts.get(); 
     switch(t.kind){ 
     case '*': 
      left *= primary(); 
      break; 
     case '/': 
     { 
     double d = primary(); 
     if (d == 0) error ("divide by zero"); 
     left /=d; 
     break; 
     } 
     default: 
      ts.unget(t); 
      return left; 
     } 
    }  
} 

double Calculator::primary(){ 
    Token t = ts.get(); 
    switch(t.kind){ 
     case '(': 
      { 
      double d = expression(); 
      t = ts.get(); 
      if(t.kind!=')') error("')' expected"); 
      return d; 
      } 
     case '-': 
      return - primary(); 
     case number: 
      return t.value; 
     case name: 
      return get_value(t.name); 
     default: 
      error("Primary expected"); 
    } 
} 

void Calculator::clean_up_mess(){ 
    ts.ignore(print); 
} 

void Calculator::calculate(){ 
    while(true){ 
     try{ 
      cout << prompt; 
      Token t = ts.get(); 
      while (t.kind == print) t=ts.get(); 
      if (t.kind == quit) return; 
      ts.unget(t); 
      cout<<result<<statement()<<endl; 
     } 
     catch(runtime_error& e){ 
      cerr<<e.what()<<endl; 
      clean_up_mess(); 
     } 
    } 
} 
+0

Это правильный способ сделать это. Скобки в программировании не совпадают с круглыми скобками по математике. –

+0

@EliSadoff Калькуляторы обычно не предназначены для программирования. –

+0

В калькуляторе :: term() вам нужно обрабатывать два последовательных праймера так же, как вы обрабатываете два первичных элемента, разделенных символом '*'. –

ответ

-1

Попробуйте это изменение

double Calculator::term() { 
    double left = primary(); 
    while(true){ 
     Token t = ts.get(); 
     switch(t.kind){ 
     case '*': 
      left *= primary(); 
      break; 
     case '/': 
     { 
     double d = primary(); 
     if (d == 0) error ("divide by zero"); 
     left /=d; 
     break; 
     } 
     default: 
      ts.unget(t); 
      // need to handle a primary here 
      // the same way as '*' followed by a primary 
      // a primary in this context can start with a 
      // '(' or be a number or a name 
      // but '-' can't be here 
      // because x-y is not interpreted as x * (-y) 
      if (t.kind == number || t.kind == name || t.kind == '(') 
       left *= primary(); 
      else 
       return left; 
     } 
    } 
} 
+0

Я бы предпочел ваш ответ с объяснением вне кода и без последних двух строк комментария. У вас тоже не может быть '+'. – EJP

+0

Вы - бог среди мужчин сэр и или мадам. –

+0

@EJP Unary - обрабатывается под первичным в этом калькуляторе, поэтому его нужно упомянуть. Там нет унарного +, поэтому + не может начать первичный. –