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