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