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