2f3868149cc8f726f832f3b7a92efedcb3ddb02e
[external/ragel.git] / rlgen-ruby / rubycodegen.cpp
1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *            2007 Adrian Thurston <thurston@cs.queensu.ca>
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 "rlgen-ruby.h"
24 #include "rubycodegen.h"
25 #include "redfsm.h"
26 #include "gendata.h"
27 #include <iomanip>
28 #include <sstream>
29
30 /* Integer array line length. */
31 #define IALL 8
32
33 using std::ostream;
34 using std::ostringstream;
35 using std::string;
36 using std::cerr;
37 using std::endl;
38
39 void lineDirective( ostream &out, char *fileName, int line )
40 {
41         /* Write a comment containing line info. */
42         out << "# line " << line  << " \"";
43         for ( char *pc = fileName; *pc != 0; pc++ ) {
44                 if ( *pc == '\\' )
45                         out << "\\\\";
46                 else
47                         out << *pc;
48         }
49         out << "\"\n";
50 }
51
52 void genLineDirective( ostream &out )
53 {
54         std::streambuf *sbuf = out.rdbuf();
55         output_filter *filter = static_cast<output_filter*>(sbuf);
56         lineDirective( out, filter->fileName, filter->line + 1 );
57 }
58
59 void RubyCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
60 {
61         out << INDENT_U() << "begin"
62                 << INDENT_S() <<     CS() << " = " << gotoDest
63                 << INDENT_S() <<     "_again.call " << CTRL_FLOW()
64                 << INDENT_D() << "end";
65 }
66
67 void RubyCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
68 {
69         out << INDENT_U() << "begin"
70                 << INDENT_S() <<    CS() << " = (";
71         INLINE_LIST( out, ilItem->children, 0, inFinish );
72         out << ")"
73                 << INDENT_S() <<    "_again.call " << CTRL_FLOW()
74                 << INDENT_D() << "end";
75 }
76
77 void RubyCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
78 {
79         out << INDENT_U() << "begin" 
80                 << INDENT_S() <<   STACK() << "[" << TOP() << "] = " << CS() 
81                 << INDENT_S() <<   TOP() << "+= 1" 
82                 << INDENT_S() <<   CS() << " = " << callDest 
83                 << INDENT_S() <<   "_again.call " << CTRL_FLOW() 
84                 << INDENT_D() << "end";
85 }
86
87 void RubyCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
88 {
89         out << INDENT_U() << "begin" 
90                 << INDENT_S() <<   STACK() << "[" << TOP() << "] = " << CS() 
91                 << INDENT_S() <<   TOP() << " += 1" 
92                 << INDENT_S() <<   CS() << " = (";
93         INLINE_LIST( out, ilItem->children, targState, inFinish );
94         out << ")" 
95                 << INDENT_S() <<   "_again.call " << CTRL_FLOW() 
96                 << INDENT_D() << "end";
97 }
98
99 void RubyCodeGen::RET( ostream &out, bool inFinish )
100 {
101         out << INDENT_U() << "begin" 
102                 << INDENT_S() <<   TOP() << " -= 1" 
103                 << INDENT_S() <<   CS() << " = " << STACK() << "[" << TOP() << "]" 
104                 << INDENT_S() <<   "_again.call " << CTRL_FLOW() 
105                 << INDENT_D() << "end";
106 }
107
108 void RubyCodeGen::BREAK( ostream &out, int targState )
109 {
110         out << "_out.call " << CTRL_FLOW();
111 }
112
113 void RubyCodeGen::COND_TRANSLATE()
114 {
115         out << INDENT_S() << "_widec = " << GET_KEY() 
116                 << INDENT_S() << "_keys = " << CO() << "[" << CS() << "]*2" 
117                 << INDENT_S() << "_klen = " << CL() << "[" << CS() << "]" 
118                 << INDENT_U() << "if _klen > 0" 
119                 << INDENT_S() <<   "_lower = _keys" 
120                 << INDENT_S() <<   "_upper = _keys + (_klen<<1) - 2" 
121                 << INDENT_U() <<   "loop do" 
122                 << INDENT_S() <<      "break if _upper < _lower"  
123                 << INDENT_S() <<      "_mid = _lower + (((_upper-_lower) >> 1) & ~1)" 
124                 << INDENT_U() <<      "if " << GET_WIDE_KEY() << " < " << CK() << "[_mid]" 
125                 << INDENT_O() <<         "_upper = _mid - 2" 
126                 << INDENT_U() <<      "elsif " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1]" 
127                 << INDENT_O() <<         "_lower = _mid + 2" 
128                 << INDENT_U() <<      "else" 
129                 << INDENT_U() <<         "case " << C() << "[" << CO() << "[" << CS() << "]" 
130                 <<                      " + ((_mid - _keys)>>1)]" 
131         ;
132
133         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
134                 CondSpace *condSpace = csi;
135                 out << INDENT_U() << "when " << condSpace->condSpaceId << ":" ;
136                 out << INDENT_S() <<    "_widec = " << KEY(condSpace->baseKey)
137                         << "+ (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ")" ;
138
139                 for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
140                         Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
141                         out << INDENT_S() << "_widec += " << condValOffset << " if ( ";
142                         CONDITION( out, *csi );
143                         out << " )";
144                 }
145         }
146
147         out << INDENT_D() << "end # case" 
148                 << INDENT_D() << "end" 
149                 << INDENT_D() << "end # loop" 
150                 << INDENT_D() << "end" 
151         ;
152 }
153
154 void RubyCodeGen::LOCATE_TRANS()
155 {
156         out << INDENT_S() << "_keys = " << KO() << "[" << CS() << "]" 
157                 << INDENT_S() << "_trans = " << IO() << "[" << CS() << "]" 
158                 << INDENT_S() << "_klen = " << SL() << "[" << CS() << "]" 
159                 << INDENT_S()
160                 << INDENT_U() << "callcc do |_match|" 
161                 << INDENT_U() <<    "if _klen > 0" 
162                 << INDENT_S() <<       "_lower = _keys" 
163                 << INDENT_S() <<       "_upper = _keys + _klen - 1" 
164                 << INDENT_S()
165                 << INDENT_U() <<       "loop do" 
166                 << INDENT_S() <<          "break if _upper < _lower" 
167                 << INDENT_S() <<          "_mid = _lower + ( (_upper - _lower) >> 1 )" 
168                 << INDENT_S()
169                 << INDENT_U() <<          "if " << GET_WIDE_KEY() << " < " << K() << "[_mid]" 
170                 << INDENT_O() <<             "_upper = _mid - 1" 
171                 << INDENT_U() <<          "elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid]" 
172                 << INDENT_O() <<             "_lower = _mid + 1" 
173                 << INDENT_U() <<          "else" 
174                 << INDENT_S() <<             "_trans += (_mid - _keys)" 
175                 << INDENT_S() <<             "_match.call" 
176                 << INDENT_D() <<          "end" 
177                 << INDENT_D() <<       "end # loop" 
178                 << INDENT_S() <<       "_keys += _klen" 
179                 << INDENT_S() <<       "_trans += _klen" 
180                 << INDENT_D() <<    "end" 
181                 << INDENT_S()
182                 << INDENT_S() <<    "_klen = " << RL() << "[" << CS() << "]" 
183                 << INDENT_U() <<    "if _klen > 0" 
184                 << INDENT_S() <<       "_lower = _keys" 
185                 << INDENT_S() <<       "_upper = _keys + (_klen << 1) - 2" 
186                 << INDENT_U() <<       "loop do" 
187                 << INDENT_S() <<          "break if _upper < _lower"
188                 << INDENT_S() <<          "_mid = _lower + (((_upper-_lower) >> 1) & ~1)" 
189                 << INDENT_U() <<          "if " << GET_WIDE_KEY() << " < " << K() << "[_mid]" 
190                 << INDENT_O() <<            "_upper = _mid - 2" 
191                 << INDENT_U() <<          "elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid+1]" 
192                 << INDENT_O() <<            "_lower = _mid + 2" 
193                 << INDENT_U() <<          "else" 
194                 << INDENT_S() <<            "_trans += ((_mid - _keys) >> 1)" 
195                 << INDENT_S() <<            "_match.call" 
196                 << INDENT_D() <<          "end" 
197                 << INDENT_D() <<       "end # loop" 
198                 << INDENT_S() <<       "_trans += _klen" 
199                 << INDENT_D() <<    "end" 
200                 << INDENT_D() << "end # cc _match" ;
201 }
202
203 void RubyCodeGen::writeExec()
204 {
205         out << INDENT_U() << "callcc do |_out|" 
206                 << INDENT_S() <<    "_klen, _trans, _keys";
207
208         if ( redFsm->anyRegCurStateRef() )
209                 out << ", _ps";
210         if ( redFsm->anyConditions() ) 
211                 out << ", _widec";
212         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
213                         || redFsm->anyFromStateActions() )
214                 out << ", _acts, _nacts";
215
216         out << " = nil" ;
217
218         if ( hasEnd ) 
219                 out << INDENT_S() << "_out.call if " << P() << " == " << PE() ;
220
221         out << INDENT_S() << "_resume = nil" 
222                 << INDENT_S() << "callcc { |_cc| _resume = _cc }" ;
223
224         if ( redFsm->errState != 0) 
225                 out << INDENT_S() << "_out.call if " << CS() << " == " << redFsm->errState->id ;
226
227         if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || 
228                         redFsm->anyActionCalls() || redFsm->anyActionRets() )
229                 out << INDENT_U() << "callcc do |_again|" ;
230
231         if ( redFsm->anyFromStateActions() ) {
232                 out << INDENT_S() << "_acts = " << FSA() << "[" << CS() << "]" 
233                         << INDENT_S() << "_nacts = " << A() << "[_acts]" 
234                         << INDENT_S() << "_acts += 1" 
235                         << INDENT_U() << "while _nacts > 0" 
236                         << INDENT_S() <<   "_nacts -= 1" 
237                         << INDENT_S() <<   " _acts += 1" 
238                         << INDENT_U() <<   "case " << A() << "[_acts - 1]" ;
239                 FROM_STATE_ACTION_SWITCH()
240                         << INDENT_D() <<   "end # from state action switch" 
241                         << INDENT_D() << "end" 
242                         << INDENT_S();
243         }
244
245         if ( redFsm->anyConditions() )
246                 COND_TRANSLATE();
247
248         LOCATE_TRANS();
249
250         if ( redFsm->anyRegCurStateRef() )
251                 out << INDENT_S() << "_ps = " << CS() ;
252
253         if ( useIndicies )
254                 out << INDENT_S() << "_trans = " << I() << "[_trans]" ;
255
256         out << INDENT_S() << CS() << " = " << TT() << "[_trans]" ;
257
258         if ( redFsm->anyRegActions() ) {
259                 out << INDENT_S() << "_again.call if " << TA() << "[_trans] == 0" 
260                         << INDENT_S()
261                         << INDENT_S() << "_acts = " << TA() << "[_trans]" 
262                         << INDENT_S() << "_nacts = " << A() << "[_acts]" 
263                         << INDENT_S() << "_acts += 1" 
264                         << INDENT_U() << "while _nacts > 0" 
265                         << INDENT_S() <<   "_nacts -= 1" 
266                         << INDENT_S() <<   "_acts += 1" 
267                         << INDENT_U() <<   "case " << A() << "[_acts - 1]" ;
268                 ACTION_SWITCH()
269                         << INDENT_D() << "end # action switch"
270                         << INDENT_D() << "end"
271                         << INDENT_S();
272         }
273
274         if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || 
275                         redFsm->anyActionCalls() || redFsm->anyActionRets() )
276                 out << INDENT_D() << "end # cc _again";
277
278         if ( redFsm->anyToStateActions() ) {
279                 out << INDENT_S() << "_acts = " << TSA() << "["  << CS() << "]"  
280                         << INDENT_S() << "_nacts = " << A() << "[_acts]" 
281                         << INDENT_S() << "_acts += 1" 
282                         << INDENT_U() << "while _nacts > 0" 
283                         << INDENT_S() <<   "_nacts -= 1" 
284                         << INDENT_S() <<   "_acts += 1" 
285                         << INDENT_U() <<   "case " << A() << "[_acts - 1]" ;
286                 TO_STATE_ACTION_SWITCH()
287                         << INDENT_D() <<     "end # to state action switch"
288                         << INDENT_D() << "end" 
289                         << INDENT_S();
290         }
291
292         out << INDENT_S() << P() << " += 1" ;
293
294         if ( hasEnd )
295                 out << INDENT_S() << "_resume.call if " << P() << " != " << PE();
296
297         out << INDENT_D() << "end # cc _out" ;          
298 }
299
300 void RubyCodeGen::writeEOF()
301 {
302         if ( redFsm->anyEofActions() ) {
303                 out << INDENT_S() << "_acts = " << EA() << "[" << CS() << "]" 
304                         << INDENT_S() << "_nacts = " << " " << A() << "[_acts]" 
305                         << INDENT_S() << "_acts += 1" 
306                         << INDENT_U() << "while _nacts > 0" 
307                         << INDENT_S() <<    "_nacts -= 1" 
308                         << INDENT_S() <<    "_acts += 1" 
309                         << INDENT_S() <<    "case " << A() << "[_acts - 1]" ;
310                 EOF_ACTION_SWITCH()
311                         << INDENT_D() << "end # eof action switch" 
312                         << INDENT_D() << "end" 
313                         << INDENT_S();
314         }
315 }
316
317 std::ostream &RubyCodeGen::FROM_STATE_ACTION_SWITCH() 
318 {
319         /* Walk the list of functions, printing the cases. */
320         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
321                 /* Write out referenced actions. */
322                 if ( act->numFromStateRefs > 0 ) {
323                         /* Write the case label, the action */
324                         out << INDENT_S() << "when " << act->actionId << ":" ;
325                         ACTION( out, act, 0, false );
326                 }
327         }
328
329         genLineDirective( out );
330         return out;
331 }
332
333
334 std::ostream &RubyCodeGen::TO_STATE_ACTION_SWITCH()
335 {
336         /* Walk the list of functions, printing the cases. */
337         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
338                 /* Write out referenced actions. */
339                 if ( act->numToStateRefs > 0 ) {
340                         /* Write the case label, the action and the case break. */
341                         out << INDENT_S() << "when " << act->actionId << ":" ;
342                         ACTION( out, act, 0, false );
343                 }
344         }
345
346         genLineDirective( out );
347         return out;
348 }
349
350 std::ostream &RubyCodeGen::EOF_ACTION_SWITCH()
351 {
352         /* Walk the list of functions, printing the cases. */
353         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
354                 /* Write out referenced actions. */
355                 if ( act->numEofRefs > 0 ) {
356                         /* Write the case label, the action and the case break. */
357                         out << INDENT_S() << "when " << act->actionId << ":" ;
358                         ACTION( out, act, 0, true );
359                 }
360         }
361
362         genLineDirective( out );
363         return out;
364 }
365
366 std::ostream &RubyCodeGen::ACTION_SWITCH()
367 {
368         /* Walk the list of functions, printing the cases. */
369         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
370                 /* Write out referenced actions. */
371                 if ( act->numTransRefs > 0 ) {
372                         /* Write the case label, the action and the case break. */
373                         out << INDENT_S() << "when " << act->actionId << ":" ;
374                         ACTION( out, act, 0, false );
375                 }
376         }
377
378         genLineDirective( out );
379         return out;
380 }
381
382
383 void RubyCodeGen::writeInit()
384 {
385         out << INDENT_U() << "begin";
386
387         if ( writeCS )
388                 out << INDENT_S() <<   CS() << " = " << START();
389
390         /* If there are any calls, then the stack top needs initialization. */
391         if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
392                 out << INDENT_S() << TOP() << " = 0";
393
394         if ( hasLongestMatch ) {
395                 out << INDENT_S() << TOKSTART() << " = " << NULL_ITEM() 
396                         << INDENT_S() << TOKEND() << " = " << NULL_ITEM()
397                         << INDENT_S() << ACT() << " = 0"
398                         << INDENT_S();
399         }
400         out << INDENT_D() << "end";
401 }
402
403 std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
404 {
405         out << "class << self" << endl
406                 << INDENT(1) << "attr_accessor :" << name << endl
407                 << INDENT(1) << "private :" << name << ", :" << name << "=" << endl
408                 << "end" << endl
409                 << "self." << name << " = [" << endl;
410         return out;
411 }
412
413 std::ostream &RubyCodeGen::CLOSE_ARRAY()
414 {
415         return out << "]" << endl;
416 }
417
418 std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
419 {
420         out << "class << self" << endl
421                 << INDENT(1) << "attr_accessor :" << name << endl
422                 << "end" << endl
423                 << "self." << name;
424         return out;
425 }
426
427 string RubyCodeGen::ARR_OFF( string ptr, string offset )
428 {
429         return ptr + " + " + offset;
430 }
431
432 string RubyCodeGen::NULL_ITEM()
433 {
434         return "nil";
435 }
436
437 string RubyCodeGen::GET_KEY()
438 {
439         ostringstream ret;
440         if ( getKeyExpr != 0 ) { 
441                 /* Emit the user supplied method of retrieving the key. */
442                 ret << "(";
443                 INLINE_LIST( ret, getKeyExpr, 0, false );
444                 ret << ")";
445         }
446         else {
447                 /* Expression for retrieving the key, use simple dereference. */
448                 ret << "data[" << P() << "]";
449         }
450         return ret.str();
451 }
452
453 string RubyCodeGen::CTRL_FLOW()
454 {
455         return "if (true)";
456 }
457
458 void RubyCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
459 {
460         /* Write the preprocessor line info for going into the source file. */
461         lineDirective( ret, sourceFileName, action->loc.line );
462
463         /* Write the block and close it off. */
464         ret << " begin " << endl << INDENT(1);
465         INLINE_LIST( ret, action->inlineList, targState, inFinish );
466         ret << " end\n";
467         lineDirective( ret, sourceFileName, action->loc.line );
468         ret << endl;
469 }
470
471 string RubyCodeGen::INDENT(int level)
472 {
473         string result = "\n";
474         while ( level-- > 0 )
475                 result += "  "; /* The convention in ruby is 2 spaces per level */
476         return result;
477 }
478
479
480 void RubyCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
481 {
482         ret << CS() << " = " << nextDest << ";";
483 }
484
485 void RubyCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
486 {
487         ret << CS() << " = (";
488         INLINE_LIST( ret, ilItem->children, 0, inFinish );
489         ret << ");";
490 }
491
492 void RubyCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
493 {
494         /* The parser gives fexec two children. The double brackets are for D
495          * code. If the inline list is a single word it will get interpreted as a
496          * C-style cast by the D compiler. */
497         ret << " begin " << P() << " = ((";
498         INLINE_LIST( ret, item->children, targState, inFinish );
499         ret << "))-1; end\n";
500 }
501
502 void RubyCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
503 {
504         /* Tokend version of exec. */
505
506         /* The parser gives fexec two children. The double brackets are for D
507          * code. If the inline list is a single word it will get interpreted as a
508          * C-style cast by the D compiler. */
509         ret << " begin " << TOKEND() << " = ((";
510         INLINE_LIST( ret, item->children, targState, inFinish );
511         ret << ")); end\n";
512 }
513
514 /* Write out an inline tree structure. Walks the list and possibly calls out
515  * to virtual functions than handle language specific items in the tree. */
516 void RubyCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList, 
517                 int targState, bool inFinish )
518 {
519         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
520                 switch ( item->type ) {
521                 case InlineItem::Text:
522                         ret << item->data;
523                         break;
524                 case InlineItem::Goto:
525                         GOTO( ret, item->targState->id, inFinish );
526                         break;
527                 case InlineItem::Call:
528                         CALL( ret, item->targState->id, targState, inFinish );
529                         break;
530                 case InlineItem::Next:
531                         NEXT( ret, item->targState->id, inFinish );
532                         break;
533                 case InlineItem::Ret:
534                         RET( ret, inFinish );
535                         break;
536                 case InlineItem::PChar:
537                         ret << P();
538                         break;
539                 case InlineItem::Char:
540                         ret << GET_KEY();
541                         break;
542                 case InlineItem::Hold:
543                         ret << P() << " = " << P() << " - 1;";
544                         break;
545                 case InlineItem::Exec:
546                         EXEC( ret, item, targState, inFinish );
547                         break;
548                 case InlineItem::HoldTE:
549                         ret << TOKEND() << " = " << TOKEND() << " - 1;";
550                         break;
551                 case InlineItem::ExecTE:
552                         EXECTE( ret, item, targState, inFinish );
553                         break;
554                 case InlineItem::Curs:
555                         ret << "(_ps)";
556                         break;
557                 case InlineItem::Targs:
558                         ret << "(" << CS() << ")";
559                         break;
560                 case InlineItem::Entry:
561                         ret << item->targState->id;
562                         break;
563                 case InlineItem::GotoExpr:
564                         GOTO_EXPR( ret, item, inFinish );
565                         break;
566                 case InlineItem::CallExpr:
567                         CALL_EXPR( ret, item, targState, inFinish );
568                         break;
569                 case InlineItem::NextExpr:
570                         NEXT_EXPR( ret, item, inFinish );
571                         break;
572                 case InlineItem::LmSwitch:
573                         LM_SWITCH( ret, item, targState, inFinish );
574                         break;
575                 case InlineItem::LmSetActId:
576                         SET_ACT( ret, item );
577                         break;
578                 case InlineItem::LmSetTokEnd:
579                         SET_TOKEND( ret, item );
580                         break;
581                 case InlineItem::LmGetTokEnd:
582                         GET_TOKEND( ret, item );
583                         break;
584                 case InlineItem::LmInitTokStart:
585                         INIT_TOKSTART( ret, item );
586                         break;
587                 case InlineItem::LmInitAct:
588                         INIT_ACT( ret, item );
589                         break;
590                 case InlineItem::LmSetTokStart:
591                         SET_TOKSTART( ret, item );
592                         break;
593                 case InlineItem::SubAction:
594                         SUB_ACTION( ret, item, targState, inFinish );
595                         break;
596                 case InlineItem::Break:
597                         BREAK( ret, targState );
598                         break;
599                 }
600         }
601 }
602
603 string RubyCodeGen::DATA_PREFIX()
604 {
605         if ( dataPrefix )
606                 return FSM_NAME() + "_";
607         return "";
608 }
609
610 /* Emit the alphabet data type. */
611 string RubyCodeGen::ALPH_TYPE()
612 {
613         string ret = keyOps->alphType->data1;
614         if ( keyOps->alphType->data2 != 0 ) {
615                 ret += " ";
616                 ret += + keyOps->alphType->data2;
617         }
618         return ret;
619 }
620
621 /* Emit the alphabet data type. */
622 string RubyCodeGen::WIDE_ALPH_TYPE()
623 {
624         string ret;
625         if ( redFsm->maxKey <= keyOps->maxKey )
626                 ret = ALPH_TYPE();
627         else {
628                 long long maxKeyVal = redFsm->maxKey.getLongLong();
629                 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
630                 assert( wideType != 0 );
631
632                 ret = wideType->data1;
633                 if ( wideType->data2 != 0 ) {
634                         ret += " ";
635                         ret += wideType->data2;
636                 }
637         }
638         return ret;
639 }
640
641 /* Determine if we should use indicies or not. */
642 void RubyCodeGen::calcIndexSize()
643 {
644         int sizeWithInds = 0, sizeWithoutInds = 0;
645
646         /* Calculate cost of using with indicies. */
647         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
648                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
649                                 (st->defTrans == 0 ? 0 : 1);
650                 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
651         }
652         sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
653         if ( redFsm->anyActions() )
654                 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
655
656         /* Calculate the cost of not using indicies. */
657         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
658                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
659                                 (st->defTrans == 0 ? 0 : 1);
660                 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
661                 if ( redFsm->anyActions() )
662                         sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
663         }
664
665         /* If using indicies reduces the size, use them. */
666         useIndicies = sizeWithInds < sizeWithoutInds;
667 }
668
669 int RubyCodeGen::TO_STATE_ACTION( RedStateAp *state )
670 {
671         int act = 0;
672         if ( state->toStateAction != 0 )
673                 act = state->toStateAction->location+1;
674         return act;
675 }
676
677 int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
678 {
679         int act = 0;
680         if ( state->fromStateAction != 0 )
681                 act = state->fromStateAction->location+1;
682         return act;
683 }
684
685 int RubyCodeGen::EOF_ACTION( RedStateAp *state )
686 {
687         int act = 0;
688         if ( state->eofAction != 0 )
689                 act = state->eofAction->location+1;
690         return act;
691 }
692
693
694 int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
695 {
696         /* If there are actions, emit them. Otherwise emit zero. */
697         int act = 0;
698         if ( trans->action != 0 )
699                 act = trans->action->location+1;
700         return act;
701 }
702
703 std::ostream &RubyCodeGen::COND_OFFSETS()
704 {
705         START_ARRAY_LINE();
706         int totalStateNum = 0, curKeyOffset = 0;
707         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
708                 /* Write the key offset. */
709                 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
710
711                 /* Move the key offset ahead. */
712                 curKeyOffset += st->stateCondList.length();
713         }
714         END_ARRAY_LINE();
715         return out;
716 }
717
718 std::ostream &RubyCodeGen::KEY_OFFSETS()
719 {
720         START_ARRAY_LINE();
721         int totalStateNum = 0, curKeyOffset = 0;
722         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
723                 /* Write the key offset. */
724                 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
725
726                 /* Move the key offset ahead. */
727                 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
728         }
729         END_ARRAY_LINE();
730         return out;
731 }
732
733
734 std::ostream &RubyCodeGen::INDEX_OFFSETS()
735 {
736         START_ARRAY_LINE();
737         int totalStateNum = 0, curIndOffset = 0;
738         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
739                 /* Write the index offset. */
740                 ARRAY_ITEM( INT(curIndOffset), ++totalStateNum, st.last() );
741
742                 /* Move the index offset ahead. */
743                 curIndOffset += st->outSingle.length() + st->outRange.length();
744                 if ( st->defTrans != 0 )
745                         curIndOffset += 1;
746         }
747         END_ARRAY_LINE();
748         return out;
749 }
750
751 std::ostream &RubyCodeGen::COND_LENS()
752 {
753         START_ARRAY_LINE();
754         int totalStateNum = 0;
755         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
756                 /* Write singles length. */
757                 ARRAY_ITEM( INT(st->stateCondList.length()), ++totalStateNum, st.last() );
758         }
759         END_ARRAY_LINE();
760         return out;
761 }
762
763
764 std::ostream &RubyCodeGen::SINGLE_LENS()
765 {
766         START_ARRAY_LINE();
767         int totalStateNum = 0;
768         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
769                 /* Write singles length. */
770                 ARRAY_ITEM( INT(st->outSingle.length()), ++totalStateNum, st.last() );
771         }
772         END_ARRAY_LINE();
773         return out;
774 }
775
776 std::ostream &RubyCodeGen::RANGE_LENS()
777 {
778         START_ARRAY_LINE();
779         int totalStateNum = 0;
780         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
781                 /* Emit length of range index. */
782                 ARRAY_ITEM( INT(st->outRange.length()), ++totalStateNum, st.last() );
783         }
784         END_ARRAY_LINE();
785         return out;
786 }
787
788 std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
789 {
790         START_ARRAY_LINE();
791         int totalStateNum = 0;
792         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
793                 /* Write any eof action. */
794                 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), ++totalStateNum, st.last() );
795         }
796         END_ARRAY_LINE();
797         return out;
798 }
799
800 std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
801 {
802         START_ARRAY_LINE();
803         int totalStateNum = 0;
804         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
805                 /* Write any eof action. */
806                 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), ++totalStateNum, st.last() );
807         }
808         END_ARRAY_LINE();
809         return out;
810 }
811
812 std::ostream &RubyCodeGen::EOF_ACTIONS()
813 {
814         START_ARRAY_LINE();
815         int totalStateNum = 0;
816         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
817                 /* Write any eof action. */
818                 ARRAY_ITEM( INT(EOF_ACTION(st)), ++totalStateNum, st.last() );
819         }
820         END_ARRAY_LINE();
821         return out;
822 }
823
824 std::ostream &RubyCodeGen::COND_KEYS()
825 {
826         START_ARRAY_LINE();
827         int totalTrans = 0;
828         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
829                 /* Loop the state's transitions. */
830                 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
831                         /* Lower key. */
832                         ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
833                         ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
834                 }
835         }
836
837         /* Output one last number so we don't have to figure out when the last
838          * entry is and avoid writing a comma. */
839         ARRAY_ITEM( INT(0), ++totalTrans, true );
840         END_ARRAY_LINE();
841         return out;
842 }
843
844 std::ostream &RubyCodeGen::COND_SPACES()
845 {
846         START_ARRAY_LINE();
847         int totalTrans = 0;
848         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
849                 /* Loop the state's transitions. */
850                 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
851                         /* Cond Space id. */
852                         ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
853                 }
854         }
855
856         /* Output one last number so we don't have to figure out when the last
857          * entry is and avoid writing a comma. */
858         ARRAY_ITEM( INT(0), ++totalTrans, true );
859         END_ARRAY_LINE();
860         return out;
861 }
862
863 std::ostream &RubyCodeGen::KEYS()
864 {
865         START_ARRAY_LINE();
866         int totalTrans = 0;
867         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
868                 /* Loop the singles. */
869                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
870                         ARRAY_ITEM( KEY( stel->lowKey ), ++totalTrans, false );
871                 }
872
873                 /* Loop the state's transitions. */
874                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
875                         /* Lower key. */
876                         ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
877
878                         /* Upper key. */
879                         ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
880                 }
881         }
882
883         /* Output one last number so we don't have to figure out when the last
884          * entry is and avoid writing a comma. */
885         ARRAY_ITEM( INT(0), ++totalTrans, true );
886         END_ARRAY_LINE();
887         return out;
888 }
889
890 std::ostream &RubyCodeGen::INDICIES()
891 {
892         int totalTrans = 0;
893         START_ARRAY_LINE();
894         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
895                 /* Walk the singles. */
896                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
897                         ARRAY_ITEM( KEY( stel->value->id ), ++totalTrans, false );
898                 }
899
900                 /* Walk the ranges. */
901                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
902                         ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
903                 }
904
905                 /* The state's default index goes next. */
906                 if ( st->defTrans != 0 ) {
907                         ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
908                 }
909         }
910
911         /* Output one last number so we don't have to figure out when the last
912          * entry is and avoid writing a comma. */
913         ARRAY_ITEM( INT(0), ++totalTrans, true );
914         END_ARRAY_LINE();
915         return out;
916 }
917
918 std::ostream &RubyCodeGen::TRANS_TARGS()
919 {
920         int totalTrans = 0;
921         START_ARRAY_LINE();
922         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
923                 /* Walk the singles. */
924                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
925                         RedTransAp *trans = stel->value;
926                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
927                 }
928
929                 /* Walk the ranges. */
930                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
931                         RedTransAp *trans = rtel->value;
932                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
933                 }
934
935                 /* The state's default target state. */
936                 if ( st->defTrans != 0 ) {
937                         RedTransAp *trans = st->defTrans;
938                         ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
939                 }
940         }
941
942         /* Output one last number so we don't have to figure out when the last
943          * entry is and avoid writing a comma. */
944         ARRAY_ITEM( INT(0), ++totalTrans, true );
945         END_ARRAY_LINE();
946         return out;
947 }
948
949
950 std::ostream &RubyCodeGen::TRANS_ACTIONS()
951 {
952         int totalTrans = 0;
953         START_ARRAY_LINE();
954         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
955                 /* Walk the singles. */
956                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
957                         RedTransAp *trans = stel->value;
958                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
959                 }
960
961                 /* Walk the ranges. */
962                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
963                         RedTransAp *trans = rtel->value;
964                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
965                 }
966
967                 /* The state's default index goes next. */
968                 if ( st->defTrans != 0 ) {
969                         RedTransAp *trans = st->defTrans;
970                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
971                 }
972         }
973
974         /* Output one last number so we don't have to figure out when the last
975          * entry is and avoid writing a comma. */
976         ARRAY_ITEM( INT(0), ++totalTrans, true );
977         END_ARRAY_LINE();
978         return out;
979 }
980
981 std::ostream &RubyCodeGen::TRANS_TARGS_WI()
982 {
983         /* Transitions must be written ordered by their id. */
984         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
985         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
986                 transPtrs[trans->id] = trans;
987
988         /* Keep a count of the num of items in the array written. */
989         START_ARRAY_LINE();
990         int totalStates = 0;
991         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
992                 /* Write out the target state. */
993                 RedTransAp *trans = transPtrs[t];
994                 ARRAY_ITEM( INT(trans->targ->id), ++totalStates, ( t >= redFsm->transSet.length()-1 ) );
995         }
996         END_ARRAY_LINE();
997         delete[] transPtrs;
998         return out;
999 }
1000
1001
1002 std::ostream &RubyCodeGen::TRANS_ACTIONS_WI()
1003 {
1004         /* Transitions must be written ordered by their id. */
1005         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
1006         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
1007                 transPtrs[trans->id] = trans;
1008
1009         /* Keep a count of the num of items in the array written. */
1010         START_ARRAY_LINE();
1011         int totalAct = 0;
1012         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
1013                 /* Write the function for the transition. */
1014                 RedTransAp *trans = transPtrs[t];
1015                 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalAct, ( t >= redFsm->transSet.length()-1 ) );
1016         }
1017         END_ARRAY_LINE();
1018         delete[] transPtrs;
1019         return out;
1020 }
1021
1022 void RubyCodeGen::writeExports()
1023 {
1024         if ( exportList.length() > 0 ) {
1025                 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
1026                         STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name ) 
1027                                         << " = " << KEY(ex->key) << "\n";
1028                 }
1029                 out << "\n";
1030         }
1031 }
1032
1033
1034 void RubyCodeGen::writeData()
1035 {
1036         /* If there are any transtion functions then output the array. If there
1037          * are none, don't bother emitting an empty array that won't be used. */
1038         if ( redFsm->anyActions() ) {
1039                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
1040                 ACTIONS_ARRAY();
1041                 CLOSE_ARRAY() <<
1042                 "\n";
1043         }
1044
1045         if ( redFsm->anyConditions() ) {
1046                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
1047                 COND_OFFSETS();
1048                 CLOSE_ARRAY() <<
1049                 "\n";
1050
1051                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
1052                 COND_LENS();
1053                 CLOSE_ARRAY() <<
1054                 "\n";
1055
1056                 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
1057                 COND_KEYS();
1058                 CLOSE_ARRAY() <<
1059                 "\n";
1060
1061                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
1062                 COND_SPACES();
1063                 CLOSE_ARRAY() <<
1064                 "\n";
1065         }
1066
1067         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
1068         KEY_OFFSETS();
1069         CLOSE_ARRAY() <<
1070         "\n";
1071
1072         OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
1073         KEYS();
1074         CLOSE_ARRAY() <<
1075         "\n";
1076
1077         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
1078         SINGLE_LENS();
1079         CLOSE_ARRAY() <<
1080         "\n";
1081
1082         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
1083         RANGE_LENS();
1084         CLOSE_ARRAY() <<
1085         "\n";
1086
1087         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
1088         INDEX_OFFSETS();
1089         CLOSE_ARRAY() <<
1090         "\n";
1091
1092         if ( useIndicies ) {
1093                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
1094                 INDICIES();
1095                 CLOSE_ARRAY() <<
1096                 "\n";
1097
1098                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1099                 TRANS_TARGS_WI();
1100                 CLOSE_ARRAY() <<
1101                 "\n";
1102
1103                 if ( redFsm->anyActions() ) {
1104                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1105                         TRANS_ACTIONS_WI();
1106                         CLOSE_ARRAY() <<
1107                         "\n";
1108                 }
1109         }
1110         else {
1111                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1112                 TRANS_TARGS();
1113                 CLOSE_ARRAY() <<
1114                 "\n";
1115
1116                 if ( redFsm->anyActions() ) {
1117                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1118                         TRANS_ACTIONS();
1119                         CLOSE_ARRAY() <<
1120                         "\n";
1121                 }
1122         }
1123
1124         if ( redFsm->anyToStateActions() ) {
1125                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
1126                 TO_STATE_ACTIONS();
1127                 CLOSE_ARRAY() <<
1128                 "\n";
1129         }
1130
1131         if ( redFsm->anyFromStateActions() ) {
1132                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1133                 FROM_STATE_ACTIONS();
1134                 CLOSE_ARRAY() <<
1135                 "\n";
1136         }
1137
1138         if ( redFsm->anyEofActions() ) {
1139                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1140                 EOF_ACTIONS();
1141                 CLOSE_ARRAY() <<
1142                 "\n";
1143         }
1144
1145         if ( redFsm->startState != 0 )
1146                 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
1147
1148         if ( writeFirstFinal )
1149                 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
1150
1151         if ( writeErr )
1152                 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
1153         
1154         out << "\n";
1155
1156         if ( entryPointNames.length() > 0 ) {
1157                 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
1158                         STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) << 
1159                                         " = " << entryPointIds[en.pos()] << ";\n";
1160                 }
1161                 out << "\n";
1162         }
1163 }
1164
1165 std::ostream &RubyCodeGen::START_ARRAY_LINE()
1166 {
1167         out << "\t";
1168         return out;
1169 }
1170
1171 std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
1172 {
1173         out << item;
1174         if ( !last )
1175         {
1176                 out << ", ";
1177                 if ( count % IALL == 0 )
1178                 {
1179                         END_ARRAY_LINE();
1180                         START_ARRAY_LINE();
1181                 }
1182         }
1183         return out;
1184 }
1185
1186 std::ostream &RubyCodeGen::END_ARRAY_LINE()
1187 {
1188         out << "\n";
1189         return out;
1190 }
1191
1192
1193 unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
1194 {
1195         long long maxValLL = (long long) maxVal;
1196         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1197         assert( arrayType != 0 );
1198         return arrayType->size;
1199 }
1200
1201 string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
1202 {
1203         long long maxValLL = (long long) maxVal;
1204         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1205         assert( arrayType != 0 );
1206
1207         string ret = arrayType->data1;
1208         if ( arrayType->data2 != 0 ) {
1209                 ret += " ";
1210                 ret += arrayType->data2;
1211         }
1212         return ret;
1213 }
1214
1215
1216 /* Write out the fsm name. */
1217 string RubyCodeGen::FSM_NAME()
1218 {
1219         return fsmName;
1220 }
1221
1222 /* Emit the offset of the start state as a decimal integer. */
1223 string RubyCodeGen::START_STATE_ID()
1224 {
1225         ostringstream ret;
1226         ret << redFsm->startState->id;
1227         return ret.str();
1228 };
1229
1230 /* Write out the array of actions. */
1231 std::ostream &RubyCodeGen::ACTIONS_ARRAY()
1232 {
1233         START_ARRAY_LINE();
1234         int totalActions = 0;
1235         ARRAY_ITEM( INT(0), ++totalActions, false );
1236         for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1237                 /* Write out the length, which will never be the last character. */
1238                 ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
1239
1240                 for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
1241                         ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
1242                 }
1243         }
1244         END_ARRAY_LINE();
1245         return out;
1246 }
1247
1248
1249 string RubyCodeGen::ACCESS()
1250 {
1251         ostringstream ret;
1252         if ( accessExpr != 0 )
1253                 INLINE_LIST( ret, accessExpr, 0, false );
1254         return ret.str();
1255 }
1256
1257 string RubyCodeGen::P()
1258
1259         ostringstream ret;
1260         if ( pExpr == 0 )
1261                 ret << "p";
1262         else {
1263                 //ret << "(";
1264                 INLINE_LIST( ret, pExpr, 0, false );
1265                 //ret << ")";
1266         }
1267         return ret.str();
1268 }
1269
1270 string RubyCodeGen::PE()
1271 {
1272         ostringstream ret;
1273         if ( peExpr == 0 )
1274                 ret << "pe";
1275         else {
1276                 //ret << "(";
1277                 INLINE_LIST( ret, peExpr, 0, false );
1278                 //ret << ")";
1279         }
1280         return ret.str();
1281 }
1282
1283 string RubyCodeGen::CS()
1284 {
1285         ostringstream ret;
1286         if ( csExpr == 0 )
1287                 ret << ACCESS() << "cs";
1288         else {
1289                 //ret << "(";
1290                 INLINE_LIST( ret, csExpr, 0, false );
1291                 //ret << ")";
1292         }
1293         return ret.str();
1294 }
1295
1296 string RubyCodeGen::TOP()
1297 {
1298         ostringstream ret;
1299         if ( topExpr == 0 )
1300                 ret << ACCESS() + "top";
1301         else {
1302                 //ret << "(";
1303                 INLINE_LIST( ret, topExpr, 0, false );
1304                 //ret << ")";
1305         }
1306         return ret.str();
1307 }
1308
1309 string RubyCodeGen::STACK()
1310 {
1311         ostringstream ret;
1312         if ( stackExpr == 0 )
1313                 ret << ACCESS() + "stack";
1314         else {
1315                 //ret << "(";
1316                 INLINE_LIST( ret, stackExpr, 0, false );
1317                 //ret << ")";
1318         }
1319         return ret.str();
1320 }
1321
1322 string RubyCodeGen::ACT()
1323 {
1324         ostringstream ret;
1325         if ( actExpr == 0 )
1326                 ret << ACCESS() + "act";
1327         else {
1328                 //ret << "(";
1329                 INLINE_LIST( ret, actExpr, 0, false );
1330                 //ret << ")";
1331         }
1332         return ret.str();
1333 }
1334
1335 string RubyCodeGen::TOKSTART()
1336 {
1337         ostringstream ret;
1338         if ( tokstartExpr == 0 )
1339                 ret << ACCESS() + "tokstart";
1340         else {
1341                 //ret << "(";
1342                 INLINE_LIST( ret, tokstartExpr, 0, false );
1343                 //ret << ")";
1344         }
1345         return ret.str();
1346 }
1347
1348 string RubyCodeGen::TOKEND()
1349 {
1350         ostringstream ret;
1351         if ( tokendExpr == 0 )
1352                 ret << ACCESS() + "tokend";
1353         else {
1354                 //ret << "(";
1355                 INLINE_LIST( ret, tokendExpr, 0, false );
1356                 //ret << ")";
1357         }
1358         return ret.str();
1359 }
1360
1361
1362 string RubyCodeGen::GET_WIDE_KEY()
1363 {
1364         if ( redFsm->anyConditions() ) 
1365                 return "_widec";
1366         else
1367                 return GET_KEY();
1368 }
1369
1370 string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
1371 {
1372         if ( state->stateCondList.length() > 0 )
1373                 return "_widec";
1374         else
1375                 return GET_KEY();
1376 }
1377
1378 /* Write out level number of tabs. Makes the nested binary search nice
1379  * looking. */
1380 string RubyCodeGen::TABS( int level )
1381 {
1382         string result;
1383         while ( level-- > 0 )
1384                 result += "\t";
1385         return result;
1386 }
1387
1388 string RubyCodeGen::KEY( Key key )
1389 {
1390         ostringstream ret;
1391         if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1392                 ret << key.getVal();
1393         else
1394                 ret << (unsigned long) key.getVal();
1395         return ret.str();
1396 }
1397
1398 string RubyCodeGen::INT( int i )
1399 {
1400         ostringstream ret;
1401         ret << i;
1402         return ret.str();
1403 }
1404
1405 void RubyCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, 
1406                 int targState, int inFinish )
1407 {
1408         ret << 
1409                 "       case " << ACT() << "\n";
1410
1411         /* If the switch handles error then we also forced the error state. It
1412          * will exist. */
1413         if ( item->handlesError ) {
1414                 ret << "        when 0: " << TOKEND() << " = " << TOKSTART() << "; ";
1415                 GOTO( ret, redFsm->errState->id, inFinish );
1416                 ret << "\n";
1417         }
1418
1419         for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1420                 /* Write the case label, the action and the case break. */
1421                 ret << "        when " << lma->lmId << ":\n";
1422
1423                 /* Write the block and close it off. */
1424                 ret << "        begin";
1425                 INLINE_LIST( ret, lma->children, targState, inFinish );
1426                 ret << "end\n";
1427         }
1428
1429         ret << "end \n\t";
1430 }
1431
1432 void RubyCodeGen::SET_ACT( ostream &ret, InlineItem *item )
1433 {
1434         ret << ACT() << " = " << item->lmId << ";";
1435 }
1436
1437 void RubyCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
1438 {
1439         /* The tokend action sets tokend. */
1440         ret << TOKEND() << " = " << P();
1441         if ( item->offset != 0 ) 
1442                 out << "+" << item->offset;
1443         out << ";";
1444 }
1445
1446 void RubyCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
1447 {
1448         ret << TOKEND();
1449 }
1450
1451 void RubyCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
1452 {
1453         ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1454 }
1455
1456 void RubyCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
1457 {
1458         ret << ACT() << " = 0;";
1459 }
1460
1461 void RubyCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
1462 {
1463         ret << TOKSTART() << " = " << P() << ";";
1464 }
1465
1466 void RubyCodeGen::SUB_ACTION( ostream &ret, InlineItem *item, 
1467                 int targState, bool inFinish )
1468 {
1469         if ( item->children->length() > 0 ) {
1470                 /* Write the block and close it off. */
1471                 ret << " begin ";
1472                 INLINE_LIST( ret, item->children, targState, inFinish );
1473                 ret << " end\n";
1474         }
1475 }
1476
1477 void RubyCodeGen::CONDITION( ostream &ret, Action *condition )
1478 {
1479         ret << "\n";
1480         lineDirective( ret, sourceFileName, condition->loc.line );
1481         INLINE_LIST( ret, condition->inlineList, 0, false );
1482 }
1483
1484 string RubyCodeGen::ERROR_STATE()
1485 {
1486         ostringstream ret;
1487         if ( redFsm->errState != 0 )
1488                 ret << redFsm->errState->id;
1489         else
1490                 ret << "-1";
1491         return ret.str();
1492 }
1493
1494 string RubyCodeGen::FIRST_FINAL_STATE()
1495 {
1496         ostringstream ret;
1497         if ( redFsm->firstFinState != 0 )
1498                 ret << redFsm->firstFinState->id;
1499         else
1500                 ret << redFsm->nextStateId;
1501         return ret.str();
1502 }
1503
1504 void RubyCodeGen::finishRagelDef()
1505 {
1506         /* The frontend will do this for us, but it may be a good idea to force it
1507          * if the intermediate file is edited. */
1508         redFsm->sortByStateId();
1509
1510         /* Choose default transitions and the single transition. */
1511         redFsm->chooseDefaultSpan();
1512                 
1513         /* Maybe do flat expand, otherwise choose single. */
1514         redFsm->chooseSingle();
1515
1516         /* If any errors have occured in the input file then don't write anything. */
1517         if ( gblErrorCount > 0 )
1518                 return;
1519         
1520         /* Anlayze Machine will find the final action reference counts, among
1521          * other things. We will use these in reporting the usage
1522          * of fsm directives in action code. */
1523         analyzeMachine();
1524
1525         /* Determine if we should use indicies. */
1526         calcIndexSize();
1527 }
1528
1529 ostream &RubyCodeGen::source_warning( const InputLoc &loc )
1530 {
1531         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1532         return cerr;
1533 }
1534
1535 ostream &RubyCodeGen::source_error( const InputLoc &loc )
1536 {
1537         gblErrorCount += 1;
1538         assert( sourceFileName != 0 );
1539         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1540         return cerr;
1541 }
1542
1543