Improved model of the Calculator described in Chapter 4 of PSiCC2. Improvements include: - using "no me->" pointer implementation - placing the "negated1" state inside "operand1" superstate - placing the "negated2" state inside "operand2" superstate - adding handling of operator precedence '*','/' before '+','-' Calculator state machine The only inst of the Calc object (Singleton pattern). constructor : QHsm(Q_STATE_CAST(&Calc::initial)) // guard function to evaluate the current expression // taking into account the precedence of operands. // return: true if evaluation successfull // false when error encountered double result; if ((oper == KEY_NULL) || (oper == KEY_PLUS) || (oper == KEY_MINUS)) { switch (m_oper2) { case KEY_MULT: { m_op2 *= op; break; } case KEY_DIVIDE: { if ((-1e-30 < op) && (op < 1e-30)) { BSP_display_error(" Error 0 "); // divide by zero return false; } m_op2 /= op; break; } default: { /* no op2 yet */ m_op2 = op; m_oper2 = oper; break; } } switch (m_oper1) { case KEY_PLUS: { m_op1 += m_op2; break; } case KEY_MINUS: { m_op1 -= m_op2; break; } case KEY_MULT: { m_op1 *= m_op2; break; } case KEY_DIVIDE: { if ((-1e-30 < m_op2) && (m_op2 < 1e-30)) { BSP_display_error(" Error 0 "); // divide by zero return false; } m_op1 /= m_op2; break; } default: { Q_ERROR(); break; } } m_oper1 = oper; m_oper2 = KEY_NULL; result = m_op1; } else { // (oper == KEY_MULT) || (oper == KEY_DIV) switch (m_oper2) { case KEY_MULT: { m_op2 *= op; break; } case KEY_DIVIDE: { if ((-1e-30 < op) && (op < 1e-30)) { BSP_display_error(" Error 0 "); // divide by zero return false; } m_op2 /= op; break; } default: { // oper2 not provided yet m_op2 = op; break; } } m_oper2 = oper; result = m_op2; } if ((result < -99999999.0) || (99999999.0 < result)) { BSP_display_error(" Error 1 "); // out of range return false; } if ((-0.0000001 < result) && (result < 0.0000001)) { result = 0.0; } BSP_display(result); return true; BSP_clear(); (void)e; /* unused parameter */ BSP_message("on-ENTRY;"); BSP_message("on-EXIT;"); BSP_message("on-INIT;"); BSP_clear(); BSP_message("ready-ENTRY;"); m_oper2 = KEY_NULL; BSP_message("ready-EXIT;"); BSP_message("ready-INIT;"); BSP_clear(); BSP_clear(); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_clear(); BSP_insert((int)'0'); BSP_insert((int)'.'); m_op1 = BSP_get_value(); m_oper1 = Q_EVT_CAST(CalcEvt)->key_code; BSP_message("begin-ENTRY;"); BSP_message("begin-EXIT;"); Q_EVT_CAST(CalcEvt)->key_code == KEY_MINUS else BSP_message("result-ENTRY;"); BSP_message("result-EXIT;"); BSP_message("operand1-ENTRY;"); BSP_message("operand1-EXIT;"); BSP_clear(); m_op1 = BSP_get_value(); m_oper1 = Q_EVT_CAST(CalcEvt)->key_code; BSP_message("zero1-ENTRY;"); BSP_message("zero1-EXIT;"); ; BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert((int)'0'); BSP_insert((int)'.'); BSP_message("int1-ENTRY;"); BSP_message("int1-EXIT;"); BSP_insert((int)'.'); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_message("frac1-ENTRY;"); BSP_message("frac1-EXIT;"); ; BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_message("negated1-ENTRY;"); BSP_negate(); BSP_message("negated1-EXIT;"); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); else Q_EVT_CAST(CalcEvt)->key_code == KEY_MINUS ; BSP_message("opEntered-ENTRY;"); BSP_message("opEntered-EXIT;"); BSP_clear(); BSP_clear(); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_clear(); BSP_insert((int)'0'); BSP_insert((int)'.'); Q_EVT_CAST(CalcEvt)->key_code == KEY_MINUS else BSP_message("operand2-ENTRY;"); BSP_message("operand2-EXIT;"); BSP_clear(); eval(BSP_get_value(), KEY_NULL) eval(BSP_get_value(), Q_EVT_CAST(CalcEvt)->key_code) BSP_message("zero2-ENTRY;"); BSP_message("zero2-EXIT;"); ; BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert((int)'0'); BSP_insert((int)'.'); BSP_message("int2-ENTRY;"); BSP_message("int2-EXIT;"); BSP_insert((int)'.'); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_message("frac2-ENTRY;"); BSP_message("frac2-EXIT;"); ; BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_message("negated2-ENTRY;"); BSP_negate(); BSP_message("negated2-EXIT;"); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); BSP_insert(Q_EVT_CAST(CalcEvt)->key_code); else Q_EVT_CAST(CalcEvt)->key_code == KEY_MINUS ; BSP_message("error-ENTRY;"); BSP_message("error-EXIT;"); BSP_message("final-ENTRY;"); BSP_exit(); Global opaque pointer to the Calc inst = &Calc::inst; #ifndef calc1_h #define calc1_h enum CalcSignals { C_SIG = QP::Q_USER_SIG, CE_SIG, DIGIT_0_SIG, DIGIT_1_9_SIG, POINT_SIG, OPER_SIG, EQUALS_SIG, OFF_SIG }; $declare${Events::CalcEvt} $declare${SMs::the_calc} #endif // calc1_h #include "qpcpp.h" // QP/C++ #include "bsp.h" // board support package #include "calc1.h" // application Q_DEFINE_THIS_FILE #define KEY_NULL '\0' #define KEY_PLUS '+' #define KEY_MINUS '-' #define KEY_MULT '*' #define KEY_DIVIDE '/' $declare${SMs::Calc} $define${SMs::the_calc} $define(SMs::Calc)