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;
58 machine_name '=' join ';' final {
59 /* Main machine must be an instance. */
60 bool isInstance = false;
61 if ( strcmp($1->token.data, machineMain) == 0 ) {
62 warning($1->token.loc) <<
63 "main machine will be implicitly instantiated" << endl;
67 /* Generic creation of machine for instantiation and assignment. */
68 JoinOrLm *joinOrLm = new JoinOrLm( $3->join );
69 tryMachineDef( $1->token.loc, $1->token.data, joinOrLm, isInstance );
73 machine_name TK_ColonEquals join_or_lm ';' final {
74 /* Generic creation of machine for instantiation and assignment. */
75 tryMachineDef( $1->token.loc, $1->token.data, $3->joinOrLm, true );
83 nonterm machine_name uses token_type;
87 /* Make/get the priority key. The name may have already been referenced
88 * and therefore exist. */
89 PriorDictEl *priorDictEl;
90 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
91 pd->nextPriorKey += 1;
92 pd->curDefPriorKey = priorDictEl->value;
94 /* Make/get the local error key. */
95 LocalErrDictEl *localErrDictEl;
96 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
97 pd->nextLocalErrKey += 1;
98 pd->curDefLocalErrKey = localErrDictEl->value;
104 KW_Action TK_Word '{' inline_block '}' final {
105 if ( pd->actionDict.find( $2->data ) ) {
106 /* Recover by just ignoring the duplicate. */
107 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
110 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
111 /* Add the action to the list of actions. */
112 Action *newAction = new Action( $3->loc, $2->data, $4->inlineList );
114 /* Insert to list and dict. */
115 pd->actionList.append( newAction );
116 pd->actionDict.insert( newAction );
120 # Specifies the data type of the input alphabet. One or two words followed by a
123 KW_AlphType TK_Word TK_Word ';' final {
124 if ( ! pd->setAlphType( $2->data, $3->data ) ) {
125 // Recover by ignoring the alphtype statement.
126 error($2->loc) << "\"" << $2->data <<
127 " " << $3->data << "\" is not a valid alphabet type" << endl;
132 KW_AlphType TK_Word ';' final {
133 if ( ! pd->setAlphType( $2->data ) ) {
134 // Recover by ignoring the alphtype statement.
135 error($2->loc) << "\"" << $2->data <<
136 "\" is not a valid alphabet type" << endl;
140 # Specifies a range to assume that the input characters will fall into.
142 KW_Range alphabet_num alphabet_num ';' final {
143 // Save the upper and lower ends of the range and emit the line number.
144 pd->lowerNum = $2->token.data;
145 pd->upperNum = $3->token.data;
146 pd->rangeLowLoc = $2->token.loc;
147 pd->rangeHighLoc = $3->token.loc;
151 KW_GetKey inline_expr ';' final {
152 pd->getKeyExpr = $2->inlineList;
156 KW_Access inline_expr ';' final {
157 pd->accessExpr = $2->inlineList;
161 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
162 /* FIXME: Need to implement the rest of this. */
163 if ( strcmp( $3->data, "curstate" ) == 0 )
164 pd->curStateExpr = $4->inlineList;
166 error($3->loc) << "sorry, unimplementd" << endl;
170 opt_whitespace: opt_whitespace IL_WhiteSpace;
184 $$->joinOrLm = new JoinOrLm( $1->join );
187 TK_BarStar lm_part_list '*' '|' final {
188 /* Create a new factor going to a longest match structure. Record
189 * in the parse data that we have a longest match. */
190 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
191 pd->lmList.append( lm );
192 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
193 lmp->longestMatch = lm;
194 $$->joinOrLm = new JoinOrLm( lm );
199 LmPartList *lmPartList;
203 lm_part_list longest_match_part final {
204 if ( $2->lmPart != 0 )
205 $1->lmPartList->append( $2->lmPart );
206 $$->lmPartList = $1->lmPartList;
209 longest_match_part final {
210 /* Create a new list with the part. */
211 $$->lmPartList = new LmPartList;
212 if ( $1->lmPart != 0 )
213 $$->lmPartList->append( $1->lmPart );
216 nonterm longest_match_part
218 LongestMatchPart *lmPart;
222 action_spec final { $$->lmPart = 0; };
224 assignment final { $$->lmPart = 0; };
226 join opt_lm_part_action ';' final {
228 Action *action = $2->action;
230 action->isLmAction = true;
231 $$->lmPart = new LongestMatchPart( $1->join, action,
232 $3->loc, pd->nextLongestMatchId++ );
235 nonterm opt_lm_part_action
241 TK_DoubleArrow action_embed final {
242 $$->action = $2->action;
245 action_embed_block final {
246 $$->action = $1->action;
260 join ',' expression final {
261 /* Append the expression to the list and return it. */
262 $1->join->exprList.append( $3->expression );
267 $$->join = new Join( $1->expression );
272 Expression *expression;
276 expression '|' term final {
277 $$->expression = new Expression( $1->expression,
278 $3->term, Expression::OrType );
281 expression '&' term final {
282 $$->expression = new Expression( $1->expression,
283 $3->term, Expression::IntersectType );
285 # This priority specification overrides the innermost parsing strategy which
286 # results ordered choice interpretation of the grammar.
288 expression pri(1) '-' term final {
289 $$->expression = new Expression( $1->expression,
290 $3->term, Expression::SubtractType );
293 expression TK_DashDash term final {
294 $$->expression = new Expression( $1->expression,
295 $3->term, Expression::StrongSubtractType );
299 $$->expression = new Expression( $1->term );
308 term factor_with_label final {
309 $$->term = new Term( $1->term, $2->factorWithAug );
312 term '.' factor_with_label final {
313 $$->term = new Term( $1->term, $3->factorWithAug );
316 term TK_ColonGt factor_with_label final {
317 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
320 term TK_ColonGtGt factor_with_label final {
321 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
324 term TK_LtColon factor_with_label final {
325 $$->term = new Term( $1->term,
326 $3->factorWithAug, Term::LeftType );
329 factor_with_label final {
330 $$->term = new Term( $1->factorWithAug );
333 nonterm factor_with_label
335 FactorWithAug *factorWithAug;
339 TK_Word ':' factor_with_label final {
340 /* Add the label to the list and pass the factor up. */
341 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
342 $$->factorWithAug = $3->factorWithAug;
345 factor_with_ep final {
346 $$->factorWithAug = $1->factorWithAug;
349 nonterm factor_with_ep
351 FactorWithAug *factorWithAug;
355 factor_with_ep TK_Arrow local_state_ref final {
356 /* Add the target to the list and return the factor object. */
357 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
358 $$->factorWithAug = $1->factorWithAug;
361 factor_with_aug final {
362 $$->factorWithAug = $1->factorWithAug;
365 nonterm factor_with_aug
367 FactorWithAug *factorWithAug;
371 factor_with_aug aug_type_base action_embed final {
372 /* Append the action to the factorWithAug, record the refernce from
373 * factorWithAug to the action and pass up the factorWithAug. */
374 $1->factorWithAug->actions.append(
375 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
376 $$->factorWithAug = $1->factorWithAug;
379 factor_with_aug aug_type_base priority_aug final {
380 /* Append the named priority to the factorWithAug and pass it up. */
381 $1->factorWithAug->priorityAugs.append(
382 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
383 $$->factorWithAug = $1->factorWithAug;
386 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
387 /* Append the priority using a default name. */
388 $1->factorWithAug->priorityAugs.append(
389 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
390 $$->factorWithAug = $1->factorWithAug;
393 factor_with_aug aug_type_cond action_embed final {
394 $1->factorWithAug->conditions.append( ParserAction( $2->loc,
395 $2->augType, 0, $3->action ) );
396 $$->factorWithAug = $1->factorWithAug;
399 factor_with_aug aug_type_to_state action_embed final {
400 /* Append the action, pass it up. */
401 $1->factorWithAug->actions.append( ParserAction( $2->loc,
402 $2->augType, 0, $3->action ) );
403 $$->factorWithAug = $1->factorWithAug;
406 factor_with_aug aug_type_from_state action_embed final {
407 /* Append the action, pass it up. */
408 $1->factorWithAug->actions.append( ParserAction( $2->loc,
409 $2->augType, 0, $3->action ) );
410 $$->factorWithAug = $1->factorWithAug;
413 factor_with_aug aug_type_eof action_embed final {
414 /* Append the action, pass it up. */
415 $1->factorWithAug->actions.append( ParserAction( $2->loc,
416 $2->augType, 0, $3->action ) );
417 $$->factorWithAug = $1->factorWithAug;
420 factor_with_aug aug_type_gbl_error 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( ParserAction( $2->loc,
424 $2->augType, pd->curDefLocalErrKey, $3->action ) );
425 $$->factorWithAug = $1->factorWithAug;
428 factor_with_aug aug_type_local_error action_embed final {
429 /* Append the action to the factorWithAug, record the refernce from
430 * factorWithAug to the action and pass up the factorWithAug. */
431 $1->factorWithAug->actions.append( ParserAction( $2->loc,
432 $2->augType, pd->curDefLocalErrKey, $3->action ) );
433 $$->factorWithAug = $1->factorWithAug;
436 factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
437 /* Append the action to the factorWithAug, record the refernce from
438 * factorWithAug to the action and pass up the factorWithAug. */
439 $1->factorWithAug->actions.append( ParserAction( $2->loc,
440 $2->augType, $4->error_name, $6->action ) );
441 $$->factorWithAug = $1->factorWithAug;
444 factor_with_rep final {
445 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
454 # Classes of transtions on which to embed actions or change priorities.
455 nonterm aug_type_base uses aug_type;
457 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
458 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
459 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
460 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
462 # Embedding conditions.
463 nonterm aug_type_cond uses aug_type;
465 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
466 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
467 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
468 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
469 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
470 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
471 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
477 nonterm aug_type_to_state uses aug_type;
479 aug_type_to_state: TK_StartToState
480 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
481 aug_type_to_state: '>' KW_To
482 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
484 aug_type_to_state: TK_NotStartToState
485 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
486 aug_type_to_state: '<' KW_To
487 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
489 aug_type_to_state: TK_AllToState
490 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
491 aug_type_to_state: '$' KW_To
492 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
494 aug_type_to_state: TK_FinalToState
495 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
496 aug_type_to_state: '%' KW_To
497 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
499 aug_type_to_state: TK_NotFinalToState
500 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
501 aug_type_to_state: '@' KW_To
502 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
504 aug_type_to_state: TK_MiddleToState
505 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
506 aug_type_to_state: TK_Middle KW_To
507 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
510 # From state actions.
513 nonterm aug_type_from_state uses aug_type;
515 aug_type_from_state: TK_StartFromState
516 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
517 aug_type_from_state: '>' KW_From
518 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
520 aug_type_from_state: TK_NotStartFromState
521 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
522 aug_type_from_state: '<' KW_From
523 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
525 aug_type_from_state: TK_AllFromState
526 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
527 aug_type_from_state: '$' KW_From
528 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
530 aug_type_from_state: TK_FinalFromState
531 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
532 aug_type_from_state: '%' KW_From
533 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
535 aug_type_from_state: TK_NotFinalFromState
536 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
537 aug_type_from_state: '@' KW_From
538 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
540 aug_type_from_state: TK_MiddleFromState
541 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
542 aug_type_from_state: TK_Middle KW_From
543 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
549 nonterm aug_type_eof uses aug_type;
551 aug_type_eof: TK_StartEOF
552 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
553 aug_type_eof: '>' KW_Eof
554 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
556 aug_type_eof: TK_NotStartEOF
557 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
558 aug_type_eof: '<' KW_Eof
559 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
561 aug_type_eof: TK_AllEOF
562 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
563 aug_type_eof: '$' KW_Eof
564 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
566 aug_type_eof: TK_FinalEOF
567 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
568 aug_type_eof: '%' KW_Eof
569 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
571 aug_type_eof: TK_NotFinalEOF
572 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
573 aug_type_eof: '@' KW_Eof
574 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
576 aug_type_eof: TK_MiddleEOF
577 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
578 aug_type_eof: TK_Middle KW_Eof
579 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
582 # Global error actions.
585 nonterm aug_type_gbl_error uses aug_type;
587 aug_type_gbl_error: TK_StartGblError
588 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
589 aug_type_gbl_error: '>' KW_Err
590 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
592 aug_type_gbl_error: TK_NotStartGblError
593 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
594 aug_type_gbl_error: '<' KW_Err
595 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
597 aug_type_gbl_error: TK_AllGblError
598 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
599 aug_type_gbl_error: '$' KW_Err
600 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
602 aug_type_gbl_error: TK_FinalGblError
603 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
604 aug_type_gbl_error: '%' KW_Err
605 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
607 aug_type_gbl_error: TK_NotFinalGblError
608 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
609 aug_type_gbl_error: '@' KW_Err
610 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
612 aug_type_gbl_error: TK_MiddleGblError
613 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
614 aug_type_gbl_error: TK_Middle KW_Err
615 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
619 # Local error actions.
622 nonterm aug_type_local_error uses aug_type;
624 aug_type_local_error: TK_StartLocalError
625 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
626 aug_type_local_error: '>' KW_Lerr
627 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
629 aug_type_local_error: TK_NotStartLocalError
630 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
631 aug_type_local_error: '<' KW_Lerr
632 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
634 aug_type_local_error: TK_AllLocalError
635 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
636 aug_type_local_error: '$' KW_Lerr
637 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
639 aug_type_local_error: TK_FinalLocalError
640 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
641 aug_type_local_error: '%' KW_Lerr
642 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
644 aug_type_local_error: TK_NotFinalLocalError
645 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
646 aug_type_local_error: '@' KW_Lerr
647 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
649 aug_type_local_error: TK_MiddleLocalError
650 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
651 aug_type_local_error: TK_Middle KW_Lerr
652 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
660 # Different ways to embed actions. A TK_Word is reference to an action given by
661 # the user as a statement in the fsm specification. An action can also be
662 # specified immediately.
663 nonterm action_embed uses action_ref;
665 action_embed: action_embed_word final { $$->action = $1->action; };
666 action_embed: action_embed_block final { $$->action = $1->action; };
668 nonterm action_embed_word uses action_ref;
672 /* Set the name in the actionDict. */
673 Action *action = pd->actionDict.find( $1->data );
675 /* Pass up the action element */
679 /* Will recover by returning null as the action. */
680 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
685 nonterm action_embed_block uses action_ref;
688 '{' inline_block '}' final {
689 /* Create the action, add it to the list and pass up. */
690 Action *newAction = new Action( $1->loc, 0, $2->inlineList );
691 pd->actionList.append( newAction );
692 $$->action = newAction;
695 nonterm priority_name
700 # A specified priority name. Looks up the name in the current priority
704 // Lookup/create the priority key.
705 PriorDictEl *priorDictEl;
706 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
707 pd->nextPriorKey += 1;
709 // Use the inserted/found priority key.
710 $$->priorityName = priorDictEl->value;
718 # Priority change specs.
720 priority_aug_num final {
721 // Convert the priority number to a long. Check for overflow.
723 //cerr << "PRIOR AUG: " << $1->token.data << endl;
724 int aug = strtol( $1->token.data, 0, 10 );
725 if ( errno == ERANGE && aug == LONG_MAX ) {
726 /* Priority number too large. Recover by setting the priority to 0. */
727 error($1->token.loc) << "priority number " << $1->token.data <<
728 " overflows" << endl;
731 else if ( errno == ERANGE && aug == LONG_MIN ) {
732 /* Priority number too large in the neg. Recover by using 0. */
733 error($1->token.loc) << "priority number " << $1->token.data <<
734 " underflows" << endl;
738 /* No overflow or underflow. */
739 $$->priorityNum = aug;
743 nonterm priority_aug_num uses token_type;
751 $$->token.set( "+", 1 );
752 $$->token.loc = $1->loc;
753 $$->token.append( *$2 );
757 $$->token.set( "-", 1 );
758 $$->token.loc = $1->loc;
759 $$->token.append( *$2 );
762 nonterm local_err_name
769 /* Lookup/create the priority key. */
770 LocalErrDictEl *localErrDictEl;
771 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
772 pd->nextLocalErrKey += 1;
774 /* Use the inserted/found priority key. */
775 $$->error_name = localErrDictEl->value;
780 # The fourth level of precedence. These are the trailing unary operators that
781 # allow for repetition.
783 nonterm factor_with_rep
785 FactorWithRep *factorWithRep;
789 factor_with_rep '*' final {
790 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
791 0, 0, FactorWithRep::StarType );
794 factor_with_rep TK_StarStar final {
795 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
796 0, 0, FactorWithRep::StarStarType );
799 factor_with_rep '?' final {
800 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
801 0, 0, FactorWithRep::OptionalType );
804 factor_with_rep '+' final {
805 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
806 0, 0, FactorWithRep::PlusType );
809 factor_with_rep '{' factor_rep_num '}' final {
810 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
811 $3->rep, 0, FactorWithRep::ExactType );
814 factor_with_rep '{' ',' factor_rep_num '}' final {
815 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
816 0, $4->rep, FactorWithRep::MaxType );
819 factor_with_rep '{' factor_rep_num ',' '}' final {
820 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
821 $3->rep, 0, FactorWithRep::MinType );
824 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
825 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
826 $3->rep, $5->rep, FactorWithRep::RangeType );
829 factor_with_neg final {
830 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
833 nonterm factor_rep_num
840 // Convert the priority number to a long. Check for overflow.
842 int rep = strtol( $1->data, 0, 10 );
843 if ( errno == ERANGE && rep == LONG_MAX ) {
844 // Repetition too large. Recover by returing repetition 1. */
845 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
849 // Cannot be negative, so no overflow.
856 # The fifth level up in precedence. Negation.
859 nonterm factor_with_neg
861 FactorWithNeg *factorWithNeg;
865 '!' factor_with_neg final {
866 $$->factorWithNeg = new FactorWithNeg( $1->loc,
867 $2->factorWithNeg, FactorWithNeg::NegateType );
870 '^' factor_with_neg final {
871 $$->factorWithNeg = new FactorWithNeg( $1->loc,
872 $2->factorWithNeg, FactorWithNeg::CharNegateType );
876 $$->factorWithNeg = new FactorWithNeg( $1->factor );
886 /* Create a new factor node going to a concat literal. */
887 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
891 /* Create a new factor node going to a literal number. */
892 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
896 /* Find the named graph. */
897 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
899 /* Recover by returning null as the factor node. */
900 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
903 else if ( gdNode->isInstance ) {
904 /* Recover by retuning null as the factor node. */
905 error($1->loc) << "references to graph instantiations not allowed "
906 "in expressions" << endl;
910 /* Create a factor node that is a lookup of an expression. */
911 $$->factor = new Factor( $1->loc, gdNode->value );
915 RE_SqOpen regular_expr_or_data RE_SqClose final {
916 /* Create a new factor node going to an OR expression. */
917 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
920 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
921 /* Create a new factor node going to a negated OR expression. */
922 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
925 RE_Slash regular_expr RE_Slash final {
926 if ( $3->length > 1 ) {
927 for ( char *p = $3->data; *p != 0; p++ ) {
929 $2->regExpr->caseInsensitive = true;
933 /* Create a new factor node going to a regular exp. */
934 $$->factor = new Factor( $2->regExpr );
937 range_lit TK_DotDot range_lit final {
938 /* Create a new factor node going to a range. */
939 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
943 /* Create a new factor going to a parenthesized join. */
944 $$->factor = new Factor( $2->join );
952 # Literals which can be the end points of ranges.
955 /* Range literas must have only one char. We restrict this in the parse tree. */
956 $$->literal = new Literal( *$1, Literal::LitString );
960 /* Create a new literal number. */
961 $$->literal = new Literal( $1->token, Literal::Number );
964 nonterm alphabet_num uses token_type;
966 # Any form of a number that can be used as a basic machine. */
973 $$->token.set( "-", 1 );
974 $$->token.loc = $1->loc;
975 $$->token.append( *$2 );
982 # Regular Expressions.
990 # Parser for regular expression fsms. Any number of expression items which
991 # generally gives a machine one character long or one character long stared.
993 regular_expr regular_expr_item final {
994 /* An optimization to lessen the tree size. If a non-starred char is
995 * directly under the left side on the right and the right side is
996 * another non-starred char then paste them together and return the
997 * left side. Otherwise just put the two under a new reg exp node. */
998 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
999 $1->regExpr->type == RegExpr::RecurseItem &&
1000 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1002 /* Append the right side to the right side of the left and toss the
1004 $1->regExpr->item->token.append( $2->reItem->token );
1006 $$->regExpr = $1->regExpr;
1009 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1014 /* Can't optimize the tree. */
1015 $$->regExpr = new RegExpr();
1018 nonterm regular_expr_item
1023 # RegularExprItems can be a character spec with an optional staring of the char.
1025 regular_expr_char RE_Star final {
1026 $1->reItem->star = true;
1027 $$->reItem = $1->reItem;
1030 regular_expr_char final {
1031 $$->reItem = $1->reItem;
1034 nonterm regular_expr_char
1039 # A character spec can be a set of characters inside of square parenthesis, a
1040 # dot specifying any character or some explicitly stated character.
1042 RE_SqOpen regular_expr_or_data RE_SqClose final {
1043 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1046 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1047 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1051 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1055 $$->reItem = new ReItem( $1->loc, *$1 );
1058 # The data inside of a [] expression in a regular expression. Accepts any
1059 # number of characters or ranges. */
1060 nonterm regular_expr_or_data
1062 ReOrBlock *reOrBlock;
1065 regular_expr_or_data:
1066 regular_expr_or_data regular_expr_or_char final {
1067 /* An optimization to lessen the tree size. If an or char is directly
1068 * under the left side on the right and the right side is another or
1069 * char then paste them together and return the left side. Otherwise
1070 * just put the two under a new or data node. */
1071 if ( $2->reOrItem->type == ReOrItem::Data &&
1072 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1073 $1->reOrBlock->item->type == ReOrItem::Data )
1075 /* Append the right side to right side of the left and toss the
1077 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1078 delete $2->reOrItem;
1079 $$->reOrBlock = $1->reOrBlock;
1082 /* Can't optimize, put the left and right under a new node. */
1083 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1086 regular_expr_or_data:
1088 $$->reOrBlock = new ReOrBlock();
1091 # A single character inside of an or expression. Can either be a character or a
1092 # set of characters.
1093 nonterm regular_expr_or_char
1098 regular_expr_or_char:
1100 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1102 regular_expr_or_char:
1103 RE_Char RE_Dash RE_Char final {
1104 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1108 # Inline Lists for inline host code.
1113 InlineList *inlineList;
1116 nonterm inline_block uses inline_list;
1119 inline_block inline_block_item
1121 /* Append the item to the list, return the list. */
1122 $$->inlineList = $1->inlineList;
1123 $$->inlineList->append( $2->inlineItem );
1128 /* Start with empty list. */
1129 $$->inlineList = new InlineList;
1134 InlineItem *inlineItem;
1137 nonterm inline_block_item uses inline_item;
1138 nonterm inline_block_interpret uses inline_item;
1143 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1149 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1153 inline_block_interpret
1155 /* Pass the inline item up. */
1156 $$->inlineItem = $1->inlineItem;
1159 nonterm inline_block_symbol uses token_type;
1161 inline_block_symbol: ',' final { $$->token = *$1; };
1162 inline_block_symbol: ';' final { $$->token = *$1; };
1163 inline_block_symbol: '(' final { $$->token = *$1; };
1164 inline_block_symbol: ')' final { $$->token = *$1; };
1165 inline_block_symbol: '*' final { $$->token = *$1; };
1166 inline_block_symbol: TK_NameSep final { $$->token = *$1; };
1168 # Interpreted statements in a struct block. */
1169 inline_block_interpret:
1170 inline_expr_interpret final {
1171 /* Pass up interpreted items of inline expressions. */
1172 $$->inlineItem = $1->inlineItem;
1174 inline_block_interpret:
1176 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1178 inline_block_interpret:
1179 KW_Exec inline_expr ';' final {
1180 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1181 $$->inlineItem->children = $2->inlineList;
1183 inline_block_interpret:
1184 KW_Goto state_ref ';' final {
1185 $$->inlineItem = new InlineItem( $1->loc,
1186 new NameRef(nameRef), InlineItem::Goto );
1188 inline_block_interpret:
1189 KW_Goto '*' inline_expr ';' final {
1190 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1191 $$->inlineItem->children = $3->inlineList;
1193 inline_block_interpret:
1194 KW_Next state_ref ';' final {
1195 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1197 inline_block_interpret:
1198 KW_Next '*' inline_expr ';' final {
1199 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1200 $$->inlineItem->children = $3->inlineList;
1202 inline_block_interpret:
1203 KW_Call state_ref ';' final {
1204 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1206 inline_block_interpret:
1207 KW_Call '*' inline_expr ';' final {
1208 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1209 $$->inlineItem->children = $3->inlineList;
1211 inline_block_interpret:
1213 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1215 inline_block_interpret:
1216 KW_Break ';' final {
1217 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1220 nonterm inline_expr uses inline_list;
1223 inline_expr inline_expr_item
1225 $$->inlineList = $1->inlineList;
1226 $$->inlineList->append( $2->inlineItem );
1230 /* Init the list used for this expr. */
1231 $$->inlineList = new InlineList;
1234 nonterm inline_expr_item uses inline_item;
1239 /* Return a text segment. */
1240 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1245 /* Return a text segment, must heap alloc the text. */
1246 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1249 inline_expr_interpret
1251 /* Pass the inline item up. */
1252 $$->inlineItem = $1->inlineItem;
1255 nonterm inline_expr_any uses token_type;
1257 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1258 inline_expr_any: IL_Comment try { $$->token = *$1; };
1259 inline_expr_any: IL_Literal try { $$->token = *$1; };
1260 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1261 inline_expr_any: TK_UInt try { $$->token = *$1; };
1262 inline_expr_any: TK_Hex try { $$->token = *$1; };
1263 inline_expr_any: TK_Word try { $$->token = *$1; };
1265 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1266 # all special symbols caught in inline code except the semi.
1268 nonterm inline_expr_symbol uses token_type;
1270 inline_expr_symbol: ',' try { $$->token = *$1; };
1271 inline_expr_symbol: '(' try { $$->token = *$1; };
1272 inline_expr_symbol: ')' try { $$->token = *$1; };
1273 inline_expr_symbol: '*' try { $$->token = *$1; };
1274 inline_expr_symbol: TK_NameSep try { $$->token = *$1; };
1276 nonterm inline_expr_interpret uses inline_item;
1278 inline_expr_interpret:
1281 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1283 inline_expr_interpret:
1286 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1288 inline_expr_interpret:
1291 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1293 inline_expr_interpret:
1296 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1298 inline_expr_interpret:
1299 KW_Entry '(' state_ref ')'
1301 $$->inlineItem = new InlineItem( $1->loc,
1302 new NameRef(nameRef), InlineItem::Entry );
1305 # A local state reference. Cannot have :: prefix.
1307 no_name_sep state_ref_names;
1309 # Clear the name ref structure.
1315 # A qualified state reference.
1316 state_ref: opt_name_sep state_ref_names;
1318 # Optional leading name separator.
1322 /* Insert an initial null pointer val to indicate the existence of the
1323 * initial name seperator. */
1331 # List of names separated by ::
1333 state_ref_names TK_NameSep TK_Word
1335 nameRef.append( $3->data );
1340 nameRef.append( $1->data );
1355 int Parser::parseLangEl( int type, const Token *token )
1358 return errCount == 0 ? 0 : -1;
1361 void Parser::tryMachineDef( InputLoc &loc, char *name,
1362 JoinOrLm *joinOrLm, bool isInstance )
1364 GraphDictEl *newEl = pd->graphDict.insert( name );
1366 /* New element in the dict, all good. */
1367 newEl->value = new VarDef( name, joinOrLm );
1368 newEl->isInstance = isInstance;
1371 /* It it is an instance, put on the instance list. */
1373 pd->instanceList.append( newEl );
1376 // Recover by ignoring the duplicate.
1377 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1381 ostream &Parser::parse_error( int tokId, Token &token )
1383 /* Maintain the error count. */
1386 cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
1387 cerr << "at token ";
1389 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1391 cerr << Parser_lelNames[tokId];
1392 if ( token.data != 0 )
1393 cerr << " with data \"" << token.data << "\"";
1399 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1402 token.data = tokstart;
1403 token.length = toklen;
1405 int res = parseLangEl( tokId, &token );
1407 parse_error(tokId, token) << "parse error" << endl;