1388 lines
32 KiB
C++
1388 lines
32 KiB
C++
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <string>
|
|
#include <set>
|
|
|
|
#include "getopt.h"
|
|
#include "main.h"
|
|
#include "autofile.h"
|
|
#include "machine.h"
|
|
#include "state.h"
|
|
#include "config.h"
|
|
|
|
|
|
//
|
|
// globals
|
|
//
|
|
|
|
std::vector<Machine> gMachines;
|
|
int gCurMachine;
|
|
Config gConfig;
|
|
int gErrors = 0;
|
|
|
|
|
|
|
|
//
|
|
// parser interface functions
|
|
//
|
|
|
|
extern "C" FILE* yyin;
|
|
|
|
extern "C" void parseEndMachine()
|
|
{
|
|
if ( !gMachines[gCurMachine].EndMachine() )
|
|
{
|
|
gErrors++;
|
|
}
|
|
}
|
|
|
|
extern "C" void parseEndState()
|
|
{
|
|
gMachines[gCurMachine].EndState();
|
|
}
|
|
|
|
extern "C" void parseBeginMachine(char* name, int eventsize)
|
|
{
|
|
// validate event size
|
|
if ( eventsize <= 0 )
|
|
{
|
|
extern int lineno;
|
|
printf("%d: Invalid event queue size for Machine '%s'\n",
|
|
lineno,
|
|
name);
|
|
gErrors++;
|
|
}
|
|
|
|
// create new machine
|
|
Machine m;
|
|
m.name = name;
|
|
m.SetQueueSize(eventsize);
|
|
|
|
// create top state
|
|
m.AddState("TOPSTATE");
|
|
|
|
// add machine to list
|
|
gMachines.push_back(m);
|
|
|
|
// update current machine id
|
|
gCurMachine = (int)gMachines.size() - 1;
|
|
}
|
|
|
|
extern "C" void parseBeginState(char* name)
|
|
{
|
|
if ( gMachines[gCurMachine].AddState(name) < 0 )
|
|
{
|
|
extern int lineno;
|
|
printf("%d: State '%s' was previously defined\n",
|
|
lineno,
|
|
name);
|
|
gErrors++;
|
|
}
|
|
}
|
|
|
|
extern "C" void parseDefault(char* state)
|
|
{
|
|
if ( !gMachines[gCurMachine].AddDefault(state) )
|
|
{
|
|
extern int lineno;
|
|
printf("%d: multiple Default states defined in State '%s'\n",
|
|
lineno,
|
|
(gMachines[gCurMachine].CurStateName()).c_str());
|
|
gErrors++;
|
|
}
|
|
}
|
|
|
|
extern "C" void parseEntry(char* action)
|
|
{
|
|
gMachines[gCurMachine].AddEntry(action);
|
|
}
|
|
|
|
extern "C" void parseIdle(char* action)
|
|
{
|
|
gMachines[gCurMachine].AddIdle(action);
|
|
}
|
|
|
|
extern "C" void parseExit(char* action)
|
|
{
|
|
gMachines[gCurMachine].AddExit(action);
|
|
}
|
|
|
|
extern "C" void parseTransition(char* event,char* state)
|
|
{
|
|
if ( !gMachines[gCurMachine].AddTransition(event,state) )
|
|
{
|
|
extern int lineno;
|
|
printf("%d: multiple Transition's on '%s' defined in '%s'\n",
|
|
lineno,
|
|
event,
|
|
(gMachines[gCurMachine].CurStateName()).c_str());
|
|
gErrors++;
|
|
}
|
|
}
|
|
|
|
extern "C" void parseAction(char* event,char* action)
|
|
{
|
|
gMachines[gCurMachine].AddAction(event,action);
|
|
}
|
|
|
|
extern "C" void parseTimeTransition(float time,char* state)
|
|
{
|
|
gMachines[gCurMachine].AddTimeTransition(time,state);
|
|
}
|
|
|
|
extern "C" void parseTimeAction(float time,char* action)
|
|
{
|
|
gMachines[gCurMachine].AddTimeAction(time,action);
|
|
}
|
|
|
|
extern "C" void parseTerminate(char* event)
|
|
{
|
|
if ( !gMachines[gCurMachine].AddTerminate(event) )
|
|
{
|
|
extern int lineno;
|
|
printf("%d: multiple Terminate's on '%s' defined in '%s'\n",
|
|
lineno,
|
|
event,
|
|
(gMachines[gCurMachine].CurStateName()).c_str());
|
|
gErrors++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// output functions
|
|
//
|
|
|
|
void OutputEvents(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"\tenum\n"
|
|
"\t{\n"
|
|
);
|
|
bool first = true;
|
|
for ( std::set<std::string>::iterator it = m.event_refs.begin(); it != m.event_refs.end(); it++ )
|
|
{
|
|
fprintf(f,"\t\t%s%s,\n",(*it).c_str(), first?" = 0":"");
|
|
first = false;
|
|
}
|
|
fprintf(f,
|
|
"\n"
|
|
"\t\t___HSM_NUM_EVENTS___\n"
|
|
"\t};\n\n");
|
|
}
|
|
|
|
void OutputStateIDs(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"\tenum\n"
|
|
"\t{\n"
|
|
);
|
|
bool first = true;
|
|
for ( std::vector<State>::iterator it = m.states.begin(); it != m.states.end(); it++ )
|
|
{
|
|
fprintf(f,"\t\t%s%s,\n",(*it).name.c_str(), first?" = 0":"");
|
|
first = false;
|
|
}
|
|
fprintf(f,
|
|
"\n"
|
|
"\t\t___HSM_NUM_STATES___\n"
|
|
"\t};\n\n");
|
|
}
|
|
|
|
void OutputPrivateEvents(FILE* f, Machine& m)
|
|
{
|
|
// header
|
|
fprintf(f,
|
|
"\tenum\n"
|
|
"\t{\n"
|
|
"\t\t___HSM_ENTRY___ = ___HSM_NUM_EVENTS___,\n"
|
|
"\t\t___HSM_IDLE___,\n"
|
|
"\t\t___HSM_EXIT___,\n"
|
|
"\t\t___HSM_ELICIT_INITIAL_TRANSITION___,\n"
|
|
"\t\t___HSM_ELICIT_PARENT___,\n"
|
|
);
|
|
|
|
// private timer events
|
|
for ( int i=0;i<m.GetTimerDepth();i++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t___HSM_TIMER_%d___,\n",
|
|
i
|
|
);
|
|
}
|
|
|
|
// footer
|
|
fprintf(f,
|
|
"\n"
|
|
"\t\t___HSM_TOTAL_NUM_EVENTS___\n"
|
|
"\t};\n\n");
|
|
}
|
|
|
|
void OutputActionProtos(FILE* f, Machine& m)
|
|
{
|
|
for ( std::set<std::string>::iterator it = m.action_refs.begin(); it != m.action_refs.end(); it++ )
|
|
{
|
|
fprintf(f,"\tvirtual void %s()%s;\n",(*it).c_str(),gConfig.PureVirtuals ? " = 0" : "");
|
|
}
|
|
fprintf(f,"\n");
|
|
}
|
|
|
|
void OutputActions(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"//\n"
|
|
"// actions (must be overridden)\n"
|
|
"//\n"
|
|
);
|
|
|
|
for ( std::set<std::string>::iterator it = m.action_refs.begin(); it != m.action_refs.end(); it++ )
|
|
{
|
|
fprintf(f,"void %s::%s()\n",m.name.c_str(),(*it).c_str());
|
|
fprintf(f,
|
|
"{\n"
|
|
"\t// empty\n"
|
|
"}\n\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
void OutputStateProtos(FILE* f, Machine& m, int s)
|
|
{
|
|
static int indent = 0;
|
|
|
|
fprintf(f,"\tint %*s___HSMSTATE_%s___(int event);\n",indent*4,"",m.states[s].name.c_str());
|
|
|
|
indent++;
|
|
for ( unsigned int i=0;i<m.states[s].child.size();i++ )
|
|
{
|
|
OutputStateProtos(f,m,m.states[s].child[i]);
|
|
}
|
|
indent--;
|
|
}
|
|
|
|
void OutputStates(FILE* f, Machine& m)
|
|
{
|
|
for ( std::vector<State>::iterator it = m.states.begin(); it != m.states.end(); it++ )
|
|
{
|
|
State& s = (*it);
|
|
std::vector<std::string> null_events;
|
|
|
|
// header
|
|
fprintf(f,
|
|
"//\n"
|
|
"// STATE: %s::%s\n"
|
|
"//\n"
|
|
"int %s::___HSMSTATE_%s___(int event)\n"
|
|
"{\n"
|
|
"\tswitch (event)\n"
|
|
"\t{\n",
|
|
m.name.c_str(),s.name.c_str(),
|
|
m.name.c_str(),s.name.c_str());
|
|
|
|
fprintf(f,
|
|
"\t\t// internal events\n\n"
|
|
);
|
|
|
|
// entry
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_ENTRY___:\n"
|
|
);
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"Entering %s\");\n",
|
|
s.name.c_str()
|
|
);
|
|
}
|
|
for ( std::map<int,float>::iterator timeit = s.timers.begin(); timeit != s.timers.end(); timeit++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_START_TIMER___(%d,%0.7ff);\n",
|
|
(*timeit).first,
|
|
(*timeit).second
|
|
);
|
|
}
|
|
for ( unsigned int i=0;i<s.entry.size();i++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
s.entry[i].c_str()
|
|
);
|
|
}
|
|
fprintf(f,
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n"
|
|
"\n"
|
|
);
|
|
|
|
// idle
|
|
if ( s.idle.size() > 0 )
|
|
{
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_IDLE___:\n"
|
|
);
|
|
for ( unsigned int i=0;i<s.idle.size();i++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
s.idle[i].c_str()
|
|
);
|
|
}
|
|
fprintf(f,
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
// exit
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_EXIT___:\n"
|
|
);
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"Exiting %s\");\n",
|
|
s.name.c_str()
|
|
);
|
|
}
|
|
for ( std::map<int,float>::iterator timeit = s.timers.begin(); timeit != s.timers.end(); timeit++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_STOP_TIMER___(%d);\n",
|
|
(*timeit).first
|
|
);
|
|
}
|
|
for ( unsigned int i=0;i<s.exit.size();i++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
s.exit[i].c_str()
|
|
);
|
|
}
|
|
fprintf(f,
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n"
|
|
"\n"
|
|
);
|
|
|
|
// initial transition (default or history)
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_ELICIT_INITIAL_TRANSITION___:\n"
|
|
);
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"In %s\");\n",
|
|
s.name.c_str()
|
|
);
|
|
}
|
|
fprintf(f,
|
|
"\t\t\treturn %s;\n"
|
|
"\n",
|
|
s.defaultstate != "" ? s.defaultstate.c_str() : "___HSM_NULL_STATE___"
|
|
);
|
|
|
|
// timer events
|
|
if ( s.timers.size() > 0 )
|
|
{
|
|
fprintf(f,
|
|
"\t\t// timer events\n\n"
|
|
);
|
|
for ( std::map<int,float>::iterator timeit = s.timers.begin(); timeit != s.timers.end(); timeit++ )
|
|
{
|
|
// which timer
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_TIMER_%d___:\n",
|
|
(*timeit).first
|
|
);
|
|
|
|
// all actions with this time
|
|
for ( std::multimap<float,std::string>::iterator acit = s.timeaction.begin(); acit != s.timeaction.end(); acit++ )
|
|
{
|
|
if ( (*acit).first == (*timeit).second )
|
|
{
|
|
// print debug info on action
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"[TIMER EVENT]: %s()\");\n",
|
|
(*acit).second.c_str()
|
|
);
|
|
}
|
|
|
|
// call timer action
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
(*acit).second.c_str()
|
|
);
|
|
}
|
|
}
|
|
|
|
// any transition with this time?
|
|
for ( std::multimap<float,std::string>::iterator trit = s.timetransition.begin(); trit != s.timetransition.end(); trit++ )
|
|
{
|
|
if ( (*trit).first == (*timeit).second )
|
|
{
|
|
// print debug info on transition
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"[TIMER EVENT]: %s -> %s\");\n",
|
|
s.name.c_str(),
|
|
(*trit).second.c_str()
|
|
);
|
|
}
|
|
|
|
// do the transition
|
|
fprintf(f,
|
|
"\t\t\t___HSM_TRANSITION___(%s);\n",
|
|
(*trit).second.c_str()
|
|
);
|
|
break; // only ONE transition allowed; should never happen, but be safe
|
|
}
|
|
}
|
|
|
|
// return event handled
|
|
fprintf(f,
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n"
|
|
"\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
// user events
|
|
if ( s.terminate.size() > 0 || s.transition.size() > 0 || s.action.size() > 0 )
|
|
{
|
|
fprintf(f,
|
|
"\t\t// user events\n\n"
|
|
);
|
|
}
|
|
|
|
// terminate's if they exist
|
|
for ( std::set<std::string>::iterator it = s.terminate.begin(); it != s.terminate.end(); it++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\tcase %s:\n",
|
|
(*it).c_str()
|
|
);
|
|
}
|
|
if ( s.terminate.size() > 0 )
|
|
{
|
|
// print debug info on terminal event
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"[TERMINAL EVENT]: %s -> [HSM TERMINATION]\");\n",
|
|
s.name.c_str()
|
|
);
|
|
}
|
|
|
|
// terminate
|
|
fprintf(f,
|
|
"\t\t\t___HSM_STOP_MACHINE___();\n"
|
|
"\t\t\treturn ___HSM_TERMINAL_STATE___;\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
// transition's if they exist
|
|
for ( std::map<std::string,std::string>::iterator it = s.transition.begin(); it != s.transition.end(); it++ )
|
|
{
|
|
fprintf(f,
|
|
"\t\tcase %s:\n",
|
|
(*it).first.c_str()
|
|
);
|
|
|
|
// see if this event is used in any actions
|
|
for ( std::multimap<std::string,std::string>::iterator tit = s.action.lower_bound((*it).first); tit != s.action.upper_bound((*it).first); tit++ )
|
|
{
|
|
// print debug info on action
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"%s: %s()\");\n",
|
|
(*it).first.c_str(),
|
|
(*tit).second.c_str()
|
|
);
|
|
}
|
|
|
|
// call action
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
(*tit).second.c_str()
|
|
);
|
|
|
|
}
|
|
|
|
// print debug info on transition
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"%s: %s -> %s\");\n",
|
|
(*it).first.c_str(),
|
|
s.name.c_str(),
|
|
(*it).second.c_str()
|
|
);
|
|
}
|
|
|
|
// now the transition
|
|
fprintf(f,
|
|
"\t\t\t___HSM_TRANSITION___(%s);\n"
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n\n",
|
|
(*it).second.c_str()
|
|
);
|
|
}
|
|
|
|
// actions if they exist
|
|
for ( std::multimap<std::string,std::string>::iterator it = s.action.begin(); it != s.action.end(); it++ )
|
|
{
|
|
// store off for ease of typing
|
|
std::string event = (*it).first;
|
|
|
|
// did this action have a transition too?
|
|
if ( s.transition.find(event) == s.transition.end() )
|
|
{
|
|
// how many actions associated with this event?
|
|
int count = (int)s.action.count(event);
|
|
|
|
// print event
|
|
fprintf(f,
|
|
"\t\tcase %s:\n",
|
|
event.c_str()
|
|
);
|
|
|
|
for ( int i=0;i<count;i++ )
|
|
{
|
|
// print debug info on action
|
|
if ( gConfig.Debug )
|
|
{
|
|
fprintf(f,
|
|
"\t\t\t___HSM_DEBUG___(\"%s: %s()\");\n",
|
|
event.c_str(),
|
|
(*it).second.c_str()
|
|
);
|
|
}
|
|
|
|
// call action
|
|
fprintf(f,
|
|
"\t\t\t%s();\n",
|
|
(*it).second.c_str()
|
|
);
|
|
if ( i < (count - 1) )
|
|
{
|
|
it++;
|
|
}
|
|
}
|
|
|
|
fprintf(f,
|
|
"\t\t\treturn ___HSM_NULL_STATE___;\n\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
// default event / return parent
|
|
fprintf(f,
|
|
"\t\t// default event / return parent\n\n"
|
|
);
|
|
|
|
// parent
|
|
fprintf(f,
|
|
"\t\tcase ___HSM_ELICIT_PARENT___:\n"
|
|
"\t\tdefault:\n"
|
|
"\t\t\treturn %s;\n",
|
|
s.parent >= 0 ? m.states[s.parent].name.c_str() : "___HSM_NULL_STATE___"
|
|
);
|
|
|
|
// footer
|
|
fprintf(f,
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
void OutputStateTable(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"%s::___HSMSTATE_FUNC___ %s::___HSM_STATE_TAB___[___HSM_NUM_STATES___] = \n"
|
|
"{\n",
|
|
m.name.c_str(),m.name.c_str()
|
|
);
|
|
|
|
for ( unsigned int i=0;i<m.states.size();i++ )
|
|
{
|
|
fprintf(f,
|
|
"\t&%s::___HSMSTATE_%s___,\n",
|
|
m.name.c_str(),m.states[i].name.c_str()
|
|
);
|
|
}
|
|
|
|
fprintf(f,
|
|
"};\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
void OutputNotice(FILE* f)
|
|
{
|
|
fprintf(f,
|
|
"//\n"
|
|
"// N N OOO TTTTT IIIII CCCC EEEEE\n"
|
|
"// NN N O O T I C E\n"
|
|
"// N N N O O T I C EEE\n"
|
|
"// N NN O O T I C E\n"
|
|
"// N N OOO T IIIII CCCC EEEEE\n"
|
|
"//\n"
|
|
"// THIS FILE WAS MACHINE GENERATED\n"
|
|
"//\n"
|
|
"// DO NOT EDIT BY HAND\n"
|
|
"//\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
|
|
void OutputMachineH(FILE* f, Machine& m)
|
|
{
|
|
// a warning
|
|
OutputNotice(f);
|
|
|
|
// output header
|
|
fprintf(f,
|
|
"#ifndef ___HSMC_GENERATED_%s___\n"
|
|
"#define ___HSMC_GENERATED_%s___\n"
|
|
"\n"
|
|
"class %s\n"
|
|
"{\n"
|
|
"public:\n"
|
|
"\n",
|
|
m.name.c_str(),m.name.c_str(),m.name.c_str()
|
|
);
|
|
|
|
// events
|
|
fprintf(f,
|
|
"\t// events\n"
|
|
);
|
|
OutputEvents(f,m);
|
|
|
|
// states
|
|
fprintf(f,
|
|
"\t// states\n"
|
|
);
|
|
OutputStateIDs(f,m);
|
|
|
|
// public prototypes
|
|
fprintf(f,
|
|
"\t// public declarations\n"
|
|
"\t%s();\n"
|
|
"\tvirtual ~%s();\n"
|
|
"\n"
|
|
"\tint HSMGetCurrentState() const;\n"
|
|
"\tint HSMGetParentState(int state) const;\n"
|
|
"\tbool HSMIsInState(int state) const;\n"
|
|
"\tbool HSMIsRunning() const;\n"
|
|
"\n"
|
|
"\tvoid HSMConstruct();\n"
|
|
"\tvoid HSMDestruct();\n"
|
|
"\n"
|
|
"\tbool HSMUpdate(float dt = 0.0f);\n"
|
|
"\n"
|
|
"\tvoid HSMTrigger(int event);\n"
|
|
"\n"
|
|
"\tchar* HSMGetLastDebugMessage();\n"
|
|
"\n",
|
|
m.name.c_str(),
|
|
m.name.c_str()
|
|
);
|
|
|
|
// protected section
|
|
fprintf(f,
|
|
"protected:\n"
|
|
"\n"
|
|
);
|
|
|
|
// actions
|
|
fprintf(f,
|
|
"\t// actions\n"
|
|
);
|
|
OutputActionProtos(f,m);
|
|
|
|
// debug prototype
|
|
fprintf(f,
|
|
"\t// debug hook (override this to trap debug messages)\n"
|
|
"\tvirtual void HSMDebug(char* msg);\n"
|
|
"\n"
|
|
);
|
|
|
|
// private section
|
|
fprintf(f,
|
|
"private:\n"
|
|
"\n"
|
|
);
|
|
|
|
// our event queue class
|
|
fprintf(f,
|
|
"\t// our event queue class\n"
|
|
"\ttemplate<typename T,int N>\n"
|
|
"\tclass StaticQueue\n"
|
|
"\t{\n"
|
|
"\tpublic:\n"
|
|
"\n"
|
|
"\t\tStaticQueue()\n"
|
|
"\t\t{\n"
|
|
"\t\t\tclear();\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tvoid clear()\n"
|
|
"\t\t{\n"
|
|
"\t\t\tfirst = 0;\n"
|
|
"\t\t\tlast = -1;\n"
|
|
"\n"
|
|
"\t\t\tcursize = 0;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tbool put(T x)\n"
|
|
"\t\t{\n"
|
|
"\t\t\tif ( size() < N )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\tincrement(last);\n"
|
|
"\t\t\t\tdata[last] = x;\n"
|
|
"\t\t\t\tcursize++;\n"
|
|
"\t\t\t\treturn true;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t\telse\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\treturn false;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tbool get(T& x)\n"
|
|
"\t\t{\n"
|
|
"\t\t\tif ( size() > 0 )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\tx = data[first];\n"
|
|
"\t\t\t\tincrement(first);\n"
|
|
"\t\t\t\tcursize--;\n"
|
|
"\t\t\t\treturn true;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t\telse\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\treturn false;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tunsigned int size() const\n"
|
|
"\t\t{\n"
|
|
"\t\t\treturn cursize;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tbool IsEmpty() const\n"
|
|
"\t\t{\n"
|
|
"\t\t\treturn size() == 0;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\tbool IsFull() const\n"
|
|
"\t\t{\n"
|
|
"\t\t\treturn size() == N;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\tprivate:\n"
|
|
"\n"
|
|
"\t\tT data[N];\n"
|
|
"\t\tint first,last,cursize;\n"
|
|
"\n"
|
|
"\t\tvoid increment(int& x)\n"
|
|
"\t\t{\n"
|
|
"\t\t\tif ( ++x >= N )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\tx = 0;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\t};\n"
|
|
"\n"
|
|
);
|
|
|
|
// event queue instance
|
|
fprintf(f,
|
|
"\t// event queue\n"
|
|
"\tStaticQueue<int,%d> ___HSM_EVENT_QUEUE___;\n"
|
|
"\n",
|
|
m.GetQueueSize()
|
|
);
|
|
|
|
// debug string pointer
|
|
fprintf(f,
|
|
"\t// debug string pointer\n"
|
|
"\tchar* ___HSM_DEBUG_MSG___;\n"
|
|
"\n"
|
|
);
|
|
|
|
// our data
|
|
fprintf(f,
|
|
"\t// current state\n"
|
|
"\tint ___HSM_CURSTATE___;\n"
|
|
"\n"
|
|
);
|
|
|
|
// private events
|
|
fprintf(f,
|
|
"\t// private events\n"
|
|
);
|
|
OutputPrivateEvents(f,m);
|
|
|
|
// a few other #defines
|
|
fprintf(f,
|
|
"\t// special private constants\n"
|
|
"\tenum\n"
|
|
"\t{\n"
|
|
"\t\t___HSM_NULL_STATE___ = -1,\n"
|
|
"\t\t___HSM_TERMINAL_STATE___ = -2,\n"
|
|
"\t\t___HSM_ERROR___ = -3,\n"
|
|
"\t\t___HSM_MAX_DEPTH___ = %d,\n"
|
|
"\t\t___HSM_TIMER_DEPTH___ = %d\n"
|
|
"\t};\n"
|
|
"\n",
|
|
m.GetMaxDepth(),
|
|
m.GetTimerDepth()
|
|
);
|
|
|
|
// timer declaration
|
|
if ( m.GetTimerDepth() > 0 )
|
|
{
|
|
fprintf(f,
|
|
"\t// timers\n"
|
|
"\tfloat ___HSM_TIMERS___[___HSM_TIMER_DEPTH___];\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
// state prototypes
|
|
fprintf(f,
|
|
"\t// state declaration\n"
|
|
);
|
|
OutputStateProtos(f,m,0); // <-- recursive
|
|
fprintf(f,"\n");
|
|
|
|
// state table declaration
|
|
fprintf(f,
|
|
"\t// state table declaration\n"
|
|
"\ttypedef int (%s::*___HSMSTATE_FUNC___)(int);\n"
|
|
"\tstatic ___HSMSTATE_FUNC___ ___HSM_STATE_TAB___[___HSM_NUM_STATES___];\n"
|
|
"\n",
|
|
m.name.c_str()
|
|
);
|
|
|
|
// machine driver prototypes
|
|
fprintf(f,
|
|
"\t// machine driver prototypes\n"
|
|
"\tvoid ___HSM_START_MACHINE___();\n"
|
|
"\tvoid ___HSM_STOP_MACHINE___();\n"
|
|
"\tvoid ___HSM_CALC_HIERARCHY___(int state, int path[___HSM_MAX_DEPTH___]);\n"
|
|
"\tvoid ___HSM_TRANSITION___(int state);\n"
|
|
"\tint ___HSM_CALL_STATE___(int state, int event);\n"
|
|
"\tvoid ___HSM_HANDLE_EVENT___(int event);\n"
|
|
"\tvoid ___HSM_UPDATE_TIMERS___(float dt);\n"
|
|
"\tvoid ___HSM_START_TIMER___(int id, float time);\n"
|
|
"\tvoid ___HSM_STOP_TIMER___(int id);\n"
|
|
"\tvoid ___HSM_DEBUG___(char* msg);\n"
|
|
"\n"
|
|
);
|
|
|
|
// footer
|
|
fprintf(f,
|
|
"};\n"
|
|
"\n"
|
|
"#endif // ___HSMC_GENERATED_%s___\n"
|
|
"\n",
|
|
m.name.c_str()
|
|
);
|
|
|
|
}
|
|
|
|
void OutputMachineHSMDebug(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"//\n"
|
|
"// debug hook (override this to trap debug messages)\n"
|
|
"//\n"
|
|
);
|
|
|
|
fprintf(f,
|
|
"void %s::HSMDebug(char* msg)\n"
|
|
"{\n"
|
|
"\t// empty\n"
|
|
"}\n"
|
|
"\n",
|
|
m.name.c_str()
|
|
);
|
|
}
|
|
|
|
void OutputMachineDriverCode(FILE* f, Machine& m)
|
|
{
|
|
fprintf(f,
|
|
"%s::%s()\n"
|
|
"{\n"
|
|
"\t___HSM_CURSTATE___ = ___HSM_NULL_STATE___;\n"
|
|
"\t___HSM_DEBUG_MSG___ = \"\";\n"
|
|
"}\n"
|
|
"\n"
|
|
"%s::~%s()\n"
|
|
"{\n"
|
|
"\tif ( ___HSM_CURSTATE___ != ___HSM_NULL_STATE___ )\n"
|
|
"\t{\n"
|
|
"\t\t#if _DEBUG\n"
|
|
"\t\t\tprintf(\"\\n\\nHSM SHOULD BE EXITED via HSMDestruct() BEFORE DESTRUCTION!!!\\n\\n\\n\");\n"
|
|
"\t\t\twhile(1); // infinite loop\n"
|
|
"\t\t#else // _DEBUG\n"
|
|
"\t\t\tHSMDestruct();\n"
|
|
"\t\t#endif // _DEBUG\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"int %s::HSMGetCurrentState() const\n"
|
|
"{\n"
|
|
"\treturn ___HSM_CURSTATE___;\n"
|
|
"}\n"
|
|
"\n"
|
|
"int %s::HSMGetParentState(int state) const\n"
|
|
"{\n"
|
|
"\t// valid state?\n"
|
|
"\tif ( state >= 0 && state < ___HSM_NUM_STATES___ )\n"
|
|
"\t{\n"
|
|
"\t\t// const_cast used here because we know that pinging a state with ___HSM_ELICIT_PARENT___ is const-safe\n"
|
|
"\t\treturn const_cast<%s*>(this)->___HSM_CALL_STATE___(state,___HSM_ELICIT_PARENT___);\n"
|
|
"\t}\n"
|
|
"\n"
|
|
"\treturn ___HSM_NULL_STATE___;\n"
|
|
"}\n"
|
|
"\n"
|
|
"bool %s::HSMIsInState(int state) const\n"
|
|
"{\n"
|
|
"\tint parent = ___HSM_CURSTATE___;\n"
|
|
"\n"
|
|
"\t// valid state?\n"
|
|
"\tif ( state >= 0 && state < ___HSM_NUM_STATES___ )\n"
|
|
"\t{\n"
|
|
"\t\tdo\n"
|
|
"\t\t{\n"
|
|
"\t\t\tif ( state == parent )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\treturn true;\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\t\twhile ( (parent = HSMGetParentState(parent)) >= 0 );\n"
|
|
"\t}\n"
|
|
"\n"
|
|
"\treturn false;\n"
|
|
"}\n"
|
|
"\n"
|
|
"bool %s::HSMIsRunning() const\n"
|
|
"{\n"
|
|
"\tint s = HSMGetCurrentState();\n"
|
|
"\treturn (s >= 0 && s < ___HSM_NUM_STATES___);\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::HSMConstruct()\n"
|
|
"{\n"
|
|
"\t___HSM_START_MACHINE___();\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::HSMDestruct()\n"
|
|
"{\n"
|
|
"\t___HSM_STOP_MACHINE___();\n"
|
|
"}\n"
|
|
"\n"
|
|
"bool %s::HSMUpdate(float dt)\n"
|
|
"{\n"
|
|
"\t\t// TODO - update timers, trigger events as necessary\n"
|
|
"\tif ( HSMIsRunning() )\n"
|
|
"\t{\n"
|
|
"\t\t// update timers\n"
|
|
"\t\t___HSM_UPDATE_TIMERS___(dt);\n"
|
|
"\n"
|
|
"\t\t// process all current events\n"
|
|
"\t\tunsigned int numevents = ___HSM_EVENT_QUEUE___.size();\n"
|
|
"\t\tfor (unsigned int i=0;i<numevents && ___HSM_EVENT_QUEUE___.size() > 0;i++)\n"
|
|
"\t\t{\n"
|
|
"\t\t\tint e = -1;\n"
|
|
"\t\t\tif ( ___HSM_EVENT_QUEUE___.get(e) )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\t___HSM_HANDLE_EVENT___(e);\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// now handle our idle event (for the call to Update())\n"
|
|
"\t\t___HSM_HANDLE_EVENT___(___HSM_IDLE___);\n"
|
|
"\t}\n"
|
|
"\n"
|
|
"\t// return if we're still running\n"
|
|
"\treturn HSMIsRunning();\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::HSMTrigger(int event)\n"
|
|
"{\n"
|
|
"\tif ( event >= 0 && event < ___HSM_NUM_EVENTS___ )\n"
|
|
"\t{\n"
|
|
"\t\tif ( !___HSM_EVENT_QUEUE___.put(event) )\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_DEBUG___(\"Event queue overflow!!!\");\n"
|
|
"\t\t}\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"char* %s::HSMGetLastDebugMessage()\n"
|
|
"{\n"
|
|
"\treturn ___HSM_DEBUG_MSG___;\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_HANDLE_EVENT___(int event)\n"
|
|
"{\n"
|
|
"\tif ( event >= 0 && event < ___HSM_TOTAL_NUM_EVENTS___ )\n"
|
|
"\t{\n"
|
|
"\t\tint s = ___HSM_CURSTATE___;\n"
|
|
"\t\twhile ( s >= 0 && s < ___HSM_NUM_STATES___ )\n"
|
|
"\t\t{\n"
|
|
"\t\t\ts = ___HSM_CALL_STATE___(s,event);\n"
|
|
"\t\t}\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_START_MACHINE___()\n"
|
|
"{\n"
|
|
"\tif ( ___HSM_CURSTATE___ == ___HSM_NULL_STATE___ )\n"
|
|
"\t{\n"
|
|
"\t\t// empty event queue\n"
|
|
"\t\t___HSM_EVENT_QUEUE___.clear();\n"
|
|
"\n"
|
|
"\t\t// reset any timers\n"
|
|
"\t\tfor (int i=0;i<___HSM_TIMER_DEPTH___;i++)\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_STOP_TIMER___(i);\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// go to first state\n"
|
|
"\t\t___HSM_TRANSITION___(TOPSTATE);\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_STOP_MACHINE___()\n"
|
|
"{\n"
|
|
"\tif ( ___HSM_CURSTATE___ != ___HSM_NULL_STATE___ )\n"
|
|
"\t{\n"
|
|
"\t\t// exit all states to the root\n"
|
|
"\t\twhile ( ___HSM_CURSTATE___ != TOPSTATE )\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_CALL_STATE___(___HSM_CURSTATE___,___HSM_EXIT___);\n"
|
|
"\t\t\t___HSM_CURSTATE___ = ___HSM_CALL_STATE___(___HSM_CURSTATE___,___HSM_ELICIT_PARENT___);\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// and finally exit the root state\n"
|
|
"\t\t___HSM_CALL_STATE___(TOPSTATE,___HSM_EXIT___);\n"
|
|
"\t\t___HSM_CURSTATE___ = ___HSM_NULL_STATE___;\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"int %s::___HSM_CALL_STATE___(int state, int event)\n"
|
|
"{\n"
|
|
"\tif ( state < 0 || state >= ___HSM_NUM_STATES___ )\n"
|
|
"\t{\n"
|
|
"\t\t// invalid state id\n"
|
|
"\t\treturn ___HSM_ERROR___;\n"
|
|
"\t}\n"
|
|
"\telse\n"
|
|
"\t{\n"
|
|
"\t\t// valid state, lookup state function in table and call it\n"
|
|
"\t\treturn ((*this).*(___HSM_STATE_TAB___[state])) (event);\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_CALC_HIERARCHY___(int state, int path[___HSM_MAX_DEPTH___])\n"
|
|
"{\n"
|
|
"\tint num = 0;\n"
|
|
"\tint parent;\n"
|
|
"\n"
|
|
"\t// valid state?\n"
|
|
"\tif ( state >= 0 && state < ___HSM_NUM_STATES___ )\n"
|
|
"\t{\n"
|
|
"\t\t// add self\n"
|
|
"\t\tpath[num++] = state;\n"
|
|
"\n"
|
|
"\t\t// add parents\n"
|
|
"\t\tparent = state;\n"
|
|
"\t\twhile ( (parent = ___HSM_CALL_STATE___(parent,___HSM_ELICIT_PARENT___)) >= 0 )\n"
|
|
"\t\t{\n"
|
|
"\t\t\tpath[num++] = parent;\n"
|
|
"\t\t}\n"
|
|
"\t}\n"
|
|
"\n"
|
|
"\t// set remainder to NULL\n"
|
|
"\tfor (int i=num;i<___HSM_MAX_DEPTH___;i++)\n"
|
|
"\t{\n"
|
|
"\t\t// note that an invalid state comes straight here\n"
|
|
"\t\tpath[i] = ___HSM_NULL_STATE___;\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_TRANSITION___(int state)\n"
|
|
"{\n"
|
|
"\twhile ( state >= 0 && state < ___HSM_NUM_STATES___ )\n"
|
|
"\t{\n"
|
|
"\t\t// determine path to root for each state\n"
|
|
"\t\tint ExitPath[___HSM_MAX_DEPTH___];\n"
|
|
"\t\tint EntryPath[___HSM_MAX_DEPTH___];\n"
|
|
"\t\t___HSM_CALC_HIERARCHY___(___HSM_CURSTATE___,ExitPath);\n"
|
|
"\t\t___HSM_CALC_HIERARCHY___(state,EntryPath);\n"
|
|
"\n"
|
|
"\t\t//\n"
|
|
"\t\t// discover LCA\n"
|
|
"\t\t//\n"
|
|
"\t\tint ientry = ___HSM_MAX_DEPTH___ - 1;\n"
|
|
"\t\tint iexit = ___HSM_MAX_DEPTH___ - 1;\n"
|
|
"\n"
|
|
"\t\t// find root state in each path (or -1)\n"
|
|
"\t\twhile ( ientry >= 0 && EntryPath[ientry] == ___HSM_NULL_STATE___ )\n"
|
|
"\t\t{\n"
|
|
"\t\t\tientry--;\n"
|
|
"\t\t}\n"
|
|
"\t\twhile ( iexit >= 0 && ExitPath[iexit] == ___HSM_NULL_STATE___ )\n"
|
|
"\t\t{\n"
|
|
"\t\t\tiexit--;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// beginning at root states, walk backwards until we find the LCA\n"
|
|
"\t\twhile ( ientry >= 0 && iexit >= 0 && EntryPath[ientry] == ExitPath[iexit] )\n"
|
|
"\t\t{\n"
|
|
"\t\t\tientry--;\n"
|
|
"\t\t\tiexit--;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// deal with self transition\n"
|
|
"\t\tif ( ___HSM_CURSTATE___ == state && ientry == -1 && iexit == -1 )\n"
|
|
"\t\t{\n"
|
|
"\t\t\tientry++;\n"
|
|
"\t\t\tiexit++;\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t//\n"
|
|
"\t\t// walk transition\n"
|
|
"\t\t//\n"
|
|
"\n"
|
|
"\t\t// call exit routines\n"
|
|
"\t\tfor ( int i=0;i<=iexit;i++ )\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_CALL_STATE___(ExitPath[i],___HSM_EXIT___);\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// call entry routines\n"
|
|
"\t\tfor ( int i=ientry;i>=0;i-- )\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_CALL_STATE___(EntryPath[i],___HSM_ENTRY___);\n"
|
|
"\t\t}\n"
|
|
"\n"
|
|
"\t\t// set current state\n"
|
|
"\t\t___HSM_CURSTATE___ = state;\n"
|
|
"\n"
|
|
"\t\t// now check state for Default transitions\n"
|
|
"\t\tstate = ___HSM_CALL_STATE___(___HSM_CURSTATE___,___HSM_ELICIT_INITIAL_TRANSITION___);\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_DEBUG___(char* msg)\n"
|
|
"{\n"
|
|
"\t___HSM_DEBUG_MSG___ = msg;\n"
|
|
"\tHSMDebug(msg);\n"
|
|
"}\n"
|
|
"\n",
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str()
|
|
);
|
|
|
|
// timer functions
|
|
if ( m.GetTimerDepth() > 0 )
|
|
{
|
|
fprintf(f,
|
|
"void %s::___HSM_UPDATE_TIMERS___(float dt)\n"
|
|
"{\n"
|
|
"\tfor (int i=0;i<___HSM_TIMER_DEPTH___;i++)\n"
|
|
"\t{\n"
|
|
"\t\tif ( ___HSM_TIMERS___[i] >= 0.0f )\n"
|
|
"\t\t{\n"
|
|
"\t\t\t___HSM_TIMERS___[i] -= dt;\n"
|
|
"\t\t\tif ( ___HSM_TIMERS___[i] < 0.0f )\n"
|
|
"\t\t\t{\n"
|
|
"\t\t\t\tif ( !___HSM_EVENT_QUEUE___.put(___HSM_TIMER_0___+i) )\n"
|
|
"\t\t\t\t{\n"
|
|
"\t\t\t\t\t___HSM_DEBUG___(\"Event queue overflow!!!\");\n"
|
|
"\t\t\t\t}\n"
|
|
"\t\t\t}\n"
|
|
"\t\t}\n"
|
|
"\t}\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_START_TIMER___(int id, float time)\n"
|
|
"{\n"
|
|
"\t___HSM_TIMERS___[id] = time;\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_STOP_TIMER___(int id)\n"
|
|
"{\n"
|
|
"\t___HSM_TIMERS___[id] = -1.0f;\n"
|
|
"}\n"
|
|
"\n",
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
fprintf(f,
|
|
"void %s::___HSM_UPDATE_TIMERS___(float dt)\n"
|
|
"{ // no timers in this machine\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_START_TIMER___(int id, float time)\n"
|
|
"{ // no timers in this machine\n"
|
|
"}\n"
|
|
"\n"
|
|
"void %s::___HSM_STOP_TIMER___(int id)\n"
|
|
"{ // no timers in this machine\n"
|
|
"}\n"
|
|
"\n",
|
|
m.name.c_str(),
|
|
m.name.c_str(),
|
|
m.name.c_str()
|
|
);
|
|
}
|
|
}
|
|
|
|
void OutputMachineCPP(FILE* f, std::string incfile, Machine& m){
|
|
// a warning
|
|
OutputNotice(f);
|
|
|
|
fprintf(f,
|
|
"#include \"%s\"\n"
|
|
"#if _DEBUG\n"
|
|
"#\tinclude <cstdio>\n"
|
|
"#endif // _DEBUG\n"
|
|
"\n",
|
|
incfile.c_str()
|
|
);
|
|
|
|
// actions
|
|
OutputActions(f,m);
|
|
|
|
// HSMDebug() overrideable
|
|
OutputMachineHSMDebug(f,m);
|
|
|
|
// state table
|
|
OutputStateTable(f,m);
|
|
|
|
// driver code
|
|
OutputMachineDriverCode(f,m);
|
|
|
|
// now states
|
|
OutputStates(f,m);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// main program
|
|
//
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
// parse command line
|
|
if ( !gConfig.ParseCommandLine(argc,argv) )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// header
|
|
if ( !gConfig.Quiet )
|
|
{
|
|
printf("Compiling '%s'...\n",gConfig.InFileName.c_str());
|
|
}
|
|
|
|
// open input file
|
|
AutoFILE infile((char*)gConfig.InFileName.c_str(),"r");
|
|
if ( !infile.Opened() )
|
|
{
|
|
printf("ERROR: unable to open '%s'\n",gConfig.InFileName.c_str());
|
|
return 1;
|
|
}
|
|
|
|
// parse input file
|
|
yyin = infile;
|
|
if ( yyparse() != 0 )
|
|
{
|
|
printf("ERROR: parser failed\n");
|
|
return 1;
|
|
}
|
|
|
|
// bail if we had errors during parse or validation [done at EndMachine()]
|
|
if ( gErrors > 0 )
|
|
{
|
|
printf("\nERROR: compilation aborted due to errors\n");
|
|
return 1;
|
|
}
|
|
|
|
// input looks OK!
|
|
if ( !gConfig.Quiet )
|
|
{
|
|
printf("Writing '%s', '%s'...\n",gConfig.OutCPPFileName.c_str(),gConfig.OutHFileName.c_str());
|
|
}
|
|
|
|
// open output files
|
|
AutoFILE cppout((char*)gConfig.OutCPPFileName.c_str(),"w");
|
|
if ( !cppout.Opened() )
|
|
{
|
|
printf("ERROR: unable to open '%s'\n",gConfig.OutCPPFileName.c_str());
|
|
return 1;
|
|
}
|
|
AutoFILE hout((char*)gConfig.OutHFileName.c_str(),"w");
|
|
if ( !hout.Opened() )
|
|
{
|
|
printf("ERROR: unable to open '%s'\n",gConfig.OutHFileName.c_str());
|
|
return 1;
|
|
}
|
|
|
|
// output code
|
|
for ( std::vector<Machine>::iterator it = gMachines.begin(); it != gMachines.end(); it++ )
|
|
{
|
|
OutputMachineH( hout, *it );
|
|
OutputMachineCPP( cppout, gConfig.IncludeName, *it );
|
|
}
|
|
|
|
// done
|
|
if ( !gConfig.Quiet )
|
|
{
|
|
printf("done.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|