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
31 ParserDict parserDict;
41 section_list: section_list statement_list TK_EndSection;
44 statement_list: statement_list statement;
47 statement: assignment commit;
48 statement: instantiation commit;
49 statement: action_spec commit;
50 statement: alphtype_spec commit;
51 statement: range_spec commit;
52 statement: getkey_spec commit;
53 statement: access_spec commit;
54 statement: variable_spec commit;
57 machine_name '=' join ';' final {
58 /* Main machine must be an instance. */
59 bool isInstance = false;
60 if ( strcmp($1->token.data, machineMain) == 0 ) {
61 warning($1->token.loc) <<
62 "main machine will be implicitly instantiated" << endl;
66 /* Generic creation of machine for instantiation and assignment. */
67 JoinOrLm *joinOrLm = new JoinOrLm( $3->join );
68 tryMachineDef( $1->token.loc, $1->token.data, joinOrLm, isInstance );
72 machine_name TK_ColonEquals join_or_lm ';' final {
73 /* Generic creation of machine for instantiation and assignment. */
74 tryMachineDef( $1->token.loc, $1->token.data, $3->joinOrLm, true );
82 nonterm machine_name uses token_type;
86 /* Make/get the priority key. The name may have already been referenced
87 * and therefore exist. */
88 PriorDictEl *priorDictEl;
89 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
90 pd->nextPriorKey += 1;
91 pd->curDefPriorKey = priorDictEl->value;
93 /* Make/get the local error key. */
94 LocalErrDictEl *localErrDictEl;
95 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
96 pd->nextLocalErrKey += 1;
97 pd->curDefLocalErrKey = localErrDictEl->value;
103 KW_Action TK_Word '{' inline_block '}' final {
104 if ( pd->actionDict.find( $2->data ) ) {
105 /* Recover by just ignoring the duplicate. */
106 error($2->loc) << "action \"" << $2->data << "\" already defined" << endl;
109 //cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
110 /* Add the action to the list of actions. */
111 Action *newAction = new Action( $3->loc, $2->data, $4->inlineList );
113 /* Insert to list and dict. */
114 pd->actionList.append( newAction );
115 pd->actionDict.insert( newAction );
119 # Specifies the data type of the input alphabet. One or two words followed by a
122 KW_AlphType TK_Word TK_Word ';' final {
123 if ( ! pd->setAlphType( $2->data, $3->data ) ) {
124 // Recover by ignoring the alphtype statement.
125 error($2->loc) << "\"" << $2->data <<
126 " " << $3->data << "\" is not a valid alphabet type" << endl;
131 KW_AlphType TK_Word ';' final {
132 if ( ! pd->setAlphType( $2->data ) ) {
133 // Recover by ignoring the alphtype statement.
134 error($2->loc) << "\"" << $2->data <<
135 "\" is not a valid alphabet type" << endl;
139 # Specifies a range to assume that the input characters will fall into.
141 KW_Range alphabet_num alphabet_num ';' final {
142 // Save the upper and lower ends of the range and emit the line number.
143 pd->lowerNum = $2->token.data;
144 pd->upperNum = $3->token.data;
145 pd->rangeLowLoc = $2->token.loc;
146 pd->rangeHighLoc = $3->token.loc;
150 KW_GetKey inline_expr ';' final {
151 pd->getKeyExpr = $2->inlineList;
155 KW_Access inline_expr ';' final {
156 pd->accessExpr = $2->inlineList;
160 KW_Variable opt_whitespace TK_Word inline_expr ';' final {
161 /* FIXME: Need to implement the rest of this. */
162 if ( strcmp( $3->data, "curstate" ) == 0 )
163 pd->curStateExpr = $4->inlineList;
165 error($3->loc) << "sorry, unimplementd" << endl;
169 opt_whitespace: opt_whitespace IL_WhiteSpace;
183 $$->joinOrLm = new JoinOrLm( $1->join );
186 TK_BarStar lm_part_list '*' '|' final {
187 /* Create a new factor going to a longest match structure. Record
188 * in the parse data that we have a longest match. */
189 LongestMatch *lm = new LongestMatch( $1->loc, $2->lmPartList );
190 pd->lmList.append( lm );
191 for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
192 lmp->longestMatch = lm;
193 $$->joinOrLm = new JoinOrLm( lm );
198 LmPartList *lmPartList;
202 lm_part_list longest_match_part final {
203 if ( $2->lmPart != 0 )
204 $1->lmPartList->append( $2->lmPart );
205 $$->lmPartList = $1->lmPartList;
208 longest_match_part final {
209 /* Create a new list with the part. */
210 $$->lmPartList = new LmPartList;
211 if ( $1->lmPart != 0 )
212 $$->lmPartList->append( $1->lmPart );
215 nonterm longest_match_part
217 LongestMatchPart *lmPart;
221 action_spec final { $$->lmPart = 0; };
223 assignment final { $$->lmPart = 0; };
225 join opt_lm_part_action ';' final {
227 Action *action = $2->action;
229 action->isLmAction = true;
230 $$->lmPart = new LongestMatchPart( $1->join, action,
231 $3->loc, pd->nextLongestMatchId++ );
234 nonterm opt_lm_part_action
240 TK_DoubleArrow action_embed final {
241 $$->action = $2->action;
244 action_embed_block final {
245 $$->action = $1->action;
259 join ',' expression final {
260 /* Append the expression to the list and return it. */
261 $1->join->exprList.append( $3->expression );
266 $$->join = new Join( $1->expression );
271 Expression *expression;
275 expression '|' term final {
276 $$->expression = new Expression( $1->expression,
277 $3->term, Expression::OrType );
280 expression '&' term final {
281 $$->expression = new Expression( $1->expression,
282 $3->term, Expression::IntersectType );
284 # This priority specification overrides the innermost parsing strategy which
285 # results ordered choice interpretation of the grammar.
287 expression pri(1) '-' term final {
288 $$->expression = new Expression( $1->expression,
289 $3->term, Expression::SubtractType );
292 expression TK_DashDash term final {
293 $$->expression = new Expression( $1->expression,
294 $3->term, Expression::StrongSubtractType );
298 $$->expression = new Expression( $1->term );
307 term factor_with_label final {
308 $$->term = new Term( $1->term, $2->factorWithAug );
311 term '.' factor_with_label final {
312 $$->term = new Term( $1->term, $3->factorWithAug );
315 term TK_ColonGt factor_with_label final {
316 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightStartType );
319 term TK_ColonGtGt factor_with_label final {
320 $$->term = new Term( $1->term, $3->factorWithAug, Term::RightFinishType );
323 term TK_LtColon factor_with_label final {
324 $$->term = new Term( $1->term,
325 $3->factorWithAug, Term::LeftType );
328 factor_with_label final {
329 $$->term = new Term( $1->factorWithAug );
332 nonterm factor_with_label
334 FactorWithAug *factorWithAug;
338 TK_Word ':' factor_with_label final {
339 /* Add the label to the list and pass the factor up. */
340 $3->factorWithAug->labels.prepend( Label($1->loc, $1->data) );
341 $$->factorWithAug = $3->factorWithAug;
344 factor_with_ep final {
345 $$->factorWithAug = $1->factorWithAug;
348 nonterm factor_with_ep
350 FactorWithAug *factorWithAug;
354 factor_with_ep TK_Arrow local_state_ref final {
355 /* Add the target to the list and return the factor object. */
356 $1->factorWithAug->epsilonLinks.append( EpsilonLink( $2->loc, nameRef ) );
357 $$->factorWithAug = $1->factorWithAug;
360 factor_with_aug final {
361 $$->factorWithAug = $1->factorWithAug;
364 nonterm factor_with_aug
366 FactorWithAug *factorWithAug;
370 factor_with_aug aug_type_base action_embed final {
371 /* Append the action to the factorWithAug, record the refernce from
372 * factorWithAug to the action and pass up the factorWithAug. */
373 $1->factorWithAug->actions.append(
374 ParserAction( $2->loc, $2->augType, 0, $3->action ) );
375 $$->factorWithAug = $1->factorWithAug;
378 factor_with_aug aug_type_base priority_aug final {
379 /* Append the named priority to the factorWithAug and pass it up. */
380 $1->factorWithAug->priorityAugs.append(
381 PriorityAug( $2->augType, pd->curDefPriorKey, $3->priorityNum ) );
382 $$->factorWithAug = $1->factorWithAug;
385 factor_with_aug aug_type_base '(' priority_name ',' priority_aug ')' final {
386 /* Append the priority using a default name. */
387 $1->factorWithAug->priorityAugs.append(
388 PriorityAug( $2->augType, $4->priorityName, $6->priorityNum ) );
389 $$->factorWithAug = $1->factorWithAug;
392 factor_with_aug aug_type_cond action_embed final {
393 $1->factorWithAug->conditions.append( ParserAction( $2->loc,
394 $2->augType, 0, $3->action ) );
395 $$->factorWithAug = $1->factorWithAug;
398 factor_with_aug aug_type_to_state action_embed final {
399 /* Append the action, pass it up. */
400 $1->factorWithAug->actions.append( ParserAction( $2->loc,
401 $2->augType, 0, $3->action ) );
402 $$->factorWithAug = $1->factorWithAug;
405 factor_with_aug aug_type_from_state action_embed final {
406 /* Append the action, pass it up. */
407 $1->factorWithAug->actions.append( ParserAction( $2->loc,
408 $2->augType, 0, $3->action ) );
409 $$->factorWithAug = $1->factorWithAug;
412 factor_with_aug aug_type_eof action_embed final {
413 /* Append the action, pass it up. */
414 $1->factorWithAug->actions.append( ParserAction( $2->loc,
415 $2->augType, 0, $3->action ) );
416 $$->factorWithAug = $1->factorWithAug;
419 factor_with_aug aug_type_gbl_error action_embed final {
420 /* Append the action to the factorWithAug, record the refernce from
421 * factorWithAug to the action and pass up the factorWithAug. */
422 $1->factorWithAug->actions.append( ParserAction( $2->loc,
423 $2->augType, pd->curDefLocalErrKey, $3->action ) );
424 $$->factorWithAug = $1->factorWithAug;
427 factor_with_aug aug_type_local_error action_embed final {
428 /* Append the action to the factorWithAug, record the refernce from
429 * factorWithAug to the action and pass up the factorWithAug. */
430 $1->factorWithAug->actions.append( ParserAction( $2->loc,
431 $2->augType, pd->curDefLocalErrKey, $3->action ) );
432 $$->factorWithAug = $1->factorWithAug;
435 factor_with_aug aug_type_local_error '(' local_err_name ',' action_embed ')' final {
436 /* Append the action to the factorWithAug, record the refernce from
437 * factorWithAug to the action and pass up the factorWithAug. */
438 $1->factorWithAug->actions.append( ParserAction( $2->loc,
439 $2->augType, $4->error_name, $6->action ) );
440 $$->factorWithAug = $1->factorWithAug;
443 factor_with_rep final {
444 $$->factorWithAug = new FactorWithAug( $1->factorWithRep );
453 # Classes of transtions on which to embed actions or change priorities.
454 nonterm aug_type_base uses aug_type;
456 aug_type_base: '@' final { $$->loc = $1->loc; $$->augType = at_finish; };
457 aug_type_base: '%' final { $$->loc = $1->loc; $$->augType = at_leave; };
458 aug_type_base: '$' final { $$->loc = $1->loc; $$->augType = at_all; };
459 aug_type_base: '>' final { $$->loc = $1->loc; $$->augType = at_start; };
461 # Embedding conditions.
462 nonterm aug_type_cond uses aug_type;
464 aug_type_cond: TK_StartCond final { $$->loc = $1->loc; $$->augType = at_start; };
465 aug_type_cond: '>' KW_When final { $$->loc = $1->loc; $$->augType = at_start; };
466 aug_type_cond: TK_AllCond final { $$->loc = $1->loc; $$->augType = at_all; };
467 aug_type_cond: '$' KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
468 aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
469 aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
470 aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
476 nonterm aug_type_to_state uses aug_type;
478 aug_type_to_state: TK_StartToState
479 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
480 aug_type_to_state: '>' KW_To
481 final { $$->loc = $1->loc; $$->augType = at_start_to_state; };
483 aug_type_to_state: TK_NotStartToState
484 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
485 aug_type_to_state: '<' KW_To
486 final { $$->loc = $1->loc; $$->augType = at_not_start_to_state; };
488 aug_type_to_state: TK_AllToState
489 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
490 aug_type_to_state: '$' KW_To
491 final { $$->loc = $1->loc; $$->augType = at_all_to_state; };
493 aug_type_to_state: TK_FinalToState
494 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
495 aug_type_to_state: '%' KW_To
496 final { $$->loc = $1->loc; $$->augType = at_final_to_state; };
498 aug_type_to_state: TK_NotFinalToState
499 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
500 aug_type_to_state: '@' KW_To
501 final { $$->loc = $1->loc; $$->augType = at_not_final_to_state; };
503 aug_type_to_state: TK_MiddleToState
504 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
505 aug_type_to_state: TK_Middle KW_To
506 final { $$->loc = $1->loc; $$->augType = at_middle_to_state; };
509 # From state actions.
512 nonterm aug_type_from_state uses aug_type;
514 aug_type_from_state: TK_StartFromState
515 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
516 aug_type_from_state: '>' KW_From
517 final { $$->loc = $1->loc; $$->augType = at_start_from_state; };
519 aug_type_from_state: TK_NotStartFromState
520 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
521 aug_type_from_state: '<' KW_From
522 final { $$->loc = $1->loc; $$->augType = at_not_start_from_state; };
524 aug_type_from_state: TK_AllFromState
525 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
526 aug_type_from_state: '$' KW_From
527 final { $$->loc = $1->loc; $$->augType = at_all_from_state; };
529 aug_type_from_state: TK_FinalFromState
530 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
531 aug_type_from_state: '%' KW_From
532 final { $$->loc = $1->loc; $$->augType = at_final_from_state; };
534 aug_type_from_state: TK_NotFinalFromState
535 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
536 aug_type_from_state: '@' KW_From
537 final { $$->loc = $1->loc; $$->augType = at_not_final_from_state; };
539 aug_type_from_state: TK_MiddleFromState
540 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
541 aug_type_from_state: TK_Middle KW_From
542 final { $$->loc = $1->loc; $$->augType = at_middle_from_state; };
548 nonterm aug_type_eof uses aug_type;
550 aug_type_eof: TK_StartEOF
551 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
552 aug_type_eof: '>' KW_Eof
553 final { $$->loc = $1->loc; $$->augType = at_start_eof; };
555 aug_type_eof: TK_NotStartEOF
556 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
557 aug_type_eof: '<' KW_Eof
558 final { $$->loc = $1->loc; $$->augType = at_not_start_eof; };
560 aug_type_eof: TK_AllEOF
561 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
562 aug_type_eof: '$' KW_Eof
563 final { $$->loc = $1->loc; $$->augType = at_all_eof; };
565 aug_type_eof: TK_FinalEOF
566 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
567 aug_type_eof: '%' KW_Eof
568 final { $$->loc = $1->loc; $$->augType = at_final_eof; };
570 aug_type_eof: TK_NotFinalEOF
571 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
572 aug_type_eof: '@' KW_Eof
573 final { $$->loc = $1->loc; $$->augType = at_not_final_eof; };
575 aug_type_eof: TK_MiddleEOF
576 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
577 aug_type_eof: TK_Middle KW_Eof
578 final { $$->loc = $1->loc; $$->augType = at_middle_eof; };
581 # Global error actions.
584 nonterm aug_type_gbl_error uses aug_type;
586 aug_type_gbl_error: TK_StartGblError
587 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
588 aug_type_gbl_error: '>' KW_Err
589 final { $$->loc = $1->loc; $$->augType = at_start_gbl_error; };
591 aug_type_gbl_error: TK_NotStartGblError
592 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
593 aug_type_gbl_error: '<' KW_Err
594 final { $$->loc = $1->loc; $$->augType = at_not_start_gbl_error; };
596 aug_type_gbl_error: TK_AllGblError
597 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
598 aug_type_gbl_error: '$' KW_Err
599 final { $$->loc = $1->loc; $$->augType = at_all_gbl_error; };
601 aug_type_gbl_error: TK_FinalGblError
602 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
603 aug_type_gbl_error: '%' KW_Err
604 final { $$->loc = $1->loc; $$->augType = at_final_gbl_error; };
606 aug_type_gbl_error: TK_NotFinalGblError
607 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
608 aug_type_gbl_error: '@' KW_Err
609 final { $$->loc = $1->loc; $$->augType = at_not_final_gbl_error; };
611 aug_type_gbl_error: TK_MiddleGblError
612 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
613 aug_type_gbl_error: TK_Middle KW_Err
614 final { $$->loc = $1->loc; $$->augType = at_middle_gbl_error; };
618 # Local error actions.
621 nonterm aug_type_local_error uses aug_type;
623 aug_type_local_error: TK_StartLocalError
624 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
625 aug_type_local_error: '>' KW_Lerr
626 final { $$->loc = $1->loc; $$->augType = at_start_local_error; };
628 aug_type_local_error: TK_NotStartLocalError
629 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
630 aug_type_local_error: '<' KW_Lerr
631 final { $$->loc = $1->loc; $$->augType = at_not_start_local_error; };
633 aug_type_local_error: TK_AllLocalError
634 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
635 aug_type_local_error: '$' KW_Lerr
636 final { $$->loc = $1->loc; $$->augType = at_all_local_error; };
638 aug_type_local_error: TK_FinalLocalError
639 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
640 aug_type_local_error: '%' KW_Lerr
641 final { $$->loc = $1->loc; $$->augType = at_final_local_error; };
643 aug_type_local_error: TK_NotFinalLocalError
644 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
645 aug_type_local_error: '@' KW_Lerr
646 final { $$->loc = $1->loc; $$->augType = at_not_final_local_error; };
648 aug_type_local_error: TK_MiddleLocalError
649 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
650 aug_type_local_error: TK_Middle KW_Lerr
651 final { $$->loc = $1->loc; $$->augType = at_middle_local_error; };
659 # Different ways to embed actions. A TK_Word is reference to an action given by
660 # the user as a statement in the fsm specification. An action can also be
661 # specified immediately.
662 nonterm action_embed uses action_ref;
664 action_embed: action_embed_word final { $$->action = $1->action; };
665 action_embed: action_embed_block final { $$->action = $1->action; };
667 nonterm action_embed_word uses action_ref;
671 /* Set the name in the actionDict. */
672 Action *action = pd->actionDict.find( $1->data );
674 /* Pass up the action element */
678 /* Will recover by returning null as the action. */
679 error($1->loc) << "action lookup of \"" << $1->data << "\" failed" << endl;
684 nonterm action_embed_block uses action_ref;
687 '{' inline_block '}' final {
688 /* Create the action, add it to the list and pass up. */
689 Action *newAction = new Action( $1->loc, 0, $2->inlineList );
690 pd->actionList.append( newAction );
691 $$->action = newAction;
694 nonterm priority_name
699 # A specified priority name. Looks up the name in the current priority
703 // Lookup/create the priority key.
704 PriorDictEl *priorDictEl;
705 if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) )
706 pd->nextPriorKey += 1;
708 // Use the inserted/found priority key.
709 $$->priorityName = priorDictEl->value;
717 # Priority change specs.
719 priority_aug_num final {
720 // Convert the priority number to a long. Check for overflow.
722 //cerr << "PRIOR AUG: " << $1->token.data << endl;
723 int aug = strtol( $1->token.data, 0, 10 );
724 if ( errno == ERANGE && aug == LONG_MAX ) {
725 /* Priority number too large. Recover by setting the priority to 0. */
726 error($1->token.loc) << "priority number " << $1->token.data <<
727 " overflows" << endl;
730 else if ( errno == ERANGE && aug == LONG_MIN ) {
731 /* Priority number too large in the neg. Recover by using 0. */
732 error($1->token.loc) << "priority number " << $1->token.data <<
733 " underflows" << endl;
737 /* No overflow or underflow. */
738 $$->priorityNum = aug;
742 nonterm priority_aug_num uses token_type;
750 $$->token.set( "+", 1 );
751 $$->token.loc = $1->loc;
752 $$->token.append( *$2 );
756 $$->token.set( "-", 1 );
757 $$->token.loc = $1->loc;
758 $$->token.append( *$2 );
761 nonterm local_err_name
768 /* Lookup/create the priority key. */
769 LocalErrDictEl *localErrDictEl;
770 if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) )
771 pd->nextLocalErrKey += 1;
773 /* Use the inserted/found priority key. */
774 $$->error_name = localErrDictEl->value;
779 # The fourth level of precedence. These are the trailing unary operators that
780 # allow for repetition.
782 nonterm factor_with_rep
784 FactorWithRep *factorWithRep;
788 factor_with_rep '*' final {
789 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
790 0, 0, FactorWithRep::StarType );
793 factor_with_rep TK_StarStar final {
794 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
795 0, 0, FactorWithRep::StarStarType );
798 factor_with_rep '?' final {
799 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
800 0, 0, FactorWithRep::OptionalType );
803 factor_with_rep '+' final {
804 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
805 0, 0, FactorWithRep::PlusType );
808 factor_with_rep '{' factor_rep_num '}' final {
809 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
810 $3->rep, 0, FactorWithRep::ExactType );
813 factor_with_rep '{' ',' factor_rep_num '}' final {
814 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
815 0, $4->rep, FactorWithRep::MaxType );
818 factor_with_rep '{' factor_rep_num ',' '}' final {
819 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
820 $3->rep, 0, FactorWithRep::MinType );
823 factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final {
824 $$->factorWithRep = new FactorWithRep( $2->loc, $1->factorWithRep,
825 $3->rep, $5->rep, FactorWithRep::RangeType );
828 factor_with_neg final {
829 $$->factorWithRep = new FactorWithRep( $1->factorWithNeg );
832 nonterm factor_rep_num
839 // Convert the priority number to a long. Check for overflow.
841 int rep = strtol( $1->data, 0, 10 );
842 if ( errno == ERANGE && rep == LONG_MAX ) {
843 // Repetition too large. Recover by returing repetition 1. */
844 error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
848 // Cannot be negative, so no overflow.
855 # The fifth level up in precedence. Negation.
858 nonterm factor_with_neg
860 FactorWithNeg *factorWithNeg;
864 '!' factor_with_neg final {
865 $$->factorWithNeg = new FactorWithNeg( $1->loc,
866 $2->factorWithNeg, FactorWithNeg::NegateType );
869 '^' factor_with_neg final {
870 $$->factorWithNeg = new FactorWithNeg( $1->loc,
871 $2->factorWithNeg, FactorWithNeg::CharNegateType );
875 $$->factorWithNeg = new FactorWithNeg( $1->factor );
885 /* Create a new factor node going to a concat literal. */
886 $$->factor = new Factor( new Literal( *$1, Literal::LitString ) );
890 /* Create a new factor node going to a literal number. */
891 $$->factor = new Factor( new Literal( $1->token, Literal::Number ) );
895 /* Find the named graph. */
896 GraphDictEl *gdNode = pd->graphDict.find( $1->data );
898 /* Recover by returning null as the factor node. */
899 error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl;
902 else if ( gdNode->isInstance ) {
903 /* Recover by retuning null as the factor node. */
904 error($1->loc) << "references to graph instantiations not allowed "
905 "in expressions" << endl;
909 /* Create a factor node that is a lookup of an expression. */
910 $$->factor = new Factor( $1->loc, gdNode->value );
914 RE_SqOpen regular_expr_or_data RE_SqClose final {
915 /* Create a new factor node going to an OR expression. */
916 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock ) );
919 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
920 /* Create a new factor node going to a negated OR expression. */
921 $$->factor = new Factor( new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) );
924 RE_Slash regular_expr RE_Slash final {
925 if ( $3->length > 1 ) {
926 for ( char *p = $3->data; *p != 0; p++ ) {
928 $2->regExpr->caseInsensitive = true;
932 /* Create a new factor node going to a regular exp. */
933 $$->factor = new Factor( $2->regExpr );
936 range_lit TK_DotDot range_lit final {
937 /* Create a new factor node going to a range. */
938 $$->factor = new Factor( new Range( $1->literal, $3->literal ) );
942 /* Create a new factor going to a parenthesized join. */
943 $$->factor = new Factor( $2->join );
951 # Literals which can be the end points of ranges.
954 /* Range literas must have only one char. We restrict this in the parse tree. */
955 $$->literal = new Literal( *$1, Literal::LitString );
959 /* Create a new literal number. */
960 $$->literal = new Literal( $1->token, Literal::Number );
963 nonterm alphabet_num uses token_type;
965 # Any form of a number that can be used as a basic machine. */
972 $$->token.set( "-", 1 );
973 $$->token.loc = $1->loc;
974 $$->token.append( *$2 );
981 # Regular Expressions.
989 # Parser for regular expression fsms. Any number of expression items which
990 # generally gives a machine one character long or one character long stared.
992 regular_expr regular_expr_item final {
993 /* An optimization to lessen the tree size. If a non-starred char is
994 * directly under the left side on the right and the right side is
995 * another non-starred char then paste them together and return the
996 * left side. Otherwise just put the two under a new reg exp node. */
997 if ( $2->reItem->type == ReItem::Data && !$2->reItem->star &&
998 $1->regExpr->type == RegExpr::RecurseItem &&
999 $1->regExpr->item->type == ReItem::Data && !$1->regExpr->item->star )
1001 /* Append the right side to the right side of the left and toss the
1003 $1->regExpr->item->token.append( $2->reItem->token );
1005 $$->regExpr = $1->regExpr;
1008 $$->regExpr = new RegExpr( $1->regExpr, $2->reItem );
1013 /* Can't optimize the tree. */
1014 $$->regExpr = new RegExpr();
1017 nonterm regular_expr_item
1022 # RegularExprItems can be a character spec with an optional staring of the char.
1024 regular_expr_char RE_Star final {
1025 $1->reItem->star = true;
1026 $$->reItem = $1->reItem;
1029 regular_expr_char final {
1030 $$->reItem = $1->reItem;
1033 nonterm regular_expr_char
1038 # A character spec can be a set of characters inside of square parenthesis, a
1039 # dot specifying any character or some explicitly stated character.
1041 RE_SqOpen regular_expr_or_data RE_SqClose final {
1042 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::OrBlock );
1045 RE_SqOpenNeg regular_expr_or_data RE_SqClose final {
1046 $$->reItem = new ReItem( $1->loc, $2->reOrBlock, ReItem::NegOrBlock );
1050 $$->reItem = new ReItem( $1->loc, ReItem::Dot );
1054 $$->reItem = new ReItem( $1->loc, *$1 );
1057 # The data inside of a [] expression in a regular expression. Accepts any
1058 # number of characters or ranges. */
1059 nonterm regular_expr_or_data
1061 ReOrBlock *reOrBlock;
1064 regular_expr_or_data:
1065 regular_expr_or_data regular_expr_or_char final {
1066 /* An optimization to lessen the tree size. If an or char is directly
1067 * under the left side on the right and the right side is another or
1068 * char then paste them together and return the left side. Otherwise
1069 * just put the two under a new or data node. */
1070 if ( $2->reOrItem->type == ReOrItem::Data &&
1071 $1->reOrBlock->type == ReOrBlock::RecurseItem &&
1072 $1->reOrBlock->item->type == ReOrItem::Data )
1074 /* Append the right side to right side of the left and toss the
1076 $1->reOrBlock->item->token.append( $2->reOrItem->token );
1077 delete $2->reOrItem;
1078 $$->reOrBlock = $1->reOrBlock;
1081 /* Can't optimize, put the left and right under a new node. */
1082 $$->reOrBlock = new ReOrBlock( $1->reOrBlock, $2->reOrItem );
1085 regular_expr_or_data:
1087 $$->reOrBlock = new ReOrBlock();
1090 # A single character inside of an or expression. Can either be a character or a
1091 # set of characters.
1092 nonterm regular_expr_or_char
1097 regular_expr_or_char:
1099 $$->reOrItem = new ReOrItem( $1->loc, *$1 );
1101 regular_expr_or_char:
1102 RE_Char RE_Dash RE_Char final {
1103 $$->reOrItem = new ReOrItem( $2->loc, $1->data[0], $3->data[0] );
1107 # Inline Lists for inline host code.
1112 InlineList *inlineList;
1115 nonterm inline_block uses inline_list;
1118 inline_block inline_block_item
1120 /* Append the item to the list, return the list. */
1121 $$->inlineList = $1->inlineList;
1122 $$->inlineList->append( $2->inlineItem );
1127 /* Start with empty list. */
1128 $$->inlineList = new InlineList;
1133 InlineItem *inlineItem;
1136 nonterm inline_block_item uses inline_item;
1137 nonterm inline_block_interpret uses inline_item;
1142 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1148 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1152 inline_block_interpret
1154 /* Pass the inline item up. */
1155 $$->inlineItem = $1->inlineItem;
1158 nonterm inline_block_symbol uses token_type;
1160 inline_block_symbol: ',' final { $$->token = *$1; };
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: TK_NameSep final { $$->token = *$1; };
1167 # Interpreted statements in a struct block. */
1168 inline_block_interpret:
1169 inline_expr_interpret final {
1170 /* Pass up interpreted items of inline expressions. */
1171 $$->inlineItem = $1->inlineItem;
1173 inline_block_interpret:
1175 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Hold );
1177 inline_block_interpret:
1178 KW_Exec inline_expr ';' final {
1179 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Exec );
1180 $$->inlineItem->children = $2->inlineList;
1182 inline_block_interpret:
1183 KW_Goto state_ref ';' final {
1184 $$->inlineItem = new InlineItem( $1->loc,
1185 new NameRef(nameRef), InlineItem::Goto );
1187 inline_block_interpret:
1188 KW_Goto '*' inline_expr ';' final {
1189 $$->inlineItem = new InlineItem( $1->loc, InlineItem::GotoExpr );
1190 $$->inlineItem->children = $3->inlineList;
1192 inline_block_interpret:
1193 KW_Next state_ref ';' final {
1194 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Next );
1196 inline_block_interpret:
1197 KW_Next '*' inline_expr ';' final {
1198 $$->inlineItem = new InlineItem( $1->loc, InlineItem::NextExpr );
1199 $$->inlineItem->children = $3->inlineList;
1201 inline_block_interpret:
1202 KW_Call state_ref ';' final {
1203 $$->inlineItem = new InlineItem( $1->loc, new NameRef(nameRef), InlineItem::Call );
1205 inline_block_interpret:
1206 KW_Call '*' inline_expr ';' final {
1207 $$->inlineItem = new InlineItem( $1->loc, InlineItem::CallExpr );
1208 $$->inlineItem->children = $3->inlineList;
1210 inline_block_interpret:
1212 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Ret );
1214 inline_block_interpret:
1215 KW_Break ';' final {
1216 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Break );
1219 nonterm inline_expr uses inline_list;
1222 inline_expr inline_expr_item
1224 $$->inlineList = $1->inlineList;
1225 $$->inlineList->append( $2->inlineItem );
1229 /* Init the list used for this expr. */
1230 $$->inlineList = new InlineList;
1233 nonterm inline_expr_item uses inline_item;
1238 /* Return a text segment. */
1239 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1244 /* Return a text segment, must heap alloc the text. */
1245 $$->inlineItem = new InlineItem( $1->token.loc, $1->token.data, InlineItem::Text );
1248 inline_expr_interpret
1250 /* Pass the inline item up. */
1251 $$->inlineItem = $1->inlineItem;
1254 nonterm inline_expr_any uses token_type;
1256 inline_expr_any: IL_WhiteSpace try { $$->token = *$1; };
1257 inline_expr_any: IL_Comment try { $$->token = *$1; };
1258 inline_expr_any: IL_Literal try { $$->token = *$1; };
1259 inline_expr_any: IL_Symbol try { $$->token = *$1; };
1260 inline_expr_any: TK_UInt try { $$->token = *$1; };
1261 inline_expr_any: TK_Hex try { $$->token = *$1; };
1262 inline_expr_any: TK_Word try { $$->token = *$1; };
1264 # Anything in a ExecValExpr that is not dynamically allocated. This includes
1265 # all special symbols caught in inline code except the semi.
1267 nonterm inline_expr_symbol uses token_type;
1269 inline_expr_symbol: ',' try { $$->token = *$1; };
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: TK_NameSep try { $$->token = *$1; };
1275 nonterm inline_expr_interpret uses inline_item;
1277 inline_expr_interpret:
1280 $$->inlineItem = new InlineItem( $1->loc, InlineItem::PChar );
1282 inline_expr_interpret:
1285 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Char );
1287 inline_expr_interpret:
1290 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Curs );
1292 inline_expr_interpret:
1295 $$->inlineItem = new InlineItem( $1->loc, InlineItem::Targs );
1297 inline_expr_interpret:
1298 KW_Entry '(' state_ref ')'
1300 $$->inlineItem = new InlineItem( $1->loc,
1301 new NameRef(nameRef), InlineItem::Entry );
1304 # A local state reference. Cannot have :: prefix.
1306 no_name_sep state_ref_names;
1308 # Clear the name ref structure.
1314 # A qualified state reference.
1315 state_ref: opt_name_sep state_ref_names;
1317 # Optional leading name separator.
1321 /* Insert an initial null pointer val to indicate the existence of the
1322 * initial name seperator. */
1330 # List of names separated by ::
1332 state_ref_names TK_NameSep TK_Word
1334 nameRef.append( $3->data );
1339 nameRef.append( $1->data );
1354 int Parser::parseLangEl( int type, const Token *token )
1357 return errCount == 0 ? 0 : -1;
1360 void Parser::tryMachineDef( InputLoc &loc, char *name,
1361 JoinOrLm *joinOrLm, bool isInstance )
1363 GraphDictEl *newEl = pd->graphDict.insert( name );
1365 /* New element in the dict, all good. */
1366 newEl->value = new VarDef( name, joinOrLm );
1367 newEl->isInstance = isInstance;
1370 /* It it is an instance, put on the instance list. */
1372 pd->instanceList.append( newEl );
1375 // Recover by ignoring the duplicate.
1376 error(loc) << "fsm \"" << name << "\" previously defined" << endl;
1380 ostream &Parser::parse_error( int tokId, Token &token )
1382 /* Maintain the error count. */
1385 cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
1386 cerr << "at token ";
1388 cerr << "\"" << Parser_lelNames[tokId] << "\"";
1390 cerr << Parser_lelNames[tokId];
1391 if ( token.data != 0 )
1392 cerr << " with data \"" << token.data << "\"";
1398 int Parser::token( InputLoc &loc, int tokId, char *tokstart, int toklen )
1401 token.data = tokstart;
1402 token.length = toklen;
1404 int res = parseLangEl( tokId, &token );
1406 parse_error(tokId, token) << "parse error" << endl;