123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
- */
- /* This file is part of Ragel.
- *
- * Ragel is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Ragel is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Ragel; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "ragel.h"
- #include "dotcodegen.h"
- #include "gendata.h"
- using std::istream;
- using std::ifstream;
- using std::ostream;
- using std::ios;
- using std::cin;
- using std::cout;
- using std::cerr;
- using std::endl;
- /* Override this so that write statement processing is ignored */
- bool GraphvizDotGen::writeStatement( InputLoc &, int, char ** )
- {
- return false;
- }
- std::ostream &GraphvizDotGen::KEY( Key key )
- {
- if ( displayPrintables && key.isPrintable() ) {
- // Output values as characters, ensuring we escape the quote (") character
- char cVal = (char) key.getVal();
- switch ( cVal ) {
- case '"': case '\\':
- out << "'\\" << cVal << "'";
- break;
- case '\a':
- out << "'\\\\a'";
- break;
- case '\b':
- out << "'\\\\b'";
- break;
- case '\t':
- out << "'\\\\t'";
- break;
- case '\n':
- out << "'\\\\n'";
- break;
- case '\v':
- out << "'\\\\v'";
- break;
- case '\f':
- out << "'\\\\f'";
- break;
- case '\r':
- out << "'\\\\r'";
- break;
- case ' ':
- out << "SP";
- break;
- default:
- out << "'" << cVal << "'";
- break;
- }
- }
- else {
- if ( keyOps->isSigned )
- out << key.getVal();
- else
- out << (unsigned long) key.getVal();
- }
- return out;
- }
- std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
- {
- int n = 0;
- RedAction *actions[3];
- if ( fromState->fromStateAction != 0 )
- actions[n++] = fromState->fromStateAction;
- if ( trans->action != 0 )
- actions[n++] = trans->action;
- if ( trans->targ != 0 && trans->targ->toStateAction != 0 )
- actions[n++] = trans->targ->toStateAction;
- if ( n > 0 )
- out << " / ";
-
- /* Loop the existing actions and write out what's there. */
- for ( int a = 0; a < n; a++ ) {
- for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
- GenAction *action = actIt->value;
- out << action->nameOrLoc();
- if ( a < n-1 || !actIt.last() )
- out << ", ";
- }
- }
- return out;
- }
- std::ostream &GraphvizDotGen::ACTION( RedAction *action )
- {
- /* The action. */
- out << " / ";
- for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
- GenAction *action = actIt->value;
- if ( action->name != 0 )
- out << action->name;
- else
- out << action->loc.line << ":" << action->loc.col;
- if ( !actIt.last() )
- out << ", ";
- }
- return out;
- }
- std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
- {
- GenCondSpace *condSpace;
- if ( lowKey > keyOps->maxKey && (condSpace=findCondSpace(lowKey, highKey) ) ) {
- Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
- lowKey = keyOps->minKey +
- (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
- highKey = keyOps->minKey +
- (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
- KEY( lowKey );
- if ( lowKey != highKey ) {
- out << "..";
- KEY( highKey );
- }
- out << "(";
- for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
- bool set = values & (1 << csi.pos());
- if ( !set )
- out << "!";
- out << (*csi)->nameOrLoc();
- if ( !csi.last() )
- out << ", ";
- }
- out << ")";
- }
- else {
- /* Output the key. Possibly a range. */
- KEY( lowKey );
- if ( highKey != lowKey ) {
- out << "..";
- KEY( highKey );
- }
- }
- return out;
- }
- void GraphvizDotGen::writeTransList( RedStateAp *state )
- {
- /* Build the set of unique transitions out of this state. */
- RedTransSet stTransSet;
- for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
- /* If we haven't seen the transitions before, the move forward
- * emitting all the transitions on the same character. */
- if ( stTransSet.insert( tel->value ) ) {
- /* Write out the from and to states. */
- out << "\t" << state->id << " -> ";
- if ( tel->value->targ == 0 )
- out << "err_" << state->id;
- else
- out << tel->value->targ->id;
- /* Begin the label. */
- out << " [ label = \"";
- ONCHAR( tel->lowKey, tel->highKey );
- /* Walk the transition list, finding the same. */
- for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
- if ( mtel->value == tel->value ) {
- out << ", ";
- ONCHAR( mtel->lowKey, mtel->highKey );
- }
- }
- /* Write the action and close the transition. */
- TRANS_ACTION( state, tel->value );
- out << "\" ];\n";
- }
- }
- /* Write the default transition. */
- if ( state->defTrans != 0 ) {
- /* Write out the from and to states. */
- out << "\t" << state->id << " -> ";
- if ( state->defTrans->targ == 0 )
- out << "err_" << state->id;
- else
- out << state->defTrans->targ->id;
- /* Begin the label. */
- out << " [ label = \"DEF";
- /* Write the action and close the transition. */
- TRANS_ACTION( state, state->defTrans );
- out << "\" ];\n";
- }
- }
- void GraphvizDotGen::writeDotFile( )
- {
- out <<
- "digraph " << fsmName << " {\n"
- " rankdir=LR;\n";
-
- /* Define the psuedo states. Transitions will be done after the states
- * have been defined as either final or not final. */
- out << " node [ shape = point ];\n";
- if ( redFsm->startState != 0 )
- out << " ENTRY;\n";
- /* Psuedo states for entry points in the entry map. */
- for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
- RedStateAp *state = allStates + *en;
- out << " en_" << state->id << ";\n";
- }
- /* Psuedo states for final states with eof actions. */
- for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
- if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
- out << " eof_" << st->id << ";\n";
- if ( st->eofAction != 0 )
- out << " eof_" << st->id << ";\n";
- }
- out << " node [ shape = circle, height = 0.2 ];\n";
- /* Psuedo states for states whose default actions go to error. */
- for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
- bool needsErr = false;
- if ( st->defTrans != 0 && st->defTrans->targ == 0 )
- needsErr = true;
- else {
- for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
- if ( tel->value->targ == 0 ) {
- needsErr = true;
- break;
- }
- }
- }
- if ( needsErr )
- out << " err_" << st->id << " [ label=\"\"];\n";
- }
- /* Attributes common to all nodes, plus double circle for final states. */
- out << " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
- /* List Final states. */
- for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
- if ( st->isFinal )
- out << " " << st->id << ";\n";
- }
- /* List transitions. */
- out << " node [ shape = circle ];\n";
- /* Walk the states. */
- for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
- writeTransList( st );
- /* Transitions into the start state. */
- if ( redFsm->startState != 0 )
- out << " ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
- /* Transitions into the entry points. */
- for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
- RedStateAp *state = allStates + *en;
- char *name = entryPointNames[en.pos()];
- out << " en_" << state->id << " -> " << state->id <<
- " [ label = \"" << name << "\" ];\n";
- }
- /* Out action transitions. */
- for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
- if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
- out << " " << st->id << " -> eof_" <<
- st->id << " [ label = \"EOF";
- ACTION( st->eofTrans->action ) << "\" ];\n";
- }
- if ( st->eofAction != 0 ) {
- out << " " << st->id << " -> eof_" <<
- st->id << " [ label = \"EOF";
- ACTION( st->eofAction ) << "\" ];\n";
- }
- }
- out <<
- "}\n";
- }
- void GraphvizDotGen::finishRagelDef()
- {
- /* For dot file generation we want to pick default transitions. */
- redFsm->chooseDefaultSpan();
- }
|