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. This forces the backend to return a non-zero
49 * exit status, but does not print an error. */
53 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
55 tag_ragel_head: TAG_ragel
57 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
58 if ( fileNameAttr == 0 )
59 error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
61 sourceFileName = fileNameAttr->value;
63 Attribute *langAttr = $1->tag->findAttr( "lang" );
65 error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
67 if ( strcmp( langAttr->value, "C" ) == 0 ) {
69 hostLang = &hostLangC;
71 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
73 hostLang = &hostLangD;
75 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
76 hostLangType = JavaCode;
77 hostLang = &hostLangJava;
79 else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) {
80 hostLangType = RubyCode;
81 hostLang = &hostLangRuby;
84 error($1->loc) << "expecting lang attribute to be "
85 "one of C, D, Java or Ruby" << endp;
88 outStream = openOutput( sourceFileName );
93 ragel_def_list: ragel_def_list ragel_def;
96 host_or_write_list: host_or_write_list host_or_write;
99 host_or_write: tag_host;
100 host_or_write: tag_write;
103 TAG_host '/' TAG_host
105 Attribute *lineAttr = $1->tag->findAttr( "line" );
107 error($1->loc) << "tag <host> requires a line attribute" << endp;
109 int line = atoi( lineAttr->value );
111 lineDirective( *outStream, sourceFileName, line );
115 *outStream << $3->tag->content;
119 tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
121 /* Do this before distributing transitions out to singles and defaults
122 * makes life easier. */
123 cgd->redFsm->maxKey = cgd->findMaxKey();
125 cgd->redFsm->assignActionLocs();
127 /* Find the first final state (The final state with the lowest id). */
128 cgd->redFsm->findFirstFinState();
130 /* Call the user's callback. */
131 cgd->finishRagelDef();
134 tag_ragel_def_head: TAG_ragel_def
137 Attribute *nameAttr = $1->tag->findAttr( "name" );
138 if ( nameAttr != 0 ) {
139 fsmName = nameAttr->value;
141 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
145 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
146 codeGenMap.insert( fsmName, cgd );
150 cgd = makeCodeGen( sourceFileName, fsmName,
151 *outStream, wantComplete );
154 ::keyOps = &cgd->thisKeyOps;
157 ragel_def_item_list: ragel_def_item_list ragel_def_item;
158 ragel_def_item_list: ;
160 ragel_def_item: tag_alph_type;
161 ragel_def_item: tag_getkey_expr;
162 ragel_def_item: tag_access_expr;
163 ragel_def_item: tag_export_list;
164 ragel_def_item: tag_machine;
165 ragel_def_item: tag_p_expr;
166 ragel_def_item: tag_pe_expr;
167 ragel_def_item: tag_cs_expr;
168 ragel_def_item: tag_top_expr;
169 ragel_def_item: tag_stack_expr;
170 ragel_def_item: tag_act_expr;
171 ragel_def_item: tag_tokstart_expr;
172 ragel_def_item: tag_tokend_expr;
174 tag_export_list: TAG_exports export_list '/' TAG_exports;
176 export_list: export_list tag_export;
179 tag_export: TAG_ex '/' TAG_ex
181 Attribute *nameAttr = $1->tag->findAttr( "name" );
183 error($1->loc) << "tag <ex> requires a name attribute" << endp;
185 char *td = $3->tag->content;
186 Key exportKey = readKey( td, &td );
187 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
191 tag_alph_type: TAG_alphtype '/' TAG_alphtype
193 if ( ! cgd->setAlphType( $3->tag->content ) )
194 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
197 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
199 cgd->getKeyExpr = $2->inlineList;
202 tag_access_expr: TAG_access inline_list '/' TAG_access
204 cgd->accessExpr = $2->inlineList;
207 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
208 final { cgd->pExpr = $2->inlineList; };
209 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
210 final { cgd->peExpr = $2->inlineList; };
211 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
212 final { cgd->csExpr = $2->inlineList; };
213 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
214 final { cgd->topExpr = $2->inlineList; };
215 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
216 final { cgd->stackExpr = $2->inlineList; };
217 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
218 final { cgd->actExpr = $2->inlineList; };
219 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
220 final { cgd->tokstartExpr = $2->inlineList; };
221 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
222 final { cgd->tokendExpr = $2->inlineList; };
225 tag_write: tag_write_head write_option_list '/' TAG_write
227 /* Terminate the options list and call the write statement handler. */
228 writeOptions.append(0);
229 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
231 /* Clear the options in prep for the next write statement. */
232 writeOptions.empty();
235 nonterm tag_write_head
240 tag_write_head: TAG_write
242 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
243 Attribute *lineAttr = $1->tag->findAttr( "line" );
244 Attribute *colAttr = $1->tag->findAttr( "col" );
247 error($1->loc) << "tag <write> requires a def_name attribute" << endp;
249 error($1->loc) << "tag <write> requires a line attribute" << endp;
251 error($1->loc) << "tag <write> requires a col attribute" << endp;
253 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
254 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
256 error($1->loc) << "internal error: cannot find codeGen" << endp;
259 ::keyOps = &cgd->thisKeyOps;
262 $$->loc.line = atoi(lineAttr->value);
263 $$->loc.col = atoi(colAttr->value);
268 write_option_list: write_option_list tag_arg;
276 tag_arg: TAG_arg '/' TAG_arg
278 writeOptions.append( $3->tag->content );
281 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
286 tag_machine_head: TAG_machine
288 cgd->createMachine();
291 machine_item_list: machine_item_list machine_item;
294 machine_item: tag_start_state;
295 machine_item: tag_error_state;
296 machine_item: tag_entry_points;
297 machine_item: tag_state_list;
298 machine_item: tag_action_list;
299 machine_item: tag_action_table_list;
300 machine_item: tag_cond_space_list;
306 tag_start_state: TAG_start_state '/' TAG_start_state
308 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
309 cgd->setStartState( startState );
312 tag_error_state: TAG_error_state '/' TAG_error_state
314 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
315 cgd->setErrorState( errorState );
318 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
320 Attribute *errorAttr = $1->tag->findAttr( "error" );
321 if ( errorAttr != 0 )
322 cgd->setForcedErrorState();
325 entry_point_list: entry_point_list tag_entry;
328 tag_entry: TAG_entry '/' TAG_entry
330 Attribute *nameAttr = $1->tag->findAttr( "name" );
331 if ( nameAttr == 0 ) {
332 error($1->loc) << "tag <entry_points>::<entry> "
333 "requires a name attribute" << endp;
336 char *data = $3->tag->content;
337 unsigned long entry = strtoul( data, &data, 10 );
338 cgd->addEntryPoint( nameAttr->value, entry );
342 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
344 tag_state_list_head: TAG_state_list
346 Attribute *lengthAttr = $1->tag->findAttr( "length" );
347 if ( lengthAttr == 0 )
348 error($1->loc) << "tag <state_list> requires a length attribute" << endp;
350 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
351 cgd->initStateList( length );
356 state_list: state_list tag_state;
359 tag_state: TAG_state state_item_list '/' TAG_state
361 Attribute *idAttr = $1->tag->findAttr( "id" );
363 error($1->loc) << "tag <state> requires an id attribute" << endp;
365 int id = atoi( idAttr->value );
366 cgd->setId( curState, id );
369 Attribute *lengthAttr = $1->tag->findAttr( "final" );
370 if ( lengthAttr != 0 )
371 cgd->setFinal( curState );
375 state_item_list: state_item_list state_item;
378 state_item: tag_state_actions;
379 state_item: tag_state_cond_list;
380 state_item: tag_trans_list;
382 tag_state_actions: TAG_state_actions '/' TAG_state_actions
384 char *ad = $3->tag->content;
386 long toStateAction = readOffsetPtr( ad, &ad );
387 long fromStateAction = readOffsetPtr( ad, &ad );
388 long eofAction = readOffsetPtr( ad, &ad );
390 cgd->setStateActions( curState, toStateAction,
391 fromStateAction, eofAction );
394 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
396 tag_state_cond_list_head: TAG_cond_list
398 Attribute *lengthAttr = $1->tag->findAttr( "length" );
399 if ( lengthAttr == 0 )
400 error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
402 ulong length = readLength( lengthAttr->value );
403 cgd->initStateCondList( curState, length );
408 state_cond_list: state_cond_list state_cond;
411 state_cond: TAG_c '/' TAG_c
413 char *td = $3->tag->content;
414 Key lowKey = readKey( td, &td );
415 Key highKey = readKey( td, &td );
416 long condId = readOffsetPtr( td, &td );
417 cgd->addStateCond( curState, lowKey, highKey, condId );
420 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
422 cgd->finishTransList( curState );
425 tag_trans_list_head: TAG_trans_list
427 Attribute *lengthAttr = $1->tag->findAttr( "length" );
428 if ( lengthAttr == 0 )
429 error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
431 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
432 cgd->initTransList( curState, length );
437 trans_list: trans_list tag_trans;
440 tag_trans: TAG_t '/' TAG_t
442 char *td = $3->tag->content;
443 Key lowKey = readKey( td, &td );
444 Key highKey = readKey( td, &td );
445 long targ = readOffsetPtr( td, &td );
446 long action = readOffsetPtr( td, &td );
448 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
455 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
457 tag_action_list_head: TAG_action_list
459 Attribute *lengthAttr = $1->tag->findAttr( "length" );
460 if ( lengthAttr == 0 )
461 error($1->loc) << "tag <action_list> requires a length attribute" << endp;
463 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
464 cgd->initActionList( length );
469 action_list: action_list tag_action;
476 tag_action: TAG_action inline_list '/' TAG_action
478 Attribute *lineAttr = $1->tag->findAttr( "line" );
479 Attribute *colAttr = $1->tag->findAttr( "col" );
480 Attribute *nameAttr = $1->tag->findAttr( "name" );
481 if ( lineAttr == 0 || colAttr == 0)
482 error($1->loc) << "tag <action> requires a line and col attributes" << endp;
484 unsigned long line = strtoul( lineAttr->value, 0, 10 );
485 unsigned long col = strtoul( colAttr->value, 0, 10 );
489 name = nameAttr->value;
491 cgd->newAction( curAction++, name, line, col, $2->inlineList );
497 InlineList *inlineList;
501 inline_list: inline_list inline_item
503 /* Append the item to the list, return the list. */
504 $1->inlineList->append( $2->inlineItem );
505 $$->inlineList = $1->inlineList;
510 /* Start with empty list. */
511 $$->inlineList = new InlineList;
514 nonterm inline_item_type
516 InlineItem *inlineItem;
519 nonterm inline_item uses inline_item_type;
521 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
522 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
523 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
524 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
525 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
526 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
527 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
528 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
529 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
530 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
531 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
532 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
533 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
534 inline_item: tag_holdte final { $$->inlineItem = $1->inlineItem; };
535 inline_item: tag_execte final { $$->inlineItem = $1->inlineItem; };
536 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
537 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
538 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
539 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
540 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
541 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
542 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
543 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
544 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
545 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
546 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
548 nonterm tag_text uses inline_item_type;
549 nonterm tag_goto uses inline_item_type;
550 nonterm tag_call uses inline_item_type;
551 nonterm tag_next uses inline_item_type;
552 nonterm tag_goto_expr uses inline_item_type;
553 nonterm tag_call_expr uses inline_item_type;
554 nonterm tag_next_expr uses inline_item_type;
555 nonterm tag_ret uses inline_item_type;
556 nonterm tag_break uses inline_item_type;
557 nonterm tag_pchar uses inline_item_type;
558 nonterm tag_char uses inline_item_type;
559 nonterm tag_hold uses inline_item_type;
560 nonterm tag_exec uses inline_item_type;
561 nonterm tag_holdte uses inline_item_type;
562 nonterm tag_execte uses inline_item_type;
563 nonterm tag_curs uses inline_item_type;
564 nonterm tag_targs uses inline_item_type;
565 nonterm tag_il_entry uses inline_item_type;
566 nonterm tag_init_tokstart uses inline_item_type;
567 nonterm tag_init_act uses inline_item_type;
568 nonterm tag_get_tokend uses inline_item_type;
569 nonterm tag_set_tokstart uses inline_item_type;
570 nonterm tag_set_tokend uses inline_item_type;
571 nonterm tag_set_act uses inline_item_type;
572 nonterm tag_sub_action uses inline_item_type;
573 nonterm tag_lm_switch uses inline_item_type;
575 tag_text: TAG_text '/' TAG_text
577 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
578 $$->inlineItem->data = $3->tag->content;
581 tag_goto: TAG_goto '/' TAG_goto
583 int targ = strtol( $3->tag->content, 0, 10 );
584 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
585 $$->inlineItem->targId = targ;
588 tag_call: TAG_call '/' TAG_call
590 int targ = strtol( $3->tag->content, 0, 10 );
591 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
592 $$->inlineItem->targId = targ;
595 tag_next: TAG_next '/' TAG_next
597 int targ = strtol( $3->tag->content, 0, 10 );
598 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
599 $$->inlineItem->targId = targ;
602 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
604 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
605 $$->inlineItem->children = $2->inlineList;
608 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
610 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
611 $$->inlineItem->children = $2->inlineList;
614 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
616 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
617 $$->inlineItem->children = $2->inlineList;
620 tag_ret: TAG_ret '/' TAG_ret
622 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
625 tag_break: TAG_break '/' TAG_break
627 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
630 tag_pchar: TAG_pchar '/' TAG_pchar
632 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
635 tag_char: TAG_char '/' TAG_char
637 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
640 tag_hold: TAG_hold '/' TAG_hold
642 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
645 tag_exec: TAG_exec inline_list '/' TAG_exec
647 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
648 $$->inlineItem->children = $2->inlineList;
651 tag_holdte: TAG_holdte '/' TAG_holdte
653 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::HoldTE );
656 tag_execte: TAG_execte inline_list '/' TAG_execte
658 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::ExecTE );
659 $$->inlineItem->children = $2->inlineList;
662 tag_curs: TAG_curs '/' TAG_curs
664 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
667 tag_targs: TAG_targs '/' TAG_targs
669 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
672 tag_il_entry: TAG_entry '/' TAG_entry
674 int targ = strtol( $3->tag->content, 0, 10 );
675 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
676 $$->inlineItem->targId = targ;
679 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
681 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
684 tag_init_act: TAG_init_act '/' TAG_init_act
686 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
689 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
691 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
694 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
696 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
697 cgd->hasLongestMatch = true;
700 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
702 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
703 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
706 tag_set_act: TAG_set_act '/' TAG_set_act
708 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
709 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
712 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
714 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
715 $$->inlineItem->children = $2->inlineList;
719 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
721 bool handlesError = false;
722 Attribute *handlesErrorAttr = $1->tag->findAttr( "handles_error" );
723 if ( handlesErrorAttr != 0 )
726 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
727 $$->inlineItem->children = $2->inlineList;
728 $$->inlineItem->handlesError = handlesError;
731 nonterm lm_action_list
733 InlineList *inlineList;
736 lm_action_list: lm_action_list tag_inline_action
738 $$->inlineList = $1->inlineList;
739 $$->inlineList->append( $2->inlineItem );
743 $$->inlineList = new InlineList;
746 nonterm tag_inline_action uses inline_item_type;
748 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
750 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
751 $$->inlineItem->children = $2->inlineList;
753 Attribute *idAttr = $1->tag->findAttr( "id" );
755 unsigned long id = strtoul( idAttr->value, 0, 10 );
756 $$->inlineItem->lmId = id;
764 tag_action_table_list:
765 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
767 tag_action_table_list_head: TAG_action_table_list
769 Attribute *lengthAttr = $1->tag->findAttr( "length" );
770 if ( lengthAttr == 0 ) {
771 error($1->loc) << "tag <action_table_list> requires "
772 "a length attribute" << endp;
775 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
776 cgd->initActionTableList( length );
781 action_table_list: action_table_list tag_action_table;
784 tag_action_table: TAG_action_table '/' TAG_action_table
786 /* Find the length of the action table. */
787 Attribute *lengthAttr = $1->tag->findAttr( "length" );
788 if ( lengthAttr == 0 )
789 error($1->loc) << "tag <at> requires a length attribute" << endp;
791 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
793 /* Collect the action table. */
794 RedAction *redAct = cgd->allActionTables + curActionTable;
795 redAct->actListId = curActionTable;
796 redAct->key.setAsNew( length );
797 char *ptr = $3->tag->content;
799 while ( *ptr != 0 ) {
800 unsigned long actionId = strtoul( ptr, &ptr, 10 );
801 redAct->key[pos].key = 0;
802 redAct->key[pos].value = cgd->allActions+actionId;
806 /* Insert into the action table map. */
807 cgd->redFsm->actionMap.insert( redAct );
817 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
819 tag_cond_space_list_head: TAG_cond_space_list
821 Attribute *lengthAttr = $1->tag->findAttr( "length" );
822 if ( lengthAttr == 0 ) {
823 error($1->loc) << "tag <cond_space_list> "
824 "requires a length attribute" << endp;
827 ulong length = readLength( lengthAttr->value );
828 cgd->initCondSpaceList( length );
833 cond_space_list: cond_space_list tag_cond_space;
834 cond_space_list: tag_cond_space;
836 tag_cond_space: TAG_cond_space '/' TAG_cond_space
838 Attribute *lengthAttr = $1->tag->findAttr( "length" );
839 Attribute *idAttr = $1->tag->findAttr( "id" );
840 if ( lengthAttr == 0 )
841 error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
843 if ( lengthAttr == 0 )
844 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
846 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
847 ulong length = readLength( lengthAttr->value );
849 char *td = $3->tag->content;
850 Key baseKey = readKey( td, &td );
852 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
853 for ( ulong a = 0; a < length; a++ ) {
854 long actionOffset = readOffsetPtr( td, &td );
855 cgd->condSpaceItem( curCondSpace, actionOffset );
874 int Parser::parseLangEl( int type, const Token *token )
877 return errCount == 0 ? 0 : -1;
881 unsigned long readLength( char *td )
883 return strtoul( td, 0, 10 );
886 Key readKey( char *td, char **end )
888 if ( keyOps->isSigned )
889 return Key( strtol( td, end, 10 ) );
891 return Key( strtoul( td, end, 10 ) );
894 long readOffsetPtr( char *td, char **end )
896 while ( *td == ' ' || *td == '\t' )
905 return strtol( td, end, 10 );
908 ostream &Parser::warning( const InputLoc &loc )
910 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
914 ostream &Parser::error( const InputLoc &loc )
917 assert( fileName != 0 );
918 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
923 ostream &Parser::parser_error( int tokId, Token &token )
926 assert( fileName != 0 );
927 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
928 if ( token.tag != 0 ) {
929 if ( token.tag->tagId == 0 )
930 cerr << ": at unknown tag";
932 cerr << ": at tag <" << token.tag->tagId->name << ">";
939 int Parser::token( int tokenId, Token &tok )
941 int res = parseLangEl( tokenId, &tok );
943 parser_error( tokenId, tok ) << "parse error" << endp;
947 int Parser::token( int tokenId, int col, int line )
953 return token( tokenId, tok );
956 int Parser::token( XMLTag *tag, int col, int line )
963 if ( tag->type == XMLTag::Close ) {
964 int res = token( '/', tok );
970 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );