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)