1/*
2 *  Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
3 */
4
5/*  This file is part of Ragel.
6 *
7 *  Ragel is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 *
12 *  Ragel is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with Ragel; if not, write to the Free Software
19 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22#include "rlparse.h"
23#include "ragel.h"
24#include <iostream>
25#include <errno.h>
26#include <stdlib.h>
27
28using std::cout;
29using std::cerr;
30using std::endl;
31
32%%{
33
34parser Parser;
35
36include "rlparse.kh";
37
38start: section_list;
39
40section_list: section_list statement_list TK_EndSection;
41section_list: ;
42
43statement_list: statement_list statement;
44statement_list: ;
45
46statement: assignment commit;
47statement: instantiation commit;
48statement: action_spec commit;
49statement: alphtype_spec commit;
50statement: range_spec commit;
51statement: getkey_spec commit;
52statement: access_spec commit;
53statement: variable_spec commit;
54statement: export_block commit;
55statement: pre_push_spec commit;
56statement: post_pop_spec commit;
57statement: length_spec commit;
58
59length_spec:
60	KW_Length TK_Word ';'
61	final {
62		LengthDef *lengthDef = new LengthDef( $2->data );
63		pd->lengthDefList.append( lengthDef );
64
65		/* Generic creation of machine for instantiation and assignment. */
66		MachineDef *machineDef = new MachineDef( lengthDef );
67		tryMachineDef( $2->loc, $2->data, machineDef, false );
68	};
69
70pre_push_spec:
71	KW_PrePush '{' inline_block '}'
72	final {
73		if ( pd->prePushExpr != 0 ) {
74			/* Recover by just ignoring the duplicate. */
75			error($2->loc) << "pre_push code already defined" << endl;
76		}
77
78		pd->prePushExpr = $3->inlineList;
79	};
80
81
82post_pop_spec:
83	KW_PostPop '{' inline_block '}'
84	final {
85		if ( pd->postPopExpr != 0 ) {
86			/* Recover by just ignoring the duplicate. */
87			error($2->loc) << "post_pop code already defined" << endl;
88		}
89
90		pd->postPopExpr = $3->inlineList;
91	};
92
93
94export_open: KW_Export
95	final {
96		exportContext.append( true );
97	};
98
99nonterm opt_export
100{
101	bool isSet;
102};
103
104opt_export: export_open final { $$->isSet = true; };
105opt_export: final { $$->isSet = false; };
106
107export_block: export_open '{' statement_list '}'
108	final {
109		exportContext.remove( exportContext.length()-1 );
110	};
111
112assignment:
113	opt_export machine_name '=' join ';' final {
114		/* Main machine must be an instance. */
115		bool isInstance = false;
116		if ( strcmp($2->token.data, mainMachine) == 0 ) {
117			warning($2->token.loc) <<
118					"main machine will be implicitly instantiated" << endl;
119			isInstance = true;
120		}
121
122		/* Generic creation of machine for instantiation and assignment. */
123		MachineDef *machineDef = new MachineDef( $4->join );
124		tryMachineDef( $2->token.loc, $2->token.data, machineDef, isInstance );
125
126		if ( $1->isSet )
127			exportContext.remove( exportContext.length()-1 );
128
129		$4->join->loc = $3->loc;
130	};
131
132instantiation:
133	opt_export machine_name TK_ColonEquals join_or_lm ';' final {
134		/* Generic creation of machine for instantiation and assignment. */
135		tryMachineDef( $2->token.loc, $2->token.data, $4->machineDef, true );
136
137		if ( $1->isSet )
138			exportContext.remove( exportContext.length()-1 );
139
140		/* Pass a location to join_or_lm */
141		if ( $4->machineDef->join != 0 )
142			$4->machineDef->join->loc = $3->loc;
143	};
144
145type token_type
146{
147	Token token;
148};
149
150nonterm machine_name uses token_type;
151
152machine_name:
153	TK_Word final {
154		/* Make/get the priority key. The name may have already been referenced
155		 * and therefore exist. */
156		PriorDictEl *priorDictEl;
157		if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
158			pd->nextPriorKey += 1;
159		pd->curDefPriorKey = priorDictEl->value;
160
161		/* Make/get the local error key. */
162		LocalErrDictEl *localErrDictEl;
163		if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
164			pd->nextLocalErrKey += 1;
165		pd->curDefLocalErrKey = localErrDictEl->value;
166
167		$$->token = *$1;
168	};
169
170action_spec:
171	KW_Action TK_Word '{' inline_block '}' final {
172		if ( pd->actionDict.find( $2->data ) ) {
173			/* Recover by just ignoring the duplicate. */
174			error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
175		}
176		else {
177			//cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
178			/* Add the action to the list of actions. */
179			Action *newAction = new Action( $3->loc, $2->data,
180					$4->inlineList, pd->nextCondId++ );
181
182			/* Insert to list and dict. */
183			pd->actionList.append( newAction );
184			pd->actionDict.insert( newAction );
185		}
186	};
187
188# Specifies the data type of the input alphabet. One or two words followed by a
189# semi-colon.
190alphtype_spec:
191	KW_AlphType TK_Word TK_Word ';' final {
192		if ( ! pd->setAlphType( $1->loc, $2->data, $3->data ) ) {
193			// Recover by ignoring the alphtype statement.
194			error($2->loc) << "\"" << $2->data <<
195					" " << $3->data << "\" is not a valid alphabet type" << endl;
196		}
197	};
198
199alphtype_spec:
200	KW_AlphType TK_Word ';' final {
201		if ( ! pd->setAlphType( $1->loc, $2->data ) ) {
202			// Recover by ignoring the alphtype statement.
203			error($2->loc) << "\"" << $2->data <<
204					"\" is not a valid alphabet type" << endl;
205		}
206	};
207
208# Specifies a range to assume that the input characters will fall into.
209range_spec:
210	KW_Range alphabet_num alphabet_num ';' final {
211		// Save the upper and lower ends of the range and emit the line number.
212		pd->lowerNum = $2->token.data;
213		pd->upperNum = $3->token.data;
214		pd->rangeLowLoc = $2->token.loc;
215		pd->rangeHighLoc = $3->token.loc;
216	};
217
218getkey_spec:
219	KW_GetKey inline_expr ';' final {
220		pd->getKeyExpr = $2->inlineList;
221	};
222
223access_spec:
224	KW_Access inline_expr ';' final {
225		pd->accessExpr = $2->inlineList;
226	};
227
228variable_spec:
229	KW_Variable opt_whitespace TK_Word inline_expr ';' final {
230		/* FIXME: Need to implement the rest of this. */
231		bool wasSet = pd->setVariable( $3->data, $4->inlineList );
232		if ( !wasSet )
233			error($3->loc) << "bad variable name" << endl;
234	};
235
236opt_whitespace: opt_whitespace IL_WhiteSpace;
237opt_whitespace: ;
238
239#
240# Expressions
241#
242
243nonterm join_or_lm
244{
245	MachineDef *machineDef;
246};
247
248join_or_lm:
249	join final {
250		$$->machineDef = new MachineDef( $1->join );
251	};
252join_or_lm:
253	TK_BarStar lm_part_list '*' '|' final {
254		/* Create a new factor going to a longest match structure. Record
255		 * in the parse data that we have a longest match. */
256		LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
257		pd->lmList.append( lm );
258		for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
259			lmp->longestMatch = lm;
260		$$->machineDef = new MachineDef( lm );
261	};
262
263nonterm lm_part_list
264{
265	LmPartList *lmPartList;
266};
267
268lm_part_list:
269	lm_part_list longest_match_part
270	final {
271		if ( $2->lmPart != 0 )
272			$1->lmPartList->append( $2->lmPart );
273		$$->lmPartList = $1->lmPartList;
274	};
275lm_part_list:
276	longest_match_part
277	final {
278		/* Create a new list with the part. */
279		$$->lmPartList = new LmPartList;
280		if ( $1->lmPart != 0 )
281			$$->lmPartList->append( $1->lmPart );
282	};
283
284nonterm longest_match_part
285{
286	LongestMatchPart *lmPart;
287};
288
289longest_match_part:
290	action_spec final { $$->lmPart = 0; };
291longest_match_part:
292	assignment final { $$->lmPart = 0; };
293longest_match_part:
294	join opt_lm_part_action ';' final {
295		$$->lmPart = 0;
296		Action *action = $2->action;
297		if ( action != 0 )
298			action->isLmAction = true;
299		$$->lmPart = new LongestMatchPart( $1->join, action,
300				$3->loc, pd->nextLongestMatchId++ );
301
302		/* Provide a location to join. Unfortunately We don't
303		 * have the start of the join as in other occurances. Use the end. */
304		$1->join->loc = $3->loc;
305	};
306
307nonterm opt_lm_part_action
308{
309	Action *action;
310};
311
312opt_lm_part_action:
313	TK_DoubleArrow action_embed final {
314		$$->action = $2->action;
315	};
316opt_lm_part_action:
317	action_embed_block final {
318		$$->action = $1->action;
319	};
320opt_lm_part_action:
321	final {
322		$$->action = 0;
323	};
324
325
326nonterm join
327{
328	Join *join;
329};
330
331join:
332	join ',' expression final {
333		/* Append the expression to the list and return it. */
334		$1->join->exprList.append( $3->expression );
335		$$->join = $1->join;
336	};
337join:
338	expression final {
339		$$->join = new Join( $1->expression );
340	};
341
342nonterm expression
343{
344	Expression *expression;
345};
346
347expression:
348	expression '|' term_short final {
349		$$->expression = new Expression( $1->expression,
350				$3->term, Expression::OrType );
351	};
352expression:
353	expression '&' term_short final {
354		$$->expression = new Expression( $1->expression,
355				$3->term, Expression::IntersectType );
356	};
357expression:
358	expression '-' term_short final {
359		$$->expression = new Expression( $1->expression,
360				$3->term, Expression::SubtractType );
361	};
362expression:
363	expression TK_DashDash term_short final {
364		$$->expression = new Expression( $1->expression,
365				$3->term, Expression::StrongSubtractType );
366	};
367expression:
368	term_short final {
369		$$->expression = new Expression( $1->term );
370	};
371
372# This is where we resolve the ambiguity involving -. By default ragel tries to
373# do a longest match, which gives precedence to a concatenation because it is
374# innermost. What we need is to force term into a shortest match so that when -
375# is seen it doesn't try to extend term with a concatenation, but ends term and
376# goes for a subtraction.
377#
378# The shortest tag overrides the default longest match action ordering strategy
379# and instead forces a shortest match stragegy. The wrap the term production in
380# a new nonterminal 'term_short' to guarantee the shortest match behaviour.
381
382shortest term_short;
383nonterm term_short
384{
385	Term *term;
386};
387
388term_short:
389	term final {
390		$$->term = $1->term;
391	};
392
393nonterm term
394{
395	Term *term;
396};
397
398term:
399	term factor_with_label final {
400		$$->term = new Term( $1->term, $2->factorWithAug );
401	};
402term:
403	term '.' factor_with_label final {
404		$$->term = new Term( $1->term, $3->factorWithAug );
405	};
406term:
407	term TK_ColonGt factor_with_label final {
408		$$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
409	};
410term:
411	term TK_ColonGtGt factor_with_label final {
412		$$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
413	};
414term:
415	term TK_LtColon factor_with_label final {
416		$$->term = new Term( $1->term,
417				$3->factorWithAug, Term::LeftType );
418	};
419term:
420	factor_with_label final {
421		$$->term = new Term( $1->factorWithAug );
422	};
423
424nonterm factor_with_label
425{
426	FactorWithAug *factorWithAug;
427};
428
429factor_with_label:
430	TK_Word ':' factor_with_label final {
431		/* Add the label to the list and pass the factor up. */
432		$3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
433		$$->factorWithAug = $3->factorWithAug;
434	};
435factor_with_label:
436	factor_with_ep final {
437		$$->factorWithAug = $1->factorWithAug;
438	};
439
440nonterm factor_with_ep
441{
442	FactorWithAug *factorWithAug;
443};
444
445factor_with_ep:
446	factor_with_ep TK_Arrow local_state_ref final {
447		/* Add the target to the list and return the factor object. */
448		$1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
449		$$->factorWithAug = $1->factorWithAug;
450	};
451factor_with_ep:
452	factor_with_aug final {
453		$$->factorWithAug = $1->factorWithAug;
454	};
455
456nonterm factor_with_aug
457{
458	FactorWithAug *factorWithAug;
459};
460
461factor_with_aug:
462	factor_with_aug aug_type_base action_embed final {
463		/* Append the action to the factorWithAug, record the refernce from
464		 * factorWithAug to the action and pass up the factorWithAug. */
465		$1->factorWithAug->actions.append(
466				ParserAction( $2->loc, $2->augType, 0, $3->action ) );
467		$$->factorWithAug = $1->factorWithAug;
468	};
469factor_with_aug:
470	factor_with_aug aug_type_base priority_aug final {
471		/* Append the named priority to the factorWithAug and pass it up. */
472		$1->factorWithAug->priorityAugs.append(
473				PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
474		$$->factorWithAug = $1->factorWithAug;
475	};
476factor_with_aug:
477	factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
478		/* Append the priority using a default name. */
479		$1->factorWithAug->priorityAugs.append(
480				PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
481		$$->factorWithAug = $1->factorWithAug;
482	};
483factor_with_aug:
484	factor_with_aug aug_type_cond action_embed final {
485		$1->factorWithAug->conditions.append( ConditionTest( $2->loc,
486				$2->augType, $3->action, true ) );
487		$$->factorWithAug = $1->factorWithAug;
488	};
489factor_with_aug:
490	factor_with_aug aug_type_cond '!' action_embed final {
491		$1->factorWithAug->conditions.append( ConditionTest( $2->loc,
492				$2->augType, $4->action, false ) );
493		$$->factorWithAug = $1->factorWithAug;
494	};
495factor_with_aug:
496	factor_with_aug aug_type_to_state action_embed final {
497		/* Append the action, pass it up. */
498		$1->factorWithAug->actions.append( ParserAction( $2->loc,
499				$2->augType, 0, $3->action ) );
500		$$->factorWithAug = $1->factorWithAug;
501	};
502factor_with_aug:
503	factor_with_aug aug_type_from_state action_embed final {
504		/* Append the action, pass it up. */
505		$1->factorWithAug->actions.append( ParserAction( $2->loc,
506				$2->augType, 0, $3->action ) );
507		$$->factorWithAug = $1->factorWithAug;
508	};
509factor_with_aug:
510	factor_with_aug aug_type_eof action_embed final {
511		/* Append the action, pass it up. */
512		$1->factorWithAug->actions.append( ParserAction( $2->loc,
513				$2->augType, 0, $3->action ) );
514		$$->factorWithAug = $1->factorWithAug;
515	};
516factor_with_aug:
517	factor_with_aug aug_type_gbl_error action_embed final {
518		/* Append the action to the factorWithAug, record the refernce from
519		 * factorWithAug to the action and pass up the factorWithAug. */
520		$1->factorWithAug->actions.append( ParserAction( $2->loc,
521				$2->augType, pd->curDefLocalErrKey, $3->action ) );
522		$$->factorWithAug = $1->factorWithAug;
523	};
524factor_with_aug:
525	factor_with_aug aug_type_local_error action_embed final {
526		/* Append the action to the factorWithAug, record the refernce from
527		 * factorWithAug to the action and pass up the factorWithAug. */
528		$1->factorWithAug->actions.append( ParserAction( $2->loc,
529				$2->augType, pd->curDefLocalErrKey, $3->action ) );
530		$$->factorWithAug = $1->factorWithAug;
531	};
532factor_with_aug:
533	factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
534		/* Append the action to the factorWithAug, record the refernce from
535		 * factorWithAug to the action and pass up the factorWithAug. */
536		$1->factorWithAug->actions.append( ParserAction( $2->loc,
537				$2->augType, $4->error_name, $6->action ) );
538		$$->factorWithAug = $1->factorWithAug;
539	};
540factor_with_aug:
541	factor_with_rep final {
542		$$->factorWithAug = new FactorWithAug( $1->factorWithRep );
543	};
544
545type aug_type
546{
547	InputLoc loc;
548	AugType augType;
549};
550
551#  Classes of transtions on which to embed actions or change priorities.
552nonterm aug_type_base uses aug_type;
553
554aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
555aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
556aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
557aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
558
559# Embedding conditions.
560nonterm aug_type_cond uses aug_type;
561
562aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
563aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
564aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
565aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
566aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
567aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
568aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
569aug_type_cond: KW_InWhen final { $$->loc = $1->loc; $$->augType = at_start; };
570aug_type_cond: KW_OutWhen final { $$->loc = $1->loc; $$->augType = at_leave; };
571
572#
573# To state actions.
574#
575
576nonterm aug_type_to_state uses aug_type;
577
578aug_type_to_state: TK_StartToState
579		final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
580aug_type_to_state: '>' KW_To
581		final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
582
583aug_type_to_state: TK_NotStartToState
584		final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
585aug_type_to_state: '<' KW_To
586		final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
587
588aug_type_to_state: TK_AllToState
589		final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
590aug_type_to_state: '$' KW_To
591		final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
592
593aug_type_to_state: TK_FinalToState
594		final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
595aug_type_to_state: '%' KW_To
596		final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
597
598aug_type_to_state: TK_NotFinalToState
599		final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
600aug_type_to_state: '@' KW_To
601		final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
602
603aug_type_to_state: TK_MiddleToState
604		final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
605aug_type_to_state: TK_Middle KW_To
606		final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
607
608#
609# From state actions.
610#
611
612nonterm aug_type_from_state uses aug_type;
613
614aug_type_from_state: TK_StartFromState
615		final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
616aug_type_from_state: '>' KW_From
617		final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
618
619aug_type_from_state: TK_NotStartFromState
620		final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
621aug_type_from_state: '<' KW_From
622		final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
623
624aug_type_from_state: TK_AllFromState
625		final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
626aug_type_from_state: '$' KW_From
627		final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
628
629aug_type_from_state: TK_FinalFromState
630		final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
631aug_type_from_state: '%' KW_From
632		final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
633
634aug_type_from_state: TK_NotFinalFromState
635		final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
636aug_type_from_state: '@' KW_From
637		final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
638
639aug_type_from_state: TK_MiddleFromState
640		final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
641aug_type_from_state: TK_Middle KW_From
642		final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
643
644#
645# Eof state actions.
646#
647
648nonterm aug_type_eof uses aug_type;
649
650aug_type_eof: TK_StartEOF
651		final { $$->loc = $1->loc; $$->augType = at_start_eof; };
652aug_type_eof: '>' KW_Eof
653		final { $$->loc = $1->loc; $$->augType = at_start_eof; };
654
655aug_type_eof: TK_NotStartEOF
656		final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
657aug_type_eof: '<' KW_Eof
658		final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
659
660aug_type_eof: TK_AllEOF
661		final { $$->loc = $1->loc; $$->augType = at_all_eof; };
662aug_type_eof: '$' KW_Eof
663		final { $$->loc = $1->loc; $$->augType = at_all_eof; };
664
665aug_type_eof: TK_FinalEOF
666		final { $$->loc = $1->loc; $$->augType = at_final_eof; };
667aug_type_eof: '%' KW_Eof
668		final { $$->loc = $1->loc; $$->augType = at_final_eof; };
669
670aug_type_eof: TK_NotFinalEOF
671		final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
672aug_type_eof: '@' KW_Eof
673		final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
674
675aug_type_eof: TK_MiddleEOF
676		final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
677aug_type_eof: TK_Middle KW_Eof
678		final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
679
680#
681# Global error actions.
682#
683
684nonterm aug_type_gbl_error uses aug_type;
685
686aug_type_gbl_error: TK_StartGblError
687		final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
688aug_type_gbl_error: '>' KW_Err
689		final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
690
691aug_type_gbl_error: TK_NotStartGblError
692		final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
693aug_type_gbl_error: '<' KW_Err
694		final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
695
696aug_type_gbl_error: TK_AllGblError
697		final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
698aug_type_gbl_error: '$' KW_Err
699		final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
700
701aug_type_gbl_error: TK_FinalGblError
702		final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
703aug_type_gbl_error: '%' KW_Err
704		final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
705
706aug_type_gbl_error: TK_NotFinalGblError
707		final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
708aug_type_gbl_error: '@' KW_Err
709		final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
710
711aug_type_gbl_error: TK_MiddleGblError
712		final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
713aug_type_gbl_error: TK_Middle KW_Err
714		final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
715
716
717#
718# Local error actions.
719#
720
721nonterm aug_type_local_error uses aug_type;
722
723aug_type_local_error: TK_StartLocalError
724		final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
725aug_type_local_error: '>' KW_Lerr
726		final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
727
728aug_type_local_error: TK_NotStartLocalError
729		final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
730aug_type_local_error: '<' KW_Lerr
731		final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
732
733aug_type_local_error: TK_AllLocalError
734		final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
735aug_type_local_error: '$' KW_Lerr
736		final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
737
738aug_type_local_error: TK_FinalLocalError
739		final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
740aug_type_local_error: '%' KW_Lerr
741		final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
742
743aug_type_local_error: TK_NotFinalLocalError
744		final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
745aug_type_local_error: '@' KW_Lerr
746		final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
747
748aug_type_local_error: TK_MiddleLocalError
749		final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
750aug_type_local_error: TK_Middle KW_Lerr
751		final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
752
753
754type action_ref
755{
756	Action *action;
757};
758
759# Different ways to embed actions. A TK_Word is reference to an action given by
760# the user as a statement in the fsm specification. An action can also be
761# specified immediately.
762nonterm action_embed uses action_ref;
763
764action_embed: action_embed_word final { $$->action = $1->action; };
765action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
766action_embed: action_embed_block final { $$->action = $1->action; };
767
768nonterm action_embed_word uses action_ref;
769
770action_embed_word:
771	TK_Word final {
772		/* Set the name in the actionDict. */
773		Action *action = pd->actionDict.find( $1->data );
774		if ( action != 0 ) {
775			/* Pass up the action element */
776			$$->action = action;
777		}
778		else {
779			/* Will recover by returning null as the action. */
780			error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
781			$$->action = 0;
782		}
783	};
784
785nonterm action_embed_block uses action_ref;
786
787action_embed_block:
788	'{' inline_block '}' final {
789		/* Create the action, add it to the list and pass up. */
790		Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
791		pd->actionList.append( newAction );
792		$$->action = newAction;
793	};
794
795nonterm priority_name
796{
797	int priorityName;
798};
799
800# A specified priority name. Looks up the name in the current priority
801# dictionary.
802priority_name:
803	TK_Word final {
804		// Lookup/create the priority key.
805		PriorDictEl *priorDictEl;
806		if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
807			pd->nextPriorKey += 1;
808
809		// Use the inserted/found priority key.
810		$$->priorityName = priorDictEl->value;
811	};
812
813nonterm priority_aug
814{
815	int priorityNum;
816};
817
818# Priority change specs.
819priority_aug:
820	priority_aug_num final {
821		// Convert the priority number to a long. Check for overflow.
822		errno = 0;
823		//cerr << "PRIOR AUG: " << $1->token.data << endl;
824		long aug = strtol( $1->token.data, 0, 10 );
825		if ( errno == ERANGE && aug == LONG_MAX ) {
826			/* Priority number too large. Recover by setting the priority to 0. */
827			error($1->token.loc) << "priority number " << $1->token.data <<
828					" overflows" << endl;
829			$$->priorityNum = 0;
830		}
831		else if ( errno == ERANGE && aug == LONG_MIN ) {
832			/* Priority number too large in the neg. Recover by using 0. */
833			error($1->token.loc) << "priority number " << $1->token.data <<
834					" underflows" << endl;
835			$$->priorityNum = 0;
836		}
837		else {
838			/* No overflow or underflow. */
839			$$->priorityNum = aug;
840		}
841	};
842
843nonterm priority_aug_num uses token_type;
844
845priority_aug_num:
846	TK_UInt final {
847		$$->token = *$1;
848	};
849priority_aug_num:
850	'+' TK_UInt final {
851		$$->token.set( "+", 1 );
852		$$->token.loc = $1->loc;
853		$$->token.append( *$2 );
854	};
855priority_aug_num:
856	'-' TK_UInt final {
857		$$->token.set( "-", 1 );
858		$$->token.loc = $1->loc;
859		$$->token.append( *$2 );
860	};
861
862nonterm local_err_name
863{
864	int error_name;
865};
866
867local_err_name:
868	TK_Word final {
869		/* Lookup/create the priority key. */
870		LocalErrDictEl *localErrDictEl;
871		if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
872			pd->nextLocalErrKey += 1;
873
874		/* Use the inserted/found priority key. */
875		$$->error_name = localErrDictEl->value;
876	};
877
878
879
880# The fourth level of precedence. These are the trailing unary operators that
881# allow for repetition.
882
883nonterm factor_with_rep
884{
885	FactorWithRep *factorWithRep;
886};
887
888factor_with_rep:
889	factor_with_rep '*' final {
890		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
891				0, 0, FactorWithRep::StarType );
892	};
893factor_with_rep:
894	factor_with_rep TK_StarStar final {
895		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
896				0, 0, FactorWithRep::StarStarType );
897	};
898factor_with_rep:
899	factor_with_rep '?' final {
900		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
901				0, 0, FactorWithRep::OptionalType );
902	};
903factor_with_rep:
904	factor_with_rep '+' final {
905		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
906				0, 0, FactorWithRep::PlusType );
907	};
908factor_with_rep:
909	factor_with_rep '{' factor_rep_num '}' final {
910		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
911				$3->rep, 0, FactorWithRep::ExactType );
912	};
913factor_with_rep:
914	factor_with_rep '{' ',' factor_rep_num '}' final {
915		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
916				0, $4->rep, FactorWithRep::MaxType );
917	};
918factor_with_rep:
919	factor_with_rep '{' factor_rep_num ',' '}' final {
920		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
921				$3->rep, 0, FactorWithRep::MinType );
922	};
923factor_with_rep:
924	factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
925		$$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
926				$3->rep, $5->rep, FactorWithRep::RangeType );
927	};
928factor_with_rep:
929	factor_with_neg final {
930		$$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
931	};
932
933nonterm factor_rep_num
934{
935	int rep;
936};
937
938factor_rep_num:
939	TK_UInt final {
940		// Convert the priority number to a long. Check for overflow.
941		errno = 0;
942		long rep = strtol( $1->data, 0, 10 );
943		if ( errno == ERANGE && rep == LONG_MAX ) {
944			// Repetition too large. Recover by returing repetition 1. */
945			error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
946			$$->rep = 1;
947		}
948		else {
949			// Cannot be negative, so no overflow.
950			$$->rep = rep;
951 		}
952	};
953
954
955#
956# The fifth level up in precedence. Negation.
957#
958
959nonterm factor_with_neg
960{
961	FactorWithNeg *factorWithNeg;
962};
963
964factor_with_neg:
965	'!' factor_with_neg final {
966		$$->factorWithNeg = new FactorWithNeg( $1->loc,
967				$2->factorWithNeg, FactorWithNeg::NegateType );
968	};
969factor_with_neg:
970	'^' factor_with_neg final {
971		$$->factorWithNeg = new FactorWithNeg( $1->loc,
972				$2->factorWithNeg, FactorWithNeg::CharNegateType );
973	};
974factor_with_neg:
975	factor final {
976		$$->factorWithNeg = new FactorWithNeg( $1->factor );
977	};
978
979nonterm factor
980{
981	Factor *factor;
982};
983
984factor:
985	TK_Literal final {
986		/* Create a new factor node going to a concat literal. */
987		$$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
988	};
989factor:
990	alphabet_num final {
991		/* Create a new factor node going to a literal number. */
992		$$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
993	};
994factor:
995	TK_Word final {
996		/* Find the named graph. */
997		GraphDictEl *gdNode = pd->graphDict.find( $1->data );
998		if ( gdNode == 0 ) {
999			/* Recover by returning null as the factor node. */
1000			error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
1001			$$->factor = 0;
1002		}
1003		else if ( gdNode->isInstance ) {
1004			/* Recover by retuning null as the factor node. */
1005			error($1->loc) << "references to graph instantiations not allowed "
1006					"in expressions" << endl;
1007			$$->factor = 0;
1008		}
1009		else {
1010			/* Create a factor node that is a lookup of an expression. */
1011			$$->factor = new Factor( $1->loc, gdNode->value );
1012		}
1013	};
1014factor:
1015	RE_SqOpen regular_expr_or_data RE_SqClose final {
1016		/* Create a new factor node going to an OR expression. */
1017		$$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
1018	};
1019factor:
1020	RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1021		/* Create a new factor node going to a negated OR expression. */
1022		$$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
1023	};
1024factor:
1025	RE_Slash regular_expr RE_Slash final {
1026		if ( $3->length > 1 ) {
1027			for ( char *p = $3->data; *p != 0; p++ ) {
1028				if ( *p == 'i' )
1029					$2->regExpr->caseInsensitive = true;
1030			}
1031		}
1032
1033		/* Create a new factor node going to a regular exp. */
1034		$$->factor = new Factor( $2->regExpr );
1035	};
1036factor:
1037	range_lit TK_DotDot range_lit final {
1038		/* Create a new factor node going to a range. */
1039		$$->factor = new Factor( new Range( $1->literal, $3->literal ) );
1040	};
1041factor:
1042	'(' join ')' final {
1043		/* Create a new factor going to a parenthesized join. */
1044		$$->factor = new Factor( $2->join );
1045		$2->join->loc = $1->loc;
1046	};
1047
1048nonterm range_lit
1049{
1050	Literal *literal;
1051};
1052
1053# Literals which can be the end points of ranges.
1054range_lit:
1055	TK_Literal final {
1056		/* Range literas must have only one char. We restrict this in the parse tree. */
1057		$$->literal = new Literal( *$1, Literal::LitString );
1058	};
1059range_lit:
1060	alphabet_num final {
1061		/* Create a new literal number. */
1062		$$->literal = new Literal( $1->token, Literal::Number );
1063	};
1064
1065nonterm alphabet_num uses token_type;
1066
1067# Any form of a number that can be used as a basic machine. */
1068alphabet_num:
1069	TK_UInt final {
1070		$$->token = *$1;
1071	};
1072alphabet_num:
1073	'-' TK_UInt final {
1074		$$->token.set( "-", 1 );
1075		$$->token.loc = $1->loc;
1076		$$->token.append( *$2 );
1077	};
1078alphabet_num:
1079	TK_Hex final {
1080		$$->token = *$1;
1081	};
1082#
1083# Regular Expressions.
1084#
1085
1086nonterm regular_expr
1087{
1088	RegExpr *regExpr;
1089};
1090
1091# Parser for regular expression fsms. Any number of expression items which
1092# generally gives a machine one character long or one character long stared.
1093regular_expr:
1094	regular_expr regular_expr_item final {
1095		/* An optimization to lessen the tree size. If a non-starred char is
1096		 * directly under the left side on the right and the right side is
1097		 * another non-starred char then paste them together and return the
1098		 * left side. Otherwise just put the two under a new reg exp node. */
1099		if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
1100			$1->regExpr->type == RegExpr::RecurseItem &&
1101			$1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1102		{
1103			/* Append the right side to the right side of the left and toss the
1104			 * right side. */
1105			$1->regExpr->item->token.append( $2->reItem->token );
1106			delete $2->reItem;
1107			$$->regExpr = $1->regExpr;
1108		}
1109		else {
1110			$$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1111		}
1112	};
1113regular_expr:
1114	final {
1115		/* Can't optimize the tree. */
1116		$$->regExpr = new RegExpr();
1117	};
1118
1119nonterm regular_expr_item
1120{
1121	ReItem *reItem;
1122};
1123
1124# RegularExprItems can be a character spec with an optional staring of the char.
1125regular_expr_item:
1126	regular_expr_char RE_Star final {
1127		$1->reItem->star = true;
1128		$$->reItem = $1->reItem;
1129	};
1130regular_expr_item:
1131	regular_expr_char final {
1132		$$->reItem = $1->reItem;
1133	};
1134
1135nonterm regular_expr_char
1136{
1137	ReItem *reItem;
1138};
1139
1140# A character spec can be a set of characters inside of square parenthesis, a
1141# dot specifying any character or some explicitly stated character.
1142regular_expr_char:
1143	RE_SqOpen regular_expr_or_data RE_SqClose final {
1144		$$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1145	};
1146regular_expr_char:
1147	RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1148		$$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1149	};
1150regular_expr_char:
1151	RE_Dot final {
1152		$$->reItem = new ReItem( $1->loc, ReItem::Dot );
1153	};
1154regular_expr_char:
1155	RE_Char final {
1156		$$->reItem = new ReItem( $1->loc, *$1 );
1157	};
1158
1159# The data inside of a [] expression in a regular expression. Accepts any
1160# number of characters or ranges. */
1161nonterm regular_expr_or_data
1162{
1163	ReOrBlock *reOrBlock;
1164};
1165
1166regular_expr_or_data:
1167	regular_expr_or_data regular_expr_or_char final {
1168		/* An optimization to lessen the tree size. If an or char is directly
1169		 * under the left side on the right and the right side is another or
1170		 * char then paste them together and return the left side. Otherwise
1171		 * just put the two under a new or data node. */
1172		if ( $2->reOrItem->type == ReOrItem::Data &&
1173				$1->reOrBlock->type == ReOrBlock::RecurseItem &&
1174				$1->reOrBlock->item->type == ReOrItem::Data )
1175		{
1176			/* Append the right side to right side of the left and toss the
1177			 * right side. */
1178			$1->reOrBlock->item->token.append( $2->reOrItem->token );
1179			delete $2->reOrItem;
1180			$$->reOrBlock = $1->reOrBlock;
1181		}
1182		else {
1183			/* Can't optimize, put the left and right under a new node. */
1184			$$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1185		}
1186	};
1187regular_expr_or_data:
1188	final {
1189		$$->reOrBlock = new ReOrBlock();
1190	};
1191
1192# A single character inside of an or expression. Can either be a character or a
1193# set of characters.
1194nonterm regular_expr_or_char
1195{
1196	ReOrItem *reOrItem;
1197};
1198
1199regular_expr_or_char:
1200	RE_Char final {
1201		$$->reOrItem = new ReOrItem( $1->loc, *$1 );
1202	};
1203regular_expr_or_char:
1204	RE_Char RE_Dash RE_Char final {
1205		$$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1206	};
1207
1208#
1209# Inline Lists for inline host code.
1210#
1211
1212type inline_list
1213{
1214	InlineList *inlineList;
1215};
1216
1217nonterm inline_block uses inline_list;
1218
1219inline_block:
1220	inline_block inline_block_item
1221	final {
1222		/* Append the item to the list, return the list. */
1223		$$->inlineList = $1->inlineList;
1224		$$->inlineList->append( $2->inlineItem );
1225	};
1226
1227inline_block:
1228	final {
1229		/* Start with empty list. */
1230		$$->inlineList = new InlineList;
1231	};
1232
1233type inline_item
1234{
1235	InlineItem *inlineItem;
1236};
1237
1238nonterm inline_block_item uses inline_item;
1239nonterm inline_block_interpret uses inline_item;
1240
1241inline_block_item:
1242	inline_expr_any
1243	final {
1244		$$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1245	};
1246
1247inline_block_item:
1248	inline_block_symbol
1249	final {
1250		$$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1251	};
1252
1253inline_block_item:
1254	inline_block_interpret
1255	final {
1256		/* Pass the inline item up. */
1257		$$->inlineItem = $1->inlineItem;
1258	};
1259
1260nonterm inline_block_symbol uses token_type;
1261
1262inline_block_symbol: ',' final { $$->token = *$1; };
1263inline_block_symbol: ';' final { $$->token = *$1; };
1264inline_block_symbol: '(' final { $$->token = *$1; };
1265inline_block_symbol: ')' final { $$->token = *$1; };
1266inline_block_symbol: '*' final { $$->token = *$1; };
1267inline_block_symbol: TK_NameSep final { $$->token = *$1; };
1268
1269# Interpreted statements in a struct block. */
1270inline_block_interpret:
1271	inline_expr_interpret final {
1272		/* Pass up interpreted items of inline expressions. */
1273		$$->inlineItem = $1->inlineItem;
1274	};
1275inline_block_interpret:
1276	KW_Hold ';' final {
1277		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1278	};
1279inline_block_interpret:
1280	KW_Exec inline_expr ';' final {
1281		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1282		$$->inlineItem->children = $2->inlineList;
1283	};
1284inline_block_interpret:
1285	KW_Goto state_ref ';' final {
1286		$$->inlineItem = new InlineItem( $1->loc,
1287				new NameRef(nameRef), InlineItem::Goto );
1288	};
1289inline_block_interpret:
1290	KW_Goto '*' inline_expr ';' final {
1291		$$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1292		$$->inlineItem->children = $3->inlineList;
1293	};
1294inline_block_interpret:
1295	KW_Next state_ref ';' final {
1296		$$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1297	};
1298inline_block_interpret:
1299	KW_Next '*' inline_expr ';' final {
1300		$$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1301		$$->inlineItem->children = $3->inlineList;
1302	};
1303inline_block_interpret:
1304	KW_Call state_ref ';' final {
1305		$$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1306	};
1307inline_block_interpret:
1308	KW_Call '*' inline_expr ';' final {
1309		$$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1310		$$->inlineItem->children = $3->inlineList;
1311	};
1312inline_block_interpret:
1313	KW_Ret ';' final {
1314		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1315	};
1316inline_block_interpret:
1317	KW_Break ';' final {
1318		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1319	};
1320
1321nonterm inline_expr uses inline_list;
1322
1323inline_expr:
1324	inline_expr inline_expr_item
1325	final {
1326		$$->inlineList = $1->inlineList;
1327		$$->inlineList->append( $2->inlineItem );
1328	};
1329inline_expr:
1330	final {
1331		/* Init the list used for this expr. */
1332		$$->inlineList = new InlineList;
1333	};
1334
1335nonterm inline_expr_item uses inline_item;
1336
1337inline_expr_item:
1338	inline_expr_any
1339	final {
1340		/* Return a text segment. */
1341		$$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1342	};
1343inline_expr_item:
1344	inline_expr_symbol
1345	final {
1346		/* Return a text segment, must heap alloc the text. */
1347		$$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1348	};
1349inline_expr_item:
1350	inline_expr_interpret
1351	final{
1352		/* Pass the inline item up. */
1353		$$->inlineItem = $1->inlineItem;
1354	};
1355
1356nonterm inline_expr_any uses token_type;
1357
1358inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1359inline_expr_any: IL_Comment try { $$->token = *$1; };
1360inline_expr_any: IL_Literal try { $$->token = *$1; };
1361inline_expr_any: IL_Symbol try { $$->token = *$1; };
1362inline_expr_any: TK_UInt try { $$->token = *$1; };
1363inline_expr_any: TK_Hex try { $$->token = *$1; };
1364inline_expr_any: TK_Word try { $$->token = *$1; };
1365
1366# Anything in a ExecValExpr that is not dynamically allocated. This includes
1367# all special symbols caught in inline code except the semi.
1368
1369nonterm inline_expr_symbol uses token_type;
1370
1371inline_expr_symbol: ',' try { $$->token = *$1; };
1372inline_expr_symbol: '(' try { $$->token = *$1; };
1373inline_expr_symbol: ')' try { $$->token = *$1; };
1374inline_expr_symbol: '*' try { $$->token = *$1; };
1375inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
1376
1377nonterm inline_expr_interpret uses inline_item;
1378
1379inline_expr_interpret:
1380	KW_PChar
1381	final {
1382		$$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1383	};
1384inline_expr_interpret:
1385	KW_Char
1386	final {
1387		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1388	};
1389inline_expr_interpret:
1390	KW_CurState
1391	final {
1392		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1393	};
1394inline_expr_interpret:
1395	KW_TargState
1396	final {
1397		$$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1398	};
1399inline_expr_interpret:
1400	KW_Entry '(' state_ref ')'
1401	final {
1402		$$->inlineItem = new InlineItem( $1->loc,
1403			new NameRef(nameRef), InlineItem::Entry );
1404	};
1405
1406#  A local state reference. Cannot have :: prefix.
1407local_state_ref:
1408	no_name_sep state_ref_names;
1409
1410# Clear the name ref structure.
1411no_name_sep:
1412	final {
1413		nameRef.empty();
1414	};
1415
1416# A qualified state reference.
1417state_ref: opt_name_sep state_ref_names;
1418
1419# Optional leading name separator.
1420opt_name_sep:
1421	TK_NameSep
1422	final {
1423		/* Insert an initial null pointer val to indicate the existence of the
1424		 * initial name seperator. */
1425		nameRef.setAs( 0 );
1426	};
1427opt_name_sep:
1428	final {
1429		nameRef.empty();
1430	};
1431
1432# List of names separated by ::
1433state_ref_names:
1434	state_ref_names TK_NameSep TK_Word
1435	final {
1436		nameRef.append( $3->data );
1437	};
1438state_ref_names:
1439	TK_Word
1440	final {
1441		nameRef.append( $1->data );
1442	};
1443
1444}%%
1445
1446%%{
1447	write types;
1448	write data;
1449}%%
1450
1451void Parser::init()
1452{
1453	%% write init;
1454}
1455
1456int Parser::parseLangEl( int type, const Token *token )
1457{
1458	%% write exec;
1459	return errCount == 0 ? 0 : -1;
1460}
1461
1462void Parser::tryMachineDef( InputLoc &loc, char *name,
1463		MachineDef *machineDef, bool isInstance )
1464{
1465	GraphDictEl *newEl = pd->graphDict.insert( name );
1466	if ( newEl != 0 ) {
1467		/* New element in the dict, all good. */
1468		newEl->value = new VarDef( name, machineDef );
1469		newEl->isInstance = isInstance;
1470		newEl->loc = loc;
1471		newEl->value->isExport = exportContext[exportContext.length()-1];
1472
1473		/* It it is an instance, put on the instance list. */
1474		if ( isInstance )
1475			pd->instanceList.append( newEl );
1476	}
1477	else {
1478		// Recover by ignoring the duplicate.
1479		error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1480	}
1481}
1482
1483ostream &Parser::parse_error( int tokId, Token &token )
1484{
1485	/* Maintain the error count. */
1486	gblErrorCount += 1;
1487
1488	cerr << token.loc << ": ";
1489	cerr << "at token ";
1490	if ( tokId < 128 )
1491		cerr << "\"" << Parser_lelNames[tokId] << "\"";
1492	else
1493		cerr << Parser_lelNames[tokId];
1494	if ( token.data != 0 )
1495		cerr << " with data \"" << token.data << "\"";
1496	cerr << ": ";
1497
1498	return cerr;
1499}
1500
1501int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1502{
1503	Token token;
1504	token.data = tokstart;
1505	token.length = toklen;
1506	token.loc = loc;
1507	int res = parseLangEl( tokId, &token );
1508	if ( res < 0 ) {
1509		parse_error(tokId, token) << "parse error" << endl;
1510		exit(1);
1511	}
1512	return res;
1513}
1514