2 * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
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 );
45 CodeGenData *makeCodeGen( const char *sourceFileName, const char *fsmName,
46 ostream &out, bool wantComplete )
50 cgd = dotMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
51 else if ( hostLang == &hostLangC )
52 cgd = cdMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
53 else if ( hostLang == &hostLangD )
54 cgd = cdMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
55 else if ( hostLang == &hostLangJava )
56 cgd = javaMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
57 else if ( hostLang == &hostLangRuby )
58 cgd = rubyMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
59 else if ( hostLang == &hostLangCSharp )
60 cgd = csharpMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
64 void lineDirective( ostream &out, const char *fileName, int line )
67 if ( hostLang == &hostLangC )
68 cdLineDirective( out, fileName, line );
69 else if ( hostLang == &hostLangD )
70 cdLineDirective( out, fileName, line );
71 else if ( hostLang == &hostLangJava )
72 javaLineDirective( out, fileName, line );
73 else if ( hostLang == &hostLangRuby )
74 rubyLineDirective( out, fileName, line );
75 else if ( hostLang == &hostLangCSharp )
76 csharpLineDirective( out, fileName, line );
80 void genLineDirective( ostream &out )
82 std::streambuf *sbuf = out.rdbuf();
83 output_filter *filter = static_cast<output_filter*>(sbuf);
84 lineDirective( out, filter->fileName, filter->line + 1 );
91 include "xmlparse.kh";
96 /* If we get no input the assumption is that the frontend died and
97 * emitted an error. This forces the backend to return a non-zero
98 * exit status, but does not print an error. */
102 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
104 tag_ragel_head: TAG_ragel
106 /* Check version used to generated the intermediate file. */
107 Attribute *versionAttr = $1->tag->findAttr( "version" );
108 if ( versionAttr == 0 )
109 error($1->loc) << "tag <ragel> requires a version attribute" << endp;
110 if ( strcmp( versionAttr->value, VERSION ) != 0 )
111 error($1->loc) << "version mismatch between frontend and backend" << endp;
113 /* Check for file name attribute. */
114 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
115 if ( fileNameAttr == 0 )
116 error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
117 sourceFileName = fileNameAttr->value;
119 /* Check for language attribute. */
120 Attribute *langAttr = $1->tag->findAttr( "lang" );
122 error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
125 outStream = dotOpenOutput( sourceFileName );
126 else if ( strcmp( langAttr->value, "C" ) == 0 ) {
127 hostLang = &hostLangC;
128 outStream = cdOpenOutput( sourceFileName );
130 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
131 hostLang = &hostLangD;
132 outStream = cdOpenOutput( sourceFileName );
134 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
135 hostLang = &hostLangJava;
136 outStream = javaOpenOutput( sourceFileName );
138 else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) {
139 hostLang = &hostLangRuby;
140 outStream = rubyOpenOutput( sourceFileName );
142 else if ( strcmp( langAttr->value, "C#" ) == 0 ) {
143 hostLang = &hostLangCSharp;
144 outStream = csharpOpenOutput( sourceFileName );
147 error($1->loc) << "expecting lang attribute to be "
148 "one of C, D, Java, Ruby or C#" << endp;
152 ragel_def_list: ragel_def_list ragel_def;
155 host_or_write_list: host_or_write_list host_or_write;
156 host_or_write_list: ;
158 host_or_write: tag_host;
159 host_or_write: tag_write;
162 TAG_host '/' TAG_host
164 Attribute *lineAttr = $1->tag->findAttr( "line" );
166 error($1->loc) << "tag <host> requires a line attribute" << endp;
168 int line = atoi( lineAttr->value );
170 lineDirective( *outStream, sourceFileName, line );
174 *outStream << $3->tag->content;
178 tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
180 /* Do this before distributing transitions out to singles and defaults
181 * makes life easier. */
182 cgd->redFsm->maxKey = cgd->findMaxKey();
184 cgd->redFsm->assignActionLocs();
186 /* Find the first final state (The final state with the lowest id). */
187 cgd->redFsm->findFirstFinState();
189 /* Call the user's callback. */
190 cgd->finishRagelDef();
193 tag_ragel_def_head: TAG_ragel_def
196 Attribute *nameAttr = $1->tag->findAttr( "name" );
197 if ( nameAttr != 0 ) {
198 fsmName = nameAttr->value;
200 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
204 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
205 codeGenMap.insert( fsmName, cgd );
209 cgd = makeCodeGen( sourceFileName, fsmName,
210 *outStream, wantComplete );
213 ::keyOps = &cgd->thisKeyOps;
216 ragel_def_item_list: ragel_def_item_list ragel_def_item;
217 ragel_def_item_list: ;
219 ragel_def_item: tag_alph_type;
220 ragel_def_item: tag_getkey_expr;
221 ragel_def_item: tag_access_expr;
222 ragel_def_item: tag_prepush_expr;
223 ragel_def_item: tag_postpop_expr;
224 ragel_def_item: tag_export_list;
225 ragel_def_item: tag_machine;
226 ragel_def_item: tag_p_expr;
227 ragel_def_item: tag_pe_expr;
228 ragel_def_item: tag_eof_expr;
229 ragel_def_item: tag_cs_expr;
230 ragel_def_item: tag_top_expr;
231 ragel_def_item: tag_stack_expr;
232 ragel_def_item: tag_act_expr;
233 ragel_def_item: tag_tokstart_expr;
234 ragel_def_item: tag_tokend_expr;
235 ragel_def_item: tag_data_expr;
237 tag_export_list: TAG_exports export_list '/' TAG_exports;
239 export_list: export_list tag_export;
242 tag_export: TAG_ex '/' TAG_ex
244 Attribute *nameAttr = $1->tag->findAttr( "name" );
246 error($1->loc) << "tag <ex> requires a name attribute" << endp;
248 char *td = $3->tag->content;
249 Key exportKey = readKey( td, &td );
250 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
254 tag_alph_type: TAG_alphtype '/' TAG_alphtype
256 if ( ! cgd->setAlphType( $3->tag->content ) )
257 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
260 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
262 cgd->getKeyExpr = $2->inlineList;
265 tag_access_expr: TAG_access inline_list '/' TAG_access
267 cgd->accessExpr = $2->inlineList;
270 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
272 cgd->prePushExpr = $2->inlineList;
275 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
277 cgd->postPopExpr = $2->inlineList;
280 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
281 final { cgd->pExpr = $2->inlineList; };
282 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
283 final { cgd->peExpr = $2->inlineList; };
284 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
285 final { cgd->eofExpr = $2->inlineList; };
286 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
287 final { cgd->csExpr = $2->inlineList; };
288 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
289 final { cgd->topExpr = $2->inlineList; };
290 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
291 final { cgd->stackExpr = $2->inlineList; };
292 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
293 final { cgd->actExpr = $2->inlineList; };
294 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
295 final { cgd->tokstartExpr = $2->inlineList; };
296 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
297 final { cgd->tokendExpr = $2->inlineList; };
298 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
299 final { cgd->dataExpr = $2->inlineList; };
302 tag_write: tag_write_head write_option_list '/' TAG_write
304 /* Terminate the options list and call the write statement handler. */
305 writeOptions.append(0);
306 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
308 /* Clear the options in prep for the next write statement. */
309 writeOptions.empty();
312 nonterm tag_write_head
317 tag_write_head: TAG_write
319 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
320 Attribute *lineAttr = $1->tag->findAttr( "line" );
321 Attribute *colAttr = $1->tag->findAttr( "col" );
324 error($1->loc) << "tag <write> requires a def_name attribute" << endp;
326 error($1->loc) << "tag <write> requires a line attribute" << endp;
328 error($1->loc) << "tag <write> requires a col attribute" << endp;
330 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
331 $$->loc.line = atoi(lineAttr->value);
332 $$->loc.col = atoi(colAttr->value);
334 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
336 source_error($$->loc) << "write statement given "
337 "but there are no machine instantiations" << endp;
341 ::keyOps = &cgd->thisKeyOps;
347 write_option_list: write_option_list tag_arg;
355 tag_arg: TAG_arg '/' TAG_arg
357 writeOptions.append( $3->tag->content );
360 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
365 tag_machine_head: TAG_machine
367 cgd->createMachine();
370 machine_item_list: machine_item_list machine_item;
373 machine_item: tag_start_state;
374 machine_item: tag_error_state;
375 machine_item: tag_entry_points;
376 machine_item: tag_state_list;
377 machine_item: tag_action_list;
378 machine_item: tag_action_table_list;
379 machine_item: tag_cond_space_list;
385 tag_start_state: TAG_start_state '/' TAG_start_state
387 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
388 cgd->setStartState( startState );
391 tag_error_state: TAG_error_state '/' TAG_error_state
393 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
394 cgd->setErrorState( errorState );
397 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
399 Attribute *errorAttr = $1->tag->findAttr( "error" );
400 if ( errorAttr != 0 )
401 cgd->setForcedErrorState();
404 entry_point_list: entry_point_list tag_entry;
407 tag_entry: TAG_entry '/' TAG_entry
409 Attribute *nameAttr = $1->tag->findAttr( "name" );
410 if ( nameAttr == 0 ) {
411 error($1->loc) << "tag <entry_points>::<entry> "
412 "requires a name attribute" << endp;
415 char *data = $3->tag->content;
416 unsigned long entry = strtoul( data, &data, 10 );
417 cgd->addEntryPoint( nameAttr->value, entry );
421 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
423 tag_state_list_head: TAG_state_list
425 Attribute *lengthAttr = $1->tag->findAttr( "length" );
426 if ( lengthAttr == 0 )
427 error($1->loc) << "tag <state_list> requires a length attribute" << endp;
429 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
430 cgd->initStateList( length );
435 state_list: state_list tag_state;
438 tag_state: TAG_state state_item_list '/' TAG_state
440 Attribute *idAttr = $1->tag->findAttr( "id" );
442 error($1->loc) << "tag <state> requires an id attribute" << endp;
444 int id = atoi( idAttr->value );
445 cgd->setId( curState, id );
448 Attribute *lengthAttr = $1->tag->findAttr( "final" );
449 if ( lengthAttr != 0 )
450 cgd->setFinal( curState );
454 state_item_list: state_item_list state_item;
457 state_item: tag_state_actions;
458 state_item: tag_eof_t;
459 state_item: tag_state_cond_list;
460 state_item: tag_trans_list;
462 tag_state_actions: TAG_state_actions '/' TAG_state_actions
464 char *ad = $3->tag->content;
466 long toStateAction = readOffsetPtr( ad, &ad );
467 long fromStateAction = readOffsetPtr( ad, &ad );
468 long eofAction = readOffsetPtr( ad, &ad );
470 cgd->setStateActions( curState, toStateAction,
471 fromStateAction, eofAction );
474 tag_eof_t: TAG_eof_t '/' TAG_eof_t
476 char *et = $3->tag->content;
477 long targ = readOffsetPtr( et, &et );
478 long eofAction = readOffsetPtr( et, &et );
480 cgd->setEofTrans( curState, targ, eofAction );
483 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
485 tag_state_cond_list_head: TAG_cond_list
487 Attribute *lengthAttr = $1->tag->findAttr( "length" );
488 if ( lengthAttr == 0 )
489 error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
491 ulong length = readLength( lengthAttr->value );
492 cgd->initStateCondList( curState, length );
497 state_cond_list: state_cond_list state_cond;
500 state_cond: TAG_c '/' TAG_c
502 char *td = $3->tag->content;
503 Key lowKey = readKey( td, &td );
504 Key highKey = readKey( td, &td );
505 long condId = readOffsetPtr( td, &td );
506 cgd->addStateCond( curState, lowKey, highKey, condId );
509 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
511 cgd->finishTransList( curState );
514 tag_trans_list_head: TAG_trans_list
516 Attribute *lengthAttr = $1->tag->findAttr( "length" );
517 if ( lengthAttr == 0 )
518 error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
520 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
521 cgd->initTransList( curState, length );
526 trans_list: trans_list tag_trans;
529 tag_trans: TAG_t '/' TAG_t
531 char *td = $3->tag->content;
532 Key lowKey = readKey( td, &td );
533 Key highKey = readKey( td, &td );
534 long targ = readOffsetPtr( td, &td );
535 long action = readOffsetPtr( td, &td );
537 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
544 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
546 tag_action_list_head: TAG_action_list
548 Attribute *lengthAttr = $1->tag->findAttr( "length" );
549 if ( lengthAttr == 0 )
550 error($1->loc) << "tag <action_list> requires a length attribute" << endp;
552 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
553 cgd->initActionList( length );
558 action_list: action_list tag_action;
565 tag_action: TAG_action inline_list '/' TAG_action
567 Attribute *lineAttr = $1->tag->findAttr( "line" );
568 Attribute *colAttr = $1->tag->findAttr( "col" );
569 Attribute *nameAttr = $1->tag->findAttr( "name" );
570 if ( lineAttr == 0 || colAttr == 0)
571 error($1->loc) << "tag <action> requires a line and col attributes" << endp;
573 unsigned long line = strtoul( lineAttr->value, 0, 10 );
574 unsigned long col = strtoul( colAttr->value, 0, 10 );
578 name = nameAttr->value;
580 cgd->newAction( curAction++, name, line, col, $2->inlineList );
586 GenInlineList *inlineList;
590 inline_list: inline_list inline_item
592 /* Append the item to the list, return the list. */
593 $1->inlineList->append( $2->inlineItem );
594 $$->inlineList = $1->inlineList;
599 /* Start with empty list. */
600 $$->inlineList = new GenInlineList;
603 nonterm inline_item_type
605 GenInlineItem *inlineItem;
608 nonterm inline_item uses inline_item_type;
610 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
611 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
612 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
613 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
614 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
615 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
616 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
617 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
618 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
619 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
620 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
621 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
622 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
623 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
624 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
625 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
626 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
627 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
628 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
629 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
630 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
631 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
632 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
633 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
635 nonterm tag_text uses inline_item_type;
636 nonterm tag_goto uses inline_item_type;
637 nonterm tag_call uses inline_item_type;
638 nonterm tag_next uses inline_item_type;
639 nonterm tag_goto_expr uses inline_item_type;
640 nonterm tag_call_expr uses inline_item_type;
641 nonterm tag_next_expr uses inline_item_type;
642 nonterm tag_ret uses inline_item_type;
643 nonterm tag_break uses inline_item_type;
644 nonterm tag_pchar uses inline_item_type;
645 nonterm tag_char uses inline_item_type;
646 nonterm tag_hold uses inline_item_type;
647 nonterm tag_exec uses inline_item_type;
648 nonterm tag_curs uses inline_item_type;
649 nonterm tag_targs uses inline_item_type;
650 nonterm tag_il_entry uses inline_item_type;
651 nonterm tag_init_tokstart uses inline_item_type;
652 nonterm tag_init_act uses inline_item_type;
653 nonterm tag_get_tokend uses inline_item_type;
654 nonterm tag_set_tokstart uses inline_item_type;
655 nonterm tag_set_tokend uses inline_item_type;
656 nonterm tag_set_act uses inline_item_type;
657 nonterm tag_sub_action uses inline_item_type;
658 nonterm tag_lm_switch uses inline_item_type;
660 tag_text: TAG_text '/' TAG_text
662 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text );
663 $$->inlineItem->data = $3->tag->content;
666 tag_goto: TAG_goto '/' TAG_goto
668 int targ = strtol( $3->tag->content, 0, 10 );
669 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
670 $$->inlineItem->targId = targ;
673 tag_call: TAG_call '/' TAG_call
675 int targ = strtol( $3->tag->content, 0, 10 );
676 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Call );
677 $$->inlineItem->targId = targ;
680 tag_next: TAG_next '/' TAG_next
682 int targ = strtol( $3->tag->content, 0, 10 );
683 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Next );
684 $$->inlineItem->targId = targ;
687 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
689 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::GotoExpr );
690 $$->inlineItem->children = $2->inlineList;
693 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
695 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::CallExpr );
696 $$->inlineItem->children = $2->inlineList;
699 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
701 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::NextExpr );
702 $$->inlineItem->children = $2->inlineList;
705 tag_ret: TAG_ret '/' TAG_ret
707 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Ret );
710 tag_break: TAG_break '/' TAG_break
712 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Break );
715 tag_pchar: TAG_pchar '/' TAG_pchar
717 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::PChar );
720 tag_char: TAG_char '/' TAG_char
722 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Char );
725 tag_hold: TAG_hold '/' TAG_hold
727 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Hold );
730 tag_exec: TAG_exec inline_list '/' TAG_exec
732 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
733 $$->inlineItem->children = $2->inlineList;
736 tag_curs: TAG_curs '/' TAG_curs
738 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Curs );
741 tag_targs: TAG_targs '/' TAG_targs
743 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Targs );
746 tag_il_entry: TAG_entry '/' TAG_entry
748 int targ = strtol( $3->tag->content, 0, 10 );
749 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Entry );
750 $$->inlineItem->targId = targ;
753 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
755 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart );
758 tag_init_act: TAG_init_act '/' TAG_init_act
760 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct );
763 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
765 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
768 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
770 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart );
771 cgd->hasLongestMatch = true;
774 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
776 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
777 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
780 tag_set_act: TAG_set_act '/' TAG_set_act
782 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
783 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
786 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
788 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
789 $$->inlineItem->children = $2->inlineList;
793 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
795 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
796 $$->inlineItem->children = $2->inlineList;
799 nonterm lm_action_list
801 GenInlineList *inlineList;
804 lm_action_list: lm_action_list tag_inline_action
806 $$->inlineList = $1->inlineList;
807 $$->inlineList->append( $2->inlineItem );
811 $$->inlineList = new GenInlineList;
814 nonterm tag_inline_action uses inline_item_type;
816 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
818 $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
819 $$->inlineItem->children = $2->inlineList;
821 Attribute *idAttr = $1->tag->findAttr( "id" );
823 unsigned long id = strtoul( idAttr->value, 0, 10 );
824 $$->inlineItem->lmId = id;
832 tag_action_table_list:
833 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
835 tag_action_table_list_head: TAG_action_table_list
837 Attribute *lengthAttr = $1->tag->findAttr( "length" );
838 if ( lengthAttr == 0 ) {
839 error($1->loc) << "tag <action_table_list> requires "
840 "a length attribute" << endp;
843 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
844 cgd->initActionTableList( length );
849 action_table_list: action_table_list tag_action_table;
852 tag_action_table: TAG_action_table '/' TAG_action_table
854 /* Find the length of the action table. */
855 Attribute *lengthAttr = $1->tag->findAttr( "length" );
856 if ( lengthAttr == 0 )
857 error($1->loc) << "tag <at> requires a length attribute" << endp;
859 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
861 /* Collect the action table. */
862 RedAction *redAct = cgd->allActionTables + curActionTable;
863 redAct->actListId = curActionTable;
864 redAct->key.setAsNew( length );
865 char *ptr = $3->tag->content;
867 while ( *ptr != 0 ) {
868 unsigned long actionId = strtoul( ptr, &ptr, 10 );
869 redAct->key[pos].key = 0;
870 redAct->key[pos].value = cgd->allActions+actionId;
874 /* Insert into the action table map. */
875 cgd->redFsm->actionMap.insert( redAct );
885 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
887 tag_cond_space_list_head: TAG_cond_space_list
889 Attribute *lengthAttr = $1->tag->findAttr( "length" );
890 if ( lengthAttr == 0 ) {
891 error($1->loc) << "tag <cond_space_list> "
892 "requires a length attribute" << endp;
895 ulong length = readLength( lengthAttr->value );
896 cgd->initCondSpaceList( length );
901 cond_space_list: cond_space_list tag_cond_space;
902 cond_space_list: tag_cond_space;
904 tag_cond_space: TAG_cond_space '/' TAG_cond_space
906 Attribute *lengthAttr = $1->tag->findAttr( "length" );
907 Attribute *idAttr = $1->tag->findAttr( "id" );
908 if ( lengthAttr == 0 )
909 error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
911 if ( lengthAttr == 0 )
912 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
914 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
915 ulong length = readLength( lengthAttr->value );
917 char *td = $3->tag->content;
918 Key baseKey = readKey( td, &td );
920 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
921 for ( ulong a = 0; a < length; a++ ) {
922 long actionOffset = readOffsetPtr( td, &td );
923 cgd->condSpaceItem( curCondSpace, actionOffset );
937 void XmlParser::init()
942 int XmlParser::parseLangEl( int type, const Token *token )
945 return errCount == 0 ? 0 : -1;
949 unsigned long readLength( char *td )
951 return strtoul( td, 0, 10 );
954 Key readKey( char *td, char **end )
956 if ( keyOps->isSigned )
957 return Key( strtol( td, end, 10 ) );
959 return Key( strtoul( td, end, 10 ) );
962 long readOffsetPtr( char *td, char **end )
964 while ( *td == ' ' || *td == '\t' )
973 return strtol( td, end, 10 );
976 ostream &XmlParser::warning( const InputLoc &loc )
978 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
982 ostream &XmlParser::error( const InputLoc &loc )
985 assert( fileName != 0 );
986 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
991 ostream &XmlParser::parser_error( int tokId, Token &token )
994 assert( fileName != 0 );
995 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
996 if ( token.tag != 0 ) {
997 if ( token.tag->tagId == 0 )
998 cerr << ": at unknown tag";
1000 cerr << ": at tag <" << token.tag->tagId->name << ">";
1007 ostream &XmlParser::source_error( const InputLoc &loc )
1010 assert( sourceFileName != 0 );
1011 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1016 int XmlParser::token( int tokenId, Token &tok )
1018 int res = parseLangEl( tokenId, &tok );
1020 parser_error( tokenId, tok ) << "parse error" << endp;
1024 int XmlParser::token( int tokenId, int col, int line )
1028 tok.loc.line = line;
1030 return token( tokenId, tok );
1033 int XmlParser::token( XMLTag *tag, int col, int line )
1037 tok.loc.line = line;
1040 if ( tag->type == XMLTag::Close ) {
1041 int res = token( '/', tok );
1047 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );