2 * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Ragel.
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.
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.
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
32 ParserDict parserDict;
42 section_list: section_list statement_list TK_EndSection;
45 statement_list: statement_list statement;
48 statement: assignment commit;
49 statement: instantiation commit;
50 statement: action_spec commit;
51 statement: alphtype_spec commit;
52 statement: range_spec commit;
53 statement: getkey_spec commit;
54 statement: access_spec commit;
55 statement: variable_spec commit;
56 statement: export_block commit;
58 export_open: KW_Export
60 exportContext.append( true );
68 opt_export: export_open final { $$->isSet = true; };
69 opt_export: final { $$->isSet = false; };
71 export_block: export_open '{' statement_list '}'
73 exportContext.remove( exportContext.length()-1 );
77 opt_export machine_name '=' join ';' final {
78 /* Main machine must be an instance. */
79 bool isInstance = false;
80 if ( strcmp($2->token.data, mainMachine) == 0 ) {
81 warning($2->token.loc) <<
82 "main machine will be implicitly instantiated" << endl;
86 /* Generic creation of machine for instantiation and assignment. */
87 JoinOrLm *joinOrLm = new JoinOrLm( $4->join );
88 tryMachineDef( $2->token.loc, $2->token.data, joinOrLm, isInstance );
91 exportContext.remove( exportContext.length()-1 );
95 opt_export machine_name TK_ColonEquals join_or_lm ';' final {
96 /* Generic creation of machine for instantiation and assignment. */
97 tryMachineDef( $2->token.loc, $2->token.data, $4->joinOrLm, true );
100 exportContext.remove( exportContext.length()-1 );
108 nonterm machine_name uses token_type;
112 /* Make/get the priority key. The name may have already been referenced
113 * and therefore exist. */
114 PriorDictEl *priorDictEl;
115 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
116 pd->nextPriorKey += 1;
117 pd->curDefPriorKey = priorDictEl->value;
119 /* Make/get the local error key. */
120 LocalErrDictEl *localErrDictEl;
121 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
122 pd->nextLocalErrKey += 1;
123 pd->curDefLocalErrKey = localErrDictEl->value;
129 KW_Action TK_Word '{' inline_block '}' final {
130 if ( pd->actionDict.find( $2->data ) ) {
131 /* Recover by just ignoring the duplicate. */
132 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
135 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
136 /* Add the action to the list of actions. */
137 Action *newAction = new Action( $3->loc, $2->data,
138 $4->inlineList, pd->nextCondId++ );
140 /* Insert to list and dict. */
141 pd->actionList.append( newAction );
142 pd->actionDict.insert( newAction );
146 # Specifies the data type of the input alphabet. One or two words followed by a
149 KW_AlphType TK_Word TK_Word ';' final {
150 if ( ! pd->setAlphType( $2->data, $3->data ) ) {
151 // Recover by ignoring the alphtype statement.
152 error($2->loc) << "\"" << $2->data <<
153 " " << $3->data << "\" is not a valid alphabet type" << endl;
158 KW_AlphType TK_Word ';' final {
159 if ( ! pd->setAlphType( $2->data ) ) {
160 // Recover by ignoring the alphtype statement.
161 error($2->loc) << "\"" << $2->data <<
162 "\" is not a valid alphabet type" << endl;
166 # Specifies a range to assume that the input characters will fall into.
168 KW_Range alphabet_num alphabet_num ';' final {
169 // Save the upper and lower ends of the range and emit the line number.
170 pd->lowerNum = $2->token.data;
171 pd->upperNum = $3->token.data;
172 pd->rangeLowLoc = $2->token.loc;
173 pd->rangeHighLoc = $3->token.loc;
177 KW_GetKey inline_expr ';' final {
178 pd->getKeyExpr = $2->inlineList;
182 KW_Access inline_expr ';' final {
183 pd->accessExpr = $2->inlineList;
187 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
188 /* FIXME: Need to implement the rest of this. */
189 if ( strcmp( $3->data, "curstate" ) == 0 )
190 pd->curStateExpr = $4->inlineList;
192 error($3->loc) << "sorry, unimplementd" << endl;
196 opt_whitespace: opt_whitespace IL_WhiteSpace;
210 $$->joinOrLm = new JoinOrLm( $1->join );
213 TK_BarStar lm_part_list '*' '|' final {
214 /* Create a new factor going to a longest match structure. Record
215 * in the parse data that we have a longest match. */
216 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
217 pd->lmList.append( lm );
218 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
219 lmp->longestMatch = lm;
220 $$->joinOrLm = new JoinOrLm( lm );
225 LmPartList *lmPartList;
229 lm_part_list longest_match_part final {
230 if ( $2->lmPart != 0 )
231 $1->lmPartList->append( $2->lmPart );
232 $$->lmPartList = $1->lmPartList;
235 longest_match_part final {
236 /* Create a new list with the part. */
237 $$->lmPartList = new LmPartList;
238 if ( $1->lmPart != 0 )
239 $$->lmPartList->append( $1->lmPart );
242 nonterm longest_match_part
244 LongestMatchPart *lmPart;
248 action_spec final { $$->lmPart = 0; };
250 assignment final { $$->lmPart = 0; };
252 join opt_lm_part_action ';' final {
254 Action *action = $2->action;
256 action->isLmAction = true;
257 $$->lmPart = new LongestMatchPart( $1->join, action,
258 $3->loc, pd->nextLongestMatchId++ );
261 nonterm opt_lm_part_action
267 TK_DoubleArrow action_embed final {
268 $$->action = $2->action;
271 action_embed_block final {
272 $$->action = $1->action;
286 join ',' expression final {
287 /* Append the expression to the list and return it. */
288 $1->join->exprList.append( $3->expression );
293 $$->join = new Join( $1->expression );
298 Expression *expression;
302 expression '|' term final {
303 $$->expression = new Expression( $1->expression,
304 $3->term, Expression::OrType );
307 expression '&' term final {
308 $$->expression = new Expression( $1->expression,
309 $3->term, Expression::IntersectType );
311 # This priority specification overrides the innermost parsing strategy which
312 # results ordered choice interpretation of the grammar.
314 expression pri(1) '-' term final {
315 $$->expression = new Expression( $1->expression,
316 $3->term, Expression::SubtractType );
319 expression TK_DashDash term final {
320 $$->expression = new Expression( $1->expression,
321 $3->term, Expression::StrongSubtractType );
325 $$->expression = new Expression( $1->term );
334 term factor_with_label final {
335 $$->term = new Term( $1->term, $2->factorWithAug );
338 term '.' factor_with_label final {
339 $$->term = new Term( $1->term, $3->factorWithAug );
342 term TK_ColonGt factor_with_label final {
343 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
346 term TK_ColonGtGt factor_with_label final {
347 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
350 term TK_LtColon factor_with_label final {
351 $$->term = new Term( $1->term,
352 $3->factorWithAug, Term::LeftType );
355 factor_with_label final {
356 $$->term = new Term( $1->factorWithAug );
359 nonterm factor_with_label
361 FactorWithAug *factorWithAug;
365 TK_Word ':' factor_with_label final {
366 /* Add the label to the list and pass the factor up. */
367 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
368 $$->factorWithAug = $3->factorWithAug;
371 factor_with_ep final {
372 $$->factorWithAug = $1->factorWithAug;
375 nonterm factor_with_ep
377 FactorWithAug *factorWithAug;
381 factor_with_ep TK_Arrow local_state_ref final {
382 /* Add the target to the list and return the factor object. */
383 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
384 $$->factorWithAug = $1->factorWithAug;
387 factor_with_aug final {
388 $$->factorWithAug = $1->factorWithAug;
391 nonterm factor_with_aug
393 FactorWithAug *factorWithAug;
397 factor_with_aug aug_type_base action_embed final {
398 /* Append the action to the factorWithAug, record the refernce from
399 * factorWithAug to the action and pass up the factorWithAug. */
400 $1->factorWithAug->actions.append(
401 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
402 $$->factorWithAug = $1->factorWithAug;
405 factor_with_aug aug_type_base priority_aug final {
406 /* Append the named priority to the factorWithAug and pass it up. */
407 $1->factorWithAug->priorityAugs.append(
408 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
409 $$->factorWithAug = $1->factorWithAug;
412 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
413 /* Append the priority using a default name. */
414 $1->factorWithAug->priorityAugs.append(
415 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
416 $$->factorWithAug = $1->factorWithAug;
419 factor_with_aug aug_type_cond action_embed final {
420 $1->factorWithAug->conditions.append( ParserAction( $2->loc,
421 $2->augType, 0, $3->action ) );
422 $$->factorWithAug = $1->factorWithAug;
425 factor_with_aug aug_type_to_state action_embed final {
426 /* Append the action, pass it up. */
427 $1->factorWithAug->actions.append( ParserAction( $2->loc,
428 $2->augType, 0, $3->action ) );
429 $$->factorWithAug = $1->factorWithAug;
432 factor_with_aug aug_type_from_state action_embed final {
433 /* Append the action, pass it up. */
434 $1->factorWithAug->actions.append( ParserAction( $2->loc,
435 $2->augType, 0, $3->action ) );
436 $$->factorWithAug = $1->factorWithAug;
439 factor_with_aug aug_type_eof action_embed final {
440 /* Append the action, pass it up. */
441 $1->factorWithAug->actions.append( ParserAction( $2->loc,
442 $2->augType, 0, $3->action ) );
443 $$->factorWithAug = $1->factorWithAug;
446 factor_with_aug aug_type_gbl_error action_embed final {
447 /* Append the action to the factorWithAug, record the refernce from
448 * factorWithAug to the action and pass up the factorWithAug. */
449 $1->factorWithAug->actions.append( ParserAction( $2->loc,
450 $2->augType, pd->curDefLocalErrKey, $3->action ) );
451 $$->factorWithAug = $1->factorWithAug;
454 factor_with_aug aug_type_local_error 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( ParserAction( $2->loc,
458 $2->augType, pd->curDefLocalErrKey, $3->action ) );
459 $$->factorWithAug = $1->factorWithAug;
462 factor_with_aug aug_type_local_error '(' local_err_name ',' 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( ParserAction( $2->loc,
466 $2->augType, $4->error_name, $6->action ) );
467 $$->factorWithAug = $1->factorWithAug;
470 factor_with_rep final {
471 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
480 # Classes of transtions on which to embed actions or change priorities.
481 nonterm aug_type_base uses aug_type;
483 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
484 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
485 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
486 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
488 # Embedding conditions.
489 nonterm aug_type_cond uses aug_type;
491 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
492 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
493 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
494 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
495 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
496 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
497 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
503 nonterm aug_type_to_state uses aug_type;
505 aug_type_to_state: TK_StartToState
506 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
507 aug_type_to_state: '>' KW_To
508 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
510 aug_type_to_state: TK_NotStartToState
511 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
512 aug_type_to_state: '<' KW_To
513 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
515 aug_type_to_state: TK_AllToState
516 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
517 aug_type_to_state: '$' KW_To
518 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
520 aug_type_to_state: TK_FinalToState
521 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
522 aug_type_to_state: '%' KW_To
523 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
525 aug_type_to_state: TK_NotFinalToState
526 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
527 aug_type_to_state: '@' KW_To
528 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
530 aug_type_to_state: TK_MiddleToState
531 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
532 aug_type_to_state: TK_Middle KW_To
533 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
536 # From state actions.
539 nonterm aug_type_from_state uses aug_type;
541 aug_type_from_state: TK_StartFromState
542 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
543 aug_type_from_state: '>' KW_From
544 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
546 aug_type_from_state: TK_NotStartFromState
547 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
548 aug_type_from_state: '<' KW_From
549 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
551 aug_type_from_state: TK_AllFromState
552 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
553 aug_type_from_state: '$' KW_From
554 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
556 aug_type_from_state: TK_FinalFromState
557 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
558 aug_type_from_state: '%' KW_From
559 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
561 aug_type_from_state: TK_NotFinalFromState
562 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
563 aug_type_from_state: '@' KW_From
564 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
566 aug_type_from_state: TK_MiddleFromState
567 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
568 aug_type_from_state: TK_Middle KW_From
569 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
575 nonterm aug_type_eof uses aug_type;
577 aug_type_eof: TK_StartEOF
578 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
579 aug_type_eof: '>' KW_Eof
580 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
582 aug_type_eof: TK_NotStartEOF
583 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
584 aug_type_eof: '<' KW_Eof
585 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
587 aug_type_eof: TK_AllEOF
588 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
589 aug_type_eof: '$' KW_Eof
590 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
592 aug_type_eof: TK_FinalEOF
593 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
594 aug_type_eof: '%' KW_Eof
595 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
597 aug_type_eof: TK_NotFinalEOF
598 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
599 aug_type_eof: '@' KW_Eof
600 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
602 aug_type_eof: TK_MiddleEOF
603 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
604 aug_type_eof: TK_Middle KW_Eof
605 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
608 # Global error actions.
611 nonterm aug_type_gbl_error uses aug_type;
613 aug_type_gbl_error: TK_StartGblError
614 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
615 aug_type_gbl_error: '>' KW_Err
616 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
618 aug_type_gbl_error: TK_NotStartGblError
619 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
620 aug_type_gbl_error: '<' KW_Err
621 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
623 aug_type_gbl_error: TK_AllGblError
624 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
625 aug_type_gbl_error: '$' KW_Err
626 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
628 aug_type_gbl_error: TK_FinalGblError
629 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
630 aug_type_gbl_error: '%' KW_Err
631 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
633 aug_type_gbl_error: TK_NotFinalGblError
634 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
635 aug_type_gbl_error: '@' KW_Err
636 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
638 aug_type_gbl_error: TK_MiddleGblError
639 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
640 aug_type_gbl_error: TK_Middle KW_Err
641 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
645 # Local error actions.
648 nonterm aug_type_local_error uses aug_type;
650 aug_type_local_error: TK_StartLocalError
651 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
652 aug_type_local_error: '>' KW_Lerr
653 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
655 aug_type_local_error: TK_NotStartLocalError
656 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
657 aug_type_local_error: '<' KW_Lerr
658 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
660 aug_type_local_error: TK_AllLocalError
661 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
662 aug_type_local_error: '$' KW_Lerr
663 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
665 aug_type_local_error: TK_FinalLocalError
666 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
667 aug_type_local_error: '%' KW_Lerr
668 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
670 aug_type_local_error: TK_NotFinalLocalError
671 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
672 aug_type_local_error: '@' KW_Lerr
673 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
675 aug_type_local_error: TK_MiddleLocalError
676 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
677 aug_type_local_error: TK_Middle KW_Lerr
678 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
686 # Different ways to embed actions. A TK_Word is reference to an action given by
687 # the user as a statement in the fsm specification. An action can also be
688 # specified immediately.
689 nonterm action_embed uses action_ref;
691 action_embed: action_embed_word final { $$->action = $1->action; };
692 action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
693 action_embed: action_embed_block final { $$->action = $1->action; };
695 nonterm action_embed_word uses action_ref;
699 /* Set the name in the actionDict. */
700 Action *action = pd->actionDict.find( $1->data );
702 /* Pass up the action element */
706 /* Will recover by returning null as the action. */
707 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
712 nonterm action_embed_block uses action_ref;
715 '{' inline_block '}' final {
716 /* Create the action, add it to the list and pass up. */
717 Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
718 pd->actionList.append( newAction );
719 $$->action = newAction;
722 nonterm priority_name
727 # A specified priority name. Looks up the name in the current priority
731 // Lookup/create the priority key.
732 PriorDictEl *priorDictEl;
733 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
734 pd->nextPriorKey += 1;
736 // Use the inserted/found priority key.
737 $$->priorityName = priorDictEl->value;
745 # Priority change specs.
747 priority_aug_num final {
748 // Convert the priority number to a long. Check for overflow.
750 //cerr << "PRIOR AUG: " << $1->token.data << endl;
751 int aug = strtol( $1->token.data, 0, 10 );
752 if ( errno == ERANGE && aug == LONG_MAX ) {
753 /* Priority number too large. Recover by setting the priority to 0. */
754 error($1->token.loc) << "priority number " << $1->token.data <<
755 " overflows" << endl;
758 else if ( errno == ERANGE && aug == LONG_MIN ) {
759 /* Priority number too large in the neg. Recover by using 0. */
760 error($1->token.loc) << "priority number " << $1->token.data <<
761 " underflows" << endl;
765 /* No overflow or underflow. */
766 $$->priorityNum = aug;
770 nonterm priority_aug_num uses token_type;
778 $$->token.set( "+", 1 );
779 $$->token.loc = $1->loc;
780 $$->token.append( *$2 );
784 $$->token.set( "-", 1 );
785 $$->token.loc = $1->loc;
786 $$->token.append( *$2 );
789 nonterm local_err_name
796 /* Lookup/create the priority key. */
797 LocalErrDictEl *localErrDictEl;
798 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
799 pd->nextLocalErrKey += 1;
801 /* Use the inserted/found priority key. */
802 $$->error_name = localErrDictEl->value;
807 # The fourth level of precedence. These are the trailing unary operators that
808 # allow for repetition.
810 nonterm factor_with_rep
812 FactorWithRep *factorWithRep;
816 factor_with_rep '*' final {
817 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
818 0, 0, FactorWithRep::StarType );
821 factor_with_rep TK_StarStar final {
822 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
823 0, 0, FactorWithRep::StarStarType );
826 factor_with_rep '?' final {
827 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
828 0, 0, FactorWithRep::OptionalType );
831 factor_with_rep '+' final {
832 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
833 0, 0, FactorWithRep::PlusType );
836 factor_with_rep '{' factor_rep_num '}' final {
837 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
838 $3->rep, 0, FactorWithRep::ExactType );
841 factor_with_rep '{' ',' factor_rep_num '}' final {
842 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
843 0, $4->rep, FactorWithRep::MaxType );
846 factor_with_rep '{' factor_rep_num ',' '}' final {
847 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
848 $3->rep, 0, FactorWithRep::MinType );
851 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
852 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
853 $3->rep, $5->rep, FactorWithRep::RangeType );
856 factor_with_neg final {
857 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
860 nonterm factor_rep_num
867 // Convert the priority number to a long. Check for overflow.
869 int rep = strtol( $1->data, 0, 10 );
870 if ( errno == ERANGE && rep == LONG_MAX ) {
871 // Repetition too large. Recover by returing repetition 1. */
872 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
876 // Cannot be negative, so no overflow.
883 # The fifth level up in precedence. Negation.
886 nonterm factor_with_neg
888 FactorWithNeg *factorWithNeg;
892 '!' factor_with_neg final {
893 $$->factorWithNeg = new FactorWithNeg( $1->loc,
894 $2->factorWithNeg, FactorWithNeg::NegateType );
897 '^' factor_with_neg final {
898 $$->factorWithNeg = new FactorWithNeg( $1->loc,
899 $2->factorWithNeg, FactorWithNeg::CharNegateType );
903 $$->factorWithNeg = new FactorWithNeg( $1->factor );
913 /* Create a new factor node going to a concat literal. */
914 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
918 /* Create a new factor node going to a literal number. */
919 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
923 /* Find the named graph. */
924 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
926 /* Recover by returning null as the factor node. */
927 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
930 else if ( gdNode->isInstance ) {
931 /* Recover by retuning null as the factor node. */
932 error($1->loc) << "references to graph instantiations not allowed "
933 "in expressions" << endl;
937 /* Create a factor node that is a lookup of an expression. */
938 $$->factor = new Factor( $1->loc, gdNode->value );
942 RE_SqOpen regular_expr_or_data RE_SqClose final {
943 /* Create a new factor node going to an OR expression. */
944 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
947 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
948 /* Create a new factor node going to a negated OR expression. */
949 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
952 RE_Slash regular_expr RE_Slash final {
953 if ( $3->length > 1 ) {
954 for ( char *p = $3->data; *p != 0; p++ ) {
956 $2->regExpr->caseInsensitive = true;
960 /* Create a new factor node going to a regular exp. */
961 $$->factor = new Factor( $2->regExpr );
964 range_lit TK_DotDot range_lit final {
965 /* Create a new factor node going to a range. */
966 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
970 /* Create a new factor going to a parenthesized join. */
971 $$->factor = new Factor( $2->join );
979 # Literals which can be the end points of ranges.
982 /* Range literas must have only one char. We restrict this in the parse tree. */
983 $$->literal = new Literal( *$1, Literal::LitString );
987 /* Create a new literal number. */
988 $$->literal = new Literal( $1->token, Literal::Number );
991 nonterm alphabet_num uses token_type;
993 # Any form of a number that can be used as a basic machine. */
1000 $$->token.set( "-", 1 );
1001 $$->token.loc = $1->loc;
1002 $$->token.append( *$2 );
1009 # Regular Expressions.
1012 nonterm regular_expr
1017 # Parser for regular expression fsms. Any number of expression items which
1018 # generally gives a machine one character long or one character long stared.
1020 regular_expr regular_expr_item final {
1021 /* An optimization to lessen the tree size. If a non-starred char is
1022 * directly under the left side on the right and the right side is
1023 * another non-starred char then paste them together and return the
1024 * left side. Otherwise just put the two under a new reg exp node. */
1025 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
1026 $1->regExpr->type == RegExpr::RecurseItem &&
1027 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1029 /* Append the right side to the right side of the left and toss the
1031 $1->regExpr->item->token.append( $2->reItem->token );
1033 $$->regExpr = $1->regExpr;
1036 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1041 /* Can't optimize the tree. */
1042 $$->regExpr = new RegExpr();
1045 nonterm regular_expr_item
1050 # RegularExprItems can be a character spec with an optional staring of the char.
1052 regular_expr_char RE_Star final {
1053 $1->reItem->star = true;
1054 $$->reItem = $1->reItem;
1057 regular_expr_char final {
1058 $$->reItem = $1->reItem;
1061 nonterm regular_expr_char
1066 # A character spec can be a set of characters inside of square parenthesis, a
1067 # dot specifying any character or some explicitly stated character.
1069 RE_SqOpen regular_expr_or_data RE_SqClose final {
1070 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1073 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1074 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1078 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1082 $$->reItem = new ReItem( $1->loc, *$1 );
1085 # The data inside of a [] expression in a regular expression. Accepts any
1086 # number of characters or ranges. */
1087 nonterm regular_expr_or_data
1089 ReOrBlock *reOrBlock;
1092 regular_expr_or_data:
1093 regular_expr_or_data regular_expr_or_char final {
1094 /* An optimization to lessen the tree size. If an or char is directly
1095 * under the left side on the right and the right side is another or
1096 * char then paste them together and return the left side. Otherwise
1097 * just put the two under a new or data node. */
1098 if ( $2->reOrItem->type == ReOrItem::Data &&
1099 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1100 $1->reOrBlock->item->type == ReOrItem::Data )
1102 /* Append the right side to right side of the left and toss the
1104 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1105 delete $2->reOrItem;
1106 $$->reOrBlock = $1->reOrBlock;
1109 /* Can't optimize, put the left and right under a new node. */
1110 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1113 regular_expr_or_data:
1115 $$->reOrBlock = new ReOrBlock();
1118 # A single character inside of an or expression. Can either be a character or a
1119 # set of characters.
1120 nonterm regular_expr_or_char
1125 regular_expr_or_char:
1127 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1129 regular_expr_or_char:
1130 RE_Char RE_Dash RE_Char final {
1131 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1135 # Inline Lists for inline host code.
1140 InlineList *inlineList;
1143 nonterm inline_block uses inline_list;
1146 inline_block inline_block_item
1148 /* Append the item to the list, return the list. */
1149 $$->inlineList = $1->inlineList;
1150 $$->inlineList->append( $2->inlineItem );
1155 /* Start with empty list. */
1156 $$->inlineList = new InlineList;
1161 InlineItem *inlineItem;
1164 nonterm inline_block_item uses inline_item;
1165 nonterm inline_block_interpret uses inline_item;
1170 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1176 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1180 inline_block_interpret
1182 /* Pass the inline item up. */
1183 $$->inlineItem = $1->inlineItem;
1186 nonterm inline_block_symbol uses token_type;
1188 inline_block_symbol: ',' final { $$->token = *$1; };
1189 inline_block_symbol: ';' final { $$->token = *$1; };
1190 inline_block_symbol: '(' final { $$->token = *$1; };
1191 inline_block_symbol: ')' final { $$->token = *$1; };
1192 inline_block_symbol: '*' final { $$->token = *$1; };
1193 inline_block_symbol: TK_NameSep final { $$->token = *$1; };
1195 # Interpreted statements in a struct block. */
1196 inline_block_interpret:
1197 inline_expr_interpret final {
1198 /* Pass up interpreted items of inline expressions. */
1199 $$->inlineItem = $1->inlineItem;
1201 inline_block_interpret:
1203 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1205 inline_block_interpret:
1206 KW_Exec inline_expr ';' final {
1207 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1208 $$->inlineItem->children = $2->inlineList;
1210 inline_block_interpret:
1211 KW_Goto state_ref ';' final {
1212 $$->inlineItem = new InlineItem( $1->loc,
1213 new NameRef(nameRef), InlineItem::Goto );
1215 inline_block_interpret:
1216 KW_Goto '*' inline_expr ';' final {
1217 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1218 $$->inlineItem->children = $3->inlineList;
1220 inline_block_interpret:
1221 KW_Next state_ref ';' final {
1222 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1224 inline_block_interpret:
1225 KW_Next '*' inline_expr ';' final {
1226 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1227 $$->inlineItem->children = $3->inlineList;
1229 inline_block_interpret:
1230 KW_Call state_ref ';' final {
1231 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1233 inline_block_interpret:
1234 KW_Call '*' inline_expr ';' final {
1235 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1236 $$->inlineItem->children = $3->inlineList;
1238 inline_block_interpret:
1240 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1242 inline_block_interpret:
1243 KW_Break ';' final {
1244 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1247 nonterm inline_expr uses inline_list;
1250 inline_expr inline_expr_item
1252 $$->inlineList = $1->inlineList;
1253 $$->inlineList->append( $2->inlineItem );
1257 /* Init the list used for this expr. */
1258 $$->inlineList = new InlineList;
1261 nonterm inline_expr_item uses inline_item;
1266 /* Return a text segment. */
1267 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1272 /* Return a text segment, must heap alloc the text. */
1273 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1276 inline_expr_interpret
1278 /* Pass the inline item up. */
1279 $$->inlineItem = $1->inlineItem;
1282 nonterm inline_expr_any uses token_type;
1284 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1285 inline_expr_any: IL_Comment try { $$->token = *$1; };
1286 inline_expr_any: IL_Literal try { $$->token = *$1; };
1287 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1288 inline_expr_any: TK_UInt try { $$->token = *$1; };
1289 inline_expr_any: TK_Hex try { $$->token = *$1; };
1290 inline_expr_any: TK_Word try { $$->token = *$1; };
1292 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1293 # all special symbols caught in inline code except the semi.
1295 nonterm inline_expr_symbol uses token_type;
1297 inline_expr_symbol: ',' try { $$->token = *$1; };
1298 inline_expr_symbol: '(' try { $$->token = *$1; };
1299 inline_expr_symbol: ')' try { $$->token = *$1; };
1300 inline_expr_symbol: '*' try { $$->token = *$1; };
1301 inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
1303 nonterm inline_expr_interpret uses inline_item;
1305 inline_expr_interpret:
1308 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1310 inline_expr_interpret:
1313 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1315 inline_expr_interpret:
1318 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1320 inline_expr_interpret:
1323 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1325 inline_expr_interpret:
1326 KW_Entry '(' state_ref ')'
1328 $$->inlineItem = new InlineItem( $1->loc,
1329 new NameRef(nameRef), InlineItem::Entry );
1332 # A local state reference. Cannot have :: prefix.
1334 no_name_sep state_ref_names;
1336 # Clear the name ref structure.
1342 # A qualified state reference.
1343 state_ref: opt_name_sep state_ref_names;
1345 # Optional leading name separator.
1349 /* Insert an initial null pointer val to indicate the existence of the
1350 * initial name seperator. */
1358 # List of names separated by ::
1360 state_ref_names TK_NameSep TK_Word
1362 nameRef.append( $3->data );
1367 nameRef.append( $1->data );
1382 int Parser::parseLangEl( int type, const Token *token )
1385 return errCount == 0 ? 0 : -1;
1388 void Parser::tryMachineDef( InputLoc &loc, char *name,
1389 JoinOrLm *joinOrLm, bool isInstance )
1391 GraphDictEl *newEl = pd->graphDict.insert( name );
1393 /* New element in the dict, all good. */
1394 newEl->value = new VarDef( name, joinOrLm );
1395 newEl->isInstance = isInstance;
1397 newEl->value->isExport = exportContext[exportContext.length()-1];
1399 /* It it is an instance, put on the instance list. */
1401 pd->instanceList.append( newEl );
1404 // Recover by ignoring the duplicate.
1405 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1409 ostream &Parser::parse_error( int tokId, Token &token )
1411 /* Maintain the error count. */
1414 cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
1415 cerr << "at token ";
1417 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1419 cerr << Parser_lelNames[tokId];
1420 if ( token.data != 0 )
1421 cerr << " with data \"" << token.data << "\"";
1427 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1430 token.data = tokstart;
1431 token.length = toklen;
1433 int res = parseLangEl( tokId, &token );
1435 parse_error(tokId, token) << "parse error" << endl;