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