calc.cpp
00001
#include "calc.h"
00002
00003
#include <stdio.h>
00004
#include <stdarg.h>
00005
#include <time.h>
00006
#include <sys/time.h>
00007
00008
00009
static void fsm_debug(
char* format, ... )
00010 {
00011
struct timeval tval;
00012
struct tm t;
00013 gettimeofday(&tval,NULL);
00014 localtime_r(&tval.tv_sec, &t);
00015
00016 printf(
"%02d:%02d:%02d.%lu ",
00017 t.tm_hour, t.tm_min, t.tm_sec, (
unsigned long)tval.tv_usec);
00018
00019 va_list ap;
00020 va_start( ap, format );
00021 vprintf( format, ap );
00022 va_end( ap );
00023 fflush( stdout );
00024 }
00025
00026
00027
void CalculatorFSM::__processEvent( Event e )
00028 {
00029
States yOld = __Y;
00030
bool pass =
false;
00031 fsm_debug(
"CalculatorFSM:%#x:event:%s:begin\n", (
int)
this,
eventName(e) );
00032
switch( __Y ) {
00033
case Idle:
00034
if( e ==
Number ) {
00035 fsm_debug(
"CalculatorFSM:%#x:state:Idle:leave:begin\n", (
int)
this );
00036
00037 fsm_debug(
"CalculatorFSM:%#x:state:Idle:leave:end\n", (
int)
this );
00038 fsm_debug(
"CalculatorFSM:%#x:transition:0:begin\n", (
int)
this );
00039 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:begin\n", (
int)
this );
00040
addNumber();
00041 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:end\n", (
int)
this );
00042 fsm_debug(
"CalculatorFSM:%#x:transition:0:end\n", (
int)
this );
00043 __Y =
EnteringFirstOperand;
00044 pass =
true;
00045 }
00046
break;
00047
case EnteringFirstOperand:
00048
if( e ==
Number ) {
00049 fsm_debug(
"CalculatorFSM:%#x:transition:0:begin\n", (
int)
this );
00050 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:begin\n", (
int)
this );
00051
addNumber();
00052 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:end\n", (
int)
this );
00053 fsm_debug(
"CalculatorFSM:%#x:transition:0:end\n", (
int)
this );
00054 pass =
false;
00055 }
00056
else if( e ==
BinaryOp ) {
00057 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:leave:begin\n", (
int)
this );
00058
00059 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:leave:end\n", (
int)
this );
00060 fsm_debug(
"CalculatorFSM:%#x:transition:1:begin\n", (
int)
this );
00061 fsm_debug(
"CalculatorFSM:%#x:output:saveNumber:begin\n", (
int)
this );
00062
saveNumber();
00063 fsm_debug(
"CalculatorFSM:%#x:output:saveNumber:end\n", (
int)
this );
00064 fsm_debug(
"CalculatorFSM:%#x:output:saveOp:begin\n", (
int)
this );
00065
saveOp();
00066 fsm_debug(
"CalculatorFSM:%#x:output:saveOp:end\n", (
int)
this );
00067 fsm_debug(
"CalculatorFSM:%#x:transition:1:end\n", (
int)
this );
00068 __Y =
EnteringSecondOperand;
00069 pass =
true;
00070 }
00071
else if( e ==
Clear ) {
00072 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:leave:begin\n", (
int)
this );
00073
00074 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:leave:end\n", (
int)
this );
00075 fsm_debug(
"CalculatorFSM:%#x:transition:2:begin\n", (
int)
this );
00076 fsm_debug(
"CalculatorFSM:%#x:output:clear:begin\n", (
int)
this );
00077
clear();
00078 fsm_debug(
"CalculatorFSM:%#x:output:clear:end\n", (
int)
this );
00079 fsm_debug(
"CalculatorFSM:%#x:transition:2:end\n", (
int)
this );
00080 __Y =
Idle;
00081 pass =
true;
00082 }
00083
break;
00084
case Result:
00085
if( e ==
Number ) {
00086 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:begin\n", (
int)
this );
00087
00088 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:end\n", (
int)
this );
00089 fsm_debug(
"CalculatorFSM:%#x:transition:0:begin\n", (
int)
this );
00090 fsm_debug(
"CalculatorFSM:%#x:output:clear:begin\n", (
int)
this );
00091
clear();
00092 fsm_debug(
"CalculatorFSM:%#x:output:clear:end\n", (
int)
this );
00093 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:begin\n", (
int)
this );
00094
addNumber();
00095 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:end\n", (
int)
this );
00096 fsm_debug(
"CalculatorFSM:%#x:transition:0:end\n", (
int)
this );
00097 __Y =
EnteringFirstOperand;
00098 pass =
true;
00099 }
00100
else if( e ==
BinaryOp ) {
00101 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:begin\n", (
int)
this );
00102
00103 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:end\n", (
int)
this );
00104 fsm_debug(
"CalculatorFSM:%#x:transition:1:begin\n", (
int)
this );
00105 fsm_debug(
"CalculatorFSM:%#x:output:saveNumber:begin\n", (
int)
this );
00106
saveNumber();
00107 fsm_debug(
"CalculatorFSM:%#x:output:saveNumber:end\n", (
int)
this );
00108 fsm_debug(
"CalculatorFSM:%#x:output:saveOp:begin\n", (
int)
this );
00109
saveOp();
00110 fsm_debug(
"CalculatorFSM:%#x:output:saveOp:end\n", (
int)
this );
00111 fsm_debug(
"CalculatorFSM:%#x:transition:1:end\n", (
int)
this );
00112 __Y =
EnteringSecondOperand;
00113 pass =
true;
00114 }
00115
else if( e ==
Clear ) {
00116 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:begin\n", (
int)
this );
00117
00118 fsm_debug(
"CalculatorFSM:%#x:state:Result:leave:end\n", (
int)
this );
00119 fsm_debug(
"CalculatorFSM:%#x:transition:2:begin\n", (
int)
this );
00120 fsm_debug(
"CalculatorFSM:%#x:output:clear:begin\n", (
int)
this );
00121
clear();
00122 fsm_debug(
"CalculatorFSM:%#x:output:clear:end\n", (
int)
this );
00123 fsm_debug(
"CalculatorFSM:%#x:transition:2:end\n", (
int)
this );
00124 __Y =
Idle;
00125 pass =
true;
00126 }
00127
break;
00128
case EnteringSecondOperand:
00129
if( e ==
Number ) {
00130 fsm_debug(
"CalculatorFSM:%#x:transition:0:begin\n", (
int)
this );
00131 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:begin\n", (
int)
this );
00132
addNumber();
00133 fsm_debug(
"CalculatorFSM:%#x:output:addNumber:end\n", (
int)
this );
00134 fsm_debug(
"CalculatorFSM:%#x:transition:0:end\n", (
int)
this );
00135 pass =
false;
00136 }
00137
else if( e ==
ResultRequested ) {
00138 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:begin\n", (
int)
this );
00139
00140 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:end\n", (
int)
this );
00141 fsm_debug(
"CalculatorFSM:%#x:transition:1:begin\n", (
int)
this );
00142 fsm_debug(
"CalculatorFSM:%#x:transition:1:end\n", (
int)
this );
00143 __Y =
Result;
00144 pass =
true;
00145 }
00146
else if( e ==
Clear ) {
00147 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:begin\n", (
int)
this );
00148
00149 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:end\n", (
int)
this );
00150 fsm_debug(
"CalculatorFSM:%#x:transition:2:begin\n", (
int)
this );
00151 fsm_debug(
"CalculatorFSM:%#x:output:clear:begin\n", (
int)
this );
00152
clear();
00153 fsm_debug(
"CalculatorFSM:%#x:output:clear:end\n", (
int)
this );
00154 fsm_debug(
"CalculatorFSM:%#x:transition:2:end\n", (
int)
this );
00155 __Y =
Idle;
00156 pass =
true;
00157 }
00158
else if( e ==
BinaryOp ) {
00159 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:begin\n", (
int)
this );
00160
00161 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:leave:end\n", (
int)
this );
00162 fsm_debug(
"CalculatorFSM:%#x:transition:3:begin\n", (
int)
this );
00163 fsm_debug(
"CalculatorFSM:%#x:self event:BinaryOp\n", (
int)
this );
00164 this->
A( BinaryOp );
00165 fsm_debug(
"CalculatorFSM:%#x:transition:3:end\n", (
int)
this );
00166 __Y =
Result;
00167 pass =
true;
00168 }
00169
break;
00170 }
00171
00172
if( yOld == __Y && !pass ) {
00173 fsm_debug(
"CalculatorFSM:%#x:event:%s:end\n", (
int)
this,
eventName(e) );
00174
return;
00175 }
00176
00177
switch( __Y ) {
00178
case Idle:
00179 fsm_debug(
"CalculatorFSM:%#x:state:Idle:enter:begin\n", (
int)
this );
00180 fsm_debug(
"CalculatorFSM:%#x:state:Idle:enter:end\n", (
int)
this );
00181
break;
00182
case EnteringFirstOperand:
00183 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:enter:begin\n", (
int)
this );
00184 fsm_debug(
"CalculatorFSM:%#x:state:EnteringFirstOperand:enter:end\n", (
int)
this );
00185
break;
00186
case Result:
00187 fsm_debug(
"CalculatorFSM:%#x:state:Result:enter:begin\n", (
int)
this );
00188 fsm_debug(
"CalculatorFSM:%#x:output:showResult:begin\n", (
int)
this );
00189
showResult();
00190 fsm_debug(
"CalculatorFSM:%#x:output:showResult:end\n", (
int)
this );
00191 fsm_debug(
"CalculatorFSM:%#x:state:Result:enter:end\n", (
int)
this );
00192
break;
00193
case EnteringSecondOperand:
00194 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:enter:begin\n", (
int)
this );
00195 fsm_debug(
"CalculatorFSM:%#x:state:EnteringSecondOperand:enter:end\n", (
int)
this );
00196
break;
00197 }
00198 fsm_debug(
"CalculatorFSM:%#x:event:%s:end\n", (
int)
this,
eventName(e) );
00199 }
00200
00201 void CalculatorFSM::A( Event e )
00202 {
00203
bool __empty = __events.empty();
00204 __events.push( e );
00205
if( __empty ) {
00206
while( !__events.empty() ) {
00207 __processEvent( __events.front() );
00208 __events.pop();
00209 }
00210 }
00211 }
00212
00213
bool CalculatorFSM::debug_iNtErNal_input(
const char*,
const char* name,
bool i)
00214 {
00215 fsm_debug(
"CalculatorFSM:%#x:input:%s:%s\n", (
int)
this, name, i ?
"true" :
"false" );
00216
return i;
00217 }
00218 const char*
CalculatorFSM::eventName( Event e )
00219 {
00220
switch(e) {
00221
case ResultRequested:
00222
return "ResultRequested";
00223
case Number:
00224
return "Number";
00225
case BinaryOp:
00226
return "BinaryOp";
00227
case Clear:
00228
return "Clear";
00229
default:
00230
return "Unknown event";
00231 }
00232 }
00233
00234 const char*
CalculatorFSM::stateName( States s )
00235 {
00236
switch(s) {
00237
case Idle:
00238
return "Idle";
00239
case EnteringFirstOperand:
00240
return "EnteringFirstOperand";
00241
case Result:
00242
return "Result";
00243
case EnteringSecondOperand:
00244
return "EnteringSecondOperand";
00245
default:
00246
return "Unknown state";
00247 }
00248 }
00249
void CalculatorFSM::debug_show_fsm_xml()
00250 {
00251 printf(
"\nBegin FSM XML:CalculatorFSM\n%s\n\nEnd FSM XML\n\n",
00252
"<!DOCTYPE FSM> <FSM> <statemachine> <name>CalculatorFSM</name> <comment>Quite useless calculator</comment> <initialstate>Idle</initialstate> <event> <name>ResultRequested</name> <comment>A '=' have been entered</comment> </event> <event> <name>Number</name> <comment>A digit have been entered</comment> </event> <event> <name>BinaryOp</name> <comment>Pressed '+', '-', ...</comment> </event> <event> <name>Clear</name> <comment>User have pressed 'C' button. Clear all data</comment> </event> <output> <name>saveNumber</name> <comment>A number have been entered, save it and proceed to the next one</comment> </output> <output> <name>addNumber</name> <comment>Add a number to the current number, for example, if there is '12' on a screen and '3' button pressed, there should be '123' on a screen</comment> </output> <output> <name>clear</name> <comment>Just clear :)</comment> </output> <output> <name>saveOp</name> <comment>Save operation to our stack. This output follows press '+', '-', ...</comment> </output> <output> <name>showResult</name> <comment>Calculate and display result of operation</comment> </output> <state> <name>Idle</name> <comment>A result is displayed</comment> <incomeactions/> <outcomeactions/> <transitions> <transition type=\"simple\" > <name>start</name> <comment>User started to enter a number</comment> <condition>Number</condition> <destination>EnteringFirstOperand</destination> <transite_destination/> <transitionactions> <action type=\"output\" >addNumber</action> </transitionactions> </transition> </transitions> </state> <state> <name>EnteringFirstOperand</name> <comment>A first calculating operand is being entered</comment> <incomeactions/> <outcomeactions/> <transitions> <transition type=\"simple\" > <name>add</name> <comment/> <condition>Number</condition> <destination/> <transite_destination/> <transitionactions> <action type=\"output\" >addNumber</action> </transitionactions> </transition> <transition type=\"simple\" > <name>op</name> <comment/> <condition>BinaryOp</condition> <destination>EnteringSecondOperand</destination> <transite_destination/> <transitionactions> <action type=\"output\" >saveNumber</action> <action type=\"output\" >saveOp</action> </transitionactions> </transition> <transition type=\"simple\" > <name>clear</name> <comment>start from scratch</comment> <condition>Clear</condition> <destination>Idle</destination> <transite_destination/> <transitionactions> <action type=\"output\" >clear</action> </transitionactions> </transition> </transitions> </state> <state> <name>Result</name> <comment>A result is displayed, but there is a result from previous operation</comment> <incomeactions> <action type=\"output\" >showResult</action> </incomeactions> <outcomeactions/> <transitions> <transition type=\"simple\" > <name>from scratch</name> <comment>If user presses a number button when there's a result on a screen, we should clear it and start from scratch</comment> <condition>Number</condition> <destination>EnteringFirstOperand</destination> <transite_destination/> <transitionactions> <action type=\"output\" >clear</action> <action type=\"output\" >addNumber</action> </transitionactions> </transition> <transition type=\"simple\" > <name>next chain</name> <comment>If user presses an action button (+, -, *, /), we should remember it and ask for the second operand</comment> <condition>BinaryOp</condition> <destination>EnteringSecondOperand</destination> <transite_destination/> <transitionactions> <action type=\"output\" >saveNumber</action> <action type=\"output\" >saveOp</action> </transitionactions> </transition> <transition type=\"simple\" > <name>clear</name> <comment/> <condition>Clear</condition> <destination>Idle</destination> <transite_destination/> <transitionactions> <action type=\"output\" >clear</action> </transitionactions> </transition> </transitions> </state> <state> <name>EnteringSecondOperand</name> <comment>User is pressing digits to make second operand</comment> <incomeactions/> <outcomeactions/> <transitions> <transition type=\"simple\" > <name>add</name> <comment/> <condition>Number</condition> <destination/> <transite_destination/> <transitionactions> <action type=\"output\" >addNumber</action> </transitionactions> </transition> <transition type=\"simple\" > <name>result</name> <comment>User pressed '=', we should calculate and show result</comment> <condition>ResultRequested</condition> <destination>Result</destination> <transite_destination/> <transitionactions/> </transition> <transition type=\"simple\" > <name>clear</name> <comment/> <condition>Clear</condition> <destination>Idle</destination> <transite_destination/> <transitionactions> <action type=\"output\" >clear</action> </transitionactions> </transition> <transition type=\"simple\" > <name>next op</name> <comment>Pressing operation button is equal to pressing '=' and then this button</comment> <condition>BinaryOp</condition> <destination>Result</destination> <transite_destination/> <transitionactions> <action type=\"self_event\" >BinaryOp</action> </transitionactions> </transition> </transitions> </state> </statemachine> <graphics> <class classname=\"GStateSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GStateSaver\" > <qstring name=\"stateName\" >Idle</qstring> <QPoint name=\"position\" > <int>5042</int> <int>5045</int> </QPoint> </data> </class> <class classname=\"GStateSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GStateSaver\" > <qstring name=\"stateName\" >EnteringSecondOperand</qstring> <QPoint name=\"position\" > <int>5289</int> <int>5171</int> </QPoint> </data> </class> <class classname=\"GStateSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GStateSaver\" > <qstring name=\"stateName\" >Result</qstring> <QPoint name=\"position\" > <int>5259</int> <int>5034</int> </QPoint> </data> </class> <class classname=\"GStateSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GStateSaver\" > <qstring name=\"stateName\" >EnteringFirstOperand</qstring> <QPoint name=\"position\" > <int>5046</int> <int>5174</int> </QPoint> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >Idle</qstring> <int name=\"transition\" >0</int> <qvaluelist name=\"points\" /> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringFirstOperand</qstring> <int name=\"transition\" >0</int> <qvaluelist name=\"points\" > <QPoint> <int>5051</int> <int>5237</int> </QPoint> <QPoint> <int>5089</int> <int>5255</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringFirstOperand</qstring> <int name=\"transition\" >1</int> <qvaluelist name=\"points\" > <QPoint> <int>5206</int> <int>5225</int> </QPoint> <QPoint> <int>5276</int> <int>5225</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringSecondOperand</qstring> <int name=\"transition\" >0</int> <qvaluelist name=\"points\" > <QPoint> <int>5451</int> <int>5214</int> </QPoint> <QPoint> <int>5425</int> <int>5247</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringSecondOperand</qstring> <int name=\"transition\" >1</int> <qvaluelist name=\"points\" > <QPoint> <int>5355</int> <int>5108</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >Result</qstring> <int name=\"transition\" >0</int> <qvaluelist name=\"points\" > <QPoint> <int>5171</int> <int>5090</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >Result</qstring> <int name=\"transition\" >1</int> <qvaluelist name=\"points\" > <QPoint> <int>5273</int> <int>5112</int> </QPoint> <QPoint> <int>5278</int> <int>5138</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringFirstOperand</qstring> <int name=\"transition\" >2</int> <qvaluelist name=\"points\" > <QPoint> <int>5035</int> <int>5131</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringSecondOperand</qstring> <int name=\"transition\" >2</int> <qvaluelist name=\"points\" > <QPoint> <int>5316</int> <int>5263</int> </QPoint> <QPoint> <int>5105</int> <int>5305</int> </QPoint> <QPoint> <int>4996</int> <int>5258</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >Result</qstring> <int name=\"transition\" >2</int> <qvaluelist name=\"points\" > <QPoint> <int>5155</int> <int>5032</int> </QPoint> </qvaluelist> </data> </class> <class classname=\"GTransitionSaver\" > <meta classname=\"GSaver\" > <data classname=\"GSaver\" /> </meta> <data classname=\"GTransitionSaver\" > <qstring name=\"stateName\" >EnteringSecondOperand</qstring> <int name=\"transition\" >3</int> <qvaluelist name=\"points\" > <QPoint> <int>5426</int> <int>5128</int> </QPoint> <QPoint> <int>5367</int> <int>5061</int> </QPoint> </qvaluelist> </data> </class> </graphics> </FSM>" );
00253 fflush(stdout);
00254 }
Generated on Fri Oct 29 13:35:13 2004 for Calculator by
1.3.8