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: entry_block commit;
59 export_open: KW_Export
61 exportContext.append( true );
69 opt_export: export_open final { $$->isSet = true; };
70 opt_export: final { $$->isSet = false; };
72 export_block: export_open '{' statement_list '}'
74 exportContext.remove( exportContext.length()-1 );
84 entryContext.append( true );
87 opt_entry: entry_open final { $$->isSet = true; };
88 opt_entry: final { $$->isSet = false; };
90 entry_block: entry_open '{' statement_list '}'
92 entryContext.remove( entryContext.length()-1 );
96 opt_export opt_entry machine_name '=' join ';' final {
97 /* Main machine must be an instance. */
98 bool isInstance = false;
99 if ( strcmp($3->token.data, machineMain) == 0 ) {
100 warning($3->token.loc) <<
101 "main machine will be implicitly instantiated" << endl;
105 /* Generic creation of machine for instantiation and assignment. */
106 JoinOrLm *joinOrLm = new JoinOrLm( $5->join );
107 tryMachineDef( $3->token.loc, $3->token.data, joinOrLm, isInstance );
110 exportContext.remove( exportContext.length()-1 );
112 entryContext.remove( entryContext.length()-1 );
116 opt_export opt_entry machine_name TK_ColonEquals join_or_lm ';' final {
117 /* Generic creation of machine for instantiation and assignment. */
118 tryMachineDef( $3->token.loc, $3->token.data, $5->joinOrLm, true );
121 exportContext.remove( exportContext.length()-1 );
123 entryContext.remove( entryContext.length()-1 );
131 nonterm machine_name uses token_type;
135 /* Make/get the priority key. The name may have already been referenced
136 * and therefore exist. */
137 PriorDictEl *priorDictEl;
138 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
139 pd->nextPriorKey += 1;
140 pd->curDefPriorKey = priorDictEl->value;
142 /* Make/get the local error key. */
143 LocalErrDictEl *localErrDictEl;
144 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
145 pd->nextLocalErrKey += 1;
146 pd->curDefLocalErrKey = localErrDictEl->value;
152 KW_Action TK_Word '{' inline_block '}' final {
153 if ( pd->actionDict.find( $2->data ) ) {
154 /* Recover by just ignoring the duplicate. */
155 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
158 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
159 /* Add the action to the list of actions. */
160 Action *newAction = new Action( $3->loc, $2->data,
161 $4->inlineList, pd->nextCondId++ );
163 /* Insert to list and dict. */
164 pd->actionList.append( newAction );
165 pd->actionDict.insert( newAction );
169 # Specifies the data type of the input alphabet. One or two words followed by a
172 KW_AlphType TK_Word TK_Word ';' final {
173 if ( ! pd->setAlphType( $2->data, $3->data ) ) {
174 // Recover by ignoring the alphtype statement.
175 error($2->loc) << "\"" << $2->data <<
176 " " << $3->data << "\" is not a valid alphabet type" << endl;
181 KW_AlphType TK_Word ';' final {
182 if ( ! pd->setAlphType( $2->data ) ) {
183 // Recover by ignoring the alphtype statement.
184 error($2->loc) << "\"" << $2->data <<
185 "\" is not a valid alphabet type" << endl;
189 # Specifies a range to assume that the input characters will fall into.
191 KW_Range alphabet_num alphabet_num ';' final {
192 // Save the upper and lower ends of the range and emit the line number.
193 pd->lowerNum = $2->token.data;
194 pd->upperNum = $3->token.data;
195 pd->rangeLowLoc = $2->token.loc;
196 pd->rangeHighLoc = $3->token.loc;
200 KW_GetKey inline_expr ';' final {
201 pd->getKeyExpr = $2->inlineList;
205 KW_Access inline_expr ';' final {
206 pd->accessExpr = $2->inlineList;
210 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
211 /* FIXME: Need to implement the rest of this. */
212 if ( strcmp( $3->data, "curstate" ) == 0 )
213 pd->curStateExpr = $4->inlineList;
215 error($3->loc) << "sorry, unimplementd" << endl;
219 opt_whitespace: opt_whitespace IL_WhiteSpace;
233 $$->joinOrLm = new JoinOrLm( $1->join );
236 TK_BarStar lm_part_list '*' '|' final {
237 /* Create a new factor going to a longest match structure. Record
238 * in the parse data that we have a longest match. */
239 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
240 pd->lmList.append( lm );
241 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
242 lmp->longestMatch = lm;
243 $$->joinOrLm = new JoinOrLm( lm );
248 LmPartList *lmPartList;
252 lm_part_list longest_match_part final {
253 if ( $2->lmPart != 0 )
254 $1->lmPartList->append( $2->lmPart );
255 $$->lmPartList = $1->lmPartList;
258 longest_match_part final {
259 /* Create a new list with the part. */
260 $$->lmPartList = new LmPartList;
261 if ( $1->lmPart != 0 )
262 $$->lmPartList->append( $1->lmPart );
265 nonterm longest_match_part
267 LongestMatchPart *lmPart;
271 action_spec final { $$->lmPart = 0; };
273 assignment final { $$->lmPart = 0; };
275 join opt_lm_part_action ';' final {
277 Action *action = $2->action;
279 action->isLmAction = true;
280 $$->lmPart = new LongestMatchPart( $1->join, action,
281 $3->loc, pd->nextLongestMatchId++ );
284 nonterm opt_lm_part_action
290 TK_DoubleArrow action_embed final {
291 $$->action = $2->action;
294 action_embed_block final {
295 $$->action = $1->action;
309 join ',' expression final {
310 /* Append the expression to the list and return it. */
311 $1->join->exprList.append( $3->expression );
316 $$->join = new Join( $1->expression );
321 Expression *expression;
325 expression '|' term final {
326 $$->expression = new Expression( $1->expression,
327 $3->term, Expression::OrType );
330 expression '&' term final {
331 $$->expression = new Expression( $1->expression,
332 $3->term, Expression::IntersectType );
334 # This priority specification overrides the innermost parsing strategy which
335 # results ordered choice interpretation of the grammar.
337 expression pri(1) '-' term final {
338 $$->expression = new Expression( $1->expression,
339 $3->term, Expression::SubtractType );
342 expression TK_DashDash term final {
343 $$->expression = new Expression( $1->expression,
344 $3->term, Expression::StrongSubtractType );
348 $$->expression = new Expression( $1->term );
357 term factor_with_label final {
358 $$->term = new Term( $1->term, $2->factorWithAug );
361 term '.' factor_with_label final {
362 $$->term = new Term( $1->term, $3->factorWithAug );
365 term TK_ColonGt factor_with_label final {
366 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
369 term TK_ColonGtGt factor_with_label final {
370 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
373 term TK_LtColon factor_with_label final {
374 $$->term = new Term( $1->term,
375 $3->factorWithAug, Term::LeftType );
378 factor_with_label final {
379 $$->term = new Term( $1->factorWithAug );
382 nonterm factor_with_label
384 FactorWithAug *factorWithAug;
388 TK_Word ':' factor_with_label final {
389 /* Add the label to the list and pass the factor up. */
390 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
391 $$->factorWithAug = $3->factorWithAug;
394 factor_with_ep final {
395 $$->factorWithAug = $1->factorWithAug;
398 nonterm factor_with_ep
400 FactorWithAug *factorWithAug;
404 factor_with_ep TK_Arrow local_state_ref final {
405 /* Add the target to the list and return the factor object. */
406 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
407 $$->factorWithAug = $1->factorWithAug;
410 factor_with_aug final {
411 $$->factorWithAug = $1->factorWithAug;
414 nonterm factor_with_aug
416 FactorWithAug *factorWithAug;
420 factor_with_aug aug_type_base action_embed final {
421 /* Append the action to the factorWithAug, record the refernce from
422 * factorWithAug to the action and pass up the factorWithAug. */
423 $1->factorWithAug->actions.append(
424 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
425 $$->factorWithAug = $1->factorWithAug;
428 factor_with_aug aug_type_base priority_aug final {
429 /* Append the named priority to the factorWithAug and pass it up. */
430 $1->factorWithAug->priorityAugs.append(
431 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
432 $$->factorWithAug = $1->factorWithAug;
435 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
436 /* Append the priority using a default name. */
437 $1->factorWithAug->priorityAugs.append(
438 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
439 $$->factorWithAug = $1->factorWithAug;
442 factor_with_aug aug_type_cond action_embed final {
443 $1->factorWithAug->conditions.append( ParserAction( $2->loc,
444 $2->augType, 0, $3->action ) );
445 $$->factorWithAug = $1->factorWithAug;
448 factor_with_aug aug_type_to_state action_embed final {
449 /* Append the action, pass it up. */
450 $1->factorWithAug->actions.append( ParserAction( $2->loc,
451 $2->augType, 0, $3->action ) );
452 $$->factorWithAug = $1->factorWithAug;
455 factor_with_aug aug_type_from_state action_embed final {
456 /* Append the action, pass it up. */
457 $1->factorWithAug->actions.append( ParserAction( $2->loc,
458 $2->augType, 0, $3->action ) );
459 $$->factorWithAug = $1->factorWithAug;
462 factor_with_aug aug_type_eof action_embed final {
463 /* Append the action, pass it up. */
464 $1->factorWithAug->actions.append( ParserAction( $2->loc,
465 $2->augType, 0, $3->action ) );
466 $$->factorWithAug = $1->factorWithAug;
469 factor_with_aug aug_type_gbl_error action_embed final {
470 /* Append the action to the factorWithAug, record the refernce from
471 * factorWithAug to the action and pass up the factorWithAug. */
472 $1->factorWithAug->actions.append( ParserAction( $2->loc,
473 $2->augType, pd->curDefLocalErrKey, $3->action ) );
474 $$->factorWithAug = $1->factorWithAug;
477 factor_with_aug aug_type_local_error action_embed final {
478 /* Append the action to the factorWithAug, record the refernce from
479 * factorWithAug to the action and pass up the factorWithAug. */
480 $1->factorWithAug->actions.append( ParserAction( $2->loc,
481 $2->augType, pd->curDefLocalErrKey, $3->action ) );
482 $$->factorWithAug = $1->factorWithAug;
485 factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
486 /* Append the action to the factorWithAug, record the refernce from
487 * factorWithAug to the action and pass up the factorWithAug. */
488 $1->factorWithAug->actions.append( ParserAction( $2->loc,
489 $2->augType, $4->error_name, $6->action ) );
490 $$->factorWithAug = $1->factorWithAug;
493 factor_with_rep final {
494 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
503 # Classes of transtions on which to embed actions or change priorities.
504 nonterm aug_type_base uses aug_type;
506 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
507 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
508 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
509 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
511 # Embedding conditions.
512 nonterm aug_type_cond uses aug_type;
514 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
515 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
516 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
517 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
518 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
519 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
520 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
526 nonterm aug_type_to_state uses aug_type;
528 aug_type_to_state: TK_StartToState
529 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
530 aug_type_to_state: '>' KW_To
531 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
533 aug_type_to_state: TK_NotStartToState
534 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
535 aug_type_to_state: '<' KW_To
536 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
538 aug_type_to_state: TK_AllToState
539 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
540 aug_type_to_state: '$' KW_To
541 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
543 aug_type_to_state: TK_FinalToState
544 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
545 aug_type_to_state: '%' KW_To
546 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
548 aug_type_to_state: TK_NotFinalToState
549 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
550 aug_type_to_state: '@' KW_To
551 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
553 aug_type_to_state: TK_MiddleToState
554 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
555 aug_type_to_state: TK_Middle KW_To
556 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
559 # From state actions.
562 nonterm aug_type_from_state uses aug_type;
564 aug_type_from_state: TK_StartFromState
565 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
566 aug_type_from_state: '>' KW_From
567 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
569 aug_type_from_state: TK_NotStartFromState
570 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
571 aug_type_from_state: '<' KW_From
572 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
574 aug_type_from_state: TK_AllFromState
575 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
576 aug_type_from_state: '$' KW_From
577 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
579 aug_type_from_state: TK_FinalFromState
580 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
581 aug_type_from_state: '%' KW_From
582 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
584 aug_type_from_state: TK_NotFinalFromState
585 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
586 aug_type_from_state: '@' KW_From
587 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
589 aug_type_from_state: TK_MiddleFromState
590 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
591 aug_type_from_state: TK_Middle KW_From
592 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
598 nonterm aug_type_eof uses aug_type;
600 aug_type_eof: TK_StartEOF
601 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
602 aug_type_eof: '>' KW_Eof
603 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
605 aug_type_eof: TK_NotStartEOF
606 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
607 aug_type_eof: '<' KW_Eof
608 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
610 aug_type_eof: TK_AllEOF
611 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
612 aug_type_eof: '$' KW_Eof
613 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
615 aug_type_eof: TK_FinalEOF
616 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
617 aug_type_eof: '%' KW_Eof
618 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
620 aug_type_eof: TK_NotFinalEOF
621 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
622 aug_type_eof: '@' KW_Eof
623 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
625 aug_type_eof: TK_MiddleEOF
626 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
627 aug_type_eof: TK_Middle KW_Eof
628 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
631 # Global error actions.
634 nonterm aug_type_gbl_error uses aug_type;
636 aug_type_gbl_error: TK_StartGblError
637 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
638 aug_type_gbl_error: '>' KW_Err
639 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
641 aug_type_gbl_error: TK_NotStartGblError
642 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
643 aug_type_gbl_error: '<' KW_Err
644 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
646 aug_type_gbl_error: TK_AllGblError
647 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
648 aug_type_gbl_error: '$' KW_Err
649 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
651 aug_type_gbl_error: TK_FinalGblError
652 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
653 aug_type_gbl_error: '%' KW_Err
654 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
656 aug_type_gbl_error: TK_NotFinalGblError
657 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
658 aug_type_gbl_error: '@' KW_Err
659 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
661 aug_type_gbl_error: TK_MiddleGblError
662 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
663 aug_type_gbl_error: TK_Middle KW_Err
664 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
668 # Local error actions.
671 nonterm aug_type_local_error uses aug_type;
673 aug_type_local_error: TK_StartLocalError
674 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
675 aug_type_local_error: '>' KW_Lerr
676 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
678 aug_type_local_error: TK_NotStartLocalError
679 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
680 aug_type_local_error: '<' KW_Lerr
681 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
683 aug_type_local_error: TK_AllLocalError
684 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
685 aug_type_local_error: '$' KW_Lerr
686 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
688 aug_type_local_error: TK_FinalLocalError
689 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
690 aug_type_local_error: '%' KW_Lerr
691 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
693 aug_type_local_error: TK_NotFinalLocalError
694 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
695 aug_type_local_error: '@' KW_Lerr
696 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
698 aug_type_local_error: TK_MiddleLocalError
699 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
700 aug_type_local_error: TK_Middle KW_Lerr
701 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
709 # Different ways to embed actions. A TK_Word is reference to an action given by
710 # the user as a statement in the fsm specification. An action can also be
711 # specified immediately.
712 nonterm action_embed uses action_ref;
714 action_embed: action_embed_word final { $$->action = $1->action; };
715 action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
716 action_embed: action_embed_block final { $$->action = $1->action; };
718 nonterm action_embed_word uses action_ref;
722 /* Set the name in the actionDict. */
723 Action *action = pd->actionDict.find( $1->data );
725 /* Pass up the action element */
729 /* Will recover by returning null as the action. */
730 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
735 nonterm action_embed_block uses action_ref;
738 '{' inline_block '}' final {
739 /* Create the action, add it to the list and pass up. */
740 Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
741 pd->actionList.append( newAction );
742 $$->action = newAction;
745 nonterm priority_name
750 # A specified priority name. Looks up the name in the current priority
754 // Lookup/create the priority key.
755 PriorDictEl *priorDictEl;
756 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
757 pd->nextPriorKey += 1;
759 // Use the inserted/found priority key.
760 $$->priorityName = priorDictEl->value;
768 # Priority change specs.
770 priority_aug_num final {
771 // Convert the priority number to a long. Check for overflow.
773 //cerr << "PRIOR AUG: " << $1->token.data << endl;
774 int aug = strtol( $1->token.data, 0, 10 );
775 if ( errno == ERANGE && aug == LONG_MAX ) {
776 /* Priority number too large. Recover by setting the priority to 0. */
777 error($1->token.loc) << "priority number " << $1->token.data <<
778 " overflows" << endl;
781 else if ( errno == ERANGE && aug == LONG_MIN ) {
782 /* Priority number too large in the neg. Recover by using 0. */
783 error($1->token.loc) << "priority number " << $1->token.data <<
784 " underflows" << endl;
788 /* No overflow or underflow. */
789 $$->priorityNum = aug;
793 nonterm priority_aug_num uses token_type;
801 $$->token.set( "+", 1 );
802 $$->token.loc = $1->loc;
803 $$->token.append( *$2 );
807 $$->token.set( "-", 1 );
808 $$->token.loc = $1->loc;
809 $$->token.append( *$2 );
812 nonterm local_err_name
819 /* Lookup/create the priority key. */
820 LocalErrDictEl *localErrDictEl;
821 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
822 pd->nextLocalErrKey += 1;
824 /* Use the inserted/found priority key. */
825 $$->error_name = localErrDictEl->value;
830 # The fourth level of precedence. These are the trailing unary operators that
831 # allow for repetition.
833 nonterm factor_with_rep
835 FactorWithRep *factorWithRep;
839 factor_with_rep '*' final {
840 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
841 0, 0, FactorWithRep::StarType );
844 factor_with_rep TK_StarStar final {
845 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
846 0, 0, FactorWithRep::StarStarType );
849 factor_with_rep '?' final {
850 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
851 0, 0, FactorWithRep::OptionalType );
854 factor_with_rep '+' final {
855 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
856 0, 0, FactorWithRep::PlusType );
859 factor_with_rep '{' factor_rep_num '}' final {
860 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
861 $3->rep, 0, FactorWithRep::ExactType );
864 factor_with_rep '{' ',' factor_rep_num '}' final {
865 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
866 0, $4->rep, FactorWithRep::MaxType );
869 factor_with_rep '{' factor_rep_num ',' '}' final {
870 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
871 $3->rep, 0, FactorWithRep::MinType );
874 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
875 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
876 $3->rep, $5->rep, FactorWithRep::RangeType );
879 factor_with_neg final {
880 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
883 nonterm factor_rep_num
890 // Convert the priority number to a long. Check for overflow.
892 int rep = strtol( $1->data, 0, 10 );
893 if ( errno == ERANGE && rep == LONG_MAX ) {
894 // Repetition too large. Recover by returing repetition 1. */
895 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
899 // Cannot be negative, so no overflow.
906 # The fifth level up in precedence. Negation.
909 nonterm factor_with_neg
911 FactorWithNeg *factorWithNeg;
915 '!' factor_with_neg final {
916 $$->factorWithNeg = new FactorWithNeg( $1->loc,
917 $2->factorWithNeg, FactorWithNeg::NegateType );
920 '^' factor_with_neg final {
921 $$->factorWithNeg = new FactorWithNeg( $1->loc,
922 $2->factorWithNeg, FactorWithNeg::CharNegateType );
926 $$->factorWithNeg = new FactorWithNeg( $1->factor );
936 /* Create a new factor node going to a concat literal. */
937 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
941 /* Create a new factor node going to a literal number. */
942 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
946 /* Find the named graph. */
947 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
949 /* Recover by returning null as the factor node. */
950 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
953 else if ( gdNode->isInstance ) {
954 /* Recover by retuning null as the factor node. */
955 error($1->loc) << "references to graph instantiations not allowed "
956 "in expressions" << endl;
960 /* Create a factor node that is a lookup of an expression. */
961 $$->factor = new Factor( $1->loc, gdNode->value );
965 RE_SqOpen regular_expr_or_data RE_SqClose final {
966 /* Create a new factor node going to an OR expression. */
967 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
970 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
971 /* Create a new factor node going to a negated OR expression. */
972 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
975 RE_Slash regular_expr RE_Slash final {
976 if ( $3->length > 1 ) {
977 for ( char *p = $3->data; *p != 0; p++ ) {
979 $2->regExpr->caseInsensitive = true;
983 /* Create a new factor node going to a regular exp. */
984 $$->factor = new Factor( $2->regExpr );
987 range_lit TK_DotDot range_lit final {
988 /* Create a new factor node going to a range. */
989 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
993 /* Create a new factor going to a parenthesized join. */
994 $$->factor = new Factor( $2->join );
1002 # Literals which can be the end points of ranges.
1005 /* Range literas must have only one char. We restrict this in the parse tree. */
1006 $$->literal = new Literal( *$1, Literal::LitString );
1009 alphabet_num final {
1010 /* Create a new literal number. */
1011 $$->literal = new Literal( $1->token, Literal::Number );
1014 nonterm alphabet_num uses token_type;
1016 # Any form of a number that can be used as a basic machine. */
1023 $$->token.set( "-", 1 );
1024 $$->token.loc = $1->loc;
1025 $$->token.append( *$2 );
1032 # Regular Expressions.
1035 nonterm regular_expr
1040 # Parser for regular expression fsms. Any number of expression items which
1041 # generally gives a machine one character long or one character long stared.
1043 regular_expr regular_expr_item final {
1044 /* An optimization to lessen the tree size. If a non-starred char is
1045 * directly under the left side on the right and the right side is
1046 * another non-starred char then paste them together and return the
1047 * left side. Otherwise just put the two under a new reg exp node. */
1048 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
1049 $1->regExpr->type == RegExpr::RecurseItem &&
1050 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1052 /* Append the right side to the right side of the left and toss the
1054 $1->regExpr->item->token.append( $2->reItem->token );
1056 $$->regExpr = $1->regExpr;
1059 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1064 /* Can't optimize the tree. */
1065 $$->regExpr = new RegExpr();
1068 nonterm regular_expr_item
1073 # RegularExprItems can be a character spec with an optional staring of the char.
1075 regular_expr_char RE_Star final {
1076 $1->reItem->star = true;
1077 $$->reItem = $1->reItem;
1080 regular_expr_char final {
1081 $$->reItem = $1->reItem;
1084 nonterm regular_expr_char
1089 # A character spec can be a set of characters inside of square parenthesis, a
1090 # dot specifying any character or some explicitly stated character.
1092 RE_SqOpen regular_expr_or_data RE_SqClose final {
1093 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1096 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1097 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1101 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1105 $$->reItem = new ReItem( $1->loc, *$1 );
1108 # The data inside of a [] expression in a regular expression. Accepts any
1109 # number of characters or ranges. */
1110 nonterm regular_expr_or_data
1112 ReOrBlock *reOrBlock;
1115 regular_expr_or_data:
1116 regular_expr_or_data regular_expr_or_char final {
1117 /* An optimization to lessen the tree size. If an or char is directly
1118 * under the left side on the right and the right side is another or
1119 * char then paste them together and return the left side. Otherwise
1120 * just put the two under a new or data node. */
1121 if ( $2->reOrItem->type == ReOrItem::Data &&
1122 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1123 $1->reOrBlock->item->type == ReOrItem::Data )
1125 /* Append the right side to right side of the left and toss the
1127 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1128 delete $2->reOrItem;
1129 $$->reOrBlock = $1->reOrBlock;
1132 /* Can't optimize, put the left and right under a new node. */
1133 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1136 regular_expr_or_data:
1138 $$->reOrBlock = new ReOrBlock();
1141 # A single character inside of an or expression. Can either be a character or a
1142 # set of characters.
1143 nonterm regular_expr_or_char
1148 regular_expr_or_char:
1150 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1152 regular_expr_or_char:
1153 RE_Char RE_Dash RE_Char final {
1154 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1158 # Inline Lists for inline host code.
1163 InlineList *inlineList;
1166 nonterm inline_block uses inline_list;
1169 inline_block inline_block_item
1171 /* Append the item to the list, return the list. */
1172 $$->inlineList = $1->inlineList;
1173 $$->inlineList->append( $2->inlineItem );
1178 /* Start with empty list. */
1179 $$->inlineList = new InlineList;
1184 InlineItem *inlineItem;
1187 nonterm inline_block_item uses inline_item;
1188 nonterm inline_block_interpret uses inline_item;
1193 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1199 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1203 inline_block_interpret
1205 /* Pass the inline item up. */
1206 $$->inlineItem = $1->inlineItem;
1209 nonterm inline_block_symbol uses token_type;
1211 inline_block_symbol: ',' final { $$->token = *$1; };
1212 inline_block_symbol: ';' final { $$->token = *$1; };
1213 inline_block_symbol: '(' final { $$->token = *$1; };
1214 inline_block_symbol: ')' final { $$->token = *$1; };
1215 inline_block_symbol: '*' final { $$->token = *$1; };
1216 inline_block_symbol: TK_NameSep final { $$->token = *$1; };
1218 # Interpreted statements in a struct block. */
1219 inline_block_interpret:
1220 inline_expr_interpret final {
1221 /* Pass up interpreted items of inline expressions. */
1222 $$->inlineItem = $1->inlineItem;
1224 inline_block_interpret:
1226 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1228 inline_block_interpret:
1229 KW_Exec inline_expr ';' final {
1230 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1231 $$->inlineItem->children = $2->inlineList;
1233 inline_block_interpret:
1234 KW_Goto state_ref ';' final {
1235 $$->inlineItem = new InlineItem( $1->loc,
1236 new NameRef(nameRef), InlineItem::Goto );
1238 inline_block_interpret:
1239 KW_Goto '*' inline_expr ';' final {
1240 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1241 $$->inlineItem->children = $3->inlineList;
1243 inline_block_interpret:
1244 KW_Next state_ref ';' final {
1245 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1247 inline_block_interpret:
1248 KW_Next '*' inline_expr ';' final {
1249 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1250 $$->inlineItem->children = $3->inlineList;
1252 inline_block_interpret:
1253 KW_Call state_ref ';' final {
1254 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1256 inline_block_interpret:
1257 KW_Call '*' inline_expr ';' final {
1258 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1259 $$->inlineItem->children = $3->inlineList;
1261 inline_block_interpret:
1263 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1265 inline_block_interpret:
1266 KW_Break ';' final {
1267 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1270 nonterm inline_expr uses inline_list;
1273 inline_expr inline_expr_item
1275 $$->inlineList = $1->inlineList;
1276 $$->inlineList->append( $2->inlineItem );
1280 /* Init the list used for this expr. */
1281 $$->inlineList = new InlineList;
1284 nonterm inline_expr_item uses inline_item;
1289 /* Return a text segment. */
1290 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1295 /* Return a text segment, must heap alloc the text. */
1296 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1299 inline_expr_interpret
1301 /* Pass the inline item up. */
1302 $$->inlineItem = $1->inlineItem;
1305 nonterm inline_expr_any uses token_type;
1307 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1308 inline_expr_any: IL_Comment try { $$->token = *$1; };
1309 inline_expr_any: IL_Literal try { $$->token = *$1; };
1310 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1311 inline_expr_any: TK_UInt try { $$->token = *$1; };
1312 inline_expr_any: TK_Hex try { $$->token = *$1; };
1313 inline_expr_any: TK_Word try { $$->token = *$1; };
1315 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1316 # all special symbols caught in inline code except the semi.
1318 nonterm inline_expr_symbol uses token_type;
1320 inline_expr_symbol: ',' try { $$->token = *$1; };
1321 inline_expr_symbol: '(' try { $$->token = *$1; };
1322 inline_expr_symbol: ')' try { $$->token = *$1; };
1323 inline_expr_symbol: '*' try { $$->token = *$1; };
1324 inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
1326 nonterm inline_expr_interpret uses inline_item;
1328 inline_expr_interpret:
1331 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1333 inline_expr_interpret:
1336 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1338 inline_expr_interpret:
1341 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1343 inline_expr_interpret:
1346 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1348 inline_expr_interpret:
1349 KW_Entry '(' state_ref ')'
1351 $$->inlineItem = new InlineItem( $1->loc,
1352 new NameRef(nameRef), InlineItem::Entry );
1355 # A local state reference. Cannot have :: prefix.
1357 no_name_sep state_ref_names;
1359 # Clear the name ref structure.
1365 # A qualified state reference.
1366 state_ref: opt_name_sep state_ref_names;
1368 # Optional leading name separator.
1372 /* Insert an initial null pointer val to indicate the existence of the
1373 * initial name seperator. */
1381 # List of names separated by ::
1383 state_ref_names TK_NameSep TK_Word
1385 nameRef.append( $3->data );
1390 nameRef.append( $1->data );
1405 int Parser::parseLangEl( int type, const Token *token )
1408 return errCount == 0 ? 0 : -1;
1411 void Parser::tryMachineDef( InputLoc &loc, char *name,
1412 JoinOrLm *joinOrLm, bool isInstance )
1414 GraphDictEl *newEl = pd->graphDict.insert( name );
1416 /* New element in the dict, all good. */
1417 newEl->value = new VarDef( name, joinOrLm );
1418 newEl->isInstance = isInstance;
1420 newEl->value->isExport = exportContext[exportContext.length()-1];
1421 newEl->value->isEntry = entryContext[entryContext.length()-1];
1423 /* It it is an instance, put on the instance list. */
1425 pd->instanceList.append( newEl );
1428 // Recover by ignoring the duplicate.
1429 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1433 ostream &Parser::parse_error( int tokId, Token &token )
1435 /* Maintain the error count. */
1438 cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
1439 cerr << "at token ";
1441 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1443 cerr << Parser_lelNames[tokId];
1444 if ( token.data != 0 )
1445 cerr << " with data \"" << token.data << "\"";
1451 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1454 token.data = tokstart;
1455 token.length = toklen;
1457 int res = parseLangEl( tokId, &token );
1459 parse_error(tokId, token) << "parse error" << endl;