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 ParserList parserList;
34 InputItemList inputItems;
44 section_list: section_list statement_list TK_EndSection;
47 statement_list: statement_list statement;
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;
63 KW_PrePush '{' inline_block '}'
65 if ( pd->prePushExpr != 0 ) {
66 /* Recover by just ignoring the duplicate. */
67 error($2->loc) << "pre_push code already defined" << endl;
70 pd->prePushExpr = $3->inlineList;
75 KW_PostPop '{' inline_block '}'
77 if ( pd->postPopExpr != 0 ) {
78 /* Recover by just ignoring the duplicate. */
79 error($2->loc) << "post_pop code already defined" << endl;
82 pd->postPopExpr = $3->inlineList;
86 export_open: KW_Export
88 exportContext.append( true );
96 opt_export: export_open final { $$->isSet = true; };
97 opt_export: final { $$->isSet = false; };
99 export_block: export_open '{' statement_list '}'
101 exportContext.remove( exportContext.length()-1 );
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;
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 );
119 exportContext.remove( exportContext.length()-1 );
121 $4->join->loc = $3->loc;
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 );
130 exportContext.remove( exportContext.length()-1 );
132 /* Pass a location to join_or_lm */
133 if ( $4->joinOrLm->join != 0 )
134 $4->joinOrLm->join->loc = $3->loc;
142 nonterm machine_name uses token_type;
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;
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;
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;
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++ );
174 /* Insert to list and dict. */
175 pd->actionList.append( newAction );
176 pd->actionDict.insert( newAction );
180 # Specifies the data type of the input alphabet. One or two words followed by a
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;
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;
200 # Specifies a range to assume that the input characters will fall into.
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;
211 KW_GetKey inline_expr ';' final {
212 pd->getKeyExpr = $2->inlineList;
216 KW_Access inline_expr ';' final {
217 pd->accessExpr = $2->inlineList;
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 );
225 error($3->loc) << "bad variable name" << endl;
228 opt_whitespace: opt_whitespace IL_WhiteSpace;
242 $$->joinOrLm = new JoinOrLm( $1->join );
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 );
257 LmPartList *lmPartList;
261 lm_part_list longest_match_part
263 if ( $2->lmPart != 0 )
264 $1->lmPartList->append( $2->lmPart );
265 $$->lmPartList = $1->lmPartList;
270 /* Create a new list with the part. */
271 $$->lmPartList = new LmPartList;
272 if ( $1->lmPart != 0 )
273 $$->lmPartList->append( $1->lmPart );
276 nonterm longest_match_part
278 LongestMatchPart *lmPart;
282 action_spec final { $$->lmPart = 0; };
284 assignment final { $$->lmPart = 0; };
286 join opt_lm_part_action ';' final {
288 Action *action = $2->action;
290 action->isLmAction = true;
291 $$->lmPart = new LongestMatchPart( $1->join, action,
292 $3->loc, pd->nextLongestMatchId++ );
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;
299 nonterm opt_lm_part_action
305 TK_DoubleArrow action_embed final {
306 $$->action = $2->action;
309 action_embed_block final {
310 $$->action = $1->action;
324 join ',' expression final {
325 /* Append the expression to the list and return it. */
326 $1->join->exprList.append( $3->expression );
331 $$->join = new Join( $1->expression );
336 Expression *expression;
340 expression '|' term_short final {
341 $$->expression = new Expression( $1->expression,
342 $3->term, Expression::OrType );
345 expression '&' term_short final {
346 $$->expression = new Expression( $1->expression,
347 $3->term, Expression::IntersectType );
350 expression '-' term_short final {
351 $$->expression = new Expression( $1->expression,
352 $3->term, Expression::SubtractType );
355 expression TK_DashDash term_short final {
356 $$->expression = new Expression( $1->expression,
357 $3->term, Expression::StrongSubtractType );
361 $$->expression = new Expression( $1->term );
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.
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.
391 term factor_with_label final {
392 $$->term = new Term( $1->term, $2->factorWithAug );
395 term '.' factor_with_label final {
396 $$->term = new Term( $1->term, $3->factorWithAug );
399 term TK_ColonGt factor_with_label final {
400 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
403 term TK_ColonGtGt factor_with_label final {
404 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
407 term TK_LtColon factor_with_label final {
408 $$->term = new Term( $1->term,
409 $3->factorWithAug, Term::LeftType );
412 factor_with_label final {
413 $$->term = new Term( $1->factorWithAug );
416 nonterm factor_with_label
418 FactorWithAug *factorWithAug;
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;
428 factor_with_ep final {
429 $$->factorWithAug = $1->factorWithAug;
432 nonterm factor_with_ep
434 FactorWithAug *factorWithAug;
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;
444 factor_with_aug final {
445 $$->factorWithAug = $1->factorWithAug;
448 nonterm factor_with_aug
450 FactorWithAug *factorWithAug;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
533 factor_with_rep final {
534 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
543 # Classes of transtions on which to embed actions or change priorities.
544 nonterm aug_type_base uses aug_type;
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; };
551 # Embedding conditions.
552 nonterm aug_type_cond uses aug_type;
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; };
568 nonterm aug_type_to_state uses aug_type;
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; };
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; };
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; };
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; };
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; };
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; };
601 # From state actions.
604 nonterm aug_type_from_state uses aug_type;
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; };
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; };
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; };
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; };
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; };
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; };
640 nonterm aug_type_eof uses aug_type;
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; };
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; };
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; };
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; };
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; };
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; };
673 # Global error actions.
676 nonterm aug_type_gbl_error uses aug_type;
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; };
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; };
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; };
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; };
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; };
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; };
710 # Local error actions.
713 nonterm aug_type_local_error uses aug_type;
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; };
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; };
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; };
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; };
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; };
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; };
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;
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; };
760 nonterm action_embed_word uses action_ref;
764 /* Set the name in the actionDict. */
765 Action *action = pd->actionDict.find( $1->data );
767 /* Pass up the action element */
771 /* Will recover by returning null as the action. */
772 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
777 nonterm action_embed_block uses action_ref;
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;
787 nonterm priority_name
792 # A specified priority name. Looks up the name in the current priority
796 // Lookup/create the priority key.
797 PriorDictEl *priorDictEl;
798 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
799 pd->nextPriorKey += 1;
801 // Use the inserted/found priority key.
802 $$->priorityName = priorDictEl->value;
810 # Priority change specs.
812 priority_aug_num final {
813 // Convert the priority number to a long. Check for overflow.
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;
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;
830 /* No overflow or underflow. */
831 $$->priorityNum = aug;
835 nonterm priority_aug_num uses token_type;
843 $$->token.set( "+", 1 );
844 $$->token.loc = $1->loc;
845 $$->token.append( *$2 );
849 $$->token.set( "-", 1 );
850 $$->token.loc = $1->loc;
851 $$->token.append( *$2 );
854 nonterm local_err_name
861 /* Lookup/create the priority key. */
862 LocalErrDictEl *localErrDictEl;
863 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
864 pd->nextLocalErrKey += 1;
866 /* Use the inserted/found priority key. */
867 $$->error_name = localErrDictEl->value;
872 # The fourth level of precedence. These are the trailing unary operators that
873 # allow for repetition.
875 nonterm factor_with_rep
877 FactorWithRep *factorWithRep;
881 factor_with_rep '*' final {
882 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
883 0, 0, FactorWithRep::StarType );
886 factor_with_rep TK_StarStar final {
887 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
888 0, 0, FactorWithRep::StarStarType );
891 factor_with_rep '?' final {
892 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
893 0, 0, FactorWithRep::OptionalType );
896 factor_with_rep '+' final {
897 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
898 0, 0, FactorWithRep::PlusType );
901 factor_with_rep '{' factor_rep_num '}' final {
902 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
903 $3->rep, 0, FactorWithRep::ExactType );
906 factor_with_rep '{' ',' factor_rep_num '}' final {
907 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
908 0, $4->rep, FactorWithRep::MaxType );
911 factor_with_rep '{' factor_rep_num ',' '}' final {
912 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
913 $3->rep, 0, FactorWithRep::MinType );
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 );
921 factor_with_neg final {
922 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
925 nonterm factor_rep_num
932 // Convert the priority number to a long. Check for overflow.
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;
941 // Cannot be negative, so no overflow.
948 # The fifth level up in precedence. Negation.
951 nonterm factor_with_neg
953 FactorWithNeg *factorWithNeg;
957 '!' factor_with_neg final {
958 $$->factorWithNeg = new FactorWithNeg( $1->loc,
959 $2->factorWithNeg, FactorWithNeg::NegateType );
962 '^' factor_with_neg final {
963 $$->factorWithNeg = new FactorWithNeg( $1->loc,
964 $2->factorWithNeg, FactorWithNeg::CharNegateType );
968 $$->factorWithNeg = new FactorWithNeg( $1->factor );
978 /* Create a new factor node going to a concat literal. */
979 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
983 /* Create a new factor node going to a literal number. */
984 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
988 /* Find the named graph. */
989 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
991 /* Recover by returning null as the factor node. */
992 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
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;
1002 /* Create a factor node that is a lookup of an expression. */
1003 $$->factor = new Factor( $1->loc, gdNode->value );
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 ) );
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 ) );
1017 RE_Slash regular_expr RE_Slash final {
1018 if ( $3->length > 1 ) {
1019 for ( char *p = $3->data; *p != 0; p++ ) {
1021 $2->regExpr->caseInsensitive = true;
1025 /* Create a new factor node going to a regular exp. */
1026 $$->factor = new Factor( $2->regExpr );
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 ) );
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;
1045 # Literals which can be the end points of ranges.
1048 /* Range literas must have only one char. We restrict this in the parse tree. */
1049 $$->literal = new Literal( *$1, Literal::LitString );
1052 alphabet_num final {
1053 /* Create a new literal number. */
1054 $$->literal = new Literal( $1->token, Literal::Number );
1057 nonterm alphabet_num uses token_type;
1059 # Any form of a number that can be used as a basic machine. */
1066 $$->token.set( "-", 1 );
1067 $$->token.loc = $1->loc;
1068 $$->token.append( *$2 );
1075 # Regular Expressions.
1078 nonterm regular_expr
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.
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 )
1095 /* Append the right side to the right side of the left and toss the
1097 $1->regExpr->item->token.append( $2->reItem->token );
1099 $$->regExpr = $1->regExpr;
1102 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1107 /* Can't optimize the tree. */
1108 $$->regExpr = new RegExpr();
1111 nonterm regular_expr_item
1116 # RegularExprItems can be a character spec with an optional staring of the char.
1118 regular_expr_char RE_Star final {
1119 $1->reItem->star = true;
1120 $$->reItem = $1->reItem;
1123 regular_expr_char final {
1124 $$->reItem = $1->reItem;
1127 nonterm regular_expr_char
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.
1135 RE_SqOpen regular_expr_or_data RE_SqClose final {
1136 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1139 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1140 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1144 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1148 $$->reItem = new ReItem( $1->loc, *$1 );
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
1155 ReOrBlock *reOrBlock;
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 )
1168 /* Append the right side to right side of the left and toss the
1170 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1171 delete $2->reOrItem;
1172 $$->reOrBlock = $1->reOrBlock;
1175 /* Can't optimize, put the left and right under a new node. */
1176 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1179 regular_expr_or_data:
1181 $$->reOrBlock = new ReOrBlock();
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
1191 regular_expr_or_char:
1193 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
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] );
1201 # Inline Lists for inline host code.
1206 InlineList *inlineList;
1209 nonterm inline_block uses inline_list;
1212 inline_block inline_block_item
1214 /* Append the item to the list, return the list. */
1215 $$->inlineList = $1->inlineList;
1216 $$->inlineList->append( $2->inlineItem );
1221 /* Start with empty list. */
1222 $$->inlineList = new InlineList;
1227 InlineItem *inlineItem;
1230 nonterm inline_block_item uses inline_item;
1231 nonterm inline_block_interpret uses inline_item;
1236 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1242 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1246 inline_block_interpret
1248 /* Pass the inline item up. */
1249 $$->inlineItem = $1->inlineItem;
1252 nonterm inline_block_symbol uses token_type;
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; };
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;
1267 inline_block_interpret:
1269 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1271 inline_block_interpret:
1272 KW_Exec inline_expr ';' final {
1273 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1274 $$->inlineItem->children = $2->inlineList;
1276 inline_block_interpret:
1277 KW_Goto state_ref ';' final {
1278 $$->inlineItem = new InlineItem( $1->loc,
1279 new NameRef(nameRef), InlineItem::Goto );
1281 inline_block_interpret:
1282 KW_Goto '*' inline_expr ';' final {
1283 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1284 $$->inlineItem->children = $3->inlineList;
1286 inline_block_interpret:
1287 KW_Next state_ref ';' final {
1288 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1290 inline_block_interpret:
1291 KW_Next '*' inline_expr ';' final {
1292 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1293 $$->inlineItem->children = $3->inlineList;
1295 inline_block_interpret:
1296 KW_Call state_ref ';' final {
1297 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1299 inline_block_interpret:
1300 KW_Call '*' inline_expr ';' final {
1301 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1302 $$->inlineItem->children = $3->inlineList;
1304 inline_block_interpret:
1306 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1308 inline_block_interpret:
1309 KW_Break ';' final {
1310 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1313 nonterm inline_expr uses inline_list;
1316 inline_expr inline_expr_item
1318 $$->inlineList = $1->inlineList;
1319 $$->inlineList->append( $2->inlineItem );
1323 /* Init the list used for this expr. */
1324 $$->inlineList = new InlineList;
1327 nonterm inline_expr_item uses inline_item;
1332 /* Return a text segment. */
1333 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1338 /* Return a text segment, must heap alloc the text. */
1339 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1342 inline_expr_interpret
1344 /* Pass the inline item up. */
1345 $$->inlineItem = $1->inlineItem;
1348 nonterm inline_expr_any uses token_type;
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; };
1358 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1359 # all special symbols caught in inline code except the semi.
1361 nonterm inline_expr_symbol uses token_type;
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; };
1369 nonterm inline_expr_interpret uses inline_item;
1371 inline_expr_interpret:
1374 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1376 inline_expr_interpret:
1379 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1381 inline_expr_interpret:
1384 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1386 inline_expr_interpret:
1389 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1391 inline_expr_interpret:
1392 KW_Entry '(' state_ref ')'
1394 $$->inlineItem = new InlineItem( $1->loc,
1395 new NameRef(nameRef), InlineItem::Entry );
1398 # A local state reference. Cannot have :: prefix.
1400 no_name_sep state_ref_names;
1402 # Clear the name ref structure.
1408 # A qualified state reference.
1409 state_ref: opt_name_sep state_ref_names;
1411 # Optional leading name separator.
1415 /* Insert an initial null pointer val to indicate the existence of the
1416 * initial name seperator. */
1424 # List of names separated by ::
1426 state_ref_names TK_NameSep TK_Word
1428 nameRef.append( $3->data );
1433 nameRef.append( $1->data );
1448 int Parser::parseLangEl( int type, const Token *token )
1451 return errCount == 0 ? 0 : -1;
1454 void Parser::tryMachineDef( InputLoc &loc, char *name,
1455 JoinOrLm *joinOrLm, bool isInstance )
1457 GraphDictEl *newEl = pd->graphDict.insert( name );
1459 /* New element in the dict, all good. */
1460 newEl->value = new VarDef( name, joinOrLm );
1461 newEl->isInstance = isInstance;
1463 newEl->value->isExport = exportContext[exportContext.length()-1];
1465 /* It it is an instance, put on the instance list. */
1467 pd->instanceList.append( newEl );
1470 // Recover by ignoring the duplicate.
1471 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1475 ostream &Parser::parse_error( int tokId, Token &token )
1477 /* Maintain the error count. */
1480 cerr << token.loc << ": ";
1481 cerr << "at token ";
1483 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1485 cerr << Parser_lelNames[tokId];
1486 if ( token.data != 0 )
1487 cerr << " with data \"" << token.data << "\"";
1493 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1496 token.data = tokstart;
1497 token.length = toklen;
1499 int res = parseLangEl( tokId, &token );
1501 parse_error(tokId, token) << "parse error" << endl;