removed redundant error check
[external/ragel.git] / rlgen-dot / gvdotgen.cpp
1 /*
2  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
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.
11  * 
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.
16  * 
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 
20  */
21
22 #include "rlgen-dot.h"
23 #include "gvdotgen.h"
24 #include "gendata.h"
25
26 using namespace std;
27
28 /* Override this so that write statement processing is ignored */
29 void GraphvizDotGen::writeStatement( GenInputLoc &, int, char ** )
30 {
31 }
32
33 std::ostream &GraphvizDotGen::KEY( Key key )
34 {
35         if ( displayPrintables && key.isPrintable() ) {
36                 // Output values as characters, ensuring we escape the quote (") character
37                 char cVal = (char) key.getVal();
38                 switch ( cVal ) {
39                         case '"': case '\\':
40                                 out << "'\\" << cVal << "'";
41                                 break;
42                         case '\a':
43                                 out << "'\\\\a'";
44                                 break;
45                         case '\b':
46                                 out << "'\\\\b'";
47                                 break;
48                         case '\t':
49                                 out << "'\\\\t'";
50                                 break;
51                         case '\n':
52                                 out << "'\\\\n'";
53                                 break;
54                         case '\v':
55                                 out << "'\\\\v'";
56                                 break;
57                         case '\f':
58                                 out << "'\\\\f'";
59                                 break;
60                         case '\r':
61                                 out << "'\\\\r'";
62                                 break;
63                         case ' ':
64                                 out << "SP";
65                                 break;
66                         default:        
67                                 out << "'" << cVal << "'";
68                                 break;
69                 }
70         }
71         else {
72                 if ( keyOps->isSigned )
73                         out << key.getVal();
74                 else
75                         out << (unsigned long) key.getVal();
76         }
77
78         return out;
79 }
80
81 std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
82 {
83         int n = 0;
84         RedAction *actions[3];
85
86         if ( fromState->fromStateAction != 0 )
87                 actions[n++] = fromState->fromStateAction;
88         if ( trans->action != 0 )
89                 actions[n++] = trans->action;
90         if ( trans->targ != 0 && trans->targ->toStateAction != 0 )
91                 actions[n++] = trans->targ->toStateAction;
92
93         if ( n > 0 )
94                 out << " / ";
95         
96         /* Loop the existing actions and write out what's there. */
97         for ( int a = 0; a < n; a++ ) {
98                 for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
99                         GenAction *action = actIt->value;
100                         out << action->nameOrLoc();
101                         if ( a < n-1 || !actIt.last() )
102                                 out << ", ";
103                 }
104         }
105         return out;
106 }
107
108 std::ostream &GraphvizDotGen::ACTION( RedAction *action )
109 {
110         /* The action. */
111         out << " / ";
112         for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
113                 GenAction *action = actIt->value;
114                 if ( action->name != 0 )
115                         out << action->name;
116                 else
117                         out << action->loc.line << ":" << action->loc.col;
118                 if ( !actIt.last() )
119                         out << ", ";
120         }
121         return out;
122 }
123
124 std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
125 {
126         if ( lowKey > keyOps->maxKey ) {
127                 GenCondSpace *condSpace = findCondSpace( lowKey, highKey );
128                 Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
129
130                 lowKey = keyOps->minKey + 
131                         (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
132                 highKey = keyOps->minKey + 
133                         (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
134                 KEY( lowKey );
135                 if ( lowKey != highKey ) {
136                         out << "..";
137                         KEY( highKey );
138                 }
139                 out << "(";
140
141                 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
142                         bool set = values & (1 << csi.pos());
143                         if ( !set )
144                                 out << "!";
145                         out << (*csi)->nameOrLoc();
146                         if ( !csi.last() )
147                                 out << ", ";
148                 }
149                 out << ")";
150         }
151         else {
152                 /* Output the key. Possibly a range. */
153                 KEY( lowKey );
154                 if ( highKey != lowKey ) {
155                         out << "..";
156                         KEY( highKey );
157                 }
158         }
159         return out;
160 }
161
162 void GraphvizDotGen::writeTransList( RedStateAp *state )
163 {
164         /* Build the set of unique transitions out of this state. */
165         RedTransSet stTransSet;
166         for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
167                 /* If we haven't seen the transitions before, the move forward
168                  * emitting all the transitions on the same character. */
169                 if ( stTransSet.insert( tel->value ) ) {
170                         /* Write out the from and to states. */
171                         out << "\t" << state->id << " -> ";
172
173                         if ( tel->value->targ == 0 )
174                                 out << "err_" << state->id;
175                         else
176                                 out << tel->value->targ->id;
177
178                         /* Begin the label. */
179                         out << " [ label = \""; 
180                         ONCHAR( tel->lowKey, tel->highKey );
181
182                         /* Walk the transition list, finding the same. */
183                         for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
184                                 if ( mtel->value == tel->value ) {
185                                         out << ", ";
186                                         ONCHAR( mtel->lowKey, mtel->highKey );
187                                 }
188                         }
189
190                         /* Write the action and close the transition. */
191                         TRANS_ACTION( state, tel->value );
192                         out << "\" ];\n";
193                 }
194         }
195
196         /* Write the default transition. */
197         if ( state->defTrans != 0 ) {
198                 /* Write out the from and to states. */
199                 out << "\t" << state->id << " -> ";
200
201                 if ( state->defTrans->targ == 0 )
202                         out << "err_" << state->id;
203                 else
204                         out << state->defTrans->targ->id;
205
206                 /* Begin the label. */
207                 out << " [ label = \"DEF"; 
208
209                 /* Write the action and close the transition. */
210                 TRANS_ACTION( state, state->defTrans );
211                 out << "\" ];\n";
212         }
213 }
214
215 void GraphvizDotGen::writeDotFile( )
216 {
217         out << 
218                 "digraph " << fsmName << " {\n"
219                 "       rankdir=LR;\n";
220         
221         /* Define the psuedo states. Transitions will be done after the states
222          * have been defined as either final or not final. */
223         out << "        node [ shape = point ];\n";
224
225         if ( redFsm->startState != 0 )
226                 out << "        ENTRY;\n";
227
228         /* Psuedo states for entry points in the entry map. */
229         for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
230                 RedStateAp *state = allStates + *en;
231                 out << "        en_" << state->id << ";\n";
232         }
233
234         /* Psuedo states for final states with eof actions. */
235         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
236                 if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
237                         out << "        eof_" << st->id << ";\n";
238                 if ( st->eofAction != 0 )
239                         out << "        eof_" << st->id << ";\n";
240         }
241
242         out << "        node [ shape = circle, height = 0.2 ];\n";
243
244         /* Psuedo states for states whose default actions go to error. */
245         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
246                 bool needsErr = false;
247                 if ( st->defTrans != 0 && st->defTrans->targ == 0 )
248                         needsErr = true;
249                 else {
250                         for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
251                                 if ( tel->value->targ == 0 ) {
252                                         needsErr = true;
253                                         break;
254                                 }
255                         }
256                 }
257
258                 if ( needsErr )
259                         out << "        err_" << st->id << " [ label=\"\"];\n";
260         }
261
262         /* Attributes common to all nodes, plus double circle for final states. */
263         out << "        node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
264
265         /* List Final states. */
266         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
267                 if ( st->isFinal )
268                         out << "        " << st->id << ";\n";
269         }
270
271         /* List transitions. */
272         out << "        node [ shape = circle ];\n";
273
274         /* Walk the states. */
275         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
276                 writeTransList( st );
277
278         /* Transitions into the start state. */
279         if ( redFsm->startState != 0 ) 
280                 out << "        ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
281
282         /* Transitions into the entry points. */
283         for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
284                 RedStateAp *state = allStates + *en;
285                 char *name = entryPointNames[en.pos()];
286                 out << "        en_" << state->id << " -> " << state->id <<
287                                 " [ label = \"" << name << "\" ];\n";
288         }
289
290         /* Out action transitions. */
291         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
292                 if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
293                         out << "        " << st->id << " -> eof_" << 
294                                         st->id << " [ label = \"EOF"; 
295                         ACTION( st->eofTrans->action ) << "\" ];\n";
296                 }
297                 if ( st->eofAction != 0 ) {
298                         out << "        " << st->id << " -> eof_" << 
299                                         st->id << " [ label = \"EOF"; 
300                         ACTION( st->eofAction ) << "\" ];\n";
301                 }
302         }
303
304         out <<
305                 "}\n";
306 }
307
308 void GraphvizDotGen::finishRagelDef()
309 {
310         if ( !graphvizDone ) {
311                 graphvizDone = true;
312
313                 /* For dot file generation we want to pick default transitions. */
314                 redFsm->chooseDefaultSpan();
315
316                 /* Write out with it. */
317                 writeDotFile();
318         }
319 }