dotcodegen.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
  3. */
  4. /* This file is part of Ragel.
  5. *
  6. * Ragel is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Ragel is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Ragel; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "ragel.h"
  21. #include "dotcodegen.h"
  22. #include "gendata.h"
  23. using std::istream;
  24. using std::ifstream;
  25. using std::ostream;
  26. using std::ios;
  27. using std::cin;
  28. using std::cout;
  29. using std::cerr;
  30. using std::endl;
  31. /* Override this so that write statement processing is ignored */
  32. bool GraphvizDotGen::writeStatement( InputLoc &, int, char ** )
  33. {
  34. return false;
  35. }
  36. std::ostream &GraphvizDotGen::KEY( Key key )
  37. {
  38. if ( displayPrintables && key.isPrintable() ) {
  39. // Output values as characters, ensuring we escape the quote (") character
  40. char cVal = (char) key.getVal();
  41. switch ( cVal ) {
  42. case '"': case '\\':
  43. out << "'\\" << cVal << "'";
  44. break;
  45. case '\a':
  46. out << "'\\\\a'";
  47. break;
  48. case '\b':
  49. out << "'\\\\b'";
  50. break;
  51. case '\t':
  52. out << "'\\\\t'";
  53. break;
  54. case '\n':
  55. out << "'\\\\n'";
  56. break;
  57. case '\v':
  58. out << "'\\\\v'";
  59. break;
  60. case '\f':
  61. out << "'\\\\f'";
  62. break;
  63. case '\r':
  64. out << "'\\\\r'";
  65. break;
  66. case ' ':
  67. out << "SP";
  68. break;
  69. default:
  70. out << "'" << cVal << "'";
  71. break;
  72. }
  73. }
  74. else {
  75. if ( keyOps->isSigned )
  76. out << key.getVal();
  77. else
  78. out << (unsigned long) key.getVal();
  79. }
  80. return out;
  81. }
  82. std::ostream &GraphvizDotGen::TRANS_ACTION( RedStateAp *fromState, RedTransAp *trans )
  83. {
  84. int n = 0;
  85. RedAction *actions[3];
  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. if ( n > 0 )
  93. out << " / ";
  94. /* Loop the existing actions and write out what's there. */
  95. for ( int a = 0; a < n; a++ ) {
  96. for ( GenActionTable::Iter actIt = actions[a]->key.first(); actIt.lte(); actIt++ ) {
  97. GenAction *action = actIt->value;
  98. out << action->nameOrLoc();
  99. if ( a < n-1 || !actIt.last() )
  100. out << ", ";
  101. }
  102. }
  103. return out;
  104. }
  105. std::ostream &GraphvizDotGen::ACTION( RedAction *action )
  106. {
  107. /* The action. */
  108. out << " / ";
  109. for ( GenActionTable::Iter actIt = action->key.first(); actIt.lte(); actIt++ ) {
  110. GenAction *action = actIt->value;
  111. if ( action->name != 0 )
  112. out << action->name;
  113. else
  114. out << action->loc.line << ":" << action->loc.col;
  115. if ( !actIt.last() )
  116. out << ", ";
  117. }
  118. return out;
  119. }
  120. std::ostream &GraphvizDotGen::ONCHAR( Key lowKey, Key highKey )
  121. {
  122. GenCondSpace *condSpace;
  123. if ( lowKey > keyOps->maxKey && (condSpace=findCondSpace(lowKey, highKey) ) ) {
  124. Key values = ( lowKey - condSpace->baseKey ) / keyOps->alphSize();
  125. lowKey = keyOps->minKey +
  126. (lowKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
  127. highKey = keyOps->minKey +
  128. (highKey - condSpace->baseKey - keyOps->alphSize() * values.getVal());
  129. KEY( lowKey );
  130. if ( lowKey != highKey ) {
  131. out << "..";
  132. KEY( highKey );
  133. }
  134. out << "(";
  135. for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
  136. bool set = values & (1 << csi.pos());
  137. if ( !set )
  138. out << "!";
  139. out << (*csi)->nameOrLoc();
  140. if ( !csi.last() )
  141. out << ", ";
  142. }
  143. out << ")";
  144. }
  145. else {
  146. /* Output the key. Possibly a range. */
  147. KEY( lowKey );
  148. if ( highKey != lowKey ) {
  149. out << "..";
  150. KEY( highKey );
  151. }
  152. }
  153. return out;
  154. }
  155. void GraphvizDotGen::writeTransList( RedStateAp *state )
  156. {
  157. /* Build the set of unique transitions out of this state. */
  158. RedTransSet stTransSet;
  159. for ( RedTransList::Iter tel = state->outRange; tel.lte(); tel++ ) {
  160. /* If we haven't seen the transitions before, the move forward
  161. * emitting all the transitions on the same character. */
  162. if ( stTransSet.insert( tel->value ) ) {
  163. /* Write out the from and to states. */
  164. out << "\t" << state->id << " -> ";
  165. if ( tel->value->targ == 0 )
  166. out << "err_" << state->id;
  167. else
  168. out << tel->value->targ->id;
  169. /* Begin the label. */
  170. out << " [ label = \"";
  171. ONCHAR( tel->lowKey, tel->highKey );
  172. /* Walk the transition list, finding the same. */
  173. for ( RedTransList::Iter mtel = tel.next(); mtel.lte(); mtel++ ) {
  174. if ( mtel->value == tel->value ) {
  175. out << ", ";
  176. ONCHAR( mtel->lowKey, mtel->highKey );
  177. }
  178. }
  179. /* Write the action and close the transition. */
  180. TRANS_ACTION( state, tel->value );
  181. out << "\" ];\n";
  182. }
  183. }
  184. /* Write the default transition. */
  185. if ( state->defTrans != 0 ) {
  186. /* Write out the from and to states. */
  187. out << "\t" << state->id << " -> ";
  188. if ( state->defTrans->targ == 0 )
  189. out << "err_" << state->id;
  190. else
  191. out << state->defTrans->targ->id;
  192. /* Begin the label. */
  193. out << " [ label = \"DEF";
  194. /* Write the action and close the transition. */
  195. TRANS_ACTION( state, state->defTrans );
  196. out << "\" ];\n";
  197. }
  198. }
  199. void GraphvizDotGen::writeDotFile( )
  200. {
  201. out <<
  202. "digraph " << fsmName << " {\n"
  203. " rankdir=LR;\n";
  204. /* Define the psuedo states. Transitions will be done after the states
  205. * have been defined as either final or not final. */
  206. out << " node [ shape = point ];\n";
  207. if ( redFsm->startState != 0 )
  208. out << " ENTRY;\n";
  209. /* Psuedo states for entry points in the entry map. */
  210. for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
  211. RedStateAp *state = allStates + *en;
  212. out << " en_" << state->id << ";\n";
  213. }
  214. /* Psuedo states for final states with eof actions. */
  215. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  216. if ( st->eofTrans != 0 && st->eofTrans->action != 0 )
  217. out << " eof_" << st->id << ";\n";
  218. if ( st->eofAction != 0 )
  219. out << " eof_" << st->id << ";\n";
  220. }
  221. out << " node [ shape = circle, height = 0.2 ];\n";
  222. /* Psuedo states for states whose default actions go to error. */
  223. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  224. bool needsErr = false;
  225. if ( st->defTrans != 0 && st->defTrans->targ == 0 )
  226. needsErr = true;
  227. else {
  228. for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ ) {
  229. if ( tel->value->targ == 0 ) {
  230. needsErr = true;
  231. break;
  232. }
  233. }
  234. }
  235. if ( needsErr )
  236. out << " err_" << st->id << " [ label=\"\"];\n";
  237. }
  238. /* Attributes common to all nodes, plus double circle for final states. */
  239. out << " node [ fixedsize = true, height = 0.65, shape = doublecircle ];\n";
  240. /* List Final states. */
  241. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  242. if ( st->isFinal )
  243. out << " " << st->id << ";\n";
  244. }
  245. /* List transitions. */
  246. out << " node [ shape = circle ];\n";
  247. /* Walk the states. */
  248. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  249. writeTransList( st );
  250. /* Transitions into the start state. */
  251. if ( redFsm->startState != 0 )
  252. out << " ENTRY -> " << redFsm->startState->id << " [ label = \"IN\" ];\n";
  253. /* Transitions into the entry points. */
  254. for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) {
  255. RedStateAp *state = allStates + *en;
  256. char *name = entryPointNames[en.pos()];
  257. out << " en_" << state->id << " -> " << state->id <<
  258. " [ label = \"" << name << "\" ];\n";
  259. }
  260. /* Out action transitions. */
  261. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  262. if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
  263. out << " " << st->id << " -> eof_" <<
  264. st->id << " [ label = \"EOF";
  265. ACTION( st->eofTrans->action ) << "\" ];\n";
  266. }
  267. if ( st->eofAction != 0 ) {
  268. out << " " << st->id << " -> eof_" <<
  269. st->id << " [ label = \"EOF";
  270. ACTION( st->eofAction ) << "\" ];\n";
  271. }
  272. }
  273. out <<
  274. "}\n";
  275. }
  276. void GraphvizDotGen::finishRagelDef()
  277. {
  278. /* For dot file generation we want to pick default transitions. */
  279. redFsm->chooseDefaultSpan();
  280. }