2 * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3 * 2007 Adrian Thurston <thurston@cs.queensu.ca>
6 /* This file is part of Ragel.
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.
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.
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
23 #include "rlgen-ruby.h"
24 #include "rubycodegen.h"
30 /* Integer array line length. */
34 using std::ostringstream;
39 void lineDirective( ostream &out, char *fileName, int line )
41 if ( hostLangType != JavaCode ) {
42 /* Write a comment containing line info. */
43 out << "# line " << line << " \"";
44 for ( char *pc = fileName; *pc != 0; pc++ ) {
54 void genLineDirective( ostream &out )
56 std::streambuf *sbuf = out.rdbuf();
57 output_filter *filter = static_cast<output_filter*>(sbuf);
58 lineDirective( out, filter->fileName, filter->line + 1 );
61 void RubyCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
63 out << INDENT_U() << "begin"
64 << INDENT_S() << CS() << " = " << gotoDest
65 << INDENT_S() << "_again.call " << CTRL_FLOW()
66 << INDENT_D() << "end";
69 void RubyCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
71 out << INDENT_U() << "begin"
72 << INDENT_S() << CS() << " = (";
73 INLINE_LIST( out, ilItem->children, 0, inFinish );
75 << INDENT_S() << "_again.call " << CTRL_FLOW()
76 << INDENT_D() << "end";
79 void RubyCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
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";
89 void RubyCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
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 );
97 << INDENT_S() << "_again.call " << CTRL_FLOW()
98 << INDENT_D() << "end";
101 void RubyCodeGen::RET( ostream &out, bool inFinish )
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";
110 void RubyCodeGen::BREAK( ostream &out, int targState )
112 out << "_resume.call " << CTRL_FLOW();
115 void RubyCodeGen::COND_TRANSLATE()
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)]"
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) << ")" ;
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 );
149 out << INDENT_D() << "end # case"
150 << INDENT_D() << "end"
151 << INDENT_D() << "end # loop"
152 << INDENT_D() << "end"
156 void RubyCodeGen::LOCATE_TRANS()
158 out << INDENT_S() << "_keys = " << KO() << "[" << CS() << "]"
159 << INDENT_S() << "_trans = " << IO() << "[" << CS() << "]"
160 << INDENT_S() << "_klen = " << SL() << "[" << CS() << "]"
162 << INDENT_U() << "callcc do |_match|"
163 << INDENT_U() << "if _klen > 0"
164 << INDENT_S() << "_lower = _keys"
165 << INDENT_S() << "_upper = _keys + _klen - 1"
167 << INDENT_U() << "loop do"
168 << INDENT_S() << "break if _upper < _lower"
169 << INDENT_S() << "_mid = _lower + ( (_upper - _lower) >> 1 )"
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"
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" ;
205 void RubyCodeGen::writeOutExec()
207 out << INDENT_U() << "callcc do |_out|"
208 << INDENT_S() << "_klen, _trans, _keys";
210 if ( redFsm->anyRegCurStateRef() )
212 if ( redFsm->anyConditions() )
214 if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
215 || redFsm->anyFromStateActions() )
216 out << ", _acts, _nacts";
221 out << INDENT_S() << "_out.call if " << P() << " == " << PE() ;
223 out << INDENT_S() << "_resume = nil"
224 << INDENT_S() << "callcc { |_cc| _resume = _cc }" ;
226 if ( redFsm->errState != 0)
227 out << INDENT_S() << "_out.call if " << CS() << " == " << redFsm->errState->id ;
229 if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
230 redFsm->anyActionCalls() || redFsm->anyActionRets() )
231 out << INDENT_U() << "callcc do |_again|" ;
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"
247 if ( redFsm->anyConditions() )
252 if ( redFsm->anyRegCurStateRef() )
253 out << INDENT_S() << "_ps = " << CS() ;
256 out << INDENT_S() << "_trans = " << I() << "[_trans]" ;
258 out << INDENT_S() << CS() << " = " << TT() << "[_trans]" ;
260 if ( redFsm->anyRegActions() ) {
261 out << INDENT_S() << "_again.call if " << TA() << "[_trans] == 0"
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]" ;
271 << INDENT_D() << "end # action switch"
272 << INDENT_D() << "end"
276 if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
277 redFsm->anyActionCalls() || redFsm->anyActionRets() )
278 out << INDENT_D() << "end # cc _again";
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"
294 out << INDENT_S() << P() << " += 1" ;
297 out << INDENT_S() << "_resume.call if p != pe";
299 out << INDENT_D() << "end # cc _out" ;
302 void RubyCodeGen::writeOutEOF()
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]" ;
313 << INDENT_D() << "end # eof action switch"
314 << INDENT_D() << "end"
319 std::ostream &RubyCodeGen::FROM_STATE_ACTION_SWITCH()
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 );
331 genLineDirective( out );
336 std::ostream &RubyCodeGen::TO_STATE_ACTION_SWITCH()
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 );
348 genLineDirective( out );
352 std::ostream &RubyCodeGen::EOF_ACTION_SWITCH()
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 );
364 genLineDirective( out );
368 std::ostream &RubyCodeGen::ACTION_SWITCH()
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 );
380 genLineDirective( out );
385 void RubyCodeGen::writeOutInit()
387 out << INDENT_U() << "begin"
388 << INDENT_S() << CS() << " = " << START();
390 /* If there are any calls, then the stack top needs initialization. */
391 if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
392 out << INDENT_S() << TOP() << " = 0";
394 if ( hasLongestMatch ) {
395 out << INDENT_S() << TOKSTART() << " = " << NULL_ITEM()
396 << INDENT_S() << TOKEND() << " = " << NULL_ITEM()
397 << INDENT_S() << ACT() << " = 0"
400 out << INDENT_D() << "end";
403 std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
405 out << "class << self" << endl
406 << INDENT(1) << "attr_accessor :" << name << endl
407 << INDENT(1) << "private :" << name << ", :" << name << "=" << endl
409 << "self." << name << " = [" << endl;
413 std::ostream &RubyCodeGen::CLOSE_ARRAY()
415 return out << "]" << endl;
418 std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
420 out << "class << self" << endl
421 << INDENT(1) << "attr_accessor :" << name << endl
427 string RubyCodeGen::ARR_OFF( string ptr, string offset )
429 return ptr + " + " + offset;
432 string RubyCodeGen::NULL_ITEM()
437 string RubyCodeGen::GET_KEY()
440 if ( getKeyExpr != 0 ) {
441 /* Emit the user supplied method of retrieving the key. */
443 INLINE_LIST( ret, getKeyExpr, 0, false );
447 /* Expression for retrieving the key, use simple dereference. */
448 ret << "data[" << P() << "]";
453 string RubyCodeGen::CTRL_FLOW()
458 void RubyCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
460 /* Write the preprocessor line info for going into the source file. */
461 lineDirective( ret, sourceFileName, action->loc.line );
463 /* Write the block and close it off. */
464 ret << "begin" << endl << INDENT(1);
465 INLINE_LIST( ret, action->inlineList, targState, inFinish );
467 lineDirective( ret, sourceFileName, action->loc.line );
471 string RubyCodeGen::INDENT(int level)
473 string result = "\n";
474 while ( level-- > 0 )
475 result += " "; /* The convention in ruby is 2 spaces per level */
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--); }
484 void RubyCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
486 ret << CS() << " = " << nextDest << ";";
489 void RubyCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
491 ret << CS() << " = (";
492 INLINE_LIST( ret, ilItem->children, 0, inFinish );
496 void RubyCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
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 );
506 void RubyCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
508 /* Tokend version of exec. */
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 );
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 )
523 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
524 switch ( item->type ) {
525 case InlineItem::Text:
528 case InlineItem::Goto:
529 GOTO( ret, item->targState->id, inFinish );
531 case InlineItem::Call:
532 CALL( ret, item->targState->id, targState, inFinish );
534 case InlineItem::Next:
535 NEXT( ret, item->targState->id, inFinish );
537 case InlineItem::Ret:
538 RET( ret, inFinish );
540 case InlineItem::PChar:
543 case InlineItem::Char:
546 case InlineItem::Hold:
549 case InlineItem::Exec:
550 EXEC( ret, item, targState, inFinish );
552 case InlineItem::HoldTE:
553 ret << TOKEND() << "--;";
555 case InlineItem::ExecTE:
556 EXECTE( ret, item, targState, inFinish );
558 case InlineItem::Curs:
561 case InlineItem::Targs:
562 ret << "(" << CS() << ")";
564 case InlineItem::Entry:
565 ret << item->targState->id;
567 case InlineItem::GotoExpr:
568 GOTO_EXPR( ret, item, inFinish );
570 case InlineItem::CallExpr:
571 CALL_EXPR( ret, item, targState, inFinish );
573 case InlineItem::NextExpr:
574 NEXT_EXPR( ret, item, inFinish );
576 case InlineItem::LmSwitch:
577 LM_SWITCH( ret, item, targState, inFinish );
579 case InlineItem::LmSetActId:
580 SET_ACT( ret, item );
582 case InlineItem::LmSetTokEnd:
583 SET_TOKEND( ret, item );
585 case InlineItem::LmGetTokEnd:
586 GET_TOKEND( ret, item );
588 case InlineItem::LmInitTokStart:
589 INIT_TOKSTART( ret, item );
591 case InlineItem::LmInitAct:
592 INIT_ACT( ret, item );
594 case InlineItem::LmSetTokStart:
595 SET_TOKSTART( ret, item );
597 case InlineItem::SubAction:
598 SUB_ACTION( ret, item, targState, inFinish );
600 case InlineItem::Break:
601 BREAK( ret, targState );
607 string RubyCodeGen::DATA_PREFIX()
610 return FSM_NAME() + "_";
614 /* Emit the alphabet data type. */
615 string RubyCodeGen::ALPH_TYPE()
617 string ret = keyOps->alphType->data1;
618 if ( keyOps->alphType->data2 != 0 ) {
620 ret += + keyOps->alphType->data2;
625 /* Emit the alphabet data type. */
626 string RubyCodeGen::WIDE_ALPH_TYPE()
629 if ( redFsm->maxKey <= keyOps->maxKey )
632 long long maxKeyVal = redFsm->maxKey.getLongLong();
633 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
634 assert( wideType != 0 );
636 ret = wideType->data1;
637 if ( wideType->data2 != 0 ) {
639 ret += wideType->data2;
645 /* Determine if we should use indicies or not. */
646 void RubyCodeGen::calcIndexSize()
648 int sizeWithInds = 0, sizeWithoutInds = 0;
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;
656 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
657 if ( redFsm->anyActions() )
658 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
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;
669 /* If using indicies reduces the size, use them. */
670 useIndicies = sizeWithInds < sizeWithoutInds;
673 int RubyCodeGen::TO_STATE_ACTION( RedStateAp *state )
676 if ( state->toStateAction != 0 )
677 act = state->toStateAction->location+1;
681 int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
684 if ( state->fromStateAction != 0 )
685 act = state->fromStateAction->location+1;
689 int RubyCodeGen::EOF_ACTION( RedStateAp *state )
692 if ( state->eofAction != 0 )
693 act = state->eofAction->location+1;
698 int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
700 /* If there are actions, emit them. Otherwise emit zero. */
702 if ( trans->action != 0 )
703 act = trans->action->location+1;
707 std::ostream &RubyCodeGen::COND_OFFSETS()
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() );
715 /* Move the key offset ahead. */
716 curKeyOffset += st->stateCondList.length();
722 std::ostream &RubyCodeGen::KEY_OFFSETS()
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() );
730 /* Move the key offset ahead. */
731 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
738 std::ostream &RubyCodeGen::INDEX_OFFSETS()
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() );
746 /* Move the index offset ahead. */
747 curIndOffset += st->outSingle.length() + st->outRange.length();
748 if ( st->defTrans != 0 )
755 std::ostream &RubyCodeGen::COND_LENS()
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() );
768 std::ostream &RubyCodeGen::SINGLE_LENS()
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() );
780 std::ostream &RubyCodeGen::RANGE_LENS()
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() );
792 std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
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() );
804 std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
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() );
816 std::ostream &RubyCodeGen::EOF_ACTIONS()
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() );
828 std::ostream &RubyCodeGen::COND_KEYS()
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++ ) {
836 ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
837 ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
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 );
848 std::ostream &RubyCodeGen::COND_SPACES()
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++ ) {
856 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
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 );
867 std::ostream &RubyCodeGen::KEYS()
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 );
877 /* Loop the state's transitions. */
878 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
880 ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
883 ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
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 );
894 std::ostream &RubyCodeGen::INDICIES()
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 );
904 /* Walk the ranges. */
905 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
906 ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
909 /* The state's default index goes next. */
910 if ( st->defTrans != 0 ) {
911 ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
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 );
922 std::ostream &RubyCodeGen::TRANS_TARGS()
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 );
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 );
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 );
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 );
954 std::ostream &RubyCodeGen::TRANS_ACTIONS()
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 );
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 );
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 );
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 );
985 std::ostream &RubyCodeGen::TRANS_TARGS_WI()
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;
992 /* Keep a count of the num of items in the array written. */
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 ) );
1006 std::ostream &RubyCodeGen::TRANS_ACTIONS_WI()
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;
1013 /* Keep a count of the num of items in the array written. */
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 ) );
1027 void RubyCodeGen::writeOutData()
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() );
1038 if ( redFsm->anyConditions() ) {
1039 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
1044 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
1049 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
1054 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
1060 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
1065 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
1070 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
1075 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
1080 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
1085 if ( useIndicies ) {
1086 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
1091 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1096 if ( redFsm->anyActions() ) {
1097 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1104 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1109 if ( redFsm->anyActions() ) {
1110 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1117 if ( redFsm->anyToStateActions() ) {
1118 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
1124 if ( redFsm->anyFromStateActions() ) {
1125 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1126 FROM_STATE_ACTIONS();
1131 if ( redFsm->anyEofActions() ) {
1132 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1138 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n"
1141 if ( writeFirstFinal ) {
1142 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n"
1147 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n"
1153 std::ostream &RubyCodeGen::START_ARRAY_LINE()
1159 std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
1165 if ( count % IALL == 0 )
1174 std::ostream &RubyCodeGen::END_ARRAY_LINE()
1181 unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
1183 long long maxValLL = (long long) maxVal;
1184 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1185 assert( arrayType != 0 );
1186 return arrayType->size;
1189 string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
1191 long long maxValLL = (long long) maxVal;
1192 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1193 assert( arrayType != 0 );
1195 string ret = arrayType->data1;
1196 if ( arrayType->data2 != 0 ) {
1198 ret += arrayType->data2;
1204 /* Write out the fsm name. */
1205 string RubyCodeGen::FSM_NAME()
1210 /* Emit the offset of the start state as a decimal integer. */
1211 string RubyCodeGen::START_STATE_ID()
1214 ret << redFsm->startState->id;
1218 /* Write out the array of actions. */
1219 std::ostream &RubyCodeGen::ACTIONS_ARRAY()
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 );
1228 for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
1229 ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
1237 string RubyCodeGen::CS()
1240 if ( curStateExpr != 0 ) {
1241 /* Emit the user supplied method of retrieving the key. */
1243 INLINE_LIST( ret, curStateExpr, 0, false );
1247 /* Expression for retrieving the key, use simple dereference. */
1248 ret << ACCESS() << "cs";
1253 string RubyCodeGen::ACCESS()
1256 if ( accessExpr != 0 )
1257 INLINE_LIST( ret, accessExpr, 0, false );
1261 string RubyCodeGen::GET_WIDE_KEY()
1263 if ( redFsm->anyConditions() )
1269 string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
1271 if ( state->stateCondList.length() > 0 )
1277 /* Write out level number of tabs. Makes the nested binary search nice
1279 string RubyCodeGen::TABS( int level )
1282 while ( level-- > 0 )
1287 string RubyCodeGen::KEY( Key key )
1290 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1291 ret << key.getVal();
1293 ret << (unsigned long) key.getVal();
1297 string RubyCodeGen::INT( int i )
1304 void RubyCodeGen::LM_SWITCH( ostream &ret, InlineItem *item,
1305 int targState, int inFinish )
1308 " switch( " << ACT() << " ) {\n";
1310 /* If the switch handles error then we also forced the error state. It
1312 if ( item->handlesError ) {
1313 ret << " case 0: " << TOKEND() << " = " << TOKSTART() << "; ";
1314 GOTO( ret, redFsm->errState->id, inFinish );
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";
1322 /* Write the block and close it off. */
1324 INLINE_LIST( ret, lma->children, targState, inFinish );
1329 /* Default required for D code. */
1331 " default: break;\n"
1336 void RubyCodeGen::SET_ACT( ostream &ret, InlineItem *item )
1338 ret << ACT() << " = " << item->lmId << ";";
1341 void RubyCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
1343 /* The tokend action sets tokend. */
1344 ret << TOKEND() << " = " << P();
1345 if ( item->offset != 0 )
1346 out << "+" << item->offset;
1350 void RubyCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
1355 void RubyCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
1357 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1360 void RubyCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
1362 ret << ACT() << " = 0;";
1365 void RubyCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
1367 ret << TOKSTART() << " = " << P() << ";";
1370 void RubyCodeGen::SUB_ACTION( ostream &ret, InlineItem *item,
1371 int targState, bool inFinish )
1373 if ( item->children->length() > 0 ) {
1374 /* Write the block and close it off. */
1376 INLINE_LIST( ret, item->children, targState, inFinish );
1381 void RubyCodeGen::CONDITION( ostream &ret, Action *condition )
1384 lineDirective( ret, sourceFileName, condition->loc.line );
1385 INLINE_LIST( ret, condition->inlineList, 0, false );
1388 string RubyCodeGen::ERROR_STATE()
1391 if ( redFsm->errState != 0 )
1392 ret << redFsm->errState->id;
1398 string RubyCodeGen::FIRST_FINAL_STATE()
1401 if ( redFsm->firstFinState != 0 )
1402 ret << redFsm->firstFinState->id;
1404 ret << redFsm->nextStateId;
1408 void RubyCodeGen::finishRagelDef()
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();
1414 /* Choose default transitions and the single transition. */
1415 redFsm->chooseDefaultSpan();
1417 /* Maybe do flat expand, otherwise choose single. */
1418 redFsm->chooseSingle();
1420 /* If any errors have occured in the input file then don't write anything. */
1421 if ( gblErrorCount > 0 )
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. */
1429 /* Determine if we should use indicies. */
1433 ostream &RubyCodeGen::source_warning( const InputLoc &loc )
1435 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1439 ostream &RubyCodeGen::source_error( const InputLoc &loc )
1442 assert( sourceFileName != 0 );
1443 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";