#include "fsmcodegen.h"
#include "redfsm.h"
#include "gendata.h"
+#include "gvdotgen.h"
#include <sstream>
#include <string>
#include <assert.h>
return "if (true) ";
}
+/* Generate the code for an fsm. Assumes parseData is set up properly. Called
+ * by parser code. */
+void FsmCodeGen::prepareMachine()
+{
+ if ( hasBeenPrepared )
+ return;
+ hasBeenPrepared = true;
+
+ /* Do this before distributing transitions out to singles and defaults
+ * makes life easier. */
+ redFsm->maxKey = findMaxKey();
+
+ redFsm->assignActionLocs();
+
+ /* Order the states. */
+ redFsm->depthFirstOrdering();
+
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For goto driven machines we can keep the original depth
+ * first ordering because it's ok if the state ids are not
+ * sequential. Split the the ids by final state status. */
+ redFsm->sortStateIdsByFinal();
+ }
+ else {
+ /* For table driven machines the location of the state is used to
+ * identify it so the states must be sorted by their final ids.
+ * Though having a deterministic ordering is important,
+ * specifically preserving the depth first ordering is not because
+ * states are stored in tables. */
+ redFsm->sortStatesByFinal();
+ redFsm->sequentialStateIds();
+ }
+
+ /* Find the first final state. This is the final state with the lowest
+ * id. */
+ redFsm->findFirstFinState();
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ redFsm->setInTrans();
+
+ /* Anlayze Machine will find the final action reference counts, among
+ * other things. We will use these in reporting the usage
+ * of fsm directives in action code. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ codeGen->calcIndexSize();
+}
+
+void FsmCodeGen::generateGraphviz()
+{
+ /* Do ordering and choose state ids. */
+ redFsm->depthFirstOrdering();
+ redFsm->sequentialStateIds();
+
+ /* For dot file generation we want to pick default transitions. */
+ redFsm->chooseDefaultSpan();
+
+ /* Make the generator. */
+ GraphvizDotGen dotGen( fsmName, this, redFsm, out );
+
+ /* Write out with it. */
+ dotGen.writeDotFile();
+}
+
+void FsmCodeGen::generateCode()
+{
+ if ( writeOps & WO_NOEND )
+ hasEnd = false;
+
+ if ( writeOps & WO_NOERROR )
+ writeErr = false;
+
+ if ( writeOps & WO_NOPREFIX )
+ dataPrefix = false;
+
+ if ( writeOps & WO_NOFF )
+ writeFirstFinal = false;
+
+ if ( writeData || writeInit || writeExec || writeEOF ) {
+ prepareMachine();
+
+ /* Force a newline. */
+ out << "\n";
+ genLineDirective( out );
+ }
+
+
+ if ( writeExec ) {
+ /* Must set labels immediately before writing because we may depend
+ * on the noend write option. */
+ codeGen->setLabelsNeeded();
+ }
+
+ if ( writeData )
+ codeGen->writeOutData();
+
+ if ( writeInit )
+ codeGen->writeOutInit();
+
+ if ( writeExec )
+ codeGen->writeOutExec();
+
+ if ( writeEOF )
+ codeGen->writeOutEOF();
+}
+
+void FsmCodeGen::generate()
+{
+ if ( redFsm != 0 ) {
+ if ( outputFormat == OutCode )
+ generateCode();
+ else if ( outputFormat == OutGraphvizDot && !graphvizDone ) {
+ graphvizDone = true;
+ generateGraphviz();
+ }
+ }
+}
+
bool useIndicies;
public:
+ void generateGraphviz();
+ void prepareMachine();
+ void generateCode();
+
+ virtual void generate();
+
/* Determine if we should use indicies. */
virtual void calcIndexSize() {}
};
setValueLimits();
}
-/* Generate the code for an fsm. Assumes parseData is set up properly. Called
- * by parser code. */
-void CodeGenData::prepareMachine()
-{
- if ( hasBeenPrepared )
- return;
- hasBeenPrepared = true;
-
- /* Do this before distributing transitions out to singles and defaults
- * makes life easier. */
- redFsm->maxKey = findMaxKey();
-
- redFsm->assignActionLocs();
-
- /* Order the states. */
- redFsm->depthFirstOrdering();
-
- if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
- codeStyle == GenIpGoto || codeStyle == GenSplit )
- {
- /* For goto driven machines we can keep the original depth
- * first ordering because it's ok if the state ids are not
- * sequential. Split the the ids by final state status. */
- redFsm->sortStateIdsByFinal();
- }
- else {
- /* For table driven machines the location of the state is used to
- * identify it so the states must be sorted by their final ids.
- * Though having a deterministic ordering is important,
- * specifically preserving the depth first ordering is not because
- * states are stored in tables. */
- redFsm->sortStatesByFinal();
- redFsm->sequentialStateIds();
- }
-
- /* Find the first final state. This is the final state with the lowest
- * id. */
- redFsm->findFirstFinState();
-
- /* Choose default transitions and the single transition. */
- redFsm->chooseDefaultSpan();
-
- /* Maybe do flat expand, otherwise choose single. */
- if ( codeStyle == GenFlat || codeStyle == GenFFlat )
- redFsm->makeFlat();
- else
- redFsm->chooseSingle();
-
- /* If any errors have occured in the input file then don't write anything. */
- if ( gblErrorCount > 0 )
- return;
-
- if ( codeStyle == GenSplit )
- redFsm->partitionFsm( numSplitPartitions );
-
- if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
- redFsm->setInTrans();
-
- /* Anlayze Machine will find the final action reference counts, among
- * other things. We will use these in reporting the usage
- * of fsm directives in action code. */
- analyzeMachine();
-
- /* Determine if we should use indicies. */
- codeGen->calcIndexSize();
-}
-
-void CodeGenData::generateGraphviz()
-{
- /* Do ordering and choose state ids. */
- redFsm->depthFirstOrdering();
- redFsm->sequentialStateIds();
-
- /* For dot file generation we want to pick default transitions. */
- redFsm->chooseDefaultSpan();
-
- /* Make the generator. */
- GraphvizDotGen dotGen( fsmName, this, redFsm, out );
-
- /* Write out with it. */
- dotGen.writeDotFile();
-}
-
-void CodeGenData::generateCode()
-{
- if ( writeOps & WO_NOEND )
- hasEnd = false;
-
- if ( writeOps & WO_NOERROR )
- writeErr = false;
-
- if ( writeOps & WO_NOPREFIX )
- dataPrefix = false;
-
- if ( writeOps & WO_NOFF )
- writeFirstFinal = false;
-
- if ( writeData || writeInit || writeExec || writeEOF ) {
- prepareMachine();
-
- /* Force a newline. */
- out << "\n";
- genLineDirective( out );
- }
-
-
- if ( writeExec ) {
- /* Must set labels immediately before writing because we may depend
- * on the noend write option. */
- codeGen->setLabelsNeeded();
- }
-
- if ( writeData )
- codeGen->writeOutData();
-
- if ( writeInit )
- codeGen->writeOutInit();
-
- if ( writeExec )
- codeGen->writeOutExec();
-
- if ( writeEOF )
- codeGen->writeOutEOF();
-}
-
-void CodeGenData::generate()
-{
- if ( redFsm != 0 ) {
- if ( outputFormat == OutCode )
- generateCode();
- else if ( outputFormat == OutGraphvizDot && !graphvizDone ) {
- graphvizDone = true;
- generateGraphviz();
- }
- }
-}
void lineDirective( ostream &out, char *fileName, int line )
{
struct CodeGenData
{
CodeGenData( ostream &out );
+ virtual ~CodeGenData() {}
/*
* Collecting the machine.
bool setAlphType( char *data );
- void generateGraphviz();
void resolveTargetStates( InlineList *inlineList );
Key findMaxKey();
- void generate();
- void generateCode();
-
/* Gather various info on the machine. */
void analyzeActionList( RedAction *redAct, InlineList *inlineList );
void analyzeAction( Action *act, InlineList *inlineList );
void assignActionIds();
void prepareMachine();
bool hasBeenPrepared;
+
+ /* The interface to the code generator. */
+ virtual void generate() {}
};
void lineDirective( ostream &out, char *fileName, int line );