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_curstate_expr;
165 ragel_def_item: tag_export_list;
166 ragel_def_item: tag_machine;
168 tag_export_list: TAG_exports export_list '/' TAG_exports;
170 export_list: export_list tag_export;
173 tag_export: TAG_ex '/' TAG_ex
175 Attribute *nameAttr = $1->tag->findAttr( "name" );
177 error($1->loc) << "tag <ex> requires a name attribute" << endl;
179 char *td = $3->tag->content;
180 Key exportKey = readKey( td, &td );
181 cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
185 tag_alph_type: TAG_alphtype '/' TAG_alphtype
187 if ( ! cgd->setAlphType( $3->tag->content ) )
188 error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endl;
191 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
193 cgd->getKeyExpr = $2->inlineList;
196 tag_access_expr: TAG_access inline_list '/' TAG_access
198 cgd->accessExpr = $2->inlineList;
201 tag_curstate_expr: TAG_curstate inline_list '/' TAG_curstate
203 cgd->curStateExpr = $2->inlineList;
206 tag_write: tag_write_head write_option_list '/' TAG_write
208 /* Terminate the options list and call the write statement handler. */
209 writeOptions.append(0);
210 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
212 /* CodeGenData may have issued an error. */
213 errCount += cgd->codeGenErrCount;
215 /* Clear the options in prep for the next write statement. */
216 writeOptions.empty();
219 nonterm tag_write_head
224 tag_write_head: TAG_write
226 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
227 Attribute *lineAttr = $1->tag->findAttr( "line" );
228 Attribute *colAttr = $1->tag->findAttr( "col" );
231 error($1->loc) << "tag <write> requires a def_name attribute" << endl;
233 error($1->loc) << "tag <write> requires a line attribute" << endl;
235 error($1->loc) << "tag <write> requires a col attribute" << endl;
237 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
238 CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
240 error($1->loc) << "internal error: cannot find codeGen" << endl;
243 ::keyOps = &cgd->thisKeyOps;
246 $$->loc.line = atoi(lineAttr->value);
247 $$->loc.col = atoi(colAttr->value);
252 write_option_list: write_option_list tag_arg;
260 tag_arg: TAG_arg '/' TAG_arg
262 writeOptions.append( $3->tag->content );
265 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
270 tag_machine_head: TAG_machine
272 cgd->createMachine();
275 machine_item_list: machine_item_list machine_item;
278 machine_item: tag_start_state;
279 machine_item: tag_error_state;
280 machine_item: tag_entry_points;
281 machine_item: tag_state_list;
282 machine_item: tag_action_list;
283 machine_item: tag_action_table_list;
284 machine_item: tag_cond_space_list;
290 tag_start_state: TAG_start_state '/' TAG_start_state
292 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
293 cgd->setStartState( startState );
296 tag_error_state: TAG_error_state '/' TAG_error_state
298 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
299 cgd->setErrorState( errorState );
302 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
304 Attribute *errorAttr = $1->tag->findAttr( "error" );
305 if ( errorAttr != 0 )
306 cgd->setForcedErrorState();
309 entry_point_list: entry_point_list tag_entry;
312 tag_entry: TAG_entry '/' TAG_entry
314 Attribute *nameAttr = $1->tag->findAttr( "name" );
315 if ( nameAttr == 0 ) {
316 error($1->loc) << "tag <entry_points>::<entry> "
317 "requires a name attribute" << endl;
320 char *data = $3->tag->content;
321 unsigned long entry = strtoul( data, &data, 10 );
322 cgd->addEntryPoint( nameAttr->value, entry );
326 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
328 tag_state_list_head: TAG_state_list
330 Attribute *lengthAttr = $1->tag->findAttr( "length" );
331 if ( lengthAttr == 0 )
332 error($1->loc) << "tag <state_list> requires a length attribute" << endl;
334 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
335 cgd->initStateList( length );
340 state_list: state_list tag_state;
343 tag_state: TAG_state state_item_list '/' TAG_state
345 Attribute *idAttr = $1->tag->findAttr( "id" );
347 error($1->loc) << "tag <state> requires an id attribute" << endl;
349 int id = atoi( idAttr->value );
350 cgd->setId( curState, id );
353 Attribute *lengthAttr = $1->tag->findAttr( "final" );
354 if ( lengthAttr != 0 )
355 cgd->setFinal( curState );
359 state_item_list: state_item_list state_item;
362 state_item: tag_state_actions;
363 state_item: tag_state_cond_list;
364 state_item: tag_trans_list;
366 tag_state_actions: TAG_state_actions '/' TAG_state_actions
368 char *ad = $3->tag->content;
370 long toStateAction = readOffsetPtr( ad, &ad );
371 long fromStateAction = readOffsetPtr( ad, &ad );
372 long eofAction = readOffsetPtr( ad, &ad );
374 cgd->setStateActions( curState, toStateAction,
375 fromStateAction, eofAction );
378 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
380 tag_state_cond_list_head: TAG_cond_list
382 Attribute *lengthAttr = $1->tag->findAttr( "length" );
383 if ( lengthAttr == 0 )
384 error($1->loc) << "tag <cond_list> requires a length attribute" << endl;
386 ulong length = readLength( lengthAttr->value );
387 cgd->initStateCondList( curState, length );
392 state_cond_list: state_cond_list state_cond;
395 state_cond: TAG_c '/' TAG_c
397 char *td = $3->tag->content;
398 Key lowKey = readKey( td, &td );
399 Key highKey = readKey( td, &td );
400 long condId = readOffsetPtr( td, &td );
401 cgd->addStateCond( curState, lowKey, highKey, condId );
404 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
406 cgd->finishTransList( curState );
409 tag_trans_list_head: TAG_trans_list
411 Attribute *lengthAttr = $1->tag->findAttr( "length" );
412 if ( lengthAttr == 0 )
413 error($1->loc) << "tag <trans_list> requires a length attribute" << endl;
415 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
416 cgd->initTransList( curState, length );
421 trans_list: trans_list tag_trans;
424 tag_trans: TAG_t '/' TAG_t
426 char *td = $3->tag->content;
427 Key lowKey = readKey( td, &td );
428 Key highKey = readKey( td, &td );
429 long targ = readOffsetPtr( td, &td );
430 long action = readOffsetPtr( td, &td );
432 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
439 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
441 tag_action_list_head: TAG_action_list
443 Attribute *lengthAttr = $1->tag->findAttr( "length" );
444 if ( lengthAttr == 0 )
445 error($1->loc) << "tag <action_list> requires a length attribute" << endl;
447 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
448 cgd->initActionList( length );
453 action_list: action_list tag_action;
460 tag_action: TAG_action inline_list '/' TAG_action
462 Attribute *lineAttr = $1->tag->findAttr( "line" );
463 Attribute *colAttr = $1->tag->findAttr( "col" );
464 Attribute *nameAttr = $1->tag->findAttr( "name" );
465 if ( lineAttr == 0 || colAttr == 0)
466 error($1->loc) << "tag <action> requires a line and col attributes" << endl;
468 unsigned long line = strtoul( lineAttr->value, 0, 10 );
469 unsigned long col = strtoul( colAttr->value, 0, 10 );
473 name = nameAttr->value;
475 cgd->newAction( curAction++, name, line, col, $2->inlineList );
481 InlineList *inlineList;
485 inline_list: inline_list inline_item
487 /* Append the item to the list, return the list. */
488 $1->inlineList->append( $2->inlineItem );
489 $$->inlineList = $1->inlineList;
494 /* Start with empty list. */
495 $$->inlineList = new InlineList;
498 nonterm inline_item_type
500 InlineItem *inlineItem;
503 nonterm inline_item uses inline_item_type;
505 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
506 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
507 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
508 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
509 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
510 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
511 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
512 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
513 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
514 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
515 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
516 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
517 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
518 inline_item: tag_holdte final { $$->inlineItem = $1->inlineItem; };
519 inline_item: tag_execte final { $$->inlineItem = $1->inlineItem; };
520 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
521 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
522 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
523 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
524 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
525 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
526 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
527 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
528 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
529 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
530 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
532 nonterm tag_text uses inline_item_type;
533 nonterm tag_goto uses inline_item_type;
534 nonterm tag_call uses inline_item_type;
535 nonterm tag_next uses inline_item_type;
536 nonterm tag_goto_expr uses inline_item_type;
537 nonterm tag_call_expr uses inline_item_type;
538 nonterm tag_next_expr uses inline_item_type;
539 nonterm tag_ret uses inline_item_type;
540 nonterm tag_break uses inline_item_type;
541 nonterm tag_pchar uses inline_item_type;
542 nonterm tag_char uses inline_item_type;
543 nonterm tag_hold uses inline_item_type;
544 nonterm tag_exec uses inline_item_type;
545 nonterm tag_holdte uses inline_item_type;
546 nonterm tag_execte uses inline_item_type;
547 nonterm tag_curs uses inline_item_type;
548 nonterm tag_targs uses inline_item_type;
549 nonterm tag_il_entry uses inline_item_type;
550 nonterm tag_init_tokstart uses inline_item_type;
551 nonterm tag_init_act uses inline_item_type;
552 nonterm tag_get_tokend uses inline_item_type;
553 nonterm tag_set_tokstart uses inline_item_type;
554 nonterm tag_set_tokend uses inline_item_type;
555 nonterm tag_set_act uses inline_item_type;
556 nonterm tag_sub_action uses inline_item_type;
557 nonterm tag_lm_switch uses inline_item_type;
559 tag_text: TAG_text '/' TAG_text
561 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
562 $$->inlineItem->data = $3->tag->content;
565 tag_goto: TAG_goto '/' TAG_goto
567 int targ = strtol( $3->tag->content, 0, 10 );
568 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
569 $$->inlineItem->targId = targ;
572 tag_call: TAG_call '/' TAG_call
574 int targ = strtol( $3->tag->content, 0, 10 );
575 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
576 $$->inlineItem->targId = targ;
579 tag_next: TAG_next '/' TAG_next
581 int targ = strtol( $3->tag->content, 0, 10 );
582 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
583 $$->inlineItem->targId = targ;
586 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
588 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
589 $$->inlineItem->children = $2->inlineList;
592 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
594 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
595 $$->inlineItem->children = $2->inlineList;
598 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
600 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
601 $$->inlineItem->children = $2->inlineList;
604 tag_ret: TAG_ret '/' TAG_ret
606 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
609 tag_break: TAG_break '/' TAG_break
611 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
614 tag_pchar: TAG_pchar '/' TAG_pchar
616 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
619 tag_char: TAG_char '/' TAG_char
621 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
624 tag_hold: TAG_hold '/' TAG_hold
626 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
629 tag_exec: TAG_exec inline_list '/' TAG_exec
631 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
632 $$->inlineItem->children = $2->inlineList;
635 tag_holdte: TAG_holdte '/' TAG_holdte
637 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::HoldTE );
640 tag_execte: TAG_execte inline_list '/' TAG_execte
642 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::ExecTE );
643 $$->inlineItem->children = $2->inlineList;
646 tag_curs: TAG_curs '/' TAG_curs
648 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
651 tag_targs: TAG_targs '/' TAG_targs
653 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
656 tag_il_entry: TAG_entry '/' TAG_entry
658 int targ = strtol( $3->tag->content, 0, 10 );
659 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
660 $$->inlineItem->targId = targ;
663 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
665 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
668 tag_init_act: TAG_init_act '/' TAG_init_act
670 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
673 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
675 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
678 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
680 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
681 cgd->hasLongestMatch = true;
684 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
686 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
687 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
690 tag_set_act: TAG_set_act '/' TAG_set_act
692 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
693 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
696 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
698 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
699 $$->inlineItem->children = $2->inlineList;
703 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
705 bool handlesError = false;
706 Attribute *handlesErrorAttr = $1->tag->findAttr( "handles_error" );
707 if ( handlesErrorAttr != 0 )
710 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
711 $$->inlineItem->children = $2->inlineList;
712 $$->inlineItem->handlesError = handlesError;
715 nonterm lm_action_list
717 InlineList *inlineList;
720 lm_action_list: lm_action_list tag_inline_action
722 $$->inlineList = $1->inlineList;
723 $$->inlineList->append( $2->inlineItem );
727 $$->inlineList = new InlineList;
730 nonterm tag_inline_action uses inline_item_type;
732 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
734 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
735 $$->inlineItem->children = $2->inlineList;
737 Attribute *idAttr = $1->tag->findAttr( "id" );
739 unsigned long id = strtoul( idAttr->value, 0, 10 );
740 $$->inlineItem->lmId = id;
748 tag_action_table_list:
749 tag_action_table_list_head action_table_list '/' TAG_action_table_list;
751 tag_action_table_list_head: TAG_action_table_list
753 Attribute *lengthAttr = $1->tag->findAttr( "length" );
754 if ( lengthAttr == 0 ) {
755 error($1->loc) << "tag <action_table_list> requires "
756 "a length attribute" << endl;
759 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
760 cgd->initActionTableList( length );
765 action_table_list: action_table_list tag_action_table;
768 tag_action_table: TAG_action_table '/' TAG_action_table
770 /* Find the length of the action table. */
771 Attribute *lengthAttr = $1->tag->findAttr( "length" );
772 if ( lengthAttr == 0 )
773 error($1->loc) << "tag <at> requires a length attribute" << endl;
775 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
777 /* Collect the action table. */
778 RedAction *redAct = cgd->allActionTables + curActionTable;
779 redAct->actListId = curActionTable;
780 redAct->key.setAsNew( length );
781 char *ptr = $3->tag->content;
783 while ( *ptr != 0 ) {
784 unsigned long actionId = strtoul( ptr, &ptr, 10 );
785 redAct->key[pos].key = 0;
786 redAct->key[pos].value = cgd->allActions+actionId;
790 /* Insert into the action table map. */
791 cgd->redFsm->actionMap.insert( redAct );
801 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
803 tag_cond_space_list_head: TAG_cond_space_list
805 Attribute *lengthAttr = $1->tag->findAttr( "length" );
806 if ( lengthAttr == 0 ) {
807 error($1->loc) << "tag <cond_space_list> "
808 "requires a length attribute" << endl;
811 ulong length = readLength( lengthAttr->value );
812 cgd->initCondSpaceList( length );
817 cond_space_list: cond_space_list tag_cond_space;
818 cond_space_list: tag_cond_space;
820 tag_cond_space: TAG_cond_space '/' TAG_cond_space
822 Attribute *lengthAttr = $1->tag->findAttr( "length" );
823 Attribute *idAttr = $1->tag->findAttr( "id" );
824 if ( lengthAttr == 0 )
825 error($1->loc) << "tag <cond_space> requires a length attribute" << endl;
827 if ( lengthAttr == 0 )
828 error($1->loc) << "tag <cond_space> requires an id attribute" << endl;
830 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
831 ulong length = readLength( lengthAttr->value );
833 char *td = $3->tag->content;
834 Key baseKey = readKey( td, &td );
836 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
837 for ( ulong a = 0; a < length; a++ ) {
838 long actionOffset = readOffsetPtr( td, &td );
839 cgd->condSpaceItem( curCondSpace, actionOffset );
858 int Parser::parseLangEl( int type, const Token *token )
861 return errCount == 0 ? 0 : -1;
865 unsigned long readLength( char *td )
867 return strtoul( td, 0, 10 );
870 Key readKey( char *td, char **end )
872 if ( keyOps->isSigned )
873 return Key( strtol( td, end, 10 ) );
875 return Key( strtoul( td, end, 10 ) );
878 long readOffsetPtr( char *td, char **end )
880 while ( *td == ' ' || *td == '\t' )
889 return strtol( td, end, 10 );
892 ostream &Parser::warning( const InputLoc &loc )
894 cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
898 ostream &Parser::error( const InputLoc &loc )
901 assert( fileName != 0 );
902 cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
907 ostream &Parser::parser_error( int tokId, Token &token )
910 assert( fileName != 0 );
911 cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
912 if ( token.tag != 0 ) {
913 if ( token.tag->tagId == 0 )
914 cerr << ": at unknown tag";
916 cerr << ": at tag <" << token.tag->tagId->name << ">";
923 int Parser::token( int tokenId, Token &tok )
925 int res = parseLangEl( tokenId, &tok );
927 parser_error( tokenId, tok ) << "parse error" << endl;
933 int Parser::token( int tokenId, int col, int line )
939 return token( tokenId, tok );
942 int Parser::token( XMLTag *tag, int col, int line )
949 if ( tag->type == XMLTag::Close ) {
950 int res = token( '/', tok );
956 return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );