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;
57 statement: pre_push_spec commit;
58 statement: post_pop_spec commit;
61 KW_PrePush '{' inline_block '}'
63 if ( pd->prePushExpr != 0 ) {
64 /* Recover by just ignoring the duplicate. */
65 error($2->loc) << "pre_push code already defined" << endl;
68 pd->prePushExpr = $3->inlineList;
73 KW_PostPop '{' inline_block '}'
75 if ( pd->postPopExpr != 0 ) {
76 /* Recover by just ignoring the duplicate. */
77 error($2->loc) << "post_pop code already defined" << endl;
80 pd->postPopExpr = $3->inlineList;
84 export_open: KW_Export
86 exportContext.append( true );
94 opt_export: export_open final { $$->isSet = true; };
95 opt_export: final { $$->isSet = false; };
97 export_block: export_open '{' statement_list '}'
99 exportContext.remove( exportContext.length()-1 );
103 opt_export machine_name '=' join ';' final {
104 /* Main machine must be an instance. */
105 bool isInstance = false;
106 if ( strcmp($2->token.data, mainMachine) == 0 ) {
107 warning($2->token.loc) <<
108 "main machine will be implicitly instantiated" << endl;
112 /* Generic creation of machine for instantiation and assignment. */
113 JoinOrLm *joinOrLm = new JoinOrLm( $4->join );
114 tryMachineDef( $2->token.loc, $2->token.data, joinOrLm, isInstance );
117 exportContext.remove( exportContext.length()-1 );
121 opt_export machine_name TK_ColonEquals join_or_lm ';' final {
122 /* Generic creation of machine for instantiation and assignment. */
123 tryMachineDef( $2->token.loc, $2->token.data, $4->joinOrLm, true );
126 exportContext.remove( exportContext.length()-1 );
134 nonterm machine_name uses token_type;
138 /* Make/get the priority key. The name may have already been referenced
139 * and therefore exist. */
140 PriorDictEl *priorDictEl;
141 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
142 pd->nextPriorKey += 1;
143 pd->curDefPriorKey = priorDictEl->value;
145 /* Make/get the local error key. */
146 LocalErrDictEl *localErrDictEl;
147 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
148 pd->nextLocalErrKey += 1;
149 pd->curDefLocalErrKey = localErrDictEl->value;
155 KW_Action TK_Word '{' inline_block '}' final {
156 if ( pd->actionDict.find( $2->data ) ) {
157 /* Recover by just ignoring the duplicate. */
158 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
161 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
162 /* Add the action to the list of actions. */
163 Action *newAction = new Action( $3->loc, $2->data,
164 $4->inlineList, pd->nextCondId++ );
166 /* Insert to list and dict. */
167 pd->actionList.append( newAction );
168 pd->actionDict.insert( newAction );
172 # Specifies the data type of the input alphabet. One or two words followed by a
175 KW_AlphType TK_Word TK_Word ';' final {
176 if ( ! pd->setAlphType( $1->loc, $2->data, $3->data ) ) {
177 // Recover by ignoring the alphtype statement.
178 error($2->loc) << "\"" << $2->data <<
179 " " << $3->data << "\" is not a valid alphabet type" << endl;
184 KW_AlphType TK_Word ';' final {
185 if ( ! pd->setAlphType( $1->loc, $2->data ) ) {
186 // Recover by ignoring the alphtype statement.
187 error($2->loc) << "\"" << $2->data <<
188 "\" is not a valid alphabet type" << endl;
192 # Specifies a range to assume that the input characters will fall into.
194 KW_Range alphabet_num alphabet_num ';' final {
195 // Save the upper and lower ends of the range and emit the line number.
196 pd->lowerNum = $2->token.data;
197 pd->upperNum = $3->token.data;
198 pd->rangeLowLoc = $2->token.loc;
199 pd->rangeHighLoc = $3->token.loc;
203 KW_GetKey inline_expr ';' final {
204 pd->getKeyExpr = $2->inlineList;
208 KW_Access inline_expr ';' final {
209 pd->accessExpr = $2->inlineList;
213 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
214 /* FIXME: Need to implement the rest of this. */
215 bool wasSet = pd->setVariable( $3->data, $4->inlineList );
217 error($3->loc) << "bad variable name" << endl;
220 opt_whitespace: opt_whitespace IL_WhiteSpace;
234 $$->joinOrLm = new JoinOrLm( $1->join );
237 TK_BarStar lm_part_list '*' '|' final {
238 /* Create a new factor going to a longest match structure. Record
239 * in the parse data that we have a longest match. */
240 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
241 pd->lmList.append( lm );
242 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
243 lmp->longestMatch = lm;
244 $$->joinOrLm = new JoinOrLm( lm );
249 LmPartList *lmPartList;
253 lm_part_list longest_match_part final {
254 if ( $2->lmPart != 0 )
255 $1->lmPartList->append( $2->lmPart );
256 $$->lmPartList = $1->lmPartList;
259 longest_match_part final {
260 /* Create a new list with the part. */
261 $$->lmPartList = new LmPartList;
262 if ( $1->lmPart != 0 )
263 $$->lmPartList->append( $1->lmPart );
266 nonterm longest_match_part
268 LongestMatchPart *lmPart;
272 action_spec final { $$->lmPart = 0; };
274 assignment final { $$->lmPart = 0; };
276 join opt_lm_part_action ';' final {
278 Action *action = $2->action;
280 action->isLmAction = true;
281 $$->lmPart = new LongestMatchPart( $1->join, action,
282 $3->loc, pd->nextLongestMatchId++ );
285 nonterm opt_lm_part_action
291 TK_DoubleArrow action_embed final {
292 $$->action = $2->action;
295 action_embed_block final {
296 $$->action = $1->action;
310 join ',' expression final {
311 /* Append the expression to the list and return it. */
312 $1->join->exprList.append( $3->expression );
317 $$->join = new Join( $1->expression );
322 Expression *expression;
326 expression '|' term_short final {
327 $$->expression = new Expression( $1->expression,
328 $3->term, Expression::OrType );
331 expression '&' term_short final {
332 $$->expression = new Expression( $1->expression,
333 $3->term, Expression::IntersectType );
336 expression '-' term_short final {
337 $$->expression = new Expression( $1->expression,
338 $3->term, Expression::SubtractType );
341 expression TK_DashDash term_short final {
342 $$->expression = new Expression( $1->expression,
343 $3->term, Expression::StrongSubtractType );
347 $$->expression = new Expression( $1->term );
350 # This is where we resolve the ambiguity involving -. By default ragel tries to
351 # do a longest match, which gives precedence to a concatenation because it is
352 # innermost. What we need is to force term into a shortest match so that when -
353 # is seen it doesn't try to extend term with a concatenation, but ends term and
354 # goes for a subtraction.
356 # The shortest tag overrides the default longest match action ordering strategy
357 # and instead forces a shortest match stragegy. The wrap the term production in
358 # a new nonterminal 'term_short' to guarantee the shortest match behaviour.
377 term factor_with_label final {
378 $$->term = new Term( $1->term, $2->factorWithAug );
381 term '.' factor_with_label final {
382 $$->term = new Term( $1->term, $3->factorWithAug );
385 term TK_ColonGt factor_with_label final {
386 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
389 term TK_ColonGtGt factor_with_label final {
390 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
393 term TK_LtColon factor_with_label final {
394 $$->term = new Term( $1->term,
395 $3->factorWithAug, Term::LeftType );
398 factor_with_label final {
399 $$->term = new Term( $1->factorWithAug );
402 nonterm factor_with_label
404 FactorWithAug *factorWithAug;
408 TK_Word ':' factor_with_label final {
409 /* Add the label to the list and pass the factor up. */
410 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
411 $$->factorWithAug = $3->factorWithAug;
414 factor_with_ep final {
415 $$->factorWithAug = $1->factorWithAug;
418 nonterm factor_with_ep
420 FactorWithAug *factorWithAug;
424 factor_with_ep TK_Arrow local_state_ref final {
425 /* Add the target to the list and return the factor object. */
426 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
427 $$->factorWithAug = $1->factorWithAug;
430 factor_with_aug final {
431 $$->factorWithAug = $1->factorWithAug;
434 nonterm factor_with_aug
436 FactorWithAug *factorWithAug;
440 factor_with_aug aug_type_base action_embed final {
441 /* Append the action to the factorWithAug, record the refernce from
442 * factorWithAug to the action and pass up the factorWithAug. */
443 $1->factorWithAug->actions.append(
444 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
445 $$->factorWithAug = $1->factorWithAug;
448 factor_with_aug aug_type_base priority_aug final {
449 /* Append the named priority to the factorWithAug and pass it up. */
450 $1->factorWithAug->priorityAugs.append(
451 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
452 $$->factorWithAug = $1->factorWithAug;
455 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
456 /* Append the priority using a default name. */
457 $1->factorWithAug->priorityAugs.append(
458 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
459 $$->factorWithAug = $1->factorWithAug;
462 factor_with_aug aug_type_cond action_embed final {
463 $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
464 $2->augType, $3->action, true ) );
465 $$->factorWithAug = $1->factorWithAug;
468 factor_with_aug aug_type_cond '!' action_embed final {
469 $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
470 $2->augType, $4->action, false ) );
471 $$->factorWithAug = $1->factorWithAug;
474 factor_with_aug aug_type_to_state action_embed final {
475 /* Append the action, pass it up. */
476 $1->factorWithAug->actions.append( ParserAction( $2->loc,
477 $2->augType, 0, $3->action ) );
478 $$->factorWithAug = $1->factorWithAug;
481 factor_with_aug aug_type_from_state action_embed final {
482 /* Append the action, pass it up. */
483 $1->factorWithAug->actions.append( ParserAction( $2->loc,
484 $2->augType, 0, $3->action ) );
485 $$->factorWithAug = $1->factorWithAug;
488 factor_with_aug aug_type_eof 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_gbl_error action_embed final {
496 /* Append the action to the factorWithAug, record the refernce from
497 * factorWithAug to the action and pass up the factorWithAug. */
498 $1->factorWithAug->actions.append( ParserAction( $2->loc,
499 $2->augType, pd->curDefLocalErrKey, $3->action ) );
500 $$->factorWithAug = $1->factorWithAug;
503 factor_with_aug aug_type_local_error action_embed final {
504 /* Append the action to the factorWithAug, record the refernce from
505 * factorWithAug to the action and pass up the factorWithAug. */
506 $1->factorWithAug->actions.append( ParserAction( $2->loc,
507 $2->augType, pd->curDefLocalErrKey, $3->action ) );
508 $$->factorWithAug = $1->factorWithAug;
511 factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
512 /* Append the action to the factorWithAug, record the refernce from
513 * factorWithAug to the action and pass up the factorWithAug. */
514 $1->factorWithAug->actions.append( ParserAction( $2->loc,
515 $2->augType, $4->error_name, $6->action ) );
516 $$->factorWithAug = $1->factorWithAug;
519 factor_with_rep final {
520 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
529 # Classes of transtions on which to embed actions or change priorities.
530 nonterm aug_type_base uses aug_type;
532 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
533 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
534 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
535 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
537 # Embedding conditions.
538 nonterm aug_type_cond uses aug_type;
540 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
541 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
542 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
543 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
544 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
545 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
546 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
547 aug_type_cond: KW_InWhen final { $$->loc = $1->loc; $$->augType = at_start; };
548 aug_type_cond: KW_OutWhen final { $$->loc = $1->loc; $$->augType = at_leave; };
554 nonterm aug_type_to_state uses aug_type;
556 aug_type_to_state: TK_StartToState
557 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
558 aug_type_to_state: '>' KW_To
559 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
561 aug_type_to_state: TK_NotStartToState
562 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
563 aug_type_to_state: '<' KW_To
564 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
566 aug_type_to_state: TK_AllToState
567 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
568 aug_type_to_state: '$' KW_To
569 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
571 aug_type_to_state: TK_FinalToState
572 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
573 aug_type_to_state: '%' KW_To
574 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
576 aug_type_to_state: TK_NotFinalToState
577 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
578 aug_type_to_state: '@' KW_To
579 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
581 aug_type_to_state: TK_MiddleToState
582 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
583 aug_type_to_state: TK_Middle KW_To
584 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
587 # From state actions.
590 nonterm aug_type_from_state uses aug_type;
592 aug_type_from_state: TK_StartFromState
593 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
594 aug_type_from_state: '>' KW_From
595 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
597 aug_type_from_state: TK_NotStartFromState
598 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
599 aug_type_from_state: '<' KW_From
600 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
602 aug_type_from_state: TK_AllFromState
603 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
604 aug_type_from_state: '$' KW_From
605 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
607 aug_type_from_state: TK_FinalFromState
608 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
609 aug_type_from_state: '%' KW_From
610 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
612 aug_type_from_state: TK_NotFinalFromState
613 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
614 aug_type_from_state: '@' KW_From
615 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
617 aug_type_from_state: TK_MiddleFromState
618 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
619 aug_type_from_state: TK_Middle KW_From
620 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
626 nonterm aug_type_eof uses aug_type;
628 aug_type_eof: TK_StartEOF
629 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
630 aug_type_eof: '>' KW_Eof
631 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
633 aug_type_eof: TK_NotStartEOF
634 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
635 aug_type_eof: '<' KW_Eof
636 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
638 aug_type_eof: TK_AllEOF
639 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
640 aug_type_eof: '$' KW_Eof
641 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
643 aug_type_eof: TK_FinalEOF
644 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
645 aug_type_eof: '%' KW_Eof
646 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
648 aug_type_eof: TK_NotFinalEOF
649 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
650 aug_type_eof: '@' KW_Eof
651 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
653 aug_type_eof: TK_MiddleEOF
654 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
655 aug_type_eof: TK_Middle KW_Eof
656 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
659 # Global error actions.
662 nonterm aug_type_gbl_error uses aug_type;
664 aug_type_gbl_error: TK_StartGblError
665 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
666 aug_type_gbl_error: '>' KW_Err
667 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
669 aug_type_gbl_error: TK_NotStartGblError
670 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
671 aug_type_gbl_error: '<' KW_Err
672 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
674 aug_type_gbl_error: TK_AllGblError
675 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
676 aug_type_gbl_error: '$' KW_Err
677 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
679 aug_type_gbl_error: TK_FinalGblError
680 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
681 aug_type_gbl_error: '%' KW_Err
682 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
684 aug_type_gbl_error: TK_NotFinalGblError
685 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
686 aug_type_gbl_error: '@' KW_Err
687 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
689 aug_type_gbl_error: TK_MiddleGblError
690 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
691 aug_type_gbl_error: TK_Middle KW_Err
692 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
696 # Local error actions.
699 nonterm aug_type_local_error uses aug_type;
701 aug_type_local_error: TK_StartLocalError
702 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
703 aug_type_local_error: '>' KW_Lerr
704 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
706 aug_type_local_error: TK_NotStartLocalError
707 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
708 aug_type_local_error: '<' KW_Lerr
709 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
711 aug_type_local_error: TK_AllLocalError
712 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
713 aug_type_local_error: '$' KW_Lerr
714 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
716 aug_type_local_error: TK_FinalLocalError
717 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
718 aug_type_local_error: '%' KW_Lerr
719 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
721 aug_type_local_error: TK_NotFinalLocalError
722 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
723 aug_type_local_error: '@' KW_Lerr
724 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
726 aug_type_local_error: TK_MiddleLocalError
727 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
728 aug_type_local_error: TK_Middle KW_Lerr
729 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
737 # Different ways to embed actions. A TK_Word is reference to an action given by
738 # the user as a statement in the fsm specification. An action can also be
739 # specified immediately.
740 nonterm action_embed uses action_ref;
742 action_embed: action_embed_word final { $$->action = $1->action; };
743 action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
744 action_embed: action_embed_block final { $$->action = $1->action; };
746 nonterm action_embed_word uses action_ref;
750 /* Set the name in the actionDict. */
751 Action *action = pd->actionDict.find( $1->data );
753 /* Pass up the action element */
757 /* Will recover by returning null as the action. */
758 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
763 nonterm action_embed_block uses action_ref;
766 '{' inline_block '}' final {
767 /* Create the action, add it to the list and pass up. */
768 Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
769 pd->actionList.append( newAction );
770 $$->action = newAction;
773 nonterm priority_name
778 # A specified priority name. Looks up the name in the current priority
782 // Lookup/create the priority key.
783 PriorDictEl *priorDictEl;
784 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
785 pd->nextPriorKey += 1;
787 // Use the inserted/found priority key.
788 $$->priorityName = priorDictEl->value;
796 # Priority change specs.
798 priority_aug_num final {
799 // Convert the priority number to a long. Check for overflow.
801 //cerr << "PRIOR AUG: " << $1->token.data << endl;
802 long aug = strtol( $1->token.data, 0, 10 );
803 if ( errno == ERANGE && aug == LONG_MAX ) {
804 /* Priority number too large. Recover by setting the priority to 0. */
805 error($1->token.loc) << "priority number " << $1->token.data <<
806 " overflows" << endl;
809 else if ( errno == ERANGE && aug == LONG_MIN ) {
810 /* Priority number too large in the neg. Recover by using 0. */
811 error($1->token.loc) << "priority number " << $1->token.data <<
812 " underflows" << endl;
816 /* No overflow or underflow. */
817 $$->priorityNum = aug;
821 nonterm priority_aug_num uses token_type;
829 $$->token.set( "+", 1 );
830 $$->token.loc = $1->loc;
831 $$->token.append( *$2 );
835 $$->token.set( "-", 1 );
836 $$->token.loc = $1->loc;
837 $$->token.append( *$2 );
840 nonterm local_err_name
847 /* Lookup/create the priority key. */
848 LocalErrDictEl *localErrDictEl;
849 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
850 pd->nextLocalErrKey += 1;
852 /* Use the inserted/found priority key. */
853 $$->error_name = localErrDictEl->value;
858 # The fourth level of precedence. These are the trailing unary operators that
859 # allow for repetition.
861 nonterm factor_with_rep
863 FactorWithRep *factorWithRep;
867 factor_with_rep '*' final {
868 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
869 0, 0, FactorWithRep::StarType );
872 factor_with_rep TK_StarStar final {
873 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
874 0, 0, FactorWithRep::StarStarType );
877 factor_with_rep '?' final {
878 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
879 0, 0, FactorWithRep::OptionalType );
882 factor_with_rep '+' final {
883 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
884 0, 0, FactorWithRep::PlusType );
887 factor_with_rep '{' factor_rep_num '}' final {
888 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
889 $3->rep, 0, FactorWithRep::ExactType );
892 factor_with_rep '{' ',' factor_rep_num '}' final {
893 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
894 0, $4->rep, FactorWithRep::MaxType );
897 factor_with_rep '{' factor_rep_num ',' '}' final {
898 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
899 $3->rep, 0, FactorWithRep::MinType );
902 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
903 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
904 $3->rep, $5->rep, FactorWithRep::RangeType );
907 factor_with_neg final {
908 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
911 nonterm factor_rep_num
918 // Convert the priority number to a long. Check for overflow.
920 long rep = strtol( $1->data, 0, 10 );
921 if ( errno == ERANGE && rep == LONG_MAX ) {
922 // Repetition too large. Recover by returing repetition 1. */
923 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
927 // Cannot be negative, so no overflow.
934 # The fifth level up in precedence. Negation.
937 nonterm factor_with_neg
939 FactorWithNeg *factorWithNeg;
943 '!' factor_with_neg final {
944 $$->factorWithNeg = new FactorWithNeg( $1->loc,
945 $2->factorWithNeg, FactorWithNeg::NegateType );
948 '^' factor_with_neg final {
949 $$->factorWithNeg = new FactorWithNeg( $1->loc,
950 $2->factorWithNeg, FactorWithNeg::CharNegateType );
954 $$->factorWithNeg = new FactorWithNeg( $1->factor );
964 /* Create a new factor node going to a concat literal. */
965 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
969 /* Create a new factor node going to a literal number. */
970 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
974 /* Find the named graph. */
975 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
977 /* Recover by returning null as the factor node. */
978 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
981 else if ( gdNode->isInstance ) {
982 /* Recover by retuning null as the factor node. */
983 error($1->loc) << "references to graph instantiations not allowed "
984 "in expressions" << endl;
988 /* Create a factor node that is a lookup of an expression. */
989 $$->factor = new Factor( $1->loc, gdNode->value );
993 RE_SqOpen regular_expr_or_data RE_SqClose final {
994 /* Create a new factor node going to an OR expression. */
995 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
998 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
999 /* Create a new factor node going to a negated OR expression. */
1000 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
1003 RE_Slash regular_expr RE_Slash final {
1004 if ( $3->length > 1 ) {
1005 for ( char *p = $3->data; *p != 0; p++ ) {
1007 $2->regExpr->caseInsensitive = true;
1011 /* Create a new factor node going to a regular exp. */
1012 $$->factor = new Factor( $2->regExpr );
1015 range_lit TK_DotDot range_lit final {
1016 /* Create a new factor node going to a range. */
1017 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
1020 '(' join ')' final {
1021 /* Create a new factor going to a parenthesized join. */
1022 $$->factor = new Factor( $2->join );
1030 # Literals which can be the end points of ranges.
1033 /* Range literas must have only one char. We restrict this in the parse tree. */
1034 $$->literal = new Literal( *$1, Literal::LitString );
1037 alphabet_num final {
1038 /* Create a new literal number. */
1039 $$->literal = new Literal( $1->token, Literal::Number );
1042 nonterm alphabet_num uses token_type;
1044 # Any form of a number that can be used as a basic machine. */
1051 $$->token.set( "-", 1 );
1052 $$->token.loc = $1->loc;
1053 $$->token.append( *$2 );
1060 # Regular Expressions.
1063 nonterm regular_expr
1068 # Parser for regular expression fsms. Any number of expression items which
1069 # generally gives a machine one character long or one character long stared.
1071 regular_expr regular_expr_item final {
1072 /* An optimization to lessen the tree size. If a non-starred char is
1073 * directly under the left side on the right and the right side is
1074 * another non-starred char then paste them together and return the
1075 * left side. Otherwise just put the two under a new reg exp node. */
1076 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
1077 $1->regExpr->type == RegExpr::RecurseItem &&
1078 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1080 /* Append the right side to the right side of the left and toss the
1082 $1->regExpr->item->token.append( $2->reItem->token );
1084 $$->regExpr = $1->regExpr;
1087 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1092 /* Can't optimize the tree. */
1093 $$->regExpr = new RegExpr();
1096 nonterm regular_expr_item
1101 # RegularExprItems can be a character spec with an optional staring of the char.
1103 regular_expr_char RE_Star final {
1104 $1->reItem->star = true;
1105 $$->reItem = $1->reItem;
1108 regular_expr_char final {
1109 $$->reItem = $1->reItem;
1112 nonterm regular_expr_char
1117 # A character spec can be a set of characters inside of square parenthesis, a
1118 # dot specifying any character or some explicitly stated character.
1120 RE_SqOpen regular_expr_or_data RE_SqClose final {
1121 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1124 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1125 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1129 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1133 $$->reItem = new ReItem( $1->loc, *$1 );
1136 # The data inside of a [] expression in a regular expression. Accepts any
1137 # number of characters or ranges. */
1138 nonterm regular_expr_or_data
1140 ReOrBlock *reOrBlock;
1143 regular_expr_or_data:
1144 regular_expr_or_data regular_expr_or_char final {
1145 /* An optimization to lessen the tree size. If an or char is directly
1146 * under the left side on the right and the right side is another or
1147 * char then paste them together and return the left side. Otherwise
1148 * just put the two under a new or data node. */
1149 if ( $2->reOrItem->type == ReOrItem::Data &&
1150 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1151 $1->reOrBlock->item->type == ReOrItem::Data )
1153 /* Append the right side to right side of the left and toss the
1155 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1156 delete $2->reOrItem;
1157 $$->reOrBlock = $1->reOrBlock;
1160 /* Can't optimize, put the left and right under a new node. */
1161 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1164 regular_expr_or_data:
1166 $$->reOrBlock = new ReOrBlock();
1169 # A single character inside of an or expression. Can either be a character or a
1170 # set of characters.
1171 nonterm regular_expr_or_char
1176 regular_expr_or_char:
1178 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1180 regular_expr_or_char:
1181 RE_Char RE_Dash RE_Char final {
1182 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1186 # Inline Lists for inline host code.
1191 InlineList *inlineList;
1194 nonterm inline_block uses inline_list;
1197 inline_block inline_block_item
1199 /* Append the item to the list, return the list. */
1200 $$->inlineList = $1->inlineList;
1201 $$->inlineList->append( $2->inlineItem );
1206 /* Start with empty list. */
1207 $$->inlineList = new InlineList;
1212 InlineItem *inlineItem;
1215 nonterm inline_block_item uses inline_item;
1216 nonterm inline_block_interpret uses inline_item;
1221 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1227 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1231 inline_block_interpret
1233 /* Pass the inline item up. */
1234 $$->inlineItem = $1->inlineItem;
1237 nonterm inline_block_symbol uses token_type;
1239 inline_block_symbol: ',' final { $$->token = *$1; };
1240 inline_block_symbol: ';' final { $$->token = *$1; };
1241 inline_block_symbol: '(' final { $$->token = *$1; };
1242 inline_block_symbol: ')' final { $$->token = *$1; };
1243 inline_block_symbol: '*' final { $$->token = *$1; };
1244 inline_block_symbol: TK_NameSep final { $$->token = *$1; };
1246 # Interpreted statements in a struct block. */
1247 inline_block_interpret:
1248 inline_expr_interpret final {
1249 /* Pass up interpreted items of inline expressions. */
1250 $$->inlineItem = $1->inlineItem;
1252 inline_block_interpret:
1254 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1256 inline_block_interpret:
1257 KW_Exec inline_expr ';' final {
1258 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1259 $$->inlineItem->children = $2->inlineList;
1261 inline_block_interpret:
1262 KW_Goto state_ref ';' final {
1263 $$->inlineItem = new InlineItem( $1->loc,
1264 new NameRef(nameRef), InlineItem::Goto );
1266 inline_block_interpret:
1267 KW_Goto '*' inline_expr ';' final {
1268 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1269 $$->inlineItem->children = $3->inlineList;
1271 inline_block_interpret:
1272 KW_Next state_ref ';' final {
1273 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1275 inline_block_interpret:
1276 KW_Next '*' inline_expr ';' final {
1277 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1278 $$->inlineItem->children = $3->inlineList;
1280 inline_block_interpret:
1281 KW_Call state_ref ';' final {
1282 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1284 inline_block_interpret:
1285 KW_Call '*' inline_expr ';' final {
1286 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1287 $$->inlineItem->children = $3->inlineList;
1289 inline_block_interpret:
1291 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1293 inline_block_interpret:
1294 KW_Break ';' final {
1295 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1298 nonterm inline_expr uses inline_list;
1301 inline_expr inline_expr_item
1303 $$->inlineList = $1->inlineList;
1304 $$->inlineList->append( $2->inlineItem );
1308 /* Init the list used for this expr. */
1309 $$->inlineList = new InlineList;
1312 nonterm inline_expr_item uses inline_item;
1317 /* Return a text segment. */
1318 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1323 /* Return a text segment, must heap alloc the text. */
1324 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1327 inline_expr_interpret
1329 /* Pass the inline item up. */
1330 $$->inlineItem = $1->inlineItem;
1333 nonterm inline_expr_any uses token_type;
1335 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1336 inline_expr_any: IL_Comment try { $$->token = *$1; };
1337 inline_expr_any: IL_Literal try { $$->token = *$1; };
1338 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1339 inline_expr_any: TK_UInt try { $$->token = *$1; };
1340 inline_expr_any: TK_Hex try { $$->token = *$1; };
1341 inline_expr_any: TK_Word try { $$->token = *$1; };
1343 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1344 # all special symbols caught in inline code except the semi.
1346 nonterm inline_expr_symbol uses token_type;
1348 inline_expr_symbol: ',' try { $$->token = *$1; };
1349 inline_expr_symbol: '(' try { $$->token = *$1; };
1350 inline_expr_symbol: ')' try { $$->token = *$1; };
1351 inline_expr_symbol: '*' try { $$->token = *$1; };
1352 inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
1354 nonterm inline_expr_interpret uses inline_item;
1356 inline_expr_interpret:
1359 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1361 inline_expr_interpret:
1364 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1366 inline_expr_interpret:
1369 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1371 inline_expr_interpret:
1374 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1376 inline_expr_interpret:
1377 KW_Entry '(' state_ref ')'
1379 $$->inlineItem = new InlineItem( $1->loc,
1380 new NameRef(nameRef), InlineItem::Entry );
1383 # A local state reference. Cannot have :: prefix.
1385 no_name_sep state_ref_names;
1387 # Clear the name ref structure.
1393 # A qualified state reference.
1394 state_ref: opt_name_sep state_ref_names;
1396 # Optional leading name separator.
1400 /* Insert an initial null pointer val to indicate the existence of the
1401 * initial name seperator. */
1409 # List of names separated by ::
1411 state_ref_names TK_NameSep TK_Word
1413 nameRef.append( $3->data );
1418 nameRef.append( $1->data );
1433 int Parser::parseLangEl( int type, const Token *token )
1436 return errCount == 0 ? 0 : -1;
1439 void Parser::tryMachineDef( InputLoc &loc, char *name,
1440 JoinOrLm *joinOrLm, bool isInstance )
1442 GraphDictEl *newEl = pd->graphDict.insert( name );
1444 /* New element in the dict, all good. */
1445 newEl->value = new VarDef( name, joinOrLm );
1446 newEl->isInstance = isInstance;
1448 newEl->value->isExport = exportContext[exportContext.length()-1];
1450 /* It it is an instance, put on the instance list. */
1452 pd->instanceList.append( newEl );
1455 // Recover by ignoring the duplicate.
1456 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1460 ostream &Parser::parse_error( int tokId, Token &token )
1462 /* Maintain the error count. */
1465 cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
1466 cerr << "at token ";
1468 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1470 cerr << Parser_lelNames[tokId];
1471 if ( token.data != 0 )
1472 cerr << " with data \"" << token.data << "\"";
1478 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1481 token.data = tokstart;
1482 token.length = toklen;
1484 int res = parseLangEl( tokId, &token );
1486 parse_error(tokId, token) << "parse error" << endl;