2 * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
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
22 #include "rlgen-dot.h"
28 void lineDirective( ostream
&out
, char *fileName
, int line
)
32 void genLineDirective( ostream
&out
)
36 /* Override this so that write statement processing is ignored */
37 void GraphvizDotGen::writeStatement( InputLoc
&, int, char ** )
41 std::ostream
&GraphvizDotGen::KEY( Key key
)
43 if ( displayPrintables
&& key
.isPrintable() ) {
44 // Output values as characters, ensuring we escape the quote (") character
45 char cVal
= (char) key
.getVal();
48 out
<< "'\\" << cVal
<< "'";
75 out
<< "'" << cVal
<< "'";
80 if ( keyOps
->isSigned
)
83 out
<< (unsigned long) key
.getVal();
89 std::ostream
&GraphvizDotGen::TRANS_ACTION( RedStateAp
*fromState
, RedTransAp
*trans
)
92 RedAction
*actions
[3];
94 if ( fromState
->fromStateAction
!= 0 )
95 actions
[n
++] = fromState
->fromStateAction
;
96 if ( trans
->action
!= 0 )
97 actions
[n
++] = trans
->action
;
98 if ( trans
->targ
!= 0 && trans
->targ
->toStateAction
!= 0 )
99 actions
[n
++] = trans
->targ
->toStateAction
;
104 /* Loop the existing actions and write out what's there. */
105 for ( int a
= 0; a
< n
; a
++ ) {
106 for ( ActionTable::Iter actIt
= actions
[a
]->key
.first(); actIt
.lte(); actIt
++ ) {
107 Action
*action
= actIt
->value
;
108 out
<< action
->nameOrLoc();
109 if ( a
< n
-1 || !actIt
.last() )
116 std::ostream
&GraphvizDotGen::ACTION( RedAction
*action
)
120 for ( ActionTable::Iter actIt
= action
->key
.first(); actIt
.lte(); actIt
++ ) {
121 Action
*action
= actIt
->value
;
122 if ( action
->name
!= 0 )
125 out
<< action
->loc
.line
<< ":" << action
->loc
.col
;
132 std::ostream
&GraphvizDotGen::ONCHAR( Key lowKey
, Key highKey
)
134 if ( lowKey
> keyOps
->maxKey
) {
135 CondSpace
*condSpace
= findCondSpace( lowKey
, highKey
);
136 Key values
= ( lowKey
- condSpace
->baseKey
) / keyOps
->alphSize();
138 lowKey
= keyOps
->minKey
+
139 (lowKey
- condSpace
->baseKey
- keyOps
->alphSize() * values
.getVal());
140 highKey
= keyOps
->minKey
+
141 (highKey
- condSpace
->baseKey
- keyOps
->alphSize() * values
.getVal());
143 if ( lowKey
!= highKey
) {
149 for ( CondSet::Iter csi
= condSpace
->condSet
; csi
.lte(); csi
++ ) {
150 bool set
= values
& (1 << csi
.pos());
153 out
<< (*csi
)->nameOrLoc();
160 /* Output the key. Possibly a range. */
162 if ( highKey
!= lowKey
) {
170 void GraphvizDotGen::writeTransList( RedStateAp
*state
)
172 /* Build the set of unique transitions out of this state. */
173 RedTransSet stTransSet
;
174 for ( RedTransList::Iter tel
= state
->outRange
; tel
.lte(); tel
++ ) {
175 /* If we haven't seen the transitions before, the move forward
176 * emitting all the transitions on the same character. */
177 if ( stTransSet
.insert( tel
->value
) ) {
178 /* Write out the from and to states. */
179 out
<< "\t" << state
->id
<< " -> ";
181 if ( tel
->value
->targ
== 0 )
182 out
<< "err_" << state
->id
;
184 out
<< tel
->value
->targ
->id
;
186 /* Begin the label. */
187 out
<< " [ label = \"";
188 ONCHAR( tel
->lowKey
, tel
->highKey
);
190 /* Walk the transition list, finding the same. */
191 for ( RedTransList::Iter mtel
= tel
.next(); mtel
.lte(); mtel
++ ) {
192 if ( mtel
->value
== tel
->value
) {
194 ONCHAR( mtel
->lowKey
, mtel
->highKey
);
198 /* Write the action and close the transition. */
199 TRANS_ACTION( state
, tel
->value
);
204 /* Write the default transition. */
205 if ( state
->defTrans
!= 0 ) {
206 /* Write out the from and to states. */
207 out
<< "\t" << state
->id
<< " -> ";
209 if ( state
->defTrans
->targ
== 0 )
210 out
<< "err_" << state
->id
;
212 out
<< state
->defTrans
->targ
->id
;
214 /* Begin the label. */
215 out
<< " [ label = \"DEF";
217 /* Write the action and close the transition. */
218 TRANS_ACTION( state
, state
->defTrans
);
223 void GraphvizDotGen::writeDotFile( )
226 "digraph " << fsmName
<< " {\n"
229 /* Define the psuedo states. Transitions will be done after the states
230 * have been defined as either final or not final. */
231 out
<< " node [ shape = point ];\n";
233 if ( redFsm
->startState
!= 0 )
236 /* Psuedo states for entry points in the entry map. */
237 for ( EntryIdVect::Iter en
= entryPointIds
; en
.lte(); en
++ ) {
238 RedStateAp
*state
= allStates
+ *en
;
239 out
<< " en_" << state
->id
<< ";\n";
242 /* Psuedo states for final states with eof actions. */
243 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
244 if ( st
->eofTrans
!= 0 && st
->eofTrans
->action
!= 0 )
245 out
<< " eof_" << st
->id
<< ";\n";
246 if ( st
->eofAction
!= 0 )
247 out
<< " eof_" << st
->id
<< ";\n";
250 out
<< " node [ shape = circle, height = 0.2 ];\n";
252 /* Psuedo states for states whose default actions go to error. */
253 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
254 bool needsErr
= false;
255 if ( st
->defTrans
!= 0 && st
->defTrans
->targ
== 0 )
258 for ( RedTransList::Iter tel
= st
->outRange
; tel
.lte(); tel
++ ) {
259 if ( tel
->value
->targ
== 0 ) {
267 out
<< " err_" << st
->id
<< " [ label=\"\"];\n";
270 /* Attributes common to all nodes, plus double circle for final states. */
271 out
<< " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
273 /* List Final states. */
274 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
276 out
<< " " << st
->id
<< ";\n";
279 /* List transitions. */
280 out
<< " node [ shape = circle ];\n";
282 /* Walk the states. */
283 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
284 writeTransList( st
);
286 /* Transitions into the start state. */
287 if ( redFsm
->startState
!= 0 )
288 out
<< " ENTRY -> " << redFsm
->startState
->id
<< " [ label = \"IN\" ];\n";
290 /* Transitions into the entry points. */
291 for ( EntryIdVect::Iter en
= entryPointIds
; en
.lte(); en
++ ) {
292 RedStateAp
*state
= allStates
+ *en
;
293 char *name
= entryPointNames
[en
.pos()];
294 out
<< " en_" << state
->id
<< " -> " << state
->id
<<
295 " [ label = \"" << name
<< "\" ];\n";
298 /* Out action transitions. */
299 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
300 if ( st
->eofTrans
!= 0 && st
->eofTrans
->action
!= 0 ) {
301 out
<< " " << st
->id
<< " -> eof_" <<
302 st
->id
<< " [ label = \"EOF";
303 ACTION( st
->eofTrans
->action
) << "\" ];\n";
305 if ( st
->eofAction
!= 0 ) {
306 out
<< " " << st
->id
<< " -> eof_" <<
307 st
->id
<< " [ label = \"EOF";
308 ACTION( st
->eofAction
) << "\" ];\n";
316 void GraphvizDotGen::finishRagelDef()
318 if ( !graphvizDone
) {
321 /* For dot file generation we want to pick default transitions. */
322 redFsm
->chooseDefaultSpan();
324 /* Write out with it. */