2 * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
5 /* This file is part of Ragel.
7 * Ragel is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Ragel is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Ragel; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dot-codegen.h"
35 /* Invoked by the parser when the root element is opened. */
36 ostream *dotOpenOutput( const char *inputFile )
38 /* Make sure we are not writing to the same file as the input file. */
39 if ( outputFileName != 0 && strcmp( inputFile, outputFileName ) == 0 ) {
40 error() << "output file \"" << outputFileName <<
41 "\" is the same as the input file" << endl;
44 if ( outputFileName != 0 ) {
45 /* Create the filter on the output and open it. */
46 outFilter = new output_filter( outputFileName );
47 outFilter->open( outputFileName, ios::out|ios::trunc );
48 if ( !outFilter->is_open() ) {
49 error() << "error opening " << outputFileName << " for writing" << endl;
53 /* Open the output stream, attaching it to the filter. */
54 outStream = new ostream( outFilter );
57 /* Writing out ot std out. */
63 /* Invoked by the parser when a ragel definition is opened. */
64 CodeGenData *dotMakeCodeGen( const char *sourceFileName, const char *fsmName,
65 ostream &out, bool wantComplete )
67 CodeGenData *codeGen = new GraphvizDotGen(out);
69 codeGen->sourceFileName = sourceFileName;
70 codeGen->fsmName = fsmName;
71 codeGen->wantComplete = wantComplete;
76 /* Override this so that write statement processing is ignored */
77 void GraphvizDotGen::writeStatement( InputLoc &, int, char ** )
81 std::ostream &GraphvizDotGen::KEY( Key key )
83 if ( displayPrintables && key.isPrintable() ) {
84 // Output values as characters, ensuring we escape the quote (") character
85 char cVal = (char) key.getVal();
88 out << "'\\" << cVal << "'";
115 out << "'" << cVal << "'";
120 if ( keyOps->isSigned )
123 out << (unsigned long) key.getVal();
129 std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
132 RedAction *actions[3];
134 if ( fromState->fromStateAction != 0 )
135 actions[n++] = fromState->fromStateAction;
136 if ( trans->action != 0 )
137 actions[n++] = trans->action;
138 if ( trans->targ != 0 && trans->targ->toStateAction != 0 )
139 actions[n++] = trans->targ->toStateAction;
144 /* Loop the existing actions and write out what's there. */
145 for ( int a = 0; a < n; a++ ) {
146 for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
147 GenAction *action = actIt->value;
148 out << action->nameOrLoc();
149 if ( a < n-1 || !actIt.last() )
156 std::ostream &GraphvizDotGen::ACTION( RedAction *action )
160 for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
161 GenAction *action = actIt->value;
162 if ( action->name != 0 )
165 out << action->loc.line << ":" << action->loc.col;
172 std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
174 if ( lowKey > keyOps->maxKey ) {
175 GenCondSpace *condSpace = findCondSpace( lowKey, highKey );
176 Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
178 lowKey = keyOps->minKey +
179 (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
180 highKey = keyOps->minKey +
181 (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
183 if ( lowKey != highKey ) {
189 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
190 bool set = values & (1 << csi.pos());
193 out << (*csi)->nameOrLoc();
200 /* Output the key. Possibly a range. */
202 if ( highKey != lowKey ) {
210 void GraphvizDotGen::writeTransList( RedStateAp *state )
212 /* Build the set of unique transitions out of this state. */
213 RedTransSet stTransSet;
214 for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
215 /* If we haven't seen the transitions before, the move forward
216 * emitting all the transitions on the same character. */
217 if ( stTransSet.insert( tel->value ) ) {
218 /* Write out the from and to states. */
219 out << "\t" << state->id << " -> ";
221 if ( tel->value->targ == 0 )
222 out << "err_" << state->id;
224 out << tel->value->targ->id;
226 /* Begin the label. */
227 out << " [ label = \"";
228 ONCHAR( tel->lowKey, tel->highKey );
230 /* Walk the transition list, finding the same. */
231 for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
232 if ( mtel->value == tel->value ) {
234 ONCHAR( mtel->lowKey, mtel->highKey );
238 /* Write the action and close the transition. */
239 TRANS_ACTION( state, tel->value );
244 /* Write the default transition. */
245 if ( state->defTrans != 0 ) {
246 /* Write out the from and to states. */
247 out << "\t" << state->id << " -> ";
249 if ( state->defTrans->targ == 0 )
250 out << "err_" << state->id;
252 out << state->defTrans->targ->id;
254 /* Begin the label. */
255 out << " [ label = \"DEF";
257 /* Write the action and close the transition. */
258 TRANS_ACTION( state, state->defTrans );
263 void GraphvizDotGen::writeDotFile( )
266 "digraph " << fsmName << " {\n"
269 /* Define the psuedo states. Transitions will be done after the states
270 * have been defined as either final or not final. */
271 out << " node [ shape = point ];\n";
273 if ( redFsm->startState != 0 )
276 /* Psuedo states for entry points in the entry map. */
277 for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
278 RedStateAp *state = allStates + *en;
279 out << " en_" << state->id << ";\n";
282 /* Psuedo states for final states with eof actions. */
283 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
284 if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
285 out << " eof_" << st->id << ";\n";
286 if ( st->eofAction != 0 )
287 out << " eof_" << st->id << ";\n";
290 out << " node [ shape = circle, height = 0.2 ];\n";
292 /* Psuedo states for states whose default actions go to error. */
293 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
294 bool needsErr = false;
295 if ( st->defTrans != 0 && st->defTrans->targ == 0 )
298 for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
299 if ( tel->value->targ == 0 ) {
307 out << " err_" << st->id << " [ label=\"\"];\n";
310 /* Attributes common to all nodes, plus double circle for final states. */
311 out << " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
313 /* List Final states. */
314 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
316 out << " " << st->id << ";\n";
319 /* List transitions. */
320 out << " node [ shape = circle ];\n";
322 /* Walk the states. */
323 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
324 writeTransList( st );
326 /* Transitions into the start state. */
327 if ( redFsm->startState != 0 )
328 out << " ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
330 /* Transitions into the entry points. */
331 for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
332 RedStateAp *state = allStates + *en;
333 char *name = entryPointNames[en.pos()];
334 out << " en_" << state->id << " -> " << state->id <<
335 " [ label = \"" << name << "\" ];\n";
338 /* Out action transitions. */
339 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
340 if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
341 out << " " << st->id << " -> eof_" <<
342 st->id << " [ label = \"EOF";
343 ACTION( st->eofTrans->action ) << "\" ];\n";
345 if ( st->eofAction != 0 ) {
346 out << " " << st->id << " -> eof_" <<
347 st->id << " [ label = \"EOF";
348 ACTION( st->eofAction ) << "\" ];\n";
356 void GraphvizDotGen::finishRagelDef()
358 if ( !graphvizDone ) {
361 /* For dot file generation we want to pick default transitions. */
362 redFsm->chooseDefaultSpan();
364 /* Write out with it. */