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 );
87 void XmlParser::open_ragel( const char *fileName )
89 /* Check for file name attribute. */
90 sourceFileName = fileName;
93 outStream = dotOpenOutput( sourceFileName );
94 else if ( hostLang->lang == HostLang::C ) {
95 hostLang = &hostLangC;
96 outStream = cdOpenOutput( sourceFileName );
98 else if ( hostLang->lang == HostLang::D ) {
99 hostLang = &hostLangD;
100 outStream = cdOpenOutput( sourceFileName );
102 else if ( hostLang->lang == HostLang::Java ) {
103 hostLang = &hostLangJava;
104 outStream = javaOpenOutput( sourceFileName );
106 else if ( hostLang->lang == HostLang::Ruby ) {
107 hostLang = &hostLangRuby;
108 outStream = rubyOpenOutput( sourceFileName );
110 else if ( hostLang->lang == HostLang::CSharp ) {
111 hostLang = &hostLangCSharp;
112 outStream = csharpOpenOutput( sourceFileName );
119 void XmlParser::open_ragel_def( char *fsmName )
121 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
125 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
126 codeGenMap.insert( fsmName, cgd );
134 include "xmlparse.kh";
139 /* If we get no input the assumption is that the frontend died and
140 * emitted an error. This forces the backend to return a non-zero
141 * exit status, but does not print an error. */
145 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
147 tag_ragel_head: TAG_ragel
149 /* Check version used to generated the intermediate file. */
150 Attribute *versionAttr = $1->tag->findAttr( "version" );
151 if ( versionAttr == 0 )
152 error($1->loc) << "tag <ragel> requires a version attribute" << endp;
153 if ( strcmp( versionAttr->value, VERSION ) != 0 )
154 error($1->loc) << "version mismatch between frontend and backend" << endp;
156 /* Check for file name attribute. */
157 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
158 if ( fileNameAttr == 0 )
159 error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
160 sourceFileName = fileNameAttr->value;
162 /* Check for language attribute. */
163 Attribute *langAttr = $1->tag->findAttr( "lang" );
165 error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
168 outStream = dotOpenOutput( sourceFileName );
169 else if ( strcmp( langAttr->value, "C" ) == 0 ) {
170 hostLang = &hostLangC;
171 outStream = cdOpenOutput( sourceFileName );
173 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
174 hostLang = &hostLangD;
175 outStream = cdOpenOutput( sourceFileName );
177 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
178 hostLang = &hostLangJava;
179 outStream = javaOpenOutput( sourceFileName );
181 else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) {
182 hostLang = &hostLangRuby;
183 outStream = rubyOpenOutput( sourceFileName );
185 else if ( strcmp( langAttr->value, "C#" ) == 0 ) {
186 hostLang = &hostLangCSharp;
187 outStream = csharpOpenOutput( sourceFileName );
190 error($1->loc) << "expecting lang attribute to be "
191 "one of C, D, Java, Ruby or C#" << endp;
195 ragel_def_list: ragel_def_list ragel_def;
198 host_or_write_list: host_or_write_list host_or_write;
199 host_or_write_list: ;
201 host_or_write: tag_host;
202 host_or_write: tag_write;
205 TAG_host '/' TAG_host
207 Attribute *lineAttr = $1->tag->findAttr( "line" );
209 error($1->loc) << "tag <host> requires a line attribute" << endp;
211 int line = atoi( lineAttr->value );
213 lineDirective( *outStream, sourceFileName, line );
217 *outStream << $3->tag->content;
221 tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
223 /* Do this before distributing transitions out to singles and defaults
224 * makes life easier. */
225 cgd->redFsm->maxKey = cgd->findMaxKey();
227 cgd->redFsm->assignActionLocs();
229 /* Find the first final state (The final state with the lowest id). */
230 cgd->redFsm->findFirstFinState();
232 /* Call the user's callback. */
233 cgd->finishRagelDef();
236 tag_ragel_def_head: TAG_ragel_def
239 Attribute *nameAttr = $1->tag->findAttr( "name" );
240 if ( nameAttr != 0 ) {
241 fsmName = nameAttr->value;
243 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
247 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
248 codeGenMap.insert( fsmName, cgd );
252 cgd = makeCodeGen( sourceFileName, fsmName,
253 *outStream, wantComplete );
256 ::keyOps = &cgd->thisKeyOps;
259 ragel_def_item_list: ragel_def_item_list ragel_def_item;
260 ragel_def_item_list: ;
262 ragel_def_item: tag_alph_type;
263 ragel_def_item: tag_getkey_expr;
264 ragel_def_item: tag_access_expr;
265 ragel_def_item: tag_prepush_expr;
266 ragel_def_item: tag_postpop_expr;
267 ragel_def_item: tag_export_list;
268 ragel_def_item: tag_machine;
269 ragel_def_item: tag_p_expr;
270 ragel_def_item: tag_pe_expr;
271 ragel_def_item: tag_eof_expr;
272 ragel_def_item: tag_cs_expr;
273 ragel_def_item: tag_top_expr;
274 ragel_def_item: tag_stack_expr;
275 ragel_def_item: tag_act_expr;
276 ragel_def_item: tag_tokstart_expr;
277 ragel_def_item: tag_tokend_expr;
278 ragel_def_item: tag_data_expr;
280 tag_export_list: TAG_exports export_list '/' TAG_exports;
282 export_list: export_list tag_export;
285 tag_export: TAG_ex '/' TAG_ex
287 Attribute *nameAttr = $1->tag->findAttr( "name" );
289 error($1->loc) << "tag <ex> requires a name attribute" << endp;
291 char *td = $3->tag->content;
292 Key exportKey = readKey( td, &td );
293 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
297 tag_alph_type: TAG_alphtype '/' TAG_alphtype
299 if ( ! cgd->setAlphType( $3->tag->content ) )
300 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
303 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
305 cgd->getKeyExpr = $2->inlineList;
308 tag_access_expr: TAG_access inline_list '/' TAG_access
310 cgd->accessExpr = $2->inlineList;
313 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
315 cgd->prePushExpr = $2->inlineList;
318 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
320 cgd->postPopExpr = $2->inlineList;
323 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
324 final { cgd->pExpr = $2->inlineList; };
325 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
326 final { cgd->peExpr = $2->inlineList; };
327 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
328 final { cgd->eofExpr = $2->inlineList; };
329 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
330 final { cgd->csExpr = $2->inlineList; };
331 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
332 final { cgd->topExpr = $2->inlineList; };
333 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
334 final { cgd->stackExpr = $2->inlineList; };
335 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
336 final { cgd->actExpr = $2->inlineList; };
337 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
338 final { cgd->tokstartExpr = $2->inlineList; };
339 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
340 final { cgd->tokendExpr = $2->inlineList; };
341 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
342 final { cgd->dataExpr = $2->inlineList; };
345 tag_write: tag_write_head write_option_list '/' TAG_write
347 /* Terminate the options list and call the write statement handler. */
348 writeOptions.append(0);
349 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
351 /* Clear the options in prep for the next write statement. */
352 writeOptions.empty();
355 nonterm tag_write_head
360 tag_write_head: TAG_write
362 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
363 Attribute *lineAttr = $1->tag->findAttr( "line" );
364 Attribute *colAttr = $1->tag->findAttr( "col" );
367 error($1->loc) << "tag <write> requires a def_name attribute" << endp;
369 error($1->loc) << "tag <write> requires a line attribute" << endp;
371 error($1->loc) << "tag <write> requires a col attribute" << endp;
373 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
374 $$->loc.line = atoi(lineAttr->value);
375 $$->loc.col = atoi(colAttr->value);
377 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
379 source_error($$->loc) << "write statement given "
380 "but there are no machine instantiations" << endp;
384 ::keyOps = &cgd->thisKeyOps;
390 write_option_list: write_option_list tag_arg;
398 tag_arg: TAG_arg '/' TAG_arg
400 writeOptions.append( $3->tag->content );
403 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
408 tag_machine_head: TAG_machine
410 cgd->createMachine();
413 machine_item_list: machine_item_list machine_item;
416 machine_item: tag_start_state;
417 machine_item: tag_error_state;
418 machine_item: tag_entry_points;
419 machine_item: tag_state_list;
420 machine_item: tag_action_list;
421 machine_item: tag_action_table_list;
422 machine_item: tag_cond_space_list;
428 tag_start_state: TAG_start_state '/' TAG_start_state
430 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
431 cgd->setStartState( startState );
434 tag_error_state: TAG_error_state '/' TAG_error_state
436 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
437 cgd->setErrorState( errorState );
440 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
442 Attribute *errorAttr = $1->tag->findAttr( "error" );
443 if ( errorAttr != 0 )
444 cgd->setForcedErrorState();
447 entry_point_list: entry_point_list tag_entry;
450 tag_entry: TAG_entry '/' TAG_entry
452 Attribute *nameAttr = $1->tag->findAttr( "name" );
453 if ( nameAttr == 0 ) {
454 error($1->loc) << "tag <entry_points>::<entry> "
455 "requires a name attribute" << endp;
458 char *data = $3->tag->content;
459 unsigned long entry = strtoul( data, &data, 10 );
460 cgd->addEntryPoint( nameAttr->value, entry );
464 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
466 tag_state_list_head: TAG_state_list
468 Attribute *lengthAttr = $1->tag->findAttr( "length" );
469 if ( lengthAttr == 0 )
470 error($1->loc) << "tag <state_list> requires a length attribute" << endp;
472 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
473 cgd->initStateList( length );
478 state_list: state_list tag_state;
481 tag_state: TAG_state state_item_list '/' TAG_state
483 Attribute *idAttr = $1->tag->findAttr( "id" );
485 error($1->loc) << "tag <state> requires an id attribute" << endp;
487 int id = atoi( idAttr->value );
488 cgd->setId( curState, id );
491 Attribute *lengthAttr = $1->tag->findAttr( "final" );
492 if ( lengthAttr != 0 )
493 cgd->setFinal( curState );
497 state_item_list: state_item_list state_item;
500 state_item: tag_state_actions;
501 state_item: tag_eof_t;
502 state_item: tag_state_cond_list;
503 state_item: tag_trans_list;
505 tag_state_actions: TAG_state_actions '/' TAG_state_actions
507 char *ad = $3->tag->content;
509 long toStateAction = readOffsetPtr( ad, &ad );
510 long fromStateAction = readOffsetPtr( ad, &ad );
511 long eofAction = readOffsetPtr( ad, &ad );
513 cgd->setStateActions( curState, toStateAction,
514 fromStateAction, eofAction );
517 tag_eof_t: TAG_eof_t '/' TAG_eof_t
519 char *et = $3->tag->content;
520 long targ = readOffsetPtr( et, &et );
521 long eofAction = readOffsetPtr( et, &et );
523 cgd->setEofTrans( curState, targ, eofAction );
526 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
528 tag_state_cond_list_head: TAG_cond_list
530 Attribute *lengthAttr = $1->tag->findAttr( "length" );
531 if ( lengthAttr == 0 )
532 error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
534 ulong length = readLength( lengthAttr->value );
535 cgd->initStateCondList( curState, length );
540 state_cond_list: state_cond_list state_cond;
543 state_cond: TAG_c '/' TAG_c
545 char *td = $3->tag->content;
546 Key lowKey = readKey( td, &td );
547 Key highKey = readKey( td, &td );
548 long condId = readOffsetPtr( td, &td );
549 cgd->addStateCond( curState, lowKey, highKey, condId );
552 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
554 cgd->finishTransList( curState );
557 tag_trans_list_head: TAG_trans_list
559 Attribute *lengthAttr = $1->tag->findAttr( "length" );
560 if ( lengthAttr == 0 )
561 error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
563 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
564 cgd->initTransList( curState, length );
569 trans_list: trans_list tag_trans;
572 tag_trans: TAG_t '/' TAG_t
574 char *td = $3->tag->content;
575 Key lowKey = readKey( td, &td );
576 Key highKey = readKey( td, &td );
577 long targ = readOffsetPtr( td, &td );
578 long action = readOffsetPtr( td, &td );
580 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
587 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
589 tag_action_list_head: TAG_action_list
591 Attribute *lengthAttr = $1->tag->findAttr( "length" );
592 if ( lengthAttr == 0 )
593 error($1->loc) << "tag <action_list> requires a length attribute" << endp;
595 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
596 cgd->initActionList( length );
601 action_list: action_list tag_action;
608 tag_action: TAG_action inline_list '/' TAG_action
610 Attribute *lineAttr = $1->tag->findAttr( "line" );
611 Attribute *colAttr = $1->tag->findAttr( "col" );
612 Attribute *nameAttr = $1->tag->findAttr( "name" );
613 if ( lineAttr == 0 || colAttr == 0)
614 error($1->loc) << "tag <action> requires a line and col attributes" << endp;
616 unsigned long line = strtoul( lineAttr->value, 0, 10 );
617 unsigned long col = strtoul( colAttr->value, 0, 10 );
621 name = nameAttr->value;
623 cgd->newAction( curAction++, name, line, col, $2->inlineList );
629 GenInlineList *inlineList;
633 inline_list: inline_list inline_item
635 /* Append the item to the list, return the list. */
636 $1->inlineList->append( $2->inlineItem );
637 $$->inlineList = $1->inlineList;
642 /* Start with empty list. */
643 $$->inlineList = new GenInlineList;
646 nonterm inline_item_type
648 GenInlineItem *inlineItem;
651 nonterm inline_item uses inline_item_type;
653 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
654 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
655 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
656 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
657 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
658 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
659 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
660 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
661 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
662 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
663 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
664 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
665 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
666 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
667 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
668 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
669 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
670 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
671 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
672 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
673 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
674 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
675 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
676 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
678 nonterm tag_text uses inline_item_type;
679 nonterm tag_goto uses inline_item_type;
680 nonterm tag_call uses inline_item_type;
681 nonterm tag_next uses inline_item_type;
682 nonterm tag_goto_expr uses inline_item_type;
683 nonterm tag_call_expr uses inline_item_type;
684 nonterm tag_next_expr uses inline_item_type;
685 nonterm tag_ret uses inline_item_type;
686 nonterm tag_break uses inline_item_type;
687 nonterm tag_pchar uses inline_item_type;
688 nonterm tag_char uses inline_item_type;
689 nonterm tag_hold uses inline_item_type;
690 nonterm tag_exec uses inline_item_type;
691 nonterm tag_curs uses inline_item_type;
692 nonterm tag_targs uses inline_item_type;
693 nonterm tag_il_entry uses inline_item_type;
694 nonterm tag_init_tokstart uses inline_item_type;
695 nonterm tag_init_act uses inline_item_type;
696 nonterm tag_get_tokend uses inline_item_type;
697 nonterm tag_set_tokstart uses inline_item_type;
698 nonterm tag_set_tokend uses inline_item_type;
699 nonterm tag_set_act uses inline_item_type;
700 nonterm tag_sub_action uses inline_item_type;
701 nonterm tag_lm_switch uses inline_item_type;
703 tag_text: TAG_text '/' TAG_text
705 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Text );
706 $$->inlineItem->data = $3->tag->content;
709 tag_goto: TAG_goto '/' TAG_goto
711 int targ = strtol( $3->tag->content, 0, 10 );
712 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Goto );
713 $$->inlineItem->targId = targ;
716 tag_call: TAG_call '/' TAG_call
718 int targ = strtol( $3->tag->content, 0, 10 );
719 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Call );
720 $$->inlineItem->targId = targ;
723 tag_next: TAG_next '/' TAG_next
725 int targ = strtol( $3->tag->content, 0, 10 );
726 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Next );
727 $$->inlineItem->targId = targ;
730 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
732 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::GotoExpr );
733 $$->inlineItem->children = $2->inlineList;
736 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
738 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::CallExpr );
739 $$->inlineItem->children = $2->inlineList;
742 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
744 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::NextExpr );
745 $$->inlineItem->children = $2->inlineList;
748 tag_ret: TAG_ret '/' TAG_ret
750 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Ret );
753 tag_break: TAG_break '/' TAG_break
755 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Break );
758 tag_pchar: TAG_pchar '/' TAG_pchar
760 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::PChar );
763 tag_char: TAG_char '/' TAG_char
765 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Char );
768 tag_hold: TAG_hold '/' TAG_hold
770 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Hold );
773 tag_exec: TAG_exec inline_list '/' TAG_exec
775 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Exec );
776 $$->inlineItem->children = $2->inlineList;
779 tag_curs: TAG_curs '/' TAG_curs
781 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Curs );
784 tag_targs: TAG_targs '/' TAG_targs
786 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Targs );
789 tag_il_entry: TAG_entry '/' TAG_entry
791 int targ = strtol( $3->tag->content, 0, 10 );
792 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Entry );
793 $$->inlineItem->targId = targ;
796 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
798 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitTokStart );
801 tag_init_act: TAG_init_act '/' TAG_init_act
803 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitAct );
806 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
808 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmGetTokEnd );
811 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
813 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokStart );
814 cgd->hasLongestMatch = true;
817 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
819 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokEnd );
820 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
823 tag_set_act: TAG_set_act '/' TAG_set_act
825 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetActId );
826 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
829 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
831 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::SubAction );
832 $$->inlineItem->children = $2->inlineList;
836 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
838 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSwitch );
839 $$->inlineItem->children = $2->inlineList;
842 nonterm lm_action_list
844 GenInlineList *inlineList;
847 lm_action_list: lm_action_list tag_inline_action
849 $$->inlineList = $1->inlineList;
850 $$->inlineList->append( $2->inlineItem );
854 $$->inlineList = new GenInlineList;
857 nonterm tag_inline_action uses inline_item_type;
859 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
861 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::SubAction );
862 $$->inlineItem->children = $2->inlineList;
864 Attribute *idAttr = $1->tag->findAttr( "id" );
866 unsigned long id = strtoul( idAttr->value, 0, 10 );
867 $$->inlineItem->lmId = id;
875 tag_action_table_list:
876 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
878 tag_action_table_list_head: TAG_action_table_list
880 Attribute *lengthAttr = $1->tag->findAttr( "length" );
881 if ( lengthAttr == 0 ) {
882 error($1->loc) << "tag <action_table_list> requires "
883 "a length attribute" << endp;
886 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
887 cgd->initActionTableList( length );
892 action_table_list: action_table_list tag_action_table;
895 tag_action_table: TAG_action_table '/' TAG_action_table
897 /* Find the length of the action table. */
898 Attribute *lengthAttr = $1->tag->findAttr( "length" );
899 if ( lengthAttr == 0 )
900 error($1->loc) << "tag <at> requires a length attribute" << endp;
902 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
904 /* Collect the action table. */
905 RedAction *redAct = cgd->allActionTables + curActionTable;
906 redAct->actListId = curActionTable;
907 redAct->key.setAsNew( length );
908 char *ptr = $3->tag->content;
910 while ( *ptr != 0 ) {
911 unsigned long actionId = strtoul( ptr, &ptr, 10 );
912 redAct->key[pos].key = 0;
913 redAct->key[pos].value = cgd->allActions+actionId;
917 /* Insert into the action table map. */
918 cgd->redFsm->actionMap.insert( redAct );
928 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
930 tag_cond_space_list_head: TAG_cond_space_list
932 Attribute *lengthAttr = $1->tag->findAttr( "length" );
933 if ( lengthAttr == 0 ) {
934 error($1->loc) << "tag <cond_space_list> "
935 "requires a length attribute" << endp;
938 ulong length = readLength( lengthAttr->value );
939 cgd->initCondSpaceList( length );
944 cond_space_list: cond_space_list tag_cond_space;
945 cond_space_list: tag_cond_space;
947 tag_cond_space: TAG_cond_space '/' TAG_cond_space
949 Attribute *lengthAttr = $1->tag->findAttr( "length" );
950 Attribute *idAttr = $1->tag->findAttr( "id" );
951 if ( lengthAttr == 0 )
952 error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
954 if ( lengthAttr == 0 )
955 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
957 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
958 ulong length = readLength( lengthAttr->value );
960 char *td = $3->tag->content;
961 Key baseKey = readKey( td, &td );
963 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
964 for ( ulong a = 0; a < length; a++ ) {
965 long actionOffset = readOffsetPtr( td, &td );
966 cgd->condSpaceItem( curCondSpace, actionOffset );
980 void XmlParser::init()
985 int XmlParser::parseLangEl( int type, const Token *token )
988 return errCount == 0 ? 0 : -1;
992 unsigned long readLength( char *td )
994 return strtoul( td, 0, 10 );
997 Key readKey( char *td, char **end )
999 if ( keyOps->isSigned )
1000 return Key( strtol( td, end, 10 ) );
1002 return Key( strtoul( td, end, 10 ) );
1005 long readOffsetPtr( char *td, char **end )
1007 while ( *td == ' ' || *td == '\t' )
1016 return strtol( td, end, 10 );
1019 ostream &XmlParser::warning( const GenInputLoc &loc )
1021 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1025 ostream &XmlParser::error( const GenInputLoc &loc )
1028 assert( fileName != 0 );
1029 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
1034 ostream &XmlParser::parser_error( int tokId, Token &token )
1037 assert( fileName != 0 );
1038 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
1039 if ( token.tag != 0 ) {
1040 if ( token.tag->tagId == 0 )
1041 cerr << ": at unknown tag";
1043 cerr << ": at tag <" << token.tag->tagId->name << ">";
1050 ostream &XmlParser::source_error( const GenInputLoc &loc )
1053 assert( sourceFileName != 0 );
1054 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1059 int XmlParser::token( int tokenId, Token &tok )
1061 int res = parseLangEl( tokenId, &tok );
1063 parser_error( tokenId, tok ) << "parse error" << endp;
1067 int XmlParser::token( int tokenId, int col, int line )
1071 tok.loc.line = line;
1073 return token( tokenId, tok );
1076 int XmlParser::token( XMLTag *tag, int col, int line )
1080 tok.loc.line = line;
1083 if ( tag->type == XMLTag::Close ) {
1084 int res = token( '/', tok );
1090 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );