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