//************************************************************************* // File name : dc.cpp // Description : A simple desk calculator // Related files : None // Compiler : GNU C++ 2.9.5.2 // Author : Suradet Jitprapaikulsarn // First Edit : 1999 November 2 // Reference : Bjarne Stroustrup // The C++ Programming Language, 3rd Edition // Addison Wesley, 1997 // ISBN 0-201-88954-4 // Chapter 6, Expressions and Statements // Page 107- // Modification //************************************************************************* //************************************************************************* // The grammar for the language accepted by the calculator // program: // END // END is end-of-input // expr_list END // expr_list: // expression PRINT // PRINT is semicolon // expression PRINT expr_list // expression: // expression + term // expression - term // term // term: // term / primary // term * primary // primary // primary: // NUMBER // NAME // NAME = expression // - primary // (expression) //************************************************************************* #include #include #include #include #include //************************************************************************* // Global defintions //************************************************************************* 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; int no_of_errors; map table; istream *input; // pointer to input stream //************************************************************************* // Function Prototypes //************************************************************************* double expr(bool); // add and substract double term(bool); // multiply and divide double prim(bool); // handle primaries double error(const string&); // error handling Token_value get_token(); // input function //************************************************************************* // main function //************************************************************************* int main(int argc, char* argv[]) { switch (argc) { case 1: // read from standard input input = &cin; break; case 2: // read argument string input = new istrstream(argv[1]); break; default: error("too many arguments"); return 1; } // switch table["pi"] = 3.141592653897932385; // insert predefined names table["e"] = 2.7182818284590452354; while (*input) { get_token(); if (curr_tok == END) break; if (curr_tok == PRINT) continue; cout << expr(false) << '\n'; } // while if (input != &cin) delete input; return no_of_errors; } //************************************************************************* // Function name : expr // Description : Handle expression // Paremeter : get = a flag to get the next token // Pre-condition : // Post-condition : //************************************************************************* double expr(bool get) // add and substract { double left = term(get); for(;;) // "forever" { switch (curr_tok) { case PLUS: left += term(true); break; case MINUS: left -= term(true); break; default: return left; } // switch } // for } //************************************************************************* // Function name : term // Description : Handle term // Paremeter : get = a flag to get the next token // Pre-condition : // Post-condition : //************************************************************************* 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 /= d; break; } // if return error("divide by 0"); default: return left; } // switch } // for } //************************************************************************* // Function name : prim // Description : Handle primary // Paremeter : get = a flag to get the next token // Pre-condition : // Post-condition : //************************************************************************* double prim(bool get) { if (get) get_token(); switch (curr_tok) { case NUMBER: // floating-point constant { 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: // unary minus return -prim(true); case LP: { double e = expr(true); if (curr_tok != RP) return error(") expected"); get_token(); // eat ')' return e; } default: return error("primary expected"); } // switch } //************************************************************************* // Function name : get_token // Description : read token from input // Paremeter : None // Pre-condition : None // Post-condition : a token is retrieved from input //************************************************************************* Token_value get_token() { char ch = 0; do { // skip whitespace except '\n' if (!input->get(ch)) return curr_tok = END; } while (ch != '\n' && isspace(ch)); switch (ch) { case 0: return curr_tok = END; case ';': case '\n': return curr_tok = PRINT; 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 '.': input->putback(ch); *input >> number_value; return curr_tok = NUMBER; default: // NAME, NAME=, or error if (isalpha(ch)) { string_value = ch; while(input->get(ch) && isalnum(ch)) string_value += ch; input->putback(ch); //---------------------------------- // If "quit" is enter, end program //---------------------------------- if (string_value == "quit") return curr_tok = END; return curr_tok = NAME; } // if error("bad token"); return curr_tok = PRINT; } // switch } //************************************************************************* // Function name : error // Description : handling error // Paremeter : s = error message // Pre-condition : None // Post-condition : None //************************************************************************* double error(const string& s) { no_of_errors++; cerr << "error: " << s << '\n'; return 1; }