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 /* Write a comment containing line info. */
42 out << "# line " << line << " \"";
43 for ( char *pc = fileName; *pc != 0; pc++ ) {
52 void genLineDirective( ostream &out )
54 std::streambuf *sbuf = out.rdbuf();
55 output_filter *filter = static_cast<output_filter*>(sbuf);
56 lineDirective( out, filter->fileName, filter->line + 1 );
59 void RubyCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
61 out << INDENT_U() << "begin"
62 << INDENT_S() << CS() << " = " << gotoDest
63 << INDENT_S() << "_again.call " << CTRL_FLOW()
64 << INDENT_D() << "end";
67 void RubyCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
69 out << INDENT_U() << "begin"
70 << INDENT_S() << CS() << " = (";
71 INLINE_LIST( out, ilItem->children, 0, inFinish );
73 << INDENT_S() << "_again.call " << CTRL_FLOW()
74 << INDENT_D() << "end";
77 void RubyCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
79 out << INDENT_U() << "begin"
80 << INDENT_S() << STACK() << "[" << TOP() << "] = " << CS()
81 << INDENT_S() << TOP() << "+= 1"
82 << INDENT_S() << CS() << " = " << callDest
83 << INDENT_S() << "_again.call " << CTRL_FLOW()
84 << INDENT_D() << "end";
87 void RubyCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
89 out << INDENT_U() << "begin"
90 << INDENT_S() << STACK() << "[" << TOP() << "] = " << CS()
91 << INDENT_S() << TOP() << " += 1"
92 << INDENT_S() << CS() << " = (";
93 INLINE_LIST( out, ilItem->children, targState, inFinish );
95 << INDENT_S() << "_again.call " << CTRL_FLOW()
96 << INDENT_D() << "end";
99 void RubyCodeGen::RET( ostream &out, bool inFinish )
101 out << INDENT_U() << "begin"
102 << INDENT_S() << TOP() << " -= 1"
103 << INDENT_S() << CS() << " = " << STACK() << "[" << TOP() << "]"
104 << INDENT_S() << "_again.call " << CTRL_FLOW()
105 << INDENT_D() << "end";
108 void RubyCodeGen::BREAK( ostream &out, int targState )
110 out << "_out.call " << CTRL_FLOW();
113 void RubyCodeGen::COND_TRANSLATE()
115 out << INDENT_S() << "_widec = " << GET_KEY()
116 << INDENT_S() << "_keys = " << CO() << "[" << CS() << "]*2"
117 << INDENT_S() << "_klen = " << CL() << "[" << CS() << "]"
118 << INDENT_U() << "if _klen > 0"
119 << INDENT_S() << "_lower = _keys"
120 << INDENT_S() << "_upper = _keys + (_klen<<1) - 2"
121 << INDENT_U() << "loop do"
122 << INDENT_S() << "break if _upper < _lower"
123 << INDENT_S() << "_mid = _lower + (((_upper-_lower) >> 1) & ~1)"
124 << INDENT_U() << "if " << GET_WIDE_KEY() << " < " << CK() << "[_mid]"
125 << INDENT_O() << "_upper = _mid - 2"
126 << INDENT_U() << "elsif " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1]"
127 << INDENT_O() << "_lower = _mid + 2"
128 << INDENT_U() << "else"
129 << INDENT_U() << "case " << C() << "[" << CO() << "[" << CS() << "]"
130 << " + ((_mid - _keys)>>1)]"
133 for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
134 CondSpace *condSpace = csi;
135 out << INDENT_U() << "when " << condSpace->condSpaceId << ":" ;
136 out << INDENT_S() << "_widec = " << KEY(condSpace->baseKey)
137 << "+ (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ")" ;
139 for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
140 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
141 out << INDENT_S() << "_widec += " << condValOffset << " if ( ";
142 CONDITION( out, *csi );
147 out << INDENT_D() << "end # case"
148 << INDENT_D() << "end"
149 << INDENT_D() << "end # loop"
150 << INDENT_D() << "end"
154 void RubyCodeGen::LOCATE_TRANS()
156 out << INDENT_S() << "_keys = " << KO() << "[" << CS() << "]"
157 << INDENT_S() << "_trans = " << IO() << "[" << CS() << "]"
158 << INDENT_S() << "_klen = " << SL() << "[" << CS() << "]"
160 << INDENT_U() << "callcc do |_match|"
161 << INDENT_U() << "if _klen > 0"
162 << INDENT_S() << "_lower = _keys"
163 << INDENT_S() << "_upper = _keys + _klen - 1"
165 << INDENT_U() << "loop do"
166 << INDENT_S() << "break if _upper < _lower"
167 << INDENT_S() << "_mid = _lower + ( (_upper - _lower) >> 1 )"
169 << INDENT_U() << "if " << GET_WIDE_KEY() << " < " << K() << "[_mid]"
170 << INDENT_O() << "_upper = _mid - 1"
171 << INDENT_U() << "elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid]"
172 << INDENT_O() << "_lower = _mid + 1"
173 << INDENT_U() << "else"
174 << INDENT_S() << "_trans += (_mid - _keys)"
175 << INDENT_S() << "_match.call"
176 << INDENT_D() << "end"
177 << INDENT_D() << "end # loop"
178 << INDENT_S() << "_keys += _klen"
179 << INDENT_S() << "_trans += _klen"
180 << INDENT_D() << "end"
182 << INDENT_S() << "_klen = " << RL() << "[" << CS() << "]"
183 << INDENT_U() << "if _klen > 0"
184 << INDENT_S() << "_lower = _keys"
185 << INDENT_S() << "_upper = _keys + (_klen << 1) - 2"
186 << INDENT_U() << "loop do"
187 << INDENT_S() << "break if _upper < _lower"
188 << INDENT_S() << "_mid = _lower + (((_upper-_lower) >> 1) & ~1)"
189 << INDENT_U() << "if " << GET_WIDE_KEY() << " < " << K() << "[_mid]"
190 << INDENT_O() << "_upper = _mid - 2"
191 << INDENT_U() << "elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid+1]"
192 << INDENT_O() << "_lower = _mid + 2"
193 << INDENT_U() << "else"
194 << INDENT_S() << "_trans += ((_mid - _keys) >> 1)"
195 << INDENT_S() << "_match.call"
196 << INDENT_D() << "end"
197 << INDENT_D() << "end # loop"
198 << INDENT_S() << "_trans += _klen"
199 << INDENT_D() << "end"
200 << INDENT_D() << "end # cc _match" ;
203 void RubyCodeGen::writeExec()
205 out << INDENT_U() << "callcc do |_out|"
206 << INDENT_S() << "_klen, _trans, _keys";
208 if ( redFsm->anyRegCurStateRef() )
210 if ( redFsm->anyConditions() )
212 if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
213 || redFsm->anyFromStateActions() )
214 out << ", _acts, _nacts";
219 out << INDENT_S() << "_out.call if " << P() << " == " << PE() ;
221 out << INDENT_S() << "_resume = nil"
222 << INDENT_S() << "callcc { |_cc| _resume = _cc }" ;
224 if ( redFsm->errState != 0)
225 out << INDENT_S() << "_out.call if " << CS() << " == " << redFsm->errState->id ;
227 if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
228 redFsm->anyActionCalls() || redFsm->anyActionRets() )
229 out << INDENT_U() << "callcc do |_again|" ;
231 if ( redFsm->anyFromStateActions() ) {
232 out << INDENT_S() << "_acts = " << FSA() << "[" << CS() << "]"
233 << INDENT_S() << "_nacts = " << A() << "[_acts]"
234 << INDENT_S() << "_acts += 1"
235 << INDENT_U() << "while _nacts > 0"
236 << INDENT_S() << "_nacts -= 1"
237 << INDENT_S() << " _acts += 1"
238 << INDENT_U() << "case " << A() << "[_acts - 1]" ;
239 FROM_STATE_ACTION_SWITCH()
240 << INDENT_D() << "end # from state action switch"
241 << INDENT_D() << "end"
245 if ( redFsm->anyConditions() )
250 if ( redFsm->anyRegCurStateRef() )
251 out << INDENT_S() << "_ps = " << CS() ;
254 out << INDENT_S() << "_trans = " << I() << "[_trans]" ;
256 out << INDENT_S() << CS() << " = " << TT() << "[_trans]" ;
258 if ( redFsm->anyRegActions() ) {
259 out << INDENT_S() << "_again.call if " << TA() << "[_trans] == 0"
261 << INDENT_S() << "_acts = " << TA() << "[_trans]"
262 << INDENT_S() << "_nacts = " << A() << "[_acts]"
263 << INDENT_S() << "_acts += 1"
264 << INDENT_U() << "while _nacts > 0"
265 << INDENT_S() << "_nacts -= 1"
266 << INDENT_S() << "_acts += 1"
267 << INDENT_U() << "case " << A() << "[_acts - 1]" ;
269 << INDENT_D() << "end # action switch"
270 << INDENT_D() << "end"
274 if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
275 redFsm->anyActionCalls() || redFsm->anyActionRets() )
276 out << INDENT_D() << "end # cc _again";
278 if ( redFsm->anyToStateActions() ) {
279 out << INDENT_S() << "_acts = " << TSA() << "[" << CS() << "]"
280 << INDENT_S() << "_nacts = " << A() << "[_acts]"
281 << INDENT_S() << "_acts += 1"
282 << INDENT_U() << "while _nacts > 0"
283 << INDENT_S() << "_nacts -= 1"
284 << INDENT_S() << "_acts += 1"
285 << INDENT_U() << "case " << A() << "[_acts - 1]" ;
286 TO_STATE_ACTION_SWITCH()
287 << INDENT_D() << "end # to state action switch"
288 << INDENT_D() << "end"
292 out << INDENT_S() << P() << " += 1" ;
295 out << INDENT_S() << "_resume.call if " << P() << " != " << PE();
297 out << INDENT_D() << "end # cc _out" ;
300 void RubyCodeGen::writeEOF()
302 if ( redFsm->anyEofActions() ) {
303 out << INDENT_S() << "_acts = " << EA() << "[" << CS() << "]"
304 << INDENT_S() << "_nacts = " << " " << A() << "[_acts]"
305 << INDENT_S() << "_acts += 1"
306 << INDENT_U() << "while _nacts > 0"
307 << INDENT_S() << "_nacts -= 1"
308 << INDENT_S() << "_acts += 1"
309 << INDENT_S() << "case " << A() << "[_acts - 1]" ;
311 << INDENT_D() << "end # eof action switch"
312 << INDENT_D() << "end"
317 std::ostream &RubyCodeGen::FROM_STATE_ACTION_SWITCH()
319 /* Walk the list of functions, printing the cases. */
320 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
321 /* Write out referenced actions. */
322 if ( act->numFromStateRefs > 0 ) {
323 /* Write the case label, the action */
324 out << INDENT_S() << "when " << act->actionId << ":" ;
325 ACTION( out, act, 0, false );
329 genLineDirective( out );
334 std::ostream &RubyCodeGen::TO_STATE_ACTION_SWITCH()
336 /* Walk the list of functions, printing the cases. */
337 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
338 /* Write out referenced actions. */
339 if ( act->numToStateRefs > 0 ) {
340 /* Write the case label, the action and the case break. */
341 out << INDENT_S() << "when " << act->actionId << ":" ;
342 ACTION( out, act, 0, false );
346 genLineDirective( out );
350 std::ostream &RubyCodeGen::EOF_ACTION_SWITCH()
352 /* Walk the list of functions, printing the cases. */
353 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
354 /* Write out referenced actions. */
355 if ( act->numEofRefs > 0 ) {
356 /* Write the case label, the action and the case break. */
357 out << INDENT_S() << "when " << act->actionId << ":" ;
358 ACTION( out, act, 0, true );
362 genLineDirective( out );
366 std::ostream &RubyCodeGen::ACTION_SWITCH()
368 /* Walk the list of functions, printing the cases. */
369 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
370 /* Write out referenced actions. */
371 if ( act->numTransRefs > 0 ) {
372 /* Write the case label, the action and the case break. */
373 out << INDENT_S() << "when " << act->actionId << ":" ;
374 ACTION( out, act, 0, false );
378 genLineDirective( out );
383 void RubyCodeGen::writeInit()
385 out << INDENT_U() << "begin";
388 out << 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 */
480 void RubyCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
482 ret << CS() << " = " << nextDest << ";";
485 void RubyCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
487 ret << CS() << " = (";
488 INLINE_LIST( ret, ilItem->children, 0, inFinish );
492 void RubyCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
494 /* The parser gives fexec two children. The double brackets are for D
495 * code. If the inline list is a single word it will get interpreted as a
496 * C-style cast by the D compiler. */
497 ret << " begin " << P() << " = ((";
498 INLINE_LIST( ret, item->children, targState, inFinish );
499 ret << "))-1; end\n";
502 void RubyCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
504 /* Tokend version of exec. */
506 /* The parser gives fexec two children. The double brackets are for D
507 * code. If the inline list is a single word it will get interpreted as a
508 * C-style cast by the D compiler. */
509 ret << " begin " << TOKEND() << " = ((";
510 INLINE_LIST( ret, item->children, targState, inFinish );
514 /* Write out an inline tree structure. Walks the list and possibly calls out
515 * to virtual functions than handle language specific items in the tree. */
516 void RubyCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList,
517 int targState, bool inFinish )
519 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
520 switch ( item->type ) {
521 case InlineItem::Text:
524 case InlineItem::Goto:
525 GOTO( ret, item->targState->id, inFinish );
527 case InlineItem::Call:
528 CALL( ret, item->targState->id, targState, inFinish );
530 case InlineItem::Next:
531 NEXT( ret, item->targState->id, inFinish );
533 case InlineItem::Ret:
534 RET( ret, inFinish );
536 case InlineItem::PChar:
539 case InlineItem::Char:
542 case InlineItem::Hold:
543 ret << P() << " = " << P() << " - 1;";
545 case InlineItem::Exec:
546 EXEC( ret, item, targState, inFinish );
548 case InlineItem::HoldTE:
549 ret << TOKEND() << " = " << TOKEND() << " - 1;";
551 case InlineItem::ExecTE:
552 EXECTE( ret, item, targState, inFinish );
554 case InlineItem::Curs:
557 case InlineItem::Targs:
558 ret << "(" << CS() << ")";
560 case InlineItem::Entry:
561 ret << item->targState->id;
563 case InlineItem::GotoExpr:
564 GOTO_EXPR( ret, item, inFinish );
566 case InlineItem::CallExpr:
567 CALL_EXPR( ret, item, targState, inFinish );
569 case InlineItem::NextExpr:
570 NEXT_EXPR( ret, item, inFinish );
572 case InlineItem::LmSwitch:
573 LM_SWITCH( ret, item, targState, inFinish );
575 case InlineItem::LmSetActId:
576 SET_ACT( ret, item );
578 case InlineItem::LmSetTokEnd:
579 SET_TOKEND( ret, item );
581 case InlineItem::LmGetTokEnd:
582 GET_TOKEND( ret, item );
584 case InlineItem::LmInitTokStart:
585 INIT_TOKSTART( ret, item );
587 case InlineItem::LmInitAct:
588 INIT_ACT( ret, item );
590 case InlineItem::LmSetTokStart:
591 SET_TOKSTART( ret, item );
593 case InlineItem::SubAction:
594 SUB_ACTION( ret, item, targState, inFinish );
596 case InlineItem::Break:
597 BREAK( ret, targState );
603 string RubyCodeGen::DATA_PREFIX()
606 return FSM_NAME() + "_";
610 /* Emit the alphabet data type. */
611 string RubyCodeGen::ALPH_TYPE()
613 string ret = keyOps->alphType->data1;
614 if ( keyOps->alphType->data2 != 0 ) {
616 ret += + keyOps->alphType->data2;
621 /* Emit the alphabet data type. */
622 string RubyCodeGen::WIDE_ALPH_TYPE()
625 if ( redFsm->maxKey <= keyOps->maxKey )
628 long long maxKeyVal = redFsm->maxKey.getLongLong();
629 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
630 assert( wideType != 0 );
632 ret = wideType->data1;
633 if ( wideType->data2 != 0 ) {
635 ret += wideType->data2;
641 /* Determine if we should use indicies or not. */
642 void RubyCodeGen::calcIndexSize()
644 int sizeWithInds = 0, sizeWithoutInds = 0;
646 /* Calculate cost of using with indicies. */
647 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
648 int totalIndex = st->outSingle.length() + st->outRange.length() +
649 (st->defTrans == 0 ? 0 : 1);
650 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
652 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
653 if ( redFsm->anyActions() )
654 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
656 /* Calculate the cost of not using indicies. */
657 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
658 int totalIndex = st->outSingle.length() + st->outRange.length() +
659 (st->defTrans == 0 ? 0 : 1);
660 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
661 if ( redFsm->anyActions() )
662 sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
665 /* If using indicies reduces the size, use them. */
666 useIndicies = sizeWithInds < sizeWithoutInds;
669 int RubyCodeGen::TO_STATE_ACTION( RedStateAp *state )
672 if ( state->toStateAction != 0 )
673 act = state->toStateAction->location+1;
677 int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
680 if ( state->fromStateAction != 0 )
681 act = state->fromStateAction->location+1;
685 int RubyCodeGen::EOF_ACTION( RedStateAp *state )
688 if ( state->eofAction != 0 )
689 act = state->eofAction->location+1;
694 int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
696 /* If there are actions, emit them. Otherwise emit zero. */
698 if ( trans->action != 0 )
699 act = trans->action->location+1;
703 std::ostream &RubyCodeGen::COND_OFFSETS()
706 int totalStateNum = 0, curKeyOffset = 0;
707 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
708 /* Write the key offset. */
709 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
711 /* Move the key offset ahead. */
712 curKeyOffset += st->stateCondList.length();
718 std::ostream &RubyCodeGen::KEY_OFFSETS()
721 int totalStateNum = 0, curKeyOffset = 0;
722 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
723 /* Write the key offset. */
724 ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
726 /* Move the key offset ahead. */
727 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
734 std::ostream &RubyCodeGen::INDEX_OFFSETS()
737 int totalStateNum = 0, curIndOffset = 0;
738 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
739 /* Write the index offset. */
740 ARRAY_ITEM( INT(curIndOffset), ++totalStateNum, st.last() );
742 /* Move the index offset ahead. */
743 curIndOffset += st->outSingle.length() + st->outRange.length();
744 if ( st->defTrans != 0 )
751 std::ostream &RubyCodeGen::COND_LENS()
754 int totalStateNum = 0;
755 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
756 /* Write singles length. */
757 ARRAY_ITEM( INT(st->stateCondList.length()), ++totalStateNum, st.last() );
764 std::ostream &RubyCodeGen::SINGLE_LENS()
767 int totalStateNum = 0;
768 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
769 /* Write singles length. */
770 ARRAY_ITEM( INT(st->outSingle.length()), ++totalStateNum, st.last() );
776 std::ostream &RubyCodeGen::RANGE_LENS()
779 int totalStateNum = 0;
780 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
781 /* Emit length of range index. */
782 ARRAY_ITEM( INT(st->outRange.length()), ++totalStateNum, st.last() );
788 std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
791 int totalStateNum = 0;
792 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
793 /* Write any eof action. */
794 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), ++totalStateNum, st.last() );
800 std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
803 int totalStateNum = 0;
804 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
805 /* Write any eof action. */
806 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), ++totalStateNum, st.last() );
812 std::ostream &RubyCodeGen::EOF_ACTIONS()
815 int totalStateNum = 0;
816 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
817 /* Write any eof action. */
818 ARRAY_ITEM( INT(EOF_ACTION(st)), ++totalStateNum, st.last() );
824 std::ostream &RubyCodeGen::COND_KEYS()
828 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
829 /* Loop the state's transitions. */
830 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
832 ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
833 ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
837 /* Output one last number so we don't have to figure out when the last
838 * entry is and avoid writing a comma. */
839 ARRAY_ITEM( INT(0), ++totalTrans, true );
844 std::ostream &RubyCodeGen::COND_SPACES()
848 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
849 /* Loop the state's transitions. */
850 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
852 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
856 /* Output one last number so we don't have to figure out when the last
857 * entry is and avoid writing a comma. */
858 ARRAY_ITEM( INT(0), ++totalTrans, true );
863 std::ostream &RubyCodeGen::KEYS()
867 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
868 /* Loop the singles. */
869 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
870 ARRAY_ITEM( KEY( stel->lowKey ), ++totalTrans, false );
873 /* Loop the state's transitions. */
874 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
876 ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
879 ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
883 /* Output one last number so we don't have to figure out when the last
884 * entry is and avoid writing a comma. */
885 ARRAY_ITEM( INT(0), ++totalTrans, true );
890 std::ostream &RubyCodeGen::INDICIES()
894 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
895 /* Walk the singles. */
896 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
897 ARRAY_ITEM( KEY( stel->value->id ), ++totalTrans, false );
900 /* Walk the ranges. */
901 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
902 ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
905 /* The state's default index goes next. */
906 if ( st->defTrans != 0 ) {
907 ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
911 /* Output one last number so we don't have to figure out when the last
912 * entry is and avoid writing a comma. */
913 ARRAY_ITEM( INT(0), ++totalTrans, true );
918 std::ostream &RubyCodeGen::TRANS_TARGS()
922 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
923 /* Walk the singles. */
924 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
925 RedTransAp *trans = stel->value;
926 ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
929 /* Walk the ranges. */
930 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
931 RedTransAp *trans = rtel->value;
932 ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
935 /* The state's default target state. */
936 if ( st->defTrans != 0 ) {
937 RedTransAp *trans = st->defTrans;
938 ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
942 /* Output one last number so we don't have to figure out when the last
943 * entry is and avoid writing a comma. */
944 ARRAY_ITEM( INT(0), ++totalTrans, true );
950 std::ostream &RubyCodeGen::TRANS_ACTIONS()
954 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
955 /* Walk the singles. */
956 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
957 RedTransAp *trans = stel->value;
958 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
961 /* Walk the ranges. */
962 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
963 RedTransAp *trans = rtel->value;
964 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
967 /* The state's default index goes next. */
968 if ( st->defTrans != 0 ) {
969 RedTransAp *trans = st->defTrans;
970 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
974 /* Output one last number so we don't have to figure out when the last
975 * entry is and avoid writing a comma. */
976 ARRAY_ITEM( INT(0), ++totalTrans, true );
981 std::ostream &RubyCodeGen::TRANS_TARGS_WI()
983 /* Transitions must be written ordered by their id. */
984 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
985 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
986 transPtrs[trans->id] = trans;
988 /* Keep a count of the num of items in the array written. */
991 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
992 /* Write out the target state. */
993 RedTransAp *trans = transPtrs[t];
994 ARRAY_ITEM( INT(trans->targ->id), ++totalStates, ( t >= redFsm->transSet.length()-1 ) );
1002 std::ostream &RubyCodeGen::TRANS_ACTIONS_WI()
1004 /* Transitions must be written ordered by their id. */
1005 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
1006 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
1007 transPtrs[trans->id] = trans;
1009 /* Keep a count of the num of items in the array written. */
1012 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
1013 /* Write the function for the transition. */
1014 RedTransAp *trans = transPtrs[t];
1015 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalAct, ( t >= redFsm->transSet.length()-1 ) );
1022 void RubyCodeGen::writeExports()
1024 if ( exportList.length() > 0 ) {
1025 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
1026 STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
1027 << " = " << KEY(ex->key) << "\n";
1034 void RubyCodeGen::writeData()
1036 /* If there are any transtion functions then output the array. If there
1037 * are none, don't bother emitting an empty array that won't be used. */
1038 if ( redFsm->anyActions() ) {
1039 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
1045 if ( redFsm->anyConditions() ) {
1046 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
1051 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
1056 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
1061 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
1067 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
1072 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
1077 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
1082 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
1087 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
1092 if ( useIndicies ) {
1093 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
1098 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1103 if ( redFsm->anyActions() ) {
1104 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1111 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
1116 if ( redFsm->anyActions() ) {
1117 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1124 if ( redFsm->anyToStateActions() ) {
1125 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
1131 if ( redFsm->anyFromStateActions() ) {
1132 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1133 FROM_STATE_ACTIONS();
1138 if ( redFsm->anyEofActions() ) {
1139 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1145 if ( redFsm->startState != 0 )
1146 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
1148 if ( writeFirstFinal )
1149 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
1152 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
1156 if ( entryPointNames.length() > 0 ) {
1157 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
1158 STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
1159 " = " << entryPointIds[en.pos()] << ";\n";
1165 std::ostream &RubyCodeGen::START_ARRAY_LINE()
1171 std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
1177 if ( count % IALL == 0 )
1186 std::ostream &RubyCodeGen::END_ARRAY_LINE()
1193 unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
1195 long long maxValLL = (long long) maxVal;
1196 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1197 assert( arrayType != 0 );
1198 return arrayType->size;
1201 string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
1203 long long maxValLL = (long long) maxVal;
1204 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1205 assert( arrayType != 0 );
1207 string ret = arrayType->data1;
1208 if ( arrayType->data2 != 0 ) {
1210 ret += arrayType->data2;
1216 /* Write out the fsm name. */
1217 string RubyCodeGen::FSM_NAME()
1222 /* Emit the offset of the start state as a decimal integer. */
1223 string RubyCodeGen::START_STATE_ID()
1226 ret << redFsm->startState->id;
1230 /* Write out the array of actions. */
1231 std::ostream &RubyCodeGen::ACTIONS_ARRAY()
1234 int totalActions = 0;
1235 ARRAY_ITEM( INT(0), ++totalActions, false );
1236 for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1237 /* Write out the length, which will never be the last character. */
1238 ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
1240 for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
1241 ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
1249 string RubyCodeGen::ACCESS()
1252 if ( accessExpr != 0 )
1253 INLINE_LIST( ret, accessExpr, 0, false );
1257 string RubyCodeGen::P()
1264 INLINE_LIST( ret, pExpr, 0, false );
1270 string RubyCodeGen::PE()
1277 INLINE_LIST( ret, peExpr, 0, false );
1283 string RubyCodeGen::CS()
1287 ret << ACCESS() << "cs";
1290 INLINE_LIST( ret, csExpr, 0, false );
1296 string RubyCodeGen::TOP()
1300 ret << ACCESS() + "top";
1303 INLINE_LIST( ret, topExpr, 0, false );
1309 string RubyCodeGen::STACK()
1312 if ( stackExpr == 0 )
1313 ret << ACCESS() + "stack";
1316 INLINE_LIST( ret, stackExpr, 0, false );
1322 string RubyCodeGen::ACT()
1326 ret << ACCESS() + "act";
1329 INLINE_LIST( ret, actExpr, 0, false );
1335 string RubyCodeGen::TOKSTART()
1338 if ( tokstartExpr == 0 )
1339 ret << ACCESS() + "tokstart";
1342 INLINE_LIST( ret, tokstartExpr, 0, false );
1348 string RubyCodeGen::TOKEND()
1351 if ( tokendExpr == 0 )
1352 ret << ACCESS() + "tokend";
1355 INLINE_LIST( ret, tokendExpr, 0, false );
1362 string RubyCodeGen::GET_WIDE_KEY()
1364 if ( redFsm->anyConditions() )
1370 string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
1372 if ( state->stateCondList.length() > 0 )
1378 /* Write out level number of tabs. Makes the nested binary search nice
1380 string RubyCodeGen::TABS( int level )
1383 while ( level-- > 0 )
1388 string RubyCodeGen::KEY( Key key )
1391 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1392 ret << key.getVal();
1394 ret << (unsigned long) key.getVal();
1398 string RubyCodeGen::INT( int i )
1405 void RubyCodeGen::LM_SWITCH( ostream &ret, InlineItem *item,
1406 int targState, int inFinish )
1409 " case " << ACT() << "\n";
1411 /* If the switch handles error then we also forced the error state. It
1413 if ( item->handlesError ) {
1414 ret << " when 0: " << TOKEND() << " = " << TOKSTART() << "; ";
1415 GOTO( ret, redFsm->errState->id, inFinish );
1419 for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1420 /* Write the case label, the action and the case break. */
1421 ret << " when " << lma->lmId << ":\n";
1423 /* Write the block and close it off. */
1425 INLINE_LIST( ret, lma->children, targState, inFinish );
1432 void RubyCodeGen::SET_ACT( ostream &ret, InlineItem *item )
1434 ret << ACT() << " = " << item->lmId << ";";
1437 void RubyCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
1439 /* The tokend action sets tokend. */
1440 ret << TOKEND() << " = " << P();
1441 if ( item->offset != 0 )
1442 out << "+" << item->offset;
1446 void RubyCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
1451 void RubyCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
1453 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1456 void RubyCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
1458 ret << ACT() << " = 0;";
1461 void RubyCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
1463 ret << TOKSTART() << " = " << P() << ";";
1466 void RubyCodeGen::SUB_ACTION( ostream &ret, InlineItem *item,
1467 int targState, bool inFinish )
1469 if ( item->children->length() > 0 ) {
1470 /* Write the block and close it off. */
1472 INLINE_LIST( ret, item->children, targState, inFinish );
1477 void RubyCodeGen::CONDITION( ostream &ret, Action *condition )
1480 lineDirective( ret, sourceFileName, condition->loc.line );
1481 INLINE_LIST( ret, condition->inlineList, 0, false );
1484 string RubyCodeGen::ERROR_STATE()
1487 if ( redFsm->errState != 0 )
1488 ret << redFsm->errState->id;
1494 string RubyCodeGen::FIRST_FINAL_STATE()
1497 if ( redFsm->firstFinState != 0 )
1498 ret << redFsm->firstFinState->id;
1500 ret << redFsm->nextStateId;
1504 void RubyCodeGen::finishRagelDef()
1506 /* The frontend will do this for us, but it may be a good idea to force it
1507 * if the intermediate file is edited. */
1508 redFsm->sortByStateId();
1510 /* Choose default transitions and the single transition. */
1511 redFsm->chooseDefaultSpan();
1513 /* Maybe do flat expand, otherwise choose single. */
1514 redFsm->chooseSingle();
1516 /* If any errors have occured in the input file then don't write anything. */
1517 if ( gblErrorCount > 0 )
1520 /* Anlayze Machine will find the final action reference counts, among
1521 * other things. We will use these in reporting the usage
1522 * of fsm directives in action code. */
1525 /* Determine if we should use indicies. */
1529 ostream &RubyCodeGen::source_warning( const InputLoc &loc )
1531 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1535 ostream &RubyCodeGen::source_error( const InputLoc &loc )
1538 assert( sourceFileName != 0 );
1539 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";