-/* 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();
- }
- }
-}