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
34 Key readKey( char *td, char **end );
35 long readOffsetPtr( char *td, char **end );
36 unsigned long readLength( char *td );
42 include "xmlparse.kh";
47 /* If we get no input the assumption is that the frontend died and
48 * emitted an error. */
52 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
54 tag_ragel_head: TAG_ragel
56 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
57 if ( fileNameAttr == 0 ) {
58 error($1->loc) << "tag <ragel> requires a filename attribute" << endl;
62 sourceFileName = fileNameAttr->value;
64 Attribute *langAttr = $1->tag->findAttr( "lang" );
66 error($1->loc) << "tag <ragel> requires a lang attribute" << endl;
68 if ( strcmp( langAttr->value, "C" ) == 0 ) {
70 hostLang = &hostLangC;
72 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
74 hostLang = &hostLangD;
76 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
77 hostLangType = JavaCode;
78 hostLang = &hostLangJava;
80 else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) {
81 hostLangType = RubyCode;
82 hostLang = &hostLangRuby;
85 error($1->loc) << "expecting lang attribute to be "
86 "one of C, D, Java or Ruby" << endl;
89 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" << endl;
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_export_list;
165 ragel_def_item: tag_machine;
166 ragel_def_item: tag_p_expr;
167 ragel_def_item: tag_pe_expr;
168 ragel_def_item: tag_cs_expr;
169 ragel_def_item: tag_top_expr;
170 ragel_def_item: tag_stack_expr;
171 ragel_def_item: tag_act_expr;
172 ragel_def_item: tag_tokstart_expr;
173 ragel_def_item: tag_tokend_expr;
175 tag_export_list: TAG_exports export_list '/' TAG_exports;
177 export_list: export_list tag_export;
180 tag_export: TAG_ex '/' TAG_ex
182 Attribute *nameAttr = $1->tag->findAttr( "name" );
184 error($1->loc) << "tag <ex> requires a name attribute" << endl;
186 char *td = $3->tag->content;
187 Key exportKey = readKey( td, &td );
188 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
192 tag_alph_type: TAG_alphtype '/' TAG_alphtype
194 if ( ! cgd->setAlphType( $3->tag->content ) )
195 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endl;
198 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
200 cgd->getKeyExpr = $2->inlineList;
203 tag_access_expr: TAG_access inline_list '/' TAG_access
205 cgd->accessExpr = $2->inlineList;
208 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
209 final { cgd->pExpr = $2->inlineList; };
210 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
211 final { cgd->peExpr = $2->inlineList; };
212 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
213 final { cgd->csExpr = $2->inlineList; };
214 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
215 final { cgd->topExpr = $2->inlineList; };
216 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
217 final { cgd->stackExpr = $2->inlineList; };
218 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
219 final { cgd->actExpr = $2->inlineList; };
220 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
221 final { cgd->tokstartExpr = $2->inlineList; };
222 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
223 final { cgd->tokendExpr = $2->inlineList; };
226 tag_write: tag_write_head write_option_list '/' TAG_write
228 /* Terminate the options list and call the write statement handler. */
229 writeOptions.append(0);
230 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
232 /* CodeGenData may have issued an error. */
233 errCount += cgd->codeGenErrCount;
235 /* Clear the options in prep for the next write statement. */
236 writeOptions.empty();
239 nonterm tag_write_head
244 tag_write_head: TAG_write
246 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
247 Attribute *lineAttr = $1->tag->findAttr( "line" );
248 Attribute *colAttr = $1->tag->findAttr( "col" );
251 error($1->loc) << "tag <write> requires a def_name attribute" << endl;
253 error($1->loc) << "tag <write> requires a line attribute" << endl;
255 error($1->loc) << "tag <write> requires a col attribute" << endl;
257 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
258 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
260 error($1->loc) << "internal error: cannot find codeGen" << endl;
263 ::keyOps = &cgd->thisKeyOps;
266 $$->loc.line = atoi(lineAttr->value);
267 $$->loc.col = atoi(colAttr->value);
272 write_option_list: write_option_list tag_arg;
280 tag_arg: TAG_arg '/' TAG_arg
282 writeOptions.append( $3->tag->content );
285 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
290 tag_machine_head: TAG_machine
292 cgd->createMachine();
295 machine_item_list: machine_item_list machine_item;
298 machine_item: tag_start_state;
299 machine_item: tag_error_state;
300 machine_item: tag_entry_points;
301 machine_item: tag_state_list;
302 machine_item: tag_action_list;
303 machine_item: tag_action_table_list;
304 machine_item: tag_cond_space_list;
310 tag_start_state: TAG_start_state '/' TAG_start_state
312 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
313 cgd->setStartState( startState );
316 tag_error_state: TAG_error_state '/' TAG_error_state
318 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
319 cgd->setErrorState( errorState );
322 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
324 Attribute *errorAttr = $1->tag->findAttr( "error" );
325 if ( errorAttr != 0 )
326 cgd->setForcedErrorState();
329 entry_point_list: entry_point_list tag_entry;
332 tag_entry: TAG_entry '/' TAG_entry
334 Attribute *nameAttr = $1->tag->findAttr( "name" );
335 if ( nameAttr == 0 ) {
336 error($1->loc) << "tag <entry_points>::<entry> "
337 "requires a name attribute" << endl;
340 char *data = $3->tag->content;
341 unsigned long entry = strtoul( data, &data, 10 );
342 cgd->addEntryPoint( nameAttr->value, entry );
346 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
348 tag_state_list_head: TAG_state_list
350 Attribute *lengthAttr = $1->tag->findAttr( "length" );
351 if ( lengthAttr == 0 )
352 error($1->loc) << "tag <state_list> requires a length attribute" << endl;
354 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
355 cgd->initStateList( length );
360 state_list: state_list tag_state;
363 tag_state: TAG_state state_item_list '/' TAG_state
365 Attribute *idAttr = $1->tag->findAttr( "id" );
367 error($1->loc) << "tag <state> requires an id attribute" << endl;
369 int id = atoi( idAttr->value );
370 cgd->setId( curState, id );
373 Attribute *lengthAttr = $1->tag->findAttr( "final" );
374 if ( lengthAttr != 0 )
375 cgd->setFinal( curState );
379 state_item_list: state_item_list state_item;
382 state_item: tag_state_actions;
383 state_item: tag_state_cond_list;
384 state_item: tag_trans_list;
386 tag_state_actions: TAG_state_actions '/' TAG_state_actions
388 char *ad = $3->tag->content;
390 long toStateAction = readOffsetPtr( ad, &ad );
391 long fromStateAction = readOffsetPtr( ad, &ad );
392 long eofAction = readOffsetPtr( ad, &ad );
394 cgd->setStateActions( curState, toStateAction,
395 fromStateAction, eofAction );
398 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
400 tag_state_cond_list_head: TAG_cond_list
402 Attribute *lengthAttr = $1->tag->findAttr( "length" );
403 if ( lengthAttr == 0 )
404 error($1->loc) << "tag <cond_list> requires a length attribute" << endl;
406 ulong length = readLength( lengthAttr->value );
407 cgd->initStateCondList( curState, length );
412 state_cond_list: state_cond_list state_cond;
415 state_cond: TAG_c '/' TAG_c
417 char *td = $3->tag->content;
418 Key lowKey = readKey( td, &td );
419 Key highKey = readKey( td, &td );
420 long condId = readOffsetPtr( td, &td );
421 cgd->addStateCond( curState, lowKey, highKey, condId );
424 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
426 cgd->finishTransList( curState );
429 tag_trans_list_head: TAG_trans_list
431 Attribute *lengthAttr = $1->tag->findAttr( "length" );
432 if ( lengthAttr == 0 )
433 error($1->loc) << "tag <trans_list> requires a length attribute" << endl;
435 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
436 cgd->initTransList( curState, length );
441 trans_list: trans_list tag_trans;
444 tag_trans: TAG_t '/' TAG_t
446 char *td = $3->tag->content;
447 Key lowKey = readKey( td, &td );
448 Key highKey = readKey( td, &td );
449 long targ = readOffsetPtr( td, &td );
450 long action = readOffsetPtr( td, &td );
452 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
459 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
461 tag_action_list_head: TAG_action_list
463 Attribute *lengthAttr = $1->tag->findAttr( "length" );
464 if ( lengthAttr == 0 )
465 error($1->loc) << "tag <action_list> requires a length attribute" << endl;
467 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
468 cgd->initActionList( length );
473 action_list: action_list tag_action;
480 tag_action: TAG_action inline_list '/' TAG_action
482 Attribute *lineAttr = $1->tag->findAttr( "line" );
483 Attribute *colAttr = $1->tag->findAttr( "col" );
484 Attribute *nameAttr = $1->tag->findAttr( "name" );
485 if ( lineAttr == 0 || colAttr == 0)
486 error($1->loc) << "tag <action> requires a line and col attributes" << endl;
488 unsigned long line = strtoul( lineAttr->value, 0, 10 );
489 unsigned long col = strtoul( colAttr->value, 0, 10 );
493 name = nameAttr->value;
495 cgd->newAction( curAction++, name, line, col, $2->inlineList );
501 InlineList *inlineList;
505 inline_list: inline_list inline_item
507 /* Append the item to the list, return the list. */
508 $1->inlineList->append( $2->inlineItem );
509 $$->inlineList = $1->inlineList;
514 /* Start with empty list. */
515 $$->inlineList = new InlineList;
518 nonterm inline_item_type
520 InlineItem *inlineItem;
523 nonterm inline_item uses inline_item_type;
525 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
526 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
527 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
528 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
529 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
530 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
531 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
532 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
533 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
534 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
535 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
536 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
537 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
538 inline_item: tag_holdte final { $$->inlineItem = $1->inlineItem; };
539 inline_item: tag_execte final { $$->inlineItem = $1->inlineItem; };
540 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
541 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
542 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
543 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
544 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
545 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
546 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
547 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
548 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
549 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
550 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
552 nonterm tag_text uses inline_item_type;
553 nonterm tag_goto uses inline_item_type;
554 nonterm tag_call uses inline_item_type;
555 nonterm tag_next uses inline_item_type;
556 nonterm tag_goto_expr uses inline_item_type;
557 nonterm tag_call_expr uses inline_item_type;
558 nonterm tag_next_expr uses inline_item_type;
559 nonterm tag_ret uses inline_item_type;
560 nonterm tag_break uses inline_item_type;
561 nonterm tag_pchar uses inline_item_type;
562 nonterm tag_char uses inline_item_type;
563 nonterm tag_hold uses inline_item_type;
564 nonterm tag_exec uses inline_item_type;
565 nonterm tag_holdte uses inline_item_type;
566 nonterm tag_execte uses inline_item_type;
567 nonterm tag_curs uses inline_item_type;
568 nonterm tag_targs uses inline_item_type;
569 nonterm tag_il_entry uses inline_item_type;
570 nonterm tag_init_tokstart uses inline_item_type;
571 nonterm tag_init_act uses inline_item_type;
572 nonterm tag_get_tokend uses inline_item_type;
573 nonterm tag_set_tokstart uses inline_item_type;
574 nonterm tag_set_tokend uses inline_item_type;
575 nonterm tag_set_act uses inline_item_type;
576 nonterm tag_sub_action uses inline_item_type;
577 nonterm tag_lm_switch uses inline_item_type;
579 tag_text: TAG_text '/' TAG_text
581 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
582 $$->inlineItem->data = $3->tag->content;
585 tag_goto: TAG_goto '/' TAG_goto
587 int targ = strtol( $3->tag->content, 0, 10 );
588 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
589 $$->inlineItem->targId = targ;
592 tag_call: TAG_call '/' TAG_call
594 int targ = strtol( $3->tag->content, 0, 10 );
595 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
596 $$->inlineItem->targId = targ;
599 tag_next: TAG_next '/' TAG_next
601 int targ = strtol( $3->tag->content, 0, 10 );
602 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
603 $$->inlineItem->targId = targ;
606 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
608 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
609 $$->inlineItem->children = $2->inlineList;
612 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
614 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
615 $$->inlineItem->children = $2->inlineList;
618 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
620 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
621 $$->inlineItem->children = $2->inlineList;
624 tag_ret: TAG_ret '/' TAG_ret
626 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
629 tag_break: TAG_break '/' TAG_break
631 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
634 tag_pchar: TAG_pchar '/' TAG_pchar
636 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
639 tag_char: TAG_char '/' TAG_char
641 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
644 tag_hold: TAG_hold '/' TAG_hold
646 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
649 tag_exec: TAG_exec inline_list '/' TAG_exec
651 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
652 $$->inlineItem->children = $2->inlineList;
655 tag_holdte: TAG_holdte '/' TAG_holdte
657 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::HoldTE );
660 tag_execte: TAG_execte inline_list '/' TAG_execte
662 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::ExecTE );
663 $$->inlineItem->children = $2->inlineList;
666 tag_curs: TAG_curs '/' TAG_curs
668 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
671 tag_targs: TAG_targs '/' TAG_targs
673 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
676 tag_il_entry: TAG_entry '/' TAG_entry
678 int targ = strtol( $3->tag->content, 0, 10 );
679 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
680 $$->inlineItem->targId = targ;
683 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
685 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
688 tag_init_act: TAG_init_act '/' TAG_init_act
690 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
693 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
695 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
698 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
700 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
701 cgd->hasLongestMatch = true;
704 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
706 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
707 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
710 tag_set_act: TAG_set_act '/' TAG_set_act
712 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
713 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
716 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
718 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
719 $$->inlineItem->children = $2->inlineList;
723 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
725 bool handlesError = false;
726 Attribute *handlesErrorAttr = $1->tag->findAttr( "handles_error" );
727 if ( handlesErrorAttr != 0 )
730 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
731 $$->inlineItem->children = $2->inlineList;
732 $$->inlineItem->handlesError = handlesError;
735 nonterm lm_action_list
737 InlineList *inlineList;
740 lm_action_list: lm_action_list tag_inline_action
742 $$->inlineList = $1->inlineList;
743 $$->inlineList->append( $2->inlineItem );
747 $$->inlineList = new InlineList;
750 nonterm tag_inline_action uses inline_item_type;
752 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
754 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
755 $$->inlineItem->children = $2->inlineList;
757 Attribute *idAttr = $1->tag->findAttr( "id" );
759 unsigned long id = strtoul( idAttr->value, 0, 10 );
760 $$->inlineItem->lmId = id;
768 tag_action_table_list:
769 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
771 tag_action_table_list_head: TAG_action_table_list
773 Attribute *lengthAttr = $1->tag->findAttr( "length" );
774 if ( lengthAttr == 0 ) {
775 error($1->loc) << "tag <action_table_list> requires "
776 "a length attribute" << endl;
779 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
780 cgd->initActionTableList( length );
785 action_table_list: action_table_list tag_action_table;
788 tag_action_table: TAG_action_table '/' TAG_action_table
790 /* Find the length of the action table. */
791 Attribute *lengthAttr = $1->tag->findAttr( "length" );
792 if ( lengthAttr == 0 )
793 error($1->loc) << "tag <at> requires a length attribute" << endl;
795 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
797 /* Collect the action table. */
798 RedAction *redAct = cgd->allActionTables + curActionTable;
799 redAct->actListId = curActionTable;
800 redAct->key.setAsNew( length );
801 char *ptr = $3->tag->content;
803 while ( *ptr != 0 ) {
804 unsigned long actionId = strtoul( ptr, &ptr, 10 );
805 redAct->key[pos].key = 0;
806 redAct->key[pos].value = cgd->allActions+actionId;
810 /* Insert into the action table map. */
811 cgd->redFsm->actionMap.insert( redAct );
821 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
823 tag_cond_space_list_head: TAG_cond_space_list
825 Attribute *lengthAttr = $1->tag->findAttr( "length" );
826 if ( lengthAttr == 0 ) {
827 error($1->loc) << "tag <cond_space_list> "
828 "requires a length attribute" << endl;
831 ulong length = readLength( lengthAttr->value );
832 cgd->initCondSpaceList( length );
837 cond_space_list: cond_space_list tag_cond_space;
838 cond_space_list: tag_cond_space;
840 tag_cond_space: TAG_cond_space '/' TAG_cond_space
842 Attribute *lengthAttr = $1->tag->findAttr( "length" );
843 Attribute *idAttr = $1->tag->findAttr( "id" );
844 if ( lengthAttr == 0 )
845 error($1->loc) << "tag <cond_space> requires a length attribute" << endl;
847 if ( lengthAttr == 0 )
848 error($1->loc) << "tag <cond_space> requires an id attribute" << endl;
850 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
851 ulong length = readLength( lengthAttr->value );
853 char *td = $3->tag->content;
854 Key baseKey = readKey( td, &td );
856 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
857 for ( ulong a = 0; a < length; a++ ) {
858 long actionOffset = readOffsetPtr( td, &td );
859 cgd->condSpaceItem( curCondSpace, actionOffset );
878 int Parser::parseLangEl( int type, const Token *token )
881 return errCount == 0 ? 0 : -1;
885 unsigned long readLength( char *td )
887 return strtoul( td, 0, 10 );
890 Key readKey( char *td, char **end )
892 if ( keyOps->isSigned )
893 return Key( strtol( td, end, 10 ) );
895 return Key( strtoul( td, end, 10 ) );
898 long readOffsetPtr( char *td, char **end )
900 while ( *td == ' ' || *td == '\t' )
909 return strtol( td, end, 10 );
912 ostream &Parser::warning( const InputLoc &loc )
914 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
918 ostream &Parser::error( const InputLoc &loc )
921 assert( fileName != 0 );
922 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
927 ostream &Parser::parser_error( int tokId, Token &token )
930 assert( fileName != 0 );
931 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
932 if ( token.tag != 0 ) {
933 if ( token.tag->tagId == 0 )
934 cerr << ": at unknown tag";
936 cerr << ": at tag <" << token.tag->tagId->name << ">";
943 int Parser::token( int tokenId, Token &tok )
945 int res = parseLangEl( tokenId, &tok );
947 parser_error( tokenId, tok ) << "parse error" << endl;
953 int Parser::token( int tokenId, int col, int line )
959 return token( tokenId, tok );
962 int Parser::token( XMLTag *tag, int col, int line )
969 if ( tag->type == XMLTag::Close ) {
970 int res = token( '/', tok );
976 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );