Cleanup and code movement related to makeCodeGen.
[external/ragel.git] / ragel / rubytable.cpp
1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *            2007 Adrian Thurston <thurston@complang.org>
4  */
5
6 /*  This file is part of Ragel.
7  *
8  *  Ragel is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  * 
13  *  Ragel is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  * 
18  *  You should have received a copy of the GNU General Public License
19  *  along with Ragel; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
21  */
22
23 #include <iomanip>
24 #include <sstream>
25 #include "redfsm.h"
26 #include "gendata.h"
27 #include "ragel.h"
28 #include "rubytable.h"
29
30 using std::ostream;
31 using std::ostringstream;
32 using std::string;
33 using std::cerr;
34 using std::endl;
35
36
37
38 void RubyTabCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
39 {
40         out << 
41                 "       begin\n"
42                 "               " << CS() << " = " << gotoDest << "\n"
43                 "               _trigger_goto = true\n"
44                 "               _goto_level = _again\n"
45                 "               break\n"
46                 "       end\n";
47 }
48
49 void RubyTabCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
50 {
51         out << 
52                 "       begin\n"
53                 "               " << CS() << " = (";
54         INLINE_LIST( out, ilItem->children, 0, inFinish );
55         out << ")\n";
56         out <<
57                 "               _trigger_goto = true\n"
58                 "               _goto_level = _again\n"
59                 "               break\n"
60                 "       end\n";
61 }
62
63 void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
64 {
65         if ( prePushExpr != 0 ) {
66                 out << "begin\n";
67                 INLINE_LIST( out, prePushExpr, 0, false );
68         }
69
70         out <<
71                 "       begin\n"
72                 "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
73                 "               " << TOP() << "+= 1\n"
74                 "               " << CS() << " = " << callDest << "\n"
75                 "               _trigger_goto = true\n"
76                 "               _goto_level = _again\n"
77                 "               break\n"
78                 "       end\n";
79
80         if ( prePushExpr != 0 )
81                 out << "end\n";
82 }
83
84 void RubyTabCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish )
85 {
86         if ( prePushExpr != 0 ) {
87                 out << "begin\n";
88                 INLINE_LIST( out, prePushExpr, 0, false );
89         }
90
91         out <<
92                 "       begin\n"
93                 "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
94                 "               " << TOP() << " += 1\n"
95                 "               " << CS() << " = (";
96         INLINE_LIST( out, ilItem->children, targState, inFinish );
97         out << ")\n";
98
99         out << 
100                 "               _trigger_goto = true\n"
101                 "               _goto_level = _again\n"
102                 "               break\n"
103                 "       end\n";
104
105         if ( prePushExpr != 0 )
106                 out << "end\n";
107 }
108
109 void RubyTabCodeGen::RET( ostream &out, bool inFinish )
110 {
111         out <<
112                 "       begin\n"
113                 "               " << TOP() << " -= 1\n"
114                 "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n";
115
116         if ( postPopExpr != 0 ) {
117                 out << "begin\n";
118                 INLINE_LIST( out, postPopExpr, 0, false );
119                 out << "end\n";
120         }
121
122         out <<
123                 "               _trigger_goto = true\n"
124                 "               _goto_level = _again\n"
125                 "               break\n"
126                 "       end\n";
127 }
128
129 void RubyTabCodeGen::BREAK( ostream &out, int targState )
130 {
131         out << 
132                 "       begin\n"
133                 "               " << P() << " += 1\n"
134                 "               _trigger_goto = true\n"
135                 "               _goto_level = _out\n"
136                 "               break\n"
137                 "       end\n";
138 }
139
140 void RubyTabCodeGen::COND_TRANSLATE()
141 {
142         out <<
143                 "       _widec = " << GET_KEY() << "\n"
144                 "       _keys = " << CO() << "[" << CS() << "]*2\n"
145                 "       _klen = " << CL() << "[" << CS() << "]\n"
146                 "       if _klen > 0\n"
147                 "               _lower = _keys\n"
148                 "               _upper = _keys + (_klen<<1) - 2\n"
149                 "               loop do\n"
150                 "                       break if _upper < _lower\n"
151                 "                       _mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
152                 "                       if " << GET_WIDE_KEY() << " < " << CK() << "[_mid]\n"
153                 "                               _upper = _mid - 2\n"
154                 "                       elsif " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1]\n"
155                 "                               _lower = _mid + 2\n"
156                 "                       else\n"
157                 "                               case " << C() << "[" << CO() << "[" << CS() << "]"
158                                                         " + ((_mid - _keys)>>1)]\n";
159
160         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
161                 GenCondSpace *condSpace = csi;
162                 out << "        when " << condSpace->condSpaceId << " then" ;
163                 out << "        _widec = " << KEY(condSpace->baseKey) << 
164                                 "+ (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ")\n";
165
166                 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
167                         Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
168                         out << "        _widec += " << condValOffset << " if ( ";
169                         CONDITION( out, *csi );
170                         out << " )\n";
171                 }
172         }
173
174         out <<
175                 "                               end # case\n"
176                 "                       end\n"
177                 "               end # loop\n"
178                 "       end\n";
179 }
180
181
182 void RubyTabCodeGen::LOCATE_TRANS()
183 {
184         out <<
185                 "       _keys = " << KO() << "[" << CS() << "]\n"
186                 "       _trans = " << IO() << "[" << CS() << "]\n"
187                 "       _klen = " << SL() << "[" << CS() << "]\n"
188                 "       _break_match = false\n"
189                 "       \n"
190                 "       begin\n"
191                 "         if _klen > 0\n"
192                 "            _lower = _keys\n"
193                 "            _upper = _keys + _klen - 1\n"
194                 "\n"
195                 "            loop do\n"
196                 "               break if _upper < _lower\n"
197                 "               _mid = _lower + ( (_upper - _lower) >> 1 )\n"
198                 "\n"
199                 "               if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
200                 "                  _upper = _mid - 1\n"
201                 "               elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid]\n"
202                 "                  _lower = _mid + 1\n"
203                 "               else\n"
204                 "                  _trans += (_mid - _keys)\n"
205                 "                  _break_match = true\n"
206                 "                  break\n"
207                 "               end\n"
208                 "            end # loop\n"
209                 "            break if _break_match\n"
210                 "            _keys += _klen\n"
211                 "            _trans += _klen\n"
212                 "         end"
213                 "\n"
214                 "         _klen = " << RL() << "[" << CS() << "]\n"
215                 "         if _klen > 0\n"
216                 "            _lower = _keys\n"
217                 "            _upper = _keys + (_klen << 1) - 2\n"
218                 "            loop do\n"
219                 "               break if _upper < _lower\n"
220                 "               _mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
221                 "               if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
222                 "                 _upper = _mid - 2\n"
223                 "               elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid+1]\n"
224                 "                 _lower = _mid + 2\n"
225                 "               else\n"
226                 "                 _trans += ((_mid - _keys) >> 1)\n"
227                 "                 _break_match = true\n"
228                 "                 break\n"
229                 "               end\n"
230                 "            end # loop\n"
231                 "            break if _break_match\n"
232                 "            _trans += _klen\n"
233                 "         end\n"
234                 "       end while false\n";
235 }
236
237 void RubyTabCodeGen::writeExec()
238 {
239         out << 
240                 "begin\n"
241                 "       _klen, _trans, _keys";
242
243         if ( redFsm->anyRegCurStateRef() )
244                 out << ", _ps";
245         if ( redFsm->anyConditions() ) 
246                 out << ", _widec";
247         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
248                         || redFsm->anyFromStateActions() )
249                 out << ", _acts, _nacts";
250
251         out << " = nil\n";
252
253         out << 
254                 "       _goto_level = 0\n"
255                 "       _resume = 10\n"
256                 "       _eof_trans = 15\n"
257                 "       _again = 20\n"
258                 "       _test_eof = 30\n"
259                 "       _out = 40\n";
260
261         out << 
262                 "       while true\n"
263                 "       _trigger_goto = false\n"
264                 "       if _goto_level <= 0\n";
265
266         if ( !noEnd ) {
267                 out << 
268                         "       if " << P() << " == " << PE() << "\n"
269                         "               _goto_level = _test_eof\n"
270                         "               next\n"
271                         "       end\n";
272         }
273
274         if ( redFsm->errState != 0 ) {
275                 out << 
276                         "       if " << CS() << " == " << redFsm->errState->id << "\n"
277                         "               _goto_level = _out\n"
278                         "               next\n"
279                         "       end\n";
280         }
281
282         /* The resume label. */
283         out << 
284                 "       end\n"
285                 "       if _goto_level <= _resume\n";
286         
287         if ( redFsm->anyFromStateActions() ) {
288                 out << 
289                         "       _acts = " << FSA() << "[" << CS() << "]\n"
290                         "       _nacts = " << A() << "[_acts]\n"
291                         "       _acts += 1\n"
292                         "       while _nacts > 0\n"
293                         "               _nacts -= 1\n"
294                         "               _acts += 1\n"
295                         "               case " << A() << "[_acts - 1]\n";
296                 FROM_STATE_ACTION_SWITCH();
297                 out <<
298                         "               end # from state action switch\n"
299                         "       end\n"
300                         "       if _trigger_goto\n"
301                         "               next\n"
302                         "       end\n";
303         }
304
305         if ( redFsm->anyConditions() )
306                 COND_TRANSLATE();
307
308         LOCATE_TRANS();
309
310         if ( useIndicies )
311                 out << "        _trans = " << I() << "[_trans]\n";
312
313         if ( redFsm->anyEofTrans() ) {
314                 out << 
315                         "       end\n"
316                         "       if _goto_level <= _eof_trans\n";
317         }
318
319         if ( redFsm->anyRegCurStateRef() )
320                 out << "        _ps = " << CS() << "\n";
321
322         out << "        " << CS() << " = " << TT() << "[_trans]\n";
323
324         if ( redFsm->anyRegActions() ) {
325                 out << 
326                         "       if " << TA() << "[_trans] != 0\n"
327                         "               _acts = " << TA() << "[_trans]\n"
328                         "               _nacts = " << A() << "[_acts]\n"
329                         "               _acts += 1\n"
330                         "               while _nacts > 0\n"
331                         "                       _nacts -= 1\n"
332                         "                       _acts += 1\n"
333                         "                       case " << A() << "[_acts - 1]\n";
334                 ACTION_SWITCH();
335                 out <<
336                         "                       end # action switch\n"
337                         "               end\n"
338                         "       end\n"
339                         "       if _trigger_goto\n"
340                         "               next\n"
341                         "       end\n";
342         }
343
344         /* The again label. */
345         out <<
346                 "       end\n"
347                 "       if _goto_level <= _again\n";
348
349         if ( redFsm->anyToStateActions() ) {
350                 out <<
351                         "       _acts = " << TSA() << "["  << CS() << "]\n"
352                         "       _nacts = " << A() << "[_acts]\n"
353                         "       _acts += 1\n"
354                         "       while _nacts > 0\n"
355                         "               _nacts -= 1\n"
356                         "               _acts += 1\n"
357                         "               case " << A() << "[_acts - 1]\n";
358                 TO_STATE_ACTION_SWITCH();
359                 out <<
360                         "               end # to state action switch\n"
361                         "       end\n"
362                         "       if _trigger_goto\n"
363                         "               next\n"
364                         "       end\n";
365         }
366
367         if ( redFsm->errState != 0 ) {
368                 out << 
369                         "       if " << CS() << " == " << redFsm->errState->id << "\n"
370                         "               _goto_level = _out\n"
371                         "               next\n"
372                         "       end\n";
373         }
374
375         out << "        " << P() << " += 1\n";
376
377         if ( !noEnd ) {
378                 out << 
379                         "       if " << P() << " != " << PE() << "\n"
380                         "               _goto_level = _resume\n"
381                         "               next\n"
382                         "       end\n";
383         }
384         else {
385                 out <<
386                         "       _goto_level = _resume\n"
387                         "       next\n";
388         }
389
390         /* The test_eof label. */
391         out <<
392                 "       end\n"
393                 "       if _goto_level <= _test_eof\n";
394
395         if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
396                 out << 
397                         "       if " << P() << " == " << EOFV() << "\n";
398
399                 if ( redFsm->anyEofTrans() ) {
400                         out <<
401                                 "       if " << ET() << "[" << CS() << "] > 0\n"
402                                 "               _trans = " << ET() << "[" << CS() << "] - 1;\n"
403                                 "               _goto_level = _eof_trans\n"
404                                 "               next;\n"
405                                 "       end\n";
406                 }
407
408                 if ( redFsm->anyEofActions() ) {
409                         out << 
410                                 "       __acts = " << EA() << "[" << CS() << "]\n"
411                                 "       __nacts = " << " " << A() << "[__acts]\n"
412                                 "       __acts += 1\n"
413                                 "       while __nacts > 0\n"
414                                 "               __nacts -= 1\n"
415                                 "               __acts += 1\n"
416                                 "               case " << A() << "[__acts - 1]\n";
417                         EOF_ACTION_SWITCH() <<
418                                 "               end # eof action switch\n"
419                                 "       end\n"
420                                 "       if _trigger_goto\n"
421                                 "               next\n"
422                                 "       end\n";
423                 }
424
425                 out << 
426                         "end\n";
427         }
428
429         out << 
430                 "       end\n"
431                 "       if _goto_level <= _out\n"
432                 "               break\n"
433                 "       end\n";
434
435         /* The loop for next. */
436         out << 
437                 "       end\n";
438
439         /* Wrapping the execute block. */
440         out << 
441                 "       end\n";
442 }
443
444 std::ostream &RubyTabCodeGen::FROM_STATE_ACTION_SWITCH() 
445 {
446         /* Walk the list of functions, printing the cases. */
447         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
448                 /* Write out referenced actions. */
449                 if ( act->numFromStateRefs > 0 ) {
450                         /* Write the case label, the action */
451                         out << "                        when " << act->actionId << " then\n";
452                         ACTION( out, act, 0, false );
453                 }
454         }
455
456         genLineDirective( out );
457         return out;
458 }
459
460
461 std::ostream &RubyTabCodeGen::TO_STATE_ACTION_SWITCH()
462 {
463         /* Walk the list of functions, printing the cases. */
464         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
465                 /* Write out referenced actions. */
466                 if ( act->numToStateRefs > 0 ) {
467                         /* Write the case label, the action and the case break. */
468                         out << "when " << act->actionId << " then\n";
469                         ACTION( out, act, 0, false );
470                 }
471         }
472
473         genLineDirective( out );
474         return out;
475 }
476
477 std::ostream &RubyTabCodeGen::EOF_ACTION_SWITCH()
478 {
479         /* Walk the list of functions, printing the cases. */
480         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
481                 /* Write out referenced actions. */
482                 if ( act->numEofRefs > 0 ) {
483                         /* Write the case label, the action and the case break. */
484                         out << "when " << act->actionId << " then\n";
485                         ACTION( out, act, 0, true );
486                 }
487         }
488
489         genLineDirective( out );
490         return out;
491 }
492
493 std::ostream &RubyTabCodeGen::ACTION_SWITCH()
494 {
495         /* Walk the list of functions, printing the cases. */
496         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
497                 /* Write out referenced actions. */
498                 if ( act->numTransRefs > 0 ) {
499                         /* Write the case label, the action and the case break. */
500                         out << "when " << act->actionId << " then\n";
501                         ACTION( out, act, 0, false );
502                 }
503         }
504
505         genLineDirective( out );
506         return out;
507 }
508
509
510 void RubyTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
511 {
512         ret << CS() << " = " << nextDest << ";";
513 }
514
515 void RubyTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
516 {
517         ret << CS() << " = (";
518         INLINE_LIST( ret, ilItem->children, 0, inFinish );
519         ret << ");";
520 }
521
522
523 int RubyTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
524 {
525         int act = 0;
526         if ( state->toStateAction != 0 )
527                 act = state->toStateAction->location+1;
528         return act;
529 }
530
531 int RubyTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
532 {
533         int act = 0;
534         if ( state->fromStateAction != 0 )
535                 act = state->fromStateAction->location+1;
536         return act;
537 }
538
539 int RubyTabCodeGen::EOF_ACTION( RedStateAp *state )
540 {
541         int act = 0;
542         if ( state->eofAction != 0 )
543                 act = state->eofAction->location+1;
544         return act;
545 }
546
547
548 std::ostream &RubyTabCodeGen::COND_OFFSETS()
549 {
550         START_ARRAY_LINE();
551         int totalStateNum = 0, curKeyOffset = 0;
552         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
553                 /* Write the key offset. */
554                 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
555
556                 /* Move the key offset ahead. */
557                 curKeyOffset += st->stateCondList.length();
558         }
559         END_ARRAY_LINE();
560         return out;
561 }
562
563 std::ostream &RubyTabCodeGen::KEY_OFFSETS()
564 {
565         START_ARRAY_LINE();
566         int totalStateNum = 0, curKeyOffset = 0;
567         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
568                 /* Write the key offset. */
569                 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
570
571                 /* Move the key offset ahead. */
572                 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
573         }
574         END_ARRAY_LINE();
575         return out;
576 }
577
578
579 std::ostream &RubyTabCodeGen::INDEX_OFFSETS()
580 {
581         START_ARRAY_LINE();
582         int totalStateNum = 0, curIndOffset = 0;
583         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
584                 /* Write the index offset. */
585                 ARRAY_ITEM( INT(curIndOffset), ++totalStateNum, st.last() );
586
587                 /* Move the index offset ahead. */
588                 curIndOffset += st->outSingle.length() + st->outRange.length();
589                 if ( st->defTrans != 0 )
590                         curIndOffset += 1;
591         }
592         END_ARRAY_LINE();
593         return out;
594 }
595
596 std::ostream &RubyTabCodeGen::COND_LENS()
597 {
598         START_ARRAY_LINE();
599         int totalStateNum = 0;
600         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
601                 /* Write singles length. */
602                 ARRAY_ITEM( INT(st->stateCondList.length()), ++totalStateNum, st.last() );
603         }
604         END_ARRAY_LINE();
605         return out;
606 }
607
608
609 std::ostream &RubyTabCodeGen::SINGLE_LENS()
610 {
611         START_ARRAY_LINE();
612         int totalStateNum = 0;
613         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
614                 /* Write singles length. */
615                 ARRAY_ITEM( INT(st->outSingle.length()), ++totalStateNum, st.last() );
616         }
617         END_ARRAY_LINE();
618         return out;
619 }
620
621 std::ostream &RubyTabCodeGen::RANGE_LENS()
622 {
623         START_ARRAY_LINE();
624         int totalStateNum = 0;
625         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
626                 /* Emit length of range index. */
627                 ARRAY_ITEM( INT(st->outRange.length()), ++totalStateNum, st.last() );
628         }
629         END_ARRAY_LINE();
630         return out;
631 }
632
633 std::ostream &RubyTabCodeGen::TO_STATE_ACTIONS()
634 {
635         START_ARRAY_LINE();
636         int totalStateNum = 0;
637         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
638                 /* Write any eof action. */
639                 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), ++totalStateNum, st.last() );
640         }
641         END_ARRAY_LINE();
642         return out;
643 }
644
645 std::ostream &RubyTabCodeGen::FROM_STATE_ACTIONS()
646 {
647         START_ARRAY_LINE();
648         int totalStateNum = 0;
649         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
650                 /* Write any eof action. */
651                 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), ++totalStateNum, st.last() );
652         }
653         END_ARRAY_LINE();
654         return out;
655 }
656
657 std::ostream &RubyTabCodeGen::EOF_ACTIONS()
658 {
659         START_ARRAY_LINE();
660         int totalStateNum = 0;
661         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
662                 /* Write any eof action. */
663                 ARRAY_ITEM( INT(EOF_ACTION(st)), ++totalStateNum, st.last() );
664         }
665         END_ARRAY_LINE();
666         return out;
667 }
668
669 std::ostream &RubyTabCodeGen::EOF_TRANS()
670 {
671         START_ARRAY_LINE();
672         int totalStateNum = 0;
673         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
674                 /* Write any eof action. */
675                 long trans = 0;
676                 if ( st->eofTrans != 0 ) {
677                         assert( st->eofTrans->pos >= 0 );
678                         trans = st->eofTrans->pos+1;
679                 }
680
681                 /* Write any eof action. */
682                 ARRAY_ITEM( INT(trans), ++totalStateNum, st.last() );
683         }
684         END_ARRAY_LINE();
685         return out;
686 }
687
688 std::ostream &RubyTabCodeGen::COND_KEYS()
689 {
690         START_ARRAY_LINE();
691         int totalTrans = 0;
692         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
693                 /* Loop the state's transitions. */
694                 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
695                         /* Lower key. */
696                         ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
697                         ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
698                 }
699         }
700
701         /* Output one last number so we don't have to figure out when the last
702          * entry is and avoid writing a comma. */
703         ARRAY_ITEM( INT(0), ++totalTrans, true );
704         END_ARRAY_LINE();
705         return out;
706 }
707
708 std::ostream &RubyTabCodeGen::COND_SPACES()
709 {
710         START_ARRAY_LINE();
711         int totalTrans = 0;
712         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
713                 /* Loop the state's transitions. */
714                 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
715                         /* Cond Space id. */
716                         ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
717                 }
718         }
719
720         /* Output one last number so we don't have to figure out when the last
721          * entry is and avoid writing a comma. */
722         ARRAY_ITEM( INT(0), ++totalTrans, true );
723         END_ARRAY_LINE();
724         return out;
725 }
726
727 std::ostream &RubyTabCodeGen::KEYS()
728 {
729         START_ARRAY_LINE();
730         int totalTrans = 0;
731         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
732                 /* Loop the singles. */
733                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
734                         ARRAY_ITEM( KEY( stel->lowKey ), ++totalTrans, false );
735                 }
736
737                 /* Loop the state's transitions. */
738                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
739                         /* Lower key. */
740                         ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
741
742                         /* Upper key. */
743                         ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
744                 }
745         }
746
747         /* Output one last number so we don't have to figure out when the last
748          * entry is and avoid writing a comma. */
749         ARRAY_ITEM( INT(0), ++totalTrans, true );
750         END_ARRAY_LINE();
751         return out;
752 }
753
754 std::ostream &RubyTabCodeGen::INDICIES()
755 {
756         int totalTrans = 0;
757         START_ARRAY_LINE();
758         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
759                 /* Walk the singles. */
760                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
761                         ARRAY_ITEM( KEY( stel->value->id ), ++totalTrans, false );
762                 }
763
764                 /* Walk the ranges. */
765                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
766                         ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
767                 }
768
769                 /* The state's default index goes next. */
770                 if ( st->defTrans != 0 ) {
771                         ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
772                 }
773         }
774
775         /* Output one last number so we don't have to figure out when the last
776          * entry is and avoid writing a comma. */
777         ARRAY_ITEM( INT(0), ++totalTrans, true );
778         END_ARRAY_LINE();
779         return out;
780 }
781
782 std::ostream &RubyTabCodeGen::TRANS_TARGS()
783 {
784         int totalTrans = 0;
785         START_ARRAY_LINE();
786         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
787                 /* Walk the singles. */
788                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
789                         RedTransAp *trans = stel->value;
790                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
791                 }
792
793                 /* Walk the ranges. */
794                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
795                         RedTransAp *trans = rtel->value;
796                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
797                 }
798
799                 /* The state's default target state. */
800                 if ( st->defTrans != 0 ) {
801                         RedTransAp *trans = st->defTrans;
802                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
803                 }
804         }
805
806         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
807                 if ( st->eofTrans != 0 ) {
808                         RedTransAp *trans = st->eofTrans;
809                         trans->pos = totalTrans;
810                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
811                 }
812         }
813
814         /* Output one last number so we don't have to figure out when the last
815          * entry is and avoid writing a comma. */
816         ARRAY_ITEM( INT(0), ++totalTrans, true );
817         END_ARRAY_LINE();
818         return out;
819 }
820
821
822 std::ostream &RubyTabCodeGen::TRANS_ACTIONS()
823 {
824         int totalTrans = 0;
825         START_ARRAY_LINE();
826         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
827                 /* Walk the singles. */
828                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
829                         RedTransAp *trans = stel->value;
830                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
831                 }
832
833                 /* Walk the ranges. */
834                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
835                         RedTransAp *trans = rtel->value;
836                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
837                 }
838
839                 /* The state's default index goes next. */
840                 if ( st->defTrans != 0 ) {
841                         RedTransAp *trans = st->defTrans;
842                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
843                 }
844         }
845
846         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
847                 if ( st->eofTrans != 0 ) {
848                         RedTransAp *trans = st->eofTrans;
849                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
850                 }
851         }
852
853         /* Output one last number so we don't have to figure out when the last
854          * entry is and avoid writing a comma. */
855         ARRAY_ITEM( INT(0), ++totalTrans, true );
856         END_ARRAY_LINE();
857         return out;
858 }
859
860 std::ostream &RubyTabCodeGen::TRANS_TARGS_WI()
861 {
862         /* Transitions must be written ordered by their id. */
863         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
864         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
865                 transPtrs[trans->id] = trans;
866
867         /* Keep a count of the num of items in the array written. */
868         START_ARRAY_LINE();
869         int totalStates = 0;
870         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
871                 /* Save the position. Needed for eofTargs. */
872                 RedTransAp *trans = transPtrs[t];
873                 trans->pos = t;
874
875                 /* Write out the target state. */
876                 ARRAY_ITEM( INT(trans->targ->id), ++totalStates, ( t >= redFsm->transSet.length()-1 ) );
877         }
878         END_ARRAY_LINE();
879         delete[] transPtrs;
880         return out;
881 }
882
883
884 std::ostream &RubyTabCodeGen::TRANS_ACTIONS_WI()
885 {
886         /* Transitions must be written ordered by their id. */
887         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
888         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
889                 transPtrs[trans->id] = trans;
890
891         /* Keep a count of the num of items in the array written. */
892         START_ARRAY_LINE();
893         int totalAct = 0;
894         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
895                 /* Write the function for the transition. */
896                 RedTransAp *trans = transPtrs[t];
897                 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalAct, 
898                                 ( t >= redFsm->transSet.length()-1 ) );
899         }
900         END_ARRAY_LINE();
901         delete[] transPtrs;
902         return out;
903 }
904
905
906 void RubyTabCodeGen::writeData()
907 {
908         /* If there are any transtion functions then output the array. If there
909          * are none, don't bother emitting an empty array that won't be used. */
910         if ( redFsm->anyActions() ) {
911                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
912                 ACTIONS_ARRAY();
913                 CLOSE_ARRAY() <<
914                 "\n";
915         }
916
917         if ( redFsm->anyConditions() ) {
918                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
919                 COND_OFFSETS();
920                 CLOSE_ARRAY() <<
921                 "\n";
922
923                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
924                 COND_LENS();
925                 CLOSE_ARRAY() <<
926                 "\n";
927
928                 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
929                 COND_KEYS();
930                 CLOSE_ARRAY() <<
931                 "\n";
932
933                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
934                 COND_SPACES();
935                 CLOSE_ARRAY() <<
936                 "\n";
937         }
938
939         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
940         KEY_OFFSETS();
941         CLOSE_ARRAY() <<
942         "\n";
943
944         OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
945         KEYS();
946         CLOSE_ARRAY() <<
947         "\n";
948
949         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
950         SINGLE_LENS();
951         CLOSE_ARRAY() <<
952         "\n";
953
954         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
955         RANGE_LENS();
956         CLOSE_ARRAY() <<
957         "\n";
958
959         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
960         INDEX_OFFSETS();
961         CLOSE_ARRAY() <<
962         "\n";
963
964         if ( useIndicies ) {
965                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
966                 INDICIES();
967                 CLOSE_ARRAY() <<
968                 "\n";
969
970                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
971                 TRANS_TARGS_WI();
972                 CLOSE_ARRAY() <<
973                 "\n";
974
975                 if ( redFsm->anyActions() ) {
976                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
977                         TRANS_ACTIONS_WI();
978                         CLOSE_ARRAY() <<
979                         "\n";
980                 }
981         }
982         else {
983                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
984                 TRANS_TARGS();
985                 CLOSE_ARRAY() <<
986                 "\n";
987
988                 if ( redFsm->anyActions() ) {
989                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
990                         TRANS_ACTIONS();
991                         CLOSE_ARRAY() <<
992                         "\n";
993                 }
994         }
995
996         if ( redFsm->anyToStateActions() ) {
997                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
998                 TO_STATE_ACTIONS();
999                 CLOSE_ARRAY() <<
1000                 "\n";
1001         }
1002
1003         if ( redFsm->anyFromStateActions() ) {
1004                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1005                 FROM_STATE_ACTIONS();
1006                 CLOSE_ARRAY() <<
1007                 "\n";
1008         }
1009
1010         if ( redFsm->anyEofActions() ) {
1011                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1012                 EOF_ACTIONS();
1013                 CLOSE_ARRAY() <<
1014                 "\n";
1015         }
1016
1017         if ( redFsm->anyEofTrans() ) {
1018                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
1019                 EOF_TRANS();
1020                 CLOSE_ARRAY() <<
1021                 "\n";
1022         }
1023         
1024         STATE_IDS();
1025 }
1026
1027 /*
1028  Local Variables:
1029  mode: c++
1030  indent-tabs-mode: 1
1031  c-file-style: "bsd"
1032  End:
1033  */