// @topic W130210 state machine implementing desktop calculator // @brief state machine implementing desktop calculator // main_sm_calc.cpp #include <cstdlib> #include <stack> #include <iostream> #include <string> #include <sstream> using std::stack; using std::cout; using std::cin; using std::string; using std::stringstream; enum { STATE_OPERATOR_BINARY_PLUS = '+', STATE_OPERATOR_BINARY_MINUS = '-', STATE_OPERATOR_MULTIPLY = '*', STATE_OPERATOR_DIVIDE = '/', STATE_OPERATOR_EXPR_TERMINATOR = ';', STATE_CLEAR = 1000, STATE_GET_NEXT_TOKEN, STATE_NUMBER, STATE_CIN_CLOSED, STATE_ERROR_BAD_NUMBER, STATE_EXIT }; void calculate_and_display_the_result( stack< int >& operators, stack< int >& operands ) { int op1 = 0; int op2 = 0; cout << "\t result = "; while ( operators.size() ) { switch ( operators.top() ) { case STATE_OPERATOR_BINARY_PLUS: if ( operands.size() < 2 ) { cout << "ERROR: Binary operator \'" << operators.top() << "\' requires two operands\n"; return; } op2 = operands.top(); operands.pop(); op1 = operands.top(); operands.pop(); operands.push( op2 + op1 ); cout << " " << op2 << char( operators.top() ) << op1 << " = "; break; case STATE_OPERATOR_BINARY_MINUS: if ( operands.size() < 2 ) { cout << "ERROR: Binary operator \'" << operators.top() << "\' requires two operands\n"; return; } op2 = operands.top(); operands.pop(); op1 = operands.top(); operands.pop(); operands.push( op2 - op1 ); cout << " " << op2 << char( operators.top() ) << op1 << " = "; break; case STATE_OPERATOR_MULTIPLY: if ( operands.size() < 2 ) { cout << "ERROR: Binary operator \'" << operators.top() << "\' requires two operands\n"; return; } op2 = operands.top(); operands.pop(); op1 = operands.top(); operands.pop(); operands.push( op2 * op1 ); cout << " " << op2 << char( operators.top() ) << op1 << " = "; break; case STATE_OPERATOR_DIVIDE: if ( operands.size() < 2 ) { cout << "ERROR: Binary operator \'" << operators.top() << "\' requires two operands\n"; return; } op2 = operands.top(); operands.pop(); op1 = operands.top(); operands.pop(); if ( op2 == 0 ) { cout << "ERROR: Division by zero is illegal\n"; return; } operands.push( op2 / op1 ); cout << " " << op2 << char( operators.top() ) << op1 << " = "; break; default: cout << "ERROR: Unexpected operator \'"<< char( operators.top() ) << "\'\n"; return; } operators.pop(); } if ( operands.size() != 1 ) { cout << "ERROR: bad arithmetic expression syntax\n"; return; } cout << "\t" << operands.top() << "\n"; } int main() { //int result = 0; int number = 0; string input; stack< int > states; stack< int > operands; stack< int > operators; states.push( STATE_CLEAR ); while ( states.size() > 0 ) { int state = states.top(); // get next state if ( state == STATE_EXIT ) { break; } states.pop(); // remove current state from the stack switch ( state ) { case STATE_CLEAR: while ( operands.size() ) operands.pop(); while ( operators.size() ) operators.pop(); states.push( STATE_GET_NEXT_TOKEN ); break; case STATE_CIN_CLOSED: cout << "Input stream has closed, exiting...\n"; states.push( STATE_EXIT ); break; case STATE_GET_NEXT_TOKEN: if ( cin >> input ) { // parse and process input token: if ( input == "q" || input == "Q" || input == "quit" ) states.push( STATE_EXIT ); else if ( isdigit( input[ 0 ] ) ) states.push( STATE_NUMBER ); else if ( input.length() > 1 ) states.push( STATE_NUMBER ); // assume any multi-character token is a number else if ( ispunct( input[ 0 ] ) ) states.push( input[ 0 ] ); // assume it's an operator } else { states.push( STATE_CIN_CLOSED ); } break; case STATE_NUMBER: { // convert input to a numeric value stringstream buffer( input ); if ( buffer >> number ) { states.push( STATE_GET_NEXT_TOKEN ); operands.push( number ); } else { states.push( STATE_ERROR_BAD_NUMBER ); } break; } case STATE_OPERATOR_BINARY_PLUS: case STATE_OPERATOR_BINARY_MINUS: case STATE_OPERATOR_MULTIPLY: case STATE_OPERATOR_DIVIDE: operators.push( state ); states.push( STATE_GET_NEXT_TOKEN ); break; case STATE_OPERATOR_EXPR_TERMINATOR: calculate_and_display_the_result( operators, operands ); states.push( STATE_CLEAR ); break; default: if ( ( 0 < state ) && ( state <= 255 ) && isprint( state ) ) { cout << "Unexpected token \'" << char( state ) << "\'\n"; } else { cout << "Unexpected internal state " << state << "\n"; } states.push( STATE_CLEAR ); break; }//switch }//while system( "pause" ); return 0; }