2 * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
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;
33 InputItemList inputItems;
43 section_list: section_list statement_list TK_EndSection;
46 statement_list: statement_list statement;
49 statement: assignment commit;
50 statement: instantiation commit;
51 statement: action_spec commit;
52 statement: alphtype_spec commit;
53 statement: range_spec commit;
54 statement: getkey_spec commit;
55 statement: access_spec commit;
56 statement: variable_spec commit;
57 statement: export_block commit;
58 statement: pre_push_spec commit;
59 statement: post_pop_spec commit;
62 KW_PrePush '{' inline_block '}'
64 if ( pd->prePushExpr != 0 ) {
65 /* Recover by just ignoring the duplicate. */
66 error($2->loc) << "pre_push code already defined" << endl;
69 pd->prePushExpr = $3->inlineList;
74 KW_PostPop '{' inline_block '}'
76 if ( pd->postPopExpr != 0 ) {
77 /* Recover by just ignoring the duplicate. */
78 error($2->loc) << "post_pop code already defined" << endl;
81 pd->postPopExpr = $3->inlineList;
85 export_open: KW_Export
87 exportContext.append( true );
95 opt_export: export_open final { $$->isSet = true; };
96 opt_export: final { $$->isSet = false; };
98 export_block: export_open '{' statement_list '}'
100 exportContext.remove( exportContext.length()-1 );
104 opt_export machine_name '=' join ';' final {
105 /* Main machine must be an instance. */
106 bool isInstance = false;
107 if ( strcmp($2->token.data, mainMachine) == 0 ) {
108 warning($2->token.loc) <<
109 "main machine will be implicitly instantiated" << endl;
113 /* Generic creation of machine for instantiation and assignment. */
114 JoinOrLm *joinOrLm = new JoinOrLm( $4->join );
115 tryMachineDef( $2->token.loc, $2->token.data, joinOrLm, isInstance );
118 exportContext.remove( exportContext.length()-1 );
120 $4->join->loc = $3->loc;
124 opt_export machine_name TK_ColonEquals join_or_lm ';' final {
125 /* Generic creation of machine for instantiation and assignment. */
126 tryMachineDef( $2->token.loc, $2->token.data, $4->joinOrLm, true );
129 exportContext.remove( exportContext.length()-1 );
131 /* Pass a location to join_or_lm */
132 if ( $4->joinOrLm->join != 0 )
133 $4->joinOrLm->join->loc = $3->loc;
141 nonterm machine_name uses token_type;
145 /* Make/get the priority key. The name may have already been referenced
146 * and therefore exist. */
147 PriorDictEl *priorDictEl;
148 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
149 pd->nextPriorKey += 1;
150 pd->curDefPriorKey = priorDictEl->value;
152 /* Make/get the local error key. */
153 LocalErrDictEl *localErrDictEl;
154 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
155 pd->nextLocalErrKey += 1;
156 pd->curDefLocalErrKey = localErrDictEl->value;
162 KW_Action TK_Word '{' inline_block '}' final {
163 if ( pd->actionDict.find( $2->data ) ) {
164 /* Recover by just ignoring the duplicate. */
165 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
168 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
169 /* Add the action to the list of actions. */
170 Action *newAction = new Action( $3->loc, $2->data,
171 $4->inlineList, pd->nextCondId++ );
173 /* Insert to list and dict. */
174 pd->actionList.append( newAction );
175 pd->actionDict.insert( newAction );
179 # Specifies the data type of the input alphabet. One or two words followed by a
182 KW_AlphType TK_Word TK_Word ';' final {
183 if ( ! pd->setAlphType( $1->loc, $2->data, $3->data ) ) {
184 // Recover by ignoring the alphtype statement.
185 error($2->loc) << "\"" << $2->data <<
186 " " << $3->data << "\" is not a valid alphabet type" << endl;
191 KW_AlphType TK_Word ';' final {
192 if ( ! pd->setAlphType( $1->loc, $2->data ) ) {
193 // Recover by ignoring the alphtype statement.
194 error($2->loc) << "\"" << $2->data <<
195 "\" is not a valid alphabet type" << endl;
199 # Specifies a range to assume that the input characters will fall into.
201 KW_Range alphabet_num alphabet_num ';' final {
202 // Save the upper and lower ends of the range and emit the line number.
203 pd->lowerNum = $2->token.data;
204 pd->upperNum = $3->token.data;
205 pd->rangeLowLoc = $2->token.loc;
206 pd->rangeHighLoc = $3->token.loc;
210 KW_GetKey inline_expr ';' final {
211 pd->getKeyExpr = $2->inlineList;
215 KW_Access inline_expr ';' final {
216 pd->accessExpr = $2->inlineList;
220 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
221 /* FIXME: Need to implement the rest of this. */
222 bool wasSet = pd->setVariable( $3->data, $4->inlineList );
224 error($3->loc) << "bad variable name" << endl;
227 opt_whitespace: opt_whitespace IL_WhiteSpace;
241 $$->joinOrLm = new JoinOrLm( $1->join );
244 TK_BarStar lm_part_list '*' '|' final {
245 /* Create a new factor going to a longest match structure. Record
246 * in the parse data that we have a longest match. */
247 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
248 pd->lmList.append( lm );
249 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
250 lmp->longestMatch = lm;
251 $$->joinOrLm = new JoinOrLm( lm );
256 LmPartList *lmPartList;
260 lm_part_list longest_match_part
262 if ( $2->lmPart != 0 )
263 $1->lmPartList->append( $2->lmPart );
264 $$->lmPartList = $1->lmPartList;
269 /* Create a new list with the part. */
270 $$->lmPartList = new LmPartList;
271 if ( $1->lmPart != 0 )
272 $$->lmPartList->append( $1->lmPart );
275 nonterm longest_match_part
277 LongestMatchPart *lmPart;
281 action_spec final { $$->lmPart = 0; };
283 assignment final { $$->lmPart = 0; };
285 join opt_lm_part_action ';' final {
287 Action *action = $2->action;
289 action->isLmAction = true;
290 $$->lmPart = new LongestMatchPart( $1->join, action,
291 $3->loc, pd->nextLongestMatchId++ );
293 /* Provide a location to join. Unfortunately We don't
294 * have the start of the join as in other occurances. Use the end. */
295 $1->join->loc = $3->loc;
298 nonterm opt_lm_part_action
304 TK_DoubleArrow action_embed final {
305 $$->action = $2->action;
308 action_embed_block final {
309 $$->action = $1->action;
323 join ',' expression final {
324 /* Append the expression to the list and return it. */
325 $1->join->exprList.append( $3->expression );
330 $$->join = new Join( $1->expression );
335 Expression *expression;
339 expression '|' term_short final {
340 $$->expression = new Expression( $1->expression,
341 $3->term, Expression::OrType );
344 expression '&' term_short final {
345 $$->expression = new Expression( $1->expression,
346 $3->term, Expression::IntersectType );
349 expression '-' term_short final {
350 $$->expression = new Expression( $1->expression,
351 $3->term, Expression::SubtractType );
354 expression TK_DashDash term_short final {
355 $$->expression = new Expression( $1->expression,
356 $3->term, Expression::StrongSubtractType );
360 $$->expression = new Expression( $1->term );
363 # This is where we resolve the ambiguity involving -. By default ragel tries to
364 # do a longest match, which gives precedence to a concatenation because it is
365 # innermost. What we need is to force term into a shortest match so that when -
366 # is seen it doesn't try to extend term with a concatenation, but ends term and
367 # goes for a subtraction.
369 # The shortest tag overrides the default longest match action ordering strategy
370 # and instead forces a shortest match stragegy. The wrap the term production in
371 # a new nonterminal 'term_short' to guarantee the shortest match behaviour.
390 term factor_with_label final {
391 $$->term = new Term( $1->term, $2->factorWithAug );
394 term '.' factor_with_label final {
395 $$->term = new Term( $1->term, $3->factorWithAug );
398 term TK_ColonGt factor_with_label final {
399 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
402 term TK_ColonGtGt factor_with_label final {
403 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
406 term TK_LtColon factor_with_label final {
407 $$->term = new Term( $1->term,
408 $3->factorWithAug, Term::LeftType );
411 factor_with_label final {
412 $$->term = new Term( $1->factorWithAug );
415 nonterm factor_with_label
417 FactorWithAug *factorWithAug;
421 TK_Word ':' factor_with_label final {
422 /* Add the label to the list and pass the factor up. */
423 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
424 $$->factorWithAug = $3->factorWithAug;
427 factor_with_ep final {
428 $$->factorWithAug = $1->factorWithAug;
431 nonterm factor_with_ep
433 FactorWithAug *factorWithAug;
437 factor_with_ep TK_Arrow local_state_ref final {
438 /* Add the target to the list and return the factor object. */
439 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
440 $$->factorWithAug = $1->factorWithAug;
443 factor_with_aug final {
444 $$->factorWithAug = $1->factorWithAug;
447 nonterm factor_with_aug
449 FactorWithAug *factorWithAug;
453 factor_with_aug aug_type_base action_embed final {
454 /* Append the action to the factorWithAug, record the refernce from
455 * factorWithAug to the action and pass up the factorWithAug. */
456 $1->factorWithAug->actions.append(
457 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
458 $$->factorWithAug = $1->factorWithAug;
461 factor_with_aug aug_type_base priority_aug final {
462 /* Append the named priority to the factorWithAug and pass it up. */
463 $1->factorWithAug->priorityAugs.append(
464 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
465 $$->factorWithAug = $1->factorWithAug;
468 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
469 /* Append the priority using a default name. */
470 $1->factorWithAug->priorityAugs.append(
471 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
472 $$->factorWithAug = $1->factorWithAug;
475 factor_with_aug aug_type_cond action_embed final {
476 $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
477 $2->augType, $3->action, true ) );
478 $$->factorWithAug = $1->factorWithAug;
481 factor_with_aug aug_type_cond '!' action_embed final {
482 $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
483 $2->augType, $4->action, false ) );
484 $$->factorWithAug = $1->factorWithAug;
487 factor_with_aug aug_type_to_state action_embed final {
488 /* Append the action, pass it up. */
489 $1->factorWithAug->actions.append( ParserAction( $2->loc,
490 $2->augType, 0, $3->action ) );
491 $$->factorWithAug = $1->factorWithAug;
494 factor_with_aug aug_type_from_state action_embed final {
495 /* Append the action, pass it up. */
496 $1->factorWithAug->actions.append( ParserAction( $2->loc,
497 $2->augType, 0, $3->action ) );
498 $$->factorWithAug = $1->factorWithAug;
501 factor_with_aug aug_type_eof action_embed final {
502 /* Append the action, pass it up. */
503 $1->factorWithAug->actions.append( ParserAction( $2->loc,
504 $2->augType, 0, $3->action ) );
505 $$->factorWithAug = $1->factorWithAug;
508 factor_with_aug aug_type_gbl_error action_embed final {
509 /* Append the action to the factorWithAug, record the refernce from
510 * factorWithAug to the action and pass up the factorWithAug. */
511 $1->factorWithAug->actions.append( ParserAction( $2->loc,
512 $2->augType, pd->curDefLocalErrKey, $3->action ) );
513 $$->factorWithAug = $1->factorWithAug;
516 factor_with_aug aug_type_local_error action_embed final {
517 /* Append the action to the factorWithAug, record the refernce from
518 * factorWithAug to the action and pass up the factorWithAug. */
519 $1->factorWithAug->actions.append( ParserAction( $2->loc,
520 $2->augType, pd->curDefLocalErrKey, $3->action ) );
521 $$->factorWithAug = $1->factorWithAug;
524 factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
525 /* Append the action to the factorWithAug, record the refernce from
526 * factorWithAug to the action and pass up the factorWithAug. */
527 $1->factorWithAug->actions.append( ParserAction( $2->loc,
528 $2->augType, $4->error_name, $6->action ) );
529 $$->factorWithAug = $1->factorWithAug;
532 factor_with_rep final {
533 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
542 # Classes of transtions on which to embed actions or change priorities.
543 nonterm aug_type_base uses aug_type;
545 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
546 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
547 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
548 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
550 # Embedding conditions.
551 nonterm aug_type_cond uses aug_type;
553 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
554 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
555 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
556 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
557 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
558 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
559 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
560 aug_type_cond: KW_InWhen final { $$->loc = $1->loc; $$->augType = at_start; };
561 aug_type_cond: KW_OutWhen final { $$->loc = $1->loc; $$->augType = at_leave; };
567 nonterm aug_type_to_state uses aug_type;
569 aug_type_to_state: TK_StartToState
570 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
571 aug_type_to_state: '>' KW_To
572 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
574 aug_type_to_state: TK_NotStartToState
575 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
576 aug_type_to_state: '<' KW_To
577 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
579 aug_type_to_state: TK_AllToState
580 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
581 aug_type_to_state: '$' KW_To
582 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
584 aug_type_to_state: TK_FinalToState
585 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
586 aug_type_to_state: '%' KW_To
587 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
589 aug_type_to_state: TK_NotFinalToState
590 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
591 aug_type_to_state: '@' KW_To
592 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
594 aug_type_to_state: TK_MiddleToState
595 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
596 aug_type_to_state: TK_Middle KW_To
597 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
600 # From state actions.
603 nonterm aug_type_from_state uses aug_type;
605 aug_type_from_state: TK_StartFromState
606 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
607 aug_type_from_state: '>' KW_From
608 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
610 aug_type_from_state: TK_NotStartFromState
611 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
612 aug_type_from_state: '<' KW_From
613 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
615 aug_type_from_state: TK_AllFromState
616 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
617 aug_type_from_state: '$' KW_From
618 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
620 aug_type_from_state: TK_FinalFromState
621 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
622 aug_type_from_state: '%' KW_From
623 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
625 aug_type_from_state: TK_NotFinalFromState
626 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
627 aug_type_from_state: '@' KW_From
628 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
630 aug_type_from_state: TK_MiddleFromState
631 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
632 aug_type_from_state: TK_Middle KW_From
633 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
639 nonterm aug_type_eof uses aug_type;
641 aug_type_eof: TK_StartEOF
642 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
643 aug_type_eof: '>' KW_Eof
644 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
646 aug_type_eof: TK_NotStartEOF
647 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
648 aug_type_eof: '<' KW_Eof
649 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
651 aug_type_eof: TK_AllEOF
652 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
653 aug_type_eof: '$' KW_Eof
654 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
656 aug_type_eof: TK_FinalEOF
657 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
658 aug_type_eof: '%' KW_Eof
659 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
661 aug_type_eof: TK_NotFinalEOF
662 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
663 aug_type_eof: '@' KW_Eof
664 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
666 aug_type_eof: TK_MiddleEOF
667 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
668 aug_type_eof: TK_Middle KW_Eof
669 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
672 # Global error actions.
675 nonterm aug_type_gbl_error uses aug_type;
677 aug_type_gbl_error: TK_StartGblError
678 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
679 aug_type_gbl_error: '>' KW_Err
680 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
682 aug_type_gbl_error: TK_NotStartGblError
683 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
684 aug_type_gbl_error: '<' KW_Err
685 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
687 aug_type_gbl_error: TK_AllGblError
688 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
689 aug_type_gbl_error: '$' KW_Err
690 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
692 aug_type_gbl_error: TK_FinalGblError
693 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
694 aug_type_gbl_error: '%' KW_Err
695 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
697 aug_type_gbl_error: TK_NotFinalGblError
698 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
699 aug_type_gbl_error: '@' KW_Err
700 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
702 aug_type_gbl_error: TK_MiddleGblError
703 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
704 aug_type_gbl_error: TK_Middle KW_Err
705 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
709 # Local error actions.
712 nonterm aug_type_local_error uses aug_type;
714 aug_type_local_error: TK_StartLocalError
715 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
716 aug_type_local_error: '>' KW_Lerr
717 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
719 aug_type_local_error: TK_NotStartLocalError
720 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
721 aug_type_local_error: '<' KW_Lerr
722 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
724 aug_type_local_error: TK_AllLocalError
725 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
726 aug_type_local_error: '$' KW_Lerr
727 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
729 aug_type_local_error: TK_FinalLocalError
730 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
731 aug_type_local_error: '%' KW_Lerr
732 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
734 aug_type_local_error: TK_NotFinalLocalError
735 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
736 aug_type_local_error: '@' KW_Lerr
737 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
739 aug_type_local_error: TK_MiddleLocalError
740 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
741 aug_type_local_error: TK_Middle KW_Lerr
742 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
750 # Different ways to embed actions. A TK_Word is reference to an action given by
751 # the user as a statement in the fsm specification. An action can also be
752 # specified immediately.
753 nonterm action_embed uses action_ref;
755 action_embed: action_embed_word final { $$->action = $1->action; };
756 action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
757 action_embed: action_embed_block final { $$->action = $1->action; };
759 nonterm action_embed_word uses action_ref;
763 /* Set the name in the actionDict. */
764 Action *action = pd->actionDict.find( $1->data );
766 /* Pass up the action element */
770 /* Will recover by returning null as the action. */
771 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
776 nonterm action_embed_block uses action_ref;
779 '{' inline_block '}' final {
780 /* Create the action, add it to the list and pass up. */
781 Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
782 pd->actionList.append( newAction );
783 $$->action = newAction;
786 nonterm priority_name
791 # A specified priority name. Looks up the name in the current priority
795 // Lookup/create the priority key.
796 PriorDictEl *priorDictEl;
797 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
798 pd->nextPriorKey += 1;
800 // Use the inserted/found priority key.
801 $$->priorityName = priorDictEl->value;
809 # Priority change specs.
811 priority_aug_num final {
812 // Convert the priority number to a long. Check for overflow.
814 //cerr << "PRIOR AUG: " << $1->token.data << endl;
815 long aug = strtol( $1->token.data, 0, 10 );
816 if ( errno == ERANGE && aug == LONG_MAX ) {
817 /* Priority number too large. Recover by setting the priority to 0. */
818 error($1->token.loc) << "priority number " << $1->token.data <<
819 " overflows" << endl;
822 else if ( errno == ERANGE && aug == LONG_MIN ) {
823 /* Priority number too large in the neg. Recover by using 0. */
824 error($1->token.loc) << "priority number " << $1->token.data <<
825 " underflows" << endl;
829 /* No overflow or underflow. */
830 $$->priorityNum = aug;
834 nonterm priority_aug_num uses token_type;
842 $$->token.set( "+", 1 );
843 $$->token.loc = $1->loc;
844 $$->token.append( *$2 );
848 $$->token.set( "-", 1 );
849 $$->token.loc = $1->loc;
850 $$->token.append( *$2 );
853 nonterm local_err_name
860 /* Lookup/create the priority key. */
861 LocalErrDictEl *localErrDictEl;
862 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
863 pd->nextLocalErrKey += 1;
865 /* Use the inserted/found priority key. */
866 $$->error_name = localErrDictEl->value;
871 # The fourth level of precedence. These are the trailing unary operators that
872 # allow for repetition.
874 nonterm factor_with_rep
876 FactorWithRep *factorWithRep;
880 factor_with_rep '*' final {
881 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
882 0, 0, FactorWithRep::StarType );
885 factor_with_rep TK_StarStar final {
886 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
887 0, 0, FactorWithRep::StarStarType );
890 factor_with_rep '?' final {
891 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
892 0, 0, FactorWithRep::OptionalType );
895 factor_with_rep '+' final {
896 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
897 0, 0, FactorWithRep::PlusType );
900 factor_with_rep '{' factor_rep_num '}' final {
901 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
902 $3->rep, 0, FactorWithRep::ExactType );
905 factor_with_rep '{' ',' factor_rep_num '}' final {
906 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
907 0, $4->rep, FactorWithRep::MaxType );
910 factor_with_rep '{' factor_rep_num ',' '}' final {
911 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
912 $3->rep, 0, FactorWithRep::MinType );
915 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
916 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
917 $3->rep, $5->rep, FactorWithRep::RangeType );
920 factor_with_neg final {
921 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
924 nonterm factor_rep_num
931 // Convert the priority number to a long. Check for overflow.
933 long rep = strtol( $1->data, 0, 10 );
934 if ( errno == ERANGE && rep == LONG_MAX ) {
935 // Repetition too large. Recover by returing repetition 1. */
936 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
940 // Cannot be negative, so no overflow.
947 # The fifth level up in precedence. Negation.
950 nonterm factor_with_neg
952 FactorWithNeg *factorWithNeg;
956 '!' factor_with_neg final {
957 $$->factorWithNeg = new FactorWithNeg( $1->loc,
958 $2->factorWithNeg, FactorWithNeg::NegateType );
961 '^' factor_with_neg final {
962 $$->factorWithNeg = new FactorWithNeg( $1->loc,
963 $2->factorWithNeg, FactorWithNeg::CharNegateType );
967 $$->factorWithNeg = new FactorWithNeg( $1->factor );
977 /* Create a new factor node going to a concat literal. */
978 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
982 /* Create a new factor node going to a literal number. */
983 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
987 /* Find the named graph. */
988 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
990 /* Recover by returning null as the factor node. */
991 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
994 else if ( gdNode->isInstance ) {
995 /* Recover by retuning null as the factor node. */
996 error($1->loc) << "references to graph instantiations not allowed "
997 "in expressions" << endl;
1001 /* Create a factor node that is a lookup of an expression. */
1002 $$->factor = new Factor( $1->loc, gdNode->value );
1006 RE_SqOpen regular_expr_or_data RE_SqClose final {
1007 /* Create a new factor node going to an OR expression. */
1008 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
1011 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1012 /* Create a new factor node going to a negated OR expression. */
1013 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
1016 RE_Slash regular_expr RE_Slash final {
1017 if ( $3->length > 1 ) {
1018 for ( char *p = $3->data; *p != 0; p++ ) {
1020 $2->regExpr->caseInsensitive = true;
1024 /* Create a new factor node going to a regular exp. */
1025 $$->factor = new Factor( $2->regExpr );
1028 range_lit TK_DotDot range_lit final {
1029 /* Create a new factor node going to a range. */
1030 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
1033 '(' join ')' final {
1034 /* Create a new factor going to a parenthesized join. */
1035 $$->factor = new Factor( $2->join );
1036 $2->join->loc = $1->loc;
1044 # Literals which can be the end points of ranges.
1047 /* Range literas must have only one char. We restrict this in the parse tree. */
1048 $$->literal = new Literal( *$1, Literal::LitString );
1051 alphabet_num final {
1052 /* Create a new literal number. */
1053 $$->literal = new Literal( $1->token, Literal::Number );
1056 nonterm alphabet_num uses token_type;
1058 # Any form of a number that can be used as a basic machine. */
1065 $$->token.set( "-", 1 );
1066 $$->token.loc = $1->loc;
1067 $$->token.append( *$2 );
1074 # Regular Expressions.
1077 nonterm regular_expr
1082 # Parser for regular expression fsms. Any number of expression items which
1083 # generally gives a machine one character long or one character long stared.
1085 regular_expr regular_expr_item final {
1086 /* An optimization to lessen the tree size. If a non-starred char is
1087 * directly under the left side on the right and the right side is
1088 * another non-starred char then paste them together and return the
1089 * left side. Otherwise just put the two under a new reg exp node. */
1090 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
1091 $1->regExpr->type == RegExpr::RecurseItem &&
1092 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1094 /* Append the right side to the right side of the left and toss the
1096 $1->regExpr->item->token.append( $2->reItem->token );
1098 $$->regExpr = $1->regExpr;
1101 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1106 /* Can't optimize the tree. */
1107 $$->regExpr = new RegExpr();
1110 nonterm regular_expr_item
1115 # RegularExprItems can be a character spec with an optional staring of the char.
1117 regular_expr_char RE_Star final {
1118 $1->reItem->star = true;
1119 $$->reItem = $1->reItem;
1122 regular_expr_char final {
1123 $$->reItem = $1->reItem;
1126 nonterm regular_expr_char
1131 # A character spec can be a set of characters inside of square parenthesis, a
1132 # dot specifying any character or some explicitly stated character.
1134 RE_SqOpen regular_expr_or_data RE_SqClose final {
1135 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1138 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1139 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1143 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1147 $$->reItem = new ReItem( $1->loc, *$1 );
1150 # The data inside of a [] expression in a regular expression. Accepts any
1151 # number of characters or ranges. */
1152 nonterm regular_expr_or_data
1154 ReOrBlock *reOrBlock;
1157 regular_expr_or_data:
1158 regular_expr_or_data regular_expr_or_char final {
1159 /* An optimization to lessen the tree size. If an or char is directly
1160 * under the left side on the right and the right side is another or
1161 * char then paste them together and return the left side. Otherwise
1162 * just put the two under a new or data node. */
1163 if ( $2->reOrItem->type == ReOrItem::Data &&
1164 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1165 $1->reOrBlock->item->type == ReOrItem::Data )
1167 /* Append the right side to right side of the left and toss the
1169 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1170 delete $2->reOrItem;
1171 $$->reOrBlock = $1->reOrBlock;
1174 /* Can't optimize, put the left and right under a new node. */
1175 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1178 regular_expr_or_data:
1180 $$->reOrBlock = new ReOrBlock();
1183 # A single character inside of an or expression. Can either be a character or a
1184 # set of characters.
1185 nonterm regular_expr_or_char
1190 regular_expr_or_char:
1192 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1194 regular_expr_or_char:
1195 RE_Char RE_Dash RE_Char final {
1196 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1200 # Inline Lists for inline host code.
1205 InlineList *inlineList;
1208 nonterm inline_block uses inline_list;
1211 inline_block inline_block_item
1213 /* Append the item to the list, return the list. */
1214 $$->inlineList = $1->inlineList;
1215 $$->inlineList->append( $2->inlineItem );
1220 /* Start with empty list. */
1221 $$->inlineList = new InlineList;
1226 InlineItem *inlineItem;
1229 nonterm inline_block_item uses inline_item;
1230 nonterm inline_block_interpret uses inline_item;
1235 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1241 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1245 inline_block_interpret
1247 /* Pass the inline item up. */
1248 $$->inlineItem = $1->inlineItem;
1251 nonterm inline_block_symbol uses token_type;
1253 inline_block_symbol: ',' final { $$->token = *$1; };
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: TK_NameSep final { $$->token = *$1; };
1260 # Interpreted statements in a struct block. */
1261 inline_block_interpret:
1262 inline_expr_interpret final {
1263 /* Pass up interpreted items of inline expressions. */
1264 $$->inlineItem = $1->inlineItem;
1266 inline_block_interpret:
1268 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1270 inline_block_interpret:
1271 KW_Exec inline_expr ';' final {
1272 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1273 $$->inlineItem->children = $2->inlineList;
1275 inline_block_interpret:
1276 KW_Goto state_ref ';' final {
1277 $$->inlineItem = new InlineItem( $1->loc,
1278 new NameRef(nameRef), InlineItem::Goto );
1280 inline_block_interpret:
1281 KW_Goto '*' inline_expr ';' final {
1282 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1283 $$->inlineItem->children = $3->inlineList;
1285 inline_block_interpret:
1286 KW_Next state_ref ';' final {
1287 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1289 inline_block_interpret:
1290 KW_Next '*' inline_expr ';' final {
1291 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1292 $$->inlineItem->children = $3->inlineList;
1294 inline_block_interpret:
1295 KW_Call state_ref ';' final {
1296 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1298 inline_block_interpret:
1299 KW_Call '*' inline_expr ';' final {
1300 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1301 $$->inlineItem->children = $3->inlineList;
1303 inline_block_interpret:
1305 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1307 inline_block_interpret:
1308 KW_Break ';' final {
1309 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1312 nonterm inline_expr uses inline_list;
1315 inline_expr inline_expr_item
1317 $$->inlineList = $1->inlineList;
1318 $$->inlineList->append( $2->inlineItem );
1322 /* Init the list used for this expr. */
1323 $$->inlineList = new InlineList;
1326 nonterm inline_expr_item uses inline_item;
1331 /* Return a text segment. */
1332 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1337 /* Return a text segment, must heap alloc the text. */
1338 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1341 inline_expr_interpret
1343 /* Pass the inline item up. */
1344 $$->inlineItem = $1->inlineItem;
1347 nonterm inline_expr_any uses token_type;
1349 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1350 inline_expr_any: IL_Comment try { $$->token = *$1; };
1351 inline_expr_any: IL_Literal try { $$->token = *$1; };
1352 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1353 inline_expr_any: TK_UInt try { $$->token = *$1; };
1354 inline_expr_any: TK_Hex try { $$->token = *$1; };
1355 inline_expr_any: TK_Word try { $$->token = *$1; };
1357 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1358 # all special symbols caught in inline code except the semi.
1360 nonterm inline_expr_symbol uses token_type;
1362 inline_expr_symbol: ',' try { $$->token = *$1; };
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: TK_NameSep try { $$->token = *$1; };
1368 nonterm inline_expr_interpret uses inline_item;
1370 inline_expr_interpret:
1373 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1375 inline_expr_interpret:
1378 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1380 inline_expr_interpret:
1383 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1385 inline_expr_interpret:
1388 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1390 inline_expr_interpret:
1391 KW_Entry '(' state_ref ')'
1393 $$->inlineItem = new InlineItem( $1->loc,
1394 new NameRef(nameRef), InlineItem::Entry );
1397 # A local state reference. Cannot have :: prefix.
1399 no_name_sep state_ref_names;
1401 # Clear the name ref structure.
1407 # A qualified state reference.
1408 state_ref: opt_name_sep state_ref_names;
1410 # Optional leading name separator.
1414 /* Insert an initial null pointer val to indicate the existence of the
1415 * initial name seperator. */
1423 # List of names separated by ::
1425 state_ref_names TK_NameSep TK_Word
1427 nameRef.append( $3->data );
1432 nameRef.append( $1->data );
1447 int Parser::parseLangEl( int type, const Token *token )
1450 return errCount == 0 ? 0 : -1;
1453 void Parser::tryMachineDef( InputLoc &loc, char *name,
1454 JoinOrLm *joinOrLm, bool isInstance )
1456 GraphDictEl *newEl = pd->graphDict.insert( name );
1458 /* New element in the dict, all good. */
1459 newEl->value = new VarDef( name, joinOrLm );
1460 newEl->isInstance = isInstance;
1462 newEl->value->isExport = exportContext[exportContext.length()-1];
1464 /* It it is an instance, put on the instance list. */
1466 pd->instanceList.append( newEl );
1469 // Recover by ignoring the duplicate.
1470 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1474 ostream &Parser::parse_error( int tokId, Token &token )
1476 /* Maintain the error count. */
1479 cerr << token.loc << ": ";
1480 cerr << "at token ";
1482 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1484 cerr << Parser_lelNames[tokId];
1485 if ( token.data != 0 )
1486 cerr << " with data \"" << token.data << "\"";
1492 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1495 token.data = tokstart;
1496 token.length = toklen;
1498 int res = parseLangEl( tokId, &token );
1500 parse_error(tokId, token) << "parse error" << endl;