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
35 Key readKey( char *td, char **end );
36 long readOffsetPtr( char *td, char **end );
37 unsigned long readLength( char *td );
43 include "xmlparse.kh";
48 /* If we get no input the assumption is that the frontend died and
49 * emitted an error. This forces the backend to return a non-zero
50 * exit status, but does not print an error. */
54 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
56 tag_ragel_head: TAG_ragel
58 /* Check version used to generated the intermediate file. */
59 Attribute *versionAttr = $1->tag->findAttr( "version" );
60 if ( versionAttr == 0 )
61 error($1->loc) << "tag <ragel> requires a version attribute" << endp;
62 if ( strcmp( versionAttr->value, VERSION ) != 0 )
63 error($1->loc) << "version mismatch between frontend and backend" << endp;
65 /* Check for file name attribute. */
66 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
67 if ( fileNameAttr == 0 )
68 error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
69 sourceFileName = fileNameAttr->value;
71 /* Check for language attribute. */
72 Attribute *langAttr = $1->tag->findAttr( "lang" );
74 error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
76 if ( strcmp( langAttr->value, "C" ) == 0 )
77 hostLang = &hostLangC;
78 else if ( strcmp( langAttr->value, "D" ) == 0 )
79 hostLang = &hostLangD;
80 else if ( strcmp( langAttr->value, "Java" ) == 0 )
81 hostLang = &hostLangJava;
82 else if ( strcmp( langAttr->value, "Ruby" ) == 0 )
83 hostLang = &hostLangRuby;
84 else if ( strcmp( langAttr->value, "C#" ) == 0 )
85 hostLang = &hostLangCSharp;
87 error($1->loc) << "expecting lang attribute to be "
88 "one of C, D, Java, Ruby or C#" << endp;
91 outStream = openOutput( sourceFileName );
94 ragel_def_list: ragel_def_list ragel_def;
97 host_or_write_list: host_or_write_list host_or_write;
100 host_or_write: tag_host;
101 host_or_write: tag_write;
104 TAG_host '/' TAG_host
106 Attribute *lineAttr = $1->tag->findAttr( "line" );
108 error($1->loc) << "tag <host> requires a line attribute" << endp;
110 int line = atoi( lineAttr->value );
112 lineDirective( *outStream, sourceFileName, line );
116 *outStream << $3->tag->content;
120 tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
122 /* Do this before distributing transitions out to singles and defaults
123 * makes life easier. */
124 cgd->redFsm->maxKey = cgd->findMaxKey();
126 cgd->redFsm->assignActionLocs();
128 /* Find the first final state (The final state with the lowest id). */
129 cgd->redFsm->findFirstFinState();
131 /* Call the user's callback. */
132 cgd->finishRagelDef();
135 tag_ragel_def_head: TAG_ragel_def
138 Attribute *nameAttr = $1->tag->findAttr( "name" );
139 if ( nameAttr != 0 ) {
140 fsmName = nameAttr->value;
142 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
146 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
147 codeGenMap.insert( fsmName, cgd );
151 cgd = makeCodeGen( sourceFileName, fsmName,
152 *outStream, wantComplete );
155 ::keyOps = &cgd->thisKeyOps;
158 ragel_def_item_list: ragel_def_item_list ragel_def_item;
159 ragel_def_item_list: ;
161 ragel_def_item: tag_alph_type;
162 ragel_def_item: tag_getkey_expr;
163 ragel_def_item: tag_access_expr;
164 ragel_def_item: tag_prepush_expr;
165 ragel_def_item: tag_postpop_expr;
166 ragel_def_item: tag_export_list;
167 ragel_def_item: tag_machine;
168 ragel_def_item: tag_p_expr;
169 ragel_def_item: tag_pe_expr;
170 ragel_def_item: tag_eof_expr;
171 ragel_def_item: tag_cs_expr;
172 ragel_def_item: tag_top_expr;
173 ragel_def_item: tag_stack_expr;
174 ragel_def_item: tag_act_expr;
175 ragel_def_item: tag_tokstart_expr;
176 ragel_def_item: tag_tokend_expr;
177 ragel_def_item: tag_data_expr;
179 tag_export_list: TAG_exports export_list '/' TAG_exports;
181 export_list: export_list tag_export;
184 tag_export: TAG_ex '/' TAG_ex
186 Attribute *nameAttr = $1->tag->findAttr( "name" );
188 error($1->loc) << "tag <ex> requires a name attribute" << endp;
190 char *td = $3->tag->content;
191 Key exportKey = readKey( td, &td );
192 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
196 tag_alph_type: TAG_alphtype '/' TAG_alphtype
198 if ( ! cgd->setAlphType( $3->tag->content ) )
199 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
202 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
204 cgd->getKeyExpr = $2->inlineList;
207 tag_access_expr: TAG_access inline_list '/' TAG_access
209 cgd->accessExpr = $2->inlineList;
212 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
214 cgd->prePushExpr = $2->inlineList;
217 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
219 cgd->postPopExpr = $2->inlineList;
222 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
223 final { cgd->pExpr = $2->inlineList; };
224 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
225 final { cgd->peExpr = $2->inlineList; };
226 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
227 final { cgd->eofExpr = $2->inlineList; };
228 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
229 final { cgd->csExpr = $2->inlineList; };
230 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
231 final { cgd->topExpr = $2->inlineList; };
232 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
233 final { cgd->stackExpr = $2->inlineList; };
234 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
235 final { cgd->actExpr = $2->inlineList; };
236 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
237 final { cgd->tokstartExpr = $2->inlineList; };
238 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
239 final { cgd->tokendExpr = $2->inlineList; };
240 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
241 final { cgd->dataExpr = $2->inlineList; };
244 tag_write: tag_write_head write_option_list '/' TAG_write
246 /* Terminate the options list and call the write statement handler. */
247 writeOptions.append(0);
248 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
250 /* Clear the options in prep for the next write statement. */
251 writeOptions.empty();
254 nonterm tag_write_head
259 tag_write_head: TAG_write
261 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
262 Attribute *lineAttr = $1->tag->findAttr( "line" );
263 Attribute *colAttr = $1->tag->findAttr( "col" );
266 error($1->loc) << "tag <write> requires a def_name attribute" << endp;
268 error($1->loc) << "tag <write> requires a line attribute" << endp;
270 error($1->loc) << "tag <write> requires a col attribute" << endp;
272 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
273 $$->loc.line = atoi(lineAttr->value);
274 $$->loc.col = atoi(colAttr->value);
276 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
278 source_error($$->loc) << "write statement given "
279 "but there are no machine instantiations" << endp;
283 ::keyOps = &cgd->thisKeyOps;
289 write_option_list: write_option_list tag_arg;
297 tag_arg: TAG_arg '/' TAG_arg
299 writeOptions.append( $3->tag->content );
302 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
307 tag_machine_head: TAG_machine
309 cgd->createMachine();
312 machine_item_list: machine_item_list machine_item;
315 machine_item: tag_start_state;
316 machine_item: tag_error_state;
317 machine_item: tag_entry_points;
318 machine_item: tag_state_list;
319 machine_item: tag_action_list;
320 machine_item: tag_action_table_list;
321 machine_item: tag_cond_space_list;
327 tag_start_state: TAG_start_state '/' TAG_start_state
329 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
330 cgd->setStartState( startState );
333 tag_error_state: TAG_error_state '/' TAG_error_state
335 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
336 cgd->setErrorState( errorState );
339 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
341 Attribute *errorAttr = $1->tag->findAttr( "error" );
342 if ( errorAttr != 0 )
343 cgd->setForcedErrorState();
346 entry_point_list: entry_point_list tag_entry;
349 tag_entry: TAG_entry '/' TAG_entry
351 Attribute *nameAttr = $1->tag->findAttr( "name" );
352 if ( nameAttr == 0 ) {
353 error($1->loc) << "tag <entry_points>::<entry> "
354 "requires a name attribute" << endp;
357 char *data = $3->tag->content;
358 unsigned long entry = strtoul( data, &data, 10 );
359 cgd->addEntryPoint( nameAttr->value, entry );
363 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
365 tag_state_list_head: TAG_state_list
367 Attribute *lengthAttr = $1->tag->findAttr( "length" );
368 if ( lengthAttr == 0 )
369 error($1->loc) << "tag <state_list> requires a length attribute" << endp;
371 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
372 cgd->initStateList( length );
377 state_list: state_list tag_state;
380 tag_state: TAG_state state_item_list '/' TAG_state
382 Attribute *idAttr = $1->tag->findAttr( "id" );
384 error($1->loc) << "tag <state> requires an id attribute" << endp;
386 int id = atoi( idAttr->value );
387 cgd->setId( curState, id );
390 Attribute *lengthAttr = $1->tag->findAttr( "final" );
391 if ( lengthAttr != 0 )
392 cgd->setFinal( curState );
396 state_item_list: state_item_list state_item;
399 state_item: tag_state_actions;
400 state_item: tag_eof_t;
401 state_item: tag_state_cond_list;
402 state_item: tag_trans_list;
404 tag_state_actions: TAG_state_actions '/' TAG_state_actions
406 char *ad = $3->tag->content;
408 long toStateAction = readOffsetPtr( ad, &ad );
409 long fromStateAction = readOffsetPtr( ad, &ad );
410 long eofAction = readOffsetPtr( ad, &ad );
412 cgd->setStateActions( curState, toStateAction,
413 fromStateAction, eofAction );
416 tag_eof_t: TAG_eof_t '/' TAG_eof_t
418 char *et = $3->tag->content;
419 long targ = readOffsetPtr( et, &et );
420 long eofAction = readOffsetPtr( et, &et );
422 cgd->setEofTrans( curState, targ, eofAction );
425 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
427 tag_state_cond_list_head: TAG_cond_list
429 Attribute *lengthAttr = $1->tag->findAttr( "length" );
430 if ( lengthAttr == 0 )
431 error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
433 ulong length = readLength( lengthAttr->value );
434 cgd->initStateCondList( curState, length );
439 state_cond_list: state_cond_list state_cond;
442 state_cond: TAG_c '/' TAG_c
444 char *td = $3->tag->content;
445 Key lowKey = readKey( td, &td );
446 Key highKey = readKey( td, &td );
447 long condId = readOffsetPtr( td, &td );
448 cgd->addStateCond( curState, lowKey, highKey, condId );
451 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
453 cgd->finishTransList( curState );
456 tag_trans_list_head: TAG_trans_list
458 Attribute *lengthAttr = $1->tag->findAttr( "length" );
459 if ( lengthAttr == 0 )
460 error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
462 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
463 cgd->initTransList( curState, length );
468 trans_list: trans_list tag_trans;
471 tag_trans: TAG_t '/' TAG_t
473 char *td = $3->tag->content;
474 Key lowKey = readKey( td, &td );
475 Key highKey = readKey( td, &td );
476 long targ = readOffsetPtr( td, &td );
477 long action = readOffsetPtr( td, &td );
479 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
486 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
488 tag_action_list_head: TAG_action_list
490 Attribute *lengthAttr = $1->tag->findAttr( "length" );
491 if ( lengthAttr == 0 )
492 error($1->loc) << "tag <action_list> requires a length attribute" << endp;
494 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
495 cgd->initActionList( length );
500 action_list: action_list tag_action;
507 tag_action: TAG_action inline_list '/' TAG_action
509 Attribute *lineAttr = $1->tag->findAttr( "line" );
510 Attribute *colAttr = $1->tag->findAttr( "col" );
511 Attribute *nameAttr = $1->tag->findAttr( "name" );
512 if ( lineAttr == 0 || colAttr == 0)
513 error($1->loc) << "tag <action> requires a line and col attributes" << endp;
515 unsigned long line = strtoul( lineAttr->value, 0, 10 );
516 unsigned long col = strtoul( colAttr->value, 0, 10 );
520 name = nameAttr->value;
522 cgd->newAction( curAction++, name, line, col, $2->inlineList );
528 InlineList *inlineList;
532 inline_list: inline_list inline_item
534 /* Append the item to the list, return the list. */
535 $1->inlineList->append( $2->inlineItem );
536 $$->inlineList = $1->inlineList;
541 /* Start with empty list. */
542 $$->inlineList = new InlineList;
545 nonterm inline_item_type
547 InlineItem *inlineItem;
550 nonterm inline_item uses inline_item_type;
552 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
553 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
554 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
555 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
556 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
557 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
558 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
559 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
560 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
561 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
562 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
563 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
564 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
565 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
566 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
567 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
568 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
569 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
570 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
571 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
572 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
573 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
574 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
575 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
577 nonterm tag_text uses inline_item_type;
578 nonterm tag_goto uses inline_item_type;
579 nonterm tag_call uses inline_item_type;
580 nonterm tag_next uses inline_item_type;
581 nonterm tag_goto_expr uses inline_item_type;
582 nonterm tag_call_expr uses inline_item_type;
583 nonterm tag_next_expr uses inline_item_type;
584 nonterm tag_ret uses inline_item_type;
585 nonterm tag_break uses inline_item_type;
586 nonterm tag_pchar uses inline_item_type;
587 nonterm tag_char uses inline_item_type;
588 nonterm tag_hold uses inline_item_type;
589 nonterm tag_exec uses inline_item_type;
590 nonterm tag_curs uses inline_item_type;
591 nonterm tag_targs uses inline_item_type;
592 nonterm tag_il_entry uses inline_item_type;
593 nonterm tag_init_tokstart uses inline_item_type;
594 nonterm tag_init_act uses inline_item_type;
595 nonterm tag_get_tokend uses inline_item_type;
596 nonterm tag_set_tokstart uses inline_item_type;
597 nonterm tag_set_tokend uses inline_item_type;
598 nonterm tag_set_act uses inline_item_type;
599 nonterm tag_sub_action uses inline_item_type;
600 nonterm tag_lm_switch uses inline_item_type;
602 tag_text: TAG_text '/' TAG_text
604 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
605 $$->inlineItem->data = $3->tag->content;
608 tag_goto: TAG_goto '/' TAG_goto
610 int targ = strtol( $3->tag->content, 0, 10 );
611 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
612 $$->inlineItem->targId = targ;
615 tag_call: TAG_call '/' TAG_call
617 int targ = strtol( $3->tag->content, 0, 10 );
618 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
619 $$->inlineItem->targId = targ;
622 tag_next: TAG_next '/' TAG_next
624 int targ = strtol( $3->tag->content, 0, 10 );
625 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
626 $$->inlineItem->targId = targ;
629 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
631 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
632 $$->inlineItem->children = $2->inlineList;
635 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
637 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
638 $$->inlineItem->children = $2->inlineList;
641 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
643 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
644 $$->inlineItem->children = $2->inlineList;
647 tag_ret: TAG_ret '/' TAG_ret
649 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
652 tag_break: TAG_break '/' TAG_break
654 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
657 tag_pchar: TAG_pchar '/' TAG_pchar
659 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
662 tag_char: TAG_char '/' TAG_char
664 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
667 tag_hold: TAG_hold '/' TAG_hold
669 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
672 tag_exec: TAG_exec inline_list '/' TAG_exec
674 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
675 $$->inlineItem->children = $2->inlineList;
678 tag_curs: TAG_curs '/' TAG_curs
680 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
683 tag_targs: TAG_targs '/' TAG_targs
685 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
688 tag_il_entry: TAG_entry '/' TAG_entry
690 int targ = strtol( $3->tag->content, 0, 10 );
691 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
692 $$->inlineItem->targId = targ;
695 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
697 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
700 tag_init_act: TAG_init_act '/' TAG_init_act
702 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
705 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
707 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
710 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
712 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
713 cgd->hasLongestMatch = true;
716 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
718 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
719 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
722 tag_set_act: TAG_set_act '/' TAG_set_act
724 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
725 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
728 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
730 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
731 $$->inlineItem->children = $2->inlineList;
735 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
737 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
738 $$->inlineItem->children = $2->inlineList;
741 nonterm lm_action_list
743 InlineList *inlineList;
746 lm_action_list: lm_action_list tag_inline_action
748 $$->inlineList = $1->inlineList;
749 $$->inlineList->append( $2->inlineItem );
753 $$->inlineList = new InlineList;
756 nonterm tag_inline_action uses inline_item_type;
758 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
760 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
761 $$->inlineItem->children = $2->inlineList;
763 Attribute *idAttr = $1->tag->findAttr( "id" );
765 unsigned long id = strtoul( idAttr->value, 0, 10 );
766 $$->inlineItem->lmId = id;
774 tag_action_table_list:
775 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
777 tag_action_table_list_head: TAG_action_table_list
779 Attribute *lengthAttr = $1->tag->findAttr( "length" );
780 if ( lengthAttr == 0 ) {
781 error($1->loc) << "tag <action_table_list> requires "
782 "a length attribute" << endp;
785 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
786 cgd->initActionTableList( length );
791 action_table_list: action_table_list tag_action_table;
794 tag_action_table: TAG_action_table '/' TAG_action_table
796 /* Find the length of the action table. */
797 Attribute *lengthAttr = $1->tag->findAttr( "length" );
798 if ( lengthAttr == 0 )
799 error($1->loc) << "tag <at> requires a length attribute" << endp;
801 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
803 /* Collect the action table. */
804 RedAction *redAct = cgd->allActionTables + curActionTable;
805 redAct->actListId = curActionTable;
806 redAct->key.setAsNew( length );
807 char *ptr = $3->tag->content;
809 while ( *ptr != 0 ) {
810 unsigned long actionId = strtoul( ptr, &ptr, 10 );
811 redAct->key[pos].key = 0;
812 redAct->key[pos].value = cgd->allActions+actionId;
816 /* Insert into the action table map. */
817 cgd->redFsm->actionMap.insert( redAct );
827 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
829 tag_cond_space_list_head: TAG_cond_space_list
831 Attribute *lengthAttr = $1->tag->findAttr( "length" );
832 if ( lengthAttr == 0 ) {
833 error($1->loc) << "tag <cond_space_list> "
834 "requires a length attribute" << endp;
837 ulong length = readLength( lengthAttr->value );
838 cgd->initCondSpaceList( length );
843 cond_space_list: cond_space_list tag_cond_space;
844 cond_space_list: tag_cond_space;
846 tag_cond_space: TAG_cond_space '/' TAG_cond_space
848 Attribute *lengthAttr = $1->tag->findAttr( "length" );
849 Attribute *idAttr = $1->tag->findAttr( "id" );
850 if ( lengthAttr == 0 )
851 error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
853 if ( lengthAttr == 0 )
854 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
856 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
857 ulong length = readLength( lengthAttr->value );
859 char *td = $3->tag->content;
860 Key baseKey = readKey( td, &td );
862 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
863 for ( ulong a = 0; a < length; a++ ) {
864 long actionOffset = readOffsetPtr( td, &td );
865 cgd->condSpaceItem( curCondSpace, actionOffset );
884 int Parser::parseLangEl( int type, const Token *token )
887 return errCount == 0 ? 0 : -1;
891 unsigned long readLength( char *td )
893 return strtoul( td, 0, 10 );
896 Key readKey( char *td, char **end )
898 if ( keyOps->isSigned )
899 return Key( strtol( td, end, 10 ) );
901 return Key( strtoul( td, end, 10 ) );
904 long readOffsetPtr( char *td, char **end )
906 while ( *td == ' ' || *td == '\t' )
915 return strtol( td, end, 10 );
918 ostream &Parser::warning( const InputLoc &loc )
920 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
924 ostream &Parser::error( const InputLoc &loc )
927 assert( fileName != 0 );
928 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
933 ostream &Parser::parser_error( int tokId, Token &token )
936 assert( fileName != 0 );
937 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
938 if ( token.tag != 0 ) {
939 if ( token.tag->tagId == 0 )
940 cerr << ": at unknown tag";
942 cerr << ": at tag <" << token.tag->tagId->name << ">";
949 ostream &Parser::source_error( const InputLoc &loc )
952 assert( sourceFileName != 0 );
953 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
958 int Parser::token( int tokenId, Token &tok )
960 int res = parseLangEl( tokenId, &tok );
962 parser_error( tokenId, tok ) << "parse error" << endp;
966 int Parser::token( int tokenId, int col, int line )
972 return token( tokenId, tok );
975 int Parser::token( XMLTag *tag, int col, int line )
982 if ( tag->type == XMLTag::Close ) {
983 int res = token( '/', tok );
989 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );