Logo Search packages:      
Sourcecode: ragel version File versions

gvdotgen.cpp

/*
 *  Copyright 2001-2004 Adrian Thurston <adriant@ragel.ca>
 */

/*  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 "gvdotgen.h"
#include "parsetree.h"

using namespace std;

GraphvizDotGen::GraphvizDotGen( char *fsmName, ParseData *parseData, 
            RedFsmAp *redFsm, ostream &out )
:
      fsmName(fsmName),
      parseData(parseData),
      redFsm(redFsm),
      out(out)
{
}

std::ostream &GraphvizDotGen::KEY( long key )
{
      if ( parseData->isAlphSigned() )
            out << key;
      else
            out << (unsigned long) key;
      return out;
}

std::ostream &GraphvizDotGen::ACTION( RedAction *action )
{
      /* The action. */
      out << " / ";
      for ( ActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
            Action *action = parseData->actionIndex[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( long lowKey, long highKey )
{
      /* Output the key. Possibly a range. */
      KEY( lowKey );
      if ( ! redFsm->keyOps->eq( 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. */
                  if ( tel->value->action != 0 )
                        ACTION( tel->value->action );
                  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. */
            if ( state->defTrans->action != 0 )
                  ACTION( state->defTrans->action );
            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";
      out << "    ENTRY;\n";

      /* Psuedo states for entry points in the entry map. */
      for ( int enId = 0; enId < redFsm->entryList.length(); enId++ )
            out << "    en_" << enId << ";\n";

      /* Psuedo states for final states with eof actions. */
      for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
            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. */
      out << "    ENTRY -> " << redFsm->startState->id <<
                  " [ label = \"START\" ];\n";

      /* Transitions into the entry points. */
      RedEntryList::Iter en = redFsm->entryList;
      for ( int enId = 0; en.lte(); en++, enId++ ) {
            /* Get the name instantiation from nameIndex. */
            NameInst *nameInst = parseData->nameIndex[en->key];
            out << "    en_" << enId << " -> " << en->value->id <<
                        " [ label = \"" << nameInst->name << "\" ];\n";
      }

      /* Out action transitions. */
      for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
            if ( st->eofAction != 0 ) {
                  out << "    " << st->id << " -> eof_" << 
                              st->id << " [ label = \"EOF"; 
                  ACTION( st->eofAction ) << "\" ];\n";
            }
      }

      out <<
            "}\n";
}

Generated by  Doxygen 1.6.0   Back to index