Added a flag -d for turning off the removal of duplicate actions from actions
[ragel.git] / redfsm / xmlparse.kl
blob4e12b58ed49fc728f88de5c6c863a5a14d8ca08c
1 /*
2  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
5 /*  This file is part of Ragel.
6  *
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.
11  * 
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.
16  * 
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 
20  */
22 #include "xmlparse.h"
23 #include "common.h"
24 #include "gendata.h"
25 #include "version.h"
26 #include <iostream>
27 #include <stdlib.h>
29 using std::cout;
30 using std::ostream;
31 using std::istream;
32 using std::cerr;
33 using std::endl;
35 Key readKey( char *td, char **end );
36 long readOffsetPtr( char *td, char **end );
37 unsigned long readLength( char *td );
39 %%{
41 parser Parser;
43 include "xmlparse.kh";
45 start: tag_ragel;
46 start:
47         final {
48                 /* If we get no input the assumption is that the frontend died and
49                  * emitted an error. This forces the backend to return a non-zero
50                  * exit status, but does not print an error. */
51                 gblErrorCount += 1;
52         };
54 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
56 tag_ragel_head: TAG_ragel
57         final {
58                 /* Check version used to generated the intermediate file. */
59                 Attribute *versionAttr = $1->tag->findAttr( "version" );
60                 if ( versionAttr == 0 )
61                         error($1->loc) << "tag <ragel> requires a version attribute" << endp;
62                 if ( strcmp( versionAttr->value, VERSION ) != 0 )
63                         error($1->loc) << "version mismatch between frontend and backend" << endp;
65                 /* Check for file name attribute. */
66                 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
67                 if ( fileNameAttr == 0 )
68                         error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
69                 sourceFileName = fileNameAttr->value;
71                 /* Check for language attribute. */
72                 Attribute *langAttr = $1->tag->findAttr( "lang" );
73                 if ( langAttr == 0 )
74                         error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
76                 if ( strcmp( langAttr->value, "C" ) == 0 )
77                         hostLang = &hostLangC;
78                 else if ( strcmp( langAttr->value, "D" ) == 0 )
79                         hostLang = &hostLangD;
80                 else if ( strcmp( langAttr->value, "Java" ) == 0 )
81                         hostLang = &hostLangJava;
82                 else if ( strcmp( langAttr->value, "Ruby" ) == 0 )
83                         hostLang = &hostLangRuby;
84                 else {
85                         error($1->loc) << "expecting lang attribute to be "
86                                         "one of C, D, Java or Ruby" << endp;
87                 }
89                 outStream = openOutput( sourceFileName );
90         };
92 ragel_def_list: ragel_def_list ragel_def;
93 ragel_def_list: ;
95 host_or_write_list: host_or_write_list host_or_write;
96 host_or_write_list: ;
98 host_or_write: tag_host;
99 host_or_write: tag_write;
101 tag_host: 
102         TAG_host '/' TAG_host
103         final {
104                 Attribute *lineAttr = $1->tag->findAttr( "line" );
105                 if ( lineAttr == 0 )
106                         error($1->loc) << "tag <host> requires a line attribute" << endp;
107                 else {
108                         int line = atoi( lineAttr->value );
109                         if ( outputActive )
110                                 lineDirective( *outStream, sourceFileName, line );
111                 }
113                 if ( outputActive )
114                         *outStream << $3->tag->content;
115         };
117 ragel_def: 
118         tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
119         final {
120                 /* Do this before distributing transitions out to singles and defaults
121                  * makes life easier. */
122                 cgd->redFsm->maxKey = cgd->findMaxKey();
124                 cgd->redFsm->assignActionLocs();
126                 /* Find the first final state (The final state with the lowest id). */
127                 cgd->redFsm->findFirstFinState();
129                 /* Call the user's callback. */
130                 cgd->finishRagelDef();
131         };
133 tag_ragel_def_head: TAG_ragel_def 
134         final {
135                 char *fsmName = 0;
136                 Attribute *nameAttr = $1->tag->findAttr( "name" );
137                 if ( nameAttr != 0 ) {
138                         fsmName = nameAttr->value;
140                         CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
141                         if ( mapEl != 0 )
142                                 cgd = mapEl->value;
143                         else {
144                                 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
145                                 codeGenMap.insert( fsmName, cgd );
146                         }
147                 }
148                 else {
149                         cgd = makeCodeGen( sourceFileName, fsmName, 
150                                         *outStream, wantComplete );
151                 }
153                 ::keyOps = &cgd->thisKeyOps;
154         };
156 ragel_def_item_list: ragel_def_item_list ragel_def_item;
157 ragel_def_item_list: ;
159 ragel_def_item: tag_alph_type;
160 ragel_def_item: tag_getkey_expr;
161 ragel_def_item: tag_access_expr;
162 ragel_def_item: tag_prepush_expr;
163 ragel_def_item: tag_postpop_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_eof_expr;
169 ragel_def_item: tag_cs_expr;
170 ragel_def_item: tag_top_expr;
171 ragel_def_item: tag_stack_expr;
172 ragel_def_item: tag_act_expr;
173 ragel_def_item: tag_tokstart_expr;
174 ragel_def_item: tag_tokend_expr;
175 ragel_def_item: tag_data_expr;
177 tag_export_list: TAG_exports export_list '/' TAG_exports;
179 export_list: export_list tag_export;
180 export_list: ;
182 tag_export: TAG_ex '/' TAG_ex
183         final {
184                 Attribute *nameAttr = $1->tag->findAttr( "name" );
185                 if ( nameAttr == 0 )
186                         error($1->loc) << "tag <ex> requires a name attribute" << endp;
187                 else {
188                         char *td = $3->tag->content;
189                         Key exportKey = readKey( td, &td );
190                         cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
191                 }
192         };
194 tag_alph_type: TAG_alphtype '/' TAG_alphtype
195         final {
196                 if ( ! cgd->setAlphType( $3->tag->content ) )
197                         error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
198         };
200 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
201         final {
202                 cgd->getKeyExpr = $2->inlineList;
203         };
205 tag_access_expr: TAG_access inline_list '/' TAG_access
206         final {
207                 cgd->accessExpr = $2->inlineList;
208         };
210 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
211         final {
212                 cgd->prePushExpr = $2->inlineList;
213         };
215 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
216         final {
217                 cgd->postPopExpr = $2->inlineList;
218         };
220 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
221         final { cgd->pExpr = $2->inlineList; };
222 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
223         final { cgd->peExpr = $2->inlineList; };
224 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
225         final { cgd->eofExpr = $2->inlineList; };
226 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
227         final { cgd->csExpr = $2->inlineList; };
228 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
229         final { cgd->topExpr = $2->inlineList; };
230 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
231         final { cgd->stackExpr = $2->inlineList; };
232 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
233         final { cgd->actExpr = $2->inlineList; };
234 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
235         final { cgd->tokstartExpr = $2->inlineList; };
236 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
237         final { cgd->tokendExpr = $2->inlineList; };
238 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
239         final { cgd->dataExpr = $2->inlineList; };
242 tag_write: tag_write_head write_option_list '/' TAG_write
243         final {
244                 /* Terminate the options list and call the write statement handler. */
245                 writeOptions.append(0);
246                 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
248                 /* Clear the options in prep for the next write statement. */
249                 writeOptions.empty();
250         };
252 nonterm tag_write_head
254         InputLoc loc;
257 tag_write_head: TAG_write
258         final {
259                 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
260                 Attribute *lineAttr = $1->tag->findAttr( "line" );
261                 Attribute *colAttr = $1->tag->findAttr( "col" );
263                 if ( nameAttr == 0 )
264                         error($1->loc) << "tag <write> requires a def_name attribute" << endp;
265                 if ( lineAttr == 0 )
266                         error($1->loc) << "tag <write> requires a line attribute" << endp;
267                 if ( colAttr == 0 )
268                         error($1->loc) << "tag <write> requires a col attribute" << endp;
270                 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
271                         $$->loc.line = atoi(lineAttr->value);
272                         $$->loc.col = atoi(colAttr->value);
274                         CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
275                         if ( mapEl == 0 ) {
276                                 source_error($$->loc) << "write statement given "
277                                                 "but there are no machine instantiations" << endp;
278                         }
279                         else {
280                                 cgd = mapEl->value;
281                                 ::keyOps = &cgd->thisKeyOps;
282                         }
283                 }
284         };
287 write_option_list: write_option_list tag_arg;
288 write_option_list: ;
290 nonterm tag_arg
292         char *option;
295 tag_arg: TAG_arg '/' TAG_arg
296         final {
297                 writeOptions.append( $3->tag->content );
298         };
300 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
301         final {
302                 cgd->closeMachine();
303         };
305 tag_machine_head: TAG_machine
306         final {
307                 cgd->createMachine();
308         };
310 machine_item_list: machine_item_list machine_item;
311 machine_item_list: ;
313 machine_item: tag_start_state;
314 machine_item: tag_error_state;
315 machine_item: tag_entry_points;
316 machine_item: tag_state_list;
317 machine_item: tag_action_list;
318 machine_item: tag_action_table_list;
319 machine_item: tag_cond_space_list;
322 # States.
325 tag_start_state: TAG_start_state '/' TAG_start_state
326         final {
327                 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
328                 cgd->setStartState( startState );
329         };
331 tag_error_state: TAG_error_state '/' TAG_error_state
332         final {
333                 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
334                 cgd->setErrorState( errorState );
335         };
337 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
338         final {
339                 Attribute *errorAttr = $1->tag->findAttr( "error" );
340                 if ( errorAttr != 0 )
341                         cgd->setForcedErrorState();
342         };
344 entry_point_list: entry_point_list tag_entry;
345 entry_point_list: ;
347 tag_entry: TAG_entry '/' TAG_entry
348         final {
349                 Attribute *nameAttr = $1->tag->findAttr( "name" );
350                 if ( nameAttr == 0 ) {
351                         error($1->loc) << "tag <entry_points>::<entry> "
352                                         "requires a name attribute" << endp;
353                 }
354                 else {
355                         char *data = $3->tag->content;
356                         unsigned long entry = strtoul( data, &data, 10 );
357                         cgd->addEntryPoint( nameAttr->value, entry );
358                 }
359         };
361 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
363 tag_state_list_head: TAG_state_list
364         final {
365                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
366                 if ( lengthAttr == 0 )
367                         error($1->loc) << "tag <state_list> requires a length attribute" << endp;
368                 else {
369                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
370                         cgd->initStateList( length );
371                         curState = 0;
372                 }
373         };
375 state_list: state_list tag_state;
376 state_list: ;
378 tag_state: TAG_state state_item_list '/' TAG_state
379         final {
380                 Attribute *idAttr = $1->tag->findAttr( "id" );
381                 if ( idAttr == 0 )
382                         error($1->loc) << "tag <state> requires an id attribute" << endp;
383                 else {
384                         int id = atoi( idAttr->value );
385                         cgd->setId( curState, id );
386                 }
388                 Attribute *lengthAttr = $1->tag->findAttr( "final" );
389                 if ( lengthAttr != 0 )
390                         cgd->setFinal( curState );
391                 curState += 1;
392         };
394 state_item_list: state_item_list state_item;
395 state_item_list: ;
397 state_item: tag_state_actions;
398 state_item: tag_eof_t;
399 state_item: tag_state_cond_list;
400 state_item: tag_trans_list;
402 tag_state_actions: TAG_state_actions '/' TAG_state_actions
403         final {
404                 char *ad = $3->tag->content;
406                 long toStateAction = readOffsetPtr( ad, &ad );
407                 long fromStateAction = readOffsetPtr( ad, &ad );
408                 long eofAction = readOffsetPtr( ad, &ad );
410                 cgd->setStateActions( curState, toStateAction,
411                                 fromStateAction, eofAction );
412         };
414 tag_eof_t: TAG_eof_t '/' TAG_eof_t
415         final {
416                 char *et = $3->tag->content;
417                 long targ = readOffsetPtr( et, &et );
418                 long eofAction = readOffsetPtr( et, &et );
420                 cgd->setEofTrans( curState, targ, eofAction );
421         };
423 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
425 tag_state_cond_list_head: TAG_cond_list
426         final {
427                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
428                 if ( lengthAttr == 0 )
429                         error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
430                 else {
431                         ulong length = readLength( lengthAttr->value );
432                         cgd->initStateCondList( curState, length );
433                         curStateCond = 0;
434                 }
435         };
437 state_cond_list: state_cond_list state_cond;
438 state_cond_list: ;
440 state_cond: TAG_c '/' TAG_c
441         final {
442                 char *td = $3->tag->content;
443                 Key lowKey = readKey( td, &td );
444                 Key highKey = readKey( td, &td );
445                 long condId = readOffsetPtr( td, &td );
446                 cgd->addStateCond( curState, lowKey, highKey, condId );
447         };
449 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
450         final {
451                 cgd->finishTransList( curState );
452         };
454 tag_trans_list_head: TAG_trans_list
455         final {
456                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
457                 if ( lengthAttr == 0 )
458                         error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
459                 else {
460                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
461                         cgd->initTransList( curState, length );
462                         curTrans = 0;
463                 }
464         };
466 trans_list: trans_list tag_trans;
467 trans_list: ;
469 tag_trans: TAG_t '/' TAG_t
470         final {
471                 char *td = $3->tag->content;
472                 Key lowKey = readKey( td, &td );
473                 Key highKey = readKey( td, &td );
474                 long targ = readOffsetPtr( td, &td );
475                 long action = readOffsetPtr( td, &td );
477                 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
478         };
481 # Action Lists.
484 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
486 tag_action_list_head: TAG_action_list
487         final {
488                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
489                 if ( lengthAttr == 0 )
490                         error($1->loc) << "tag <action_list> requires a length attribute" << endp;
491                 else {
492                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
493                         cgd->initActionList( length );
494                         curAction = 0;
495                 }
496         };
498 action_list: action_list tag_action;
499 action_list: ;
502 # Actions.
505 tag_action: TAG_action inline_list '/' TAG_action
506         final {
507                 Attribute *lineAttr = $1->tag->findAttr( "line" );
508                 Attribute *colAttr = $1->tag->findAttr( "col" );
509                 Attribute *nameAttr = $1->tag->findAttr( "name" );
510                 if ( lineAttr == 0 || colAttr == 0)
511                         error($1->loc) << "tag <action> requires a line and col attributes" << endp;
512                 else {
513                         unsigned long line = strtoul( lineAttr->value, 0, 10 );
514                         unsigned long col = strtoul( colAttr->value, 0, 10 );
516                         char *name = 0;
517                         if ( nameAttr != 0 )
518                                 name = nameAttr->value;
520                         cgd->newAction( curAction++, name, line, col, $2->inlineList );
521                 }
522         };
524 nonterm inline_list
526         InlineList *inlineList;
530 inline_list: inline_list inline_item
531         final {
532                 /* Append the item to the list, return the list. */
533                 $1->inlineList->append( $2->inlineItem );
534                 $$->inlineList = $1->inlineList;
535         };
537 inline_list: 
538         final {
539                 /* Start with empty list. */
540                 $$->inlineList = new InlineList;
541         };
543 nonterm inline_item_type
545         InlineItem *inlineItem;
548 nonterm inline_item uses inline_item_type;
550 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
551 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
552 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
553 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
554 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
555 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
556 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
557 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
558 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
559 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
560 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
561 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
562 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
563 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
564 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
565 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
566 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
567 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
568 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
569 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
570 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
571 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
572 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
573 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
575 nonterm tag_text uses inline_item_type;
576 nonterm tag_goto uses inline_item_type;
577 nonterm tag_call uses inline_item_type;
578 nonterm tag_next uses inline_item_type;
579 nonterm tag_goto_expr uses inline_item_type;
580 nonterm tag_call_expr uses inline_item_type;
581 nonterm tag_next_expr uses inline_item_type;
582 nonterm tag_ret uses inline_item_type;
583 nonterm tag_break uses inline_item_type;
584 nonterm tag_pchar uses inline_item_type;
585 nonterm tag_char uses inline_item_type;
586 nonterm tag_hold uses inline_item_type;
587 nonterm tag_exec uses inline_item_type;
588 nonterm tag_curs uses inline_item_type;
589 nonterm tag_targs uses inline_item_type;
590 nonterm tag_il_entry uses inline_item_type;
591 nonterm tag_init_tokstart uses inline_item_type;
592 nonterm tag_init_act uses inline_item_type;
593 nonterm tag_get_tokend uses inline_item_type;
594 nonterm tag_set_tokstart uses inline_item_type;
595 nonterm tag_set_tokend uses inline_item_type;
596 nonterm tag_set_act uses inline_item_type;
597 nonterm tag_sub_action uses inline_item_type;
598 nonterm tag_lm_switch uses inline_item_type;
600 tag_text: TAG_text '/' TAG_text
601         final {
602                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
603                 $$->inlineItem->data = $3->tag->content;
604         };
606 tag_goto: TAG_goto '/' TAG_goto
607         final {
608                 int targ = strtol( $3->tag->content, 0, 10 );
609                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
610                 $$->inlineItem->targId = targ;
611         };
613 tag_call: TAG_call '/' TAG_call
614         final {
615                 int targ = strtol( $3->tag->content, 0, 10 );
616                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
617                 $$->inlineItem->targId = targ;
618         };
620 tag_next: TAG_next '/' TAG_next
621         final {
622                 int targ = strtol( $3->tag->content, 0, 10 );
623                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
624                 $$->inlineItem->targId = targ;
625         };
627 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
628         final {
629                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
630                 $$->inlineItem->children = $2->inlineList;
631         };
633 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
634         final {
635                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
636                 $$->inlineItem->children = $2->inlineList;
637         };
639 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
640         final {
641                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
642                 $$->inlineItem->children = $2->inlineList;
643         };
645 tag_ret: TAG_ret '/' TAG_ret
646         final {
647                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
648         };
650 tag_break: TAG_break '/' TAG_break
651         final {
652                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
653         };
655 tag_pchar: TAG_pchar '/' TAG_pchar
656         final {
657                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
658         };
660 tag_char: TAG_char '/' TAG_char
661         final {
662                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
663         };
665 tag_hold: TAG_hold '/' TAG_hold
666         final {
667                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
668         };
670 tag_exec: TAG_exec inline_list '/' TAG_exec
671         final {
672                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
673                 $$->inlineItem->children = $2->inlineList;
674         };
676 tag_curs: TAG_curs '/' TAG_curs
677         final {
678                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
679         };
681 tag_targs: TAG_targs '/' TAG_targs
682         final {
683                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
684         };
686 tag_il_entry: TAG_entry '/' TAG_entry
687         final {
688                 int targ = strtol( $3->tag->content, 0, 10 );
689                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
690                 $$->inlineItem->targId = targ;
691         };
693 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
694         final {
695                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
696         };
698 tag_init_act: TAG_init_act '/' TAG_init_act
699         final {
700                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
701         };
703 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
704         final {
705                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
706         };
708 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
709         final {
710                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
711                 cgd->hasLongestMatch = true;
712         };
714 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
715         final {
716                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
717                 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
718         };
720 tag_set_act: TAG_set_act '/' TAG_set_act
721         final {
722                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
723                 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
724         };
726 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
727         final {
728                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
729                 $$->inlineItem->children = $2->inlineList;
730         };
732 # Action switches.
733 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
734         final {
735                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
736                 $$->inlineItem->children = $2->inlineList;
737         };
739 nonterm lm_action_list
741         InlineList *inlineList;
744 lm_action_list: lm_action_list tag_inline_action
745         final {
746                 $$->inlineList = $1->inlineList;
747                 $$->inlineList->append( $2->inlineItem );
748         };
749 lm_action_list:
750         final {
751                 $$->inlineList = new InlineList;
752         };
754 nonterm tag_inline_action uses inline_item_type;
756 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
757         final {
758                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
759                 $$->inlineItem->children = $2->inlineList;
761                 Attribute *idAttr = $1->tag->findAttr( "id" );
762                 if ( idAttr != 0 ) {
763                         unsigned long id = strtoul( idAttr->value, 0, 10 );
764                         $$->inlineItem->lmId = id;
765                 }
766         };
769 # Lists of Actions.
772 tag_action_table_list: 
773         tag_action_table_list_head action_table_list '/' TAG_action_table_list;
775 tag_action_table_list_head: TAG_action_table_list
776         final {
777                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
778                 if ( lengthAttr == 0 ) {
779                         error($1->loc) << "tag <action_table_list> requires "
780                                         "a length attribute" << endp;
781                 }
782                 else {
783                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
784                         cgd->initActionTableList( length );
785                         curActionTable = 0;
786                 }
787         };
789 action_table_list: action_table_list tag_action_table;
790 action_table_list: ;
792 tag_action_table: TAG_action_table '/' TAG_action_table
793         final {
794                 /* Find the length of the action table. */
795                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
796                 if ( lengthAttr == 0 )
797                         error($1->loc) << "tag <at> requires a length attribute" << endp;
798                 else {
799                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
801                         /* Collect the action table. */
802                         RedAction *redAct = cgd->allActionTables + curActionTable;
803                         redAct->actListId = curActionTable;
804                         redAct->key.setAsNew( length );
805                         char *ptr = $3->tag->content;
806                         int pos = 0;
807                         while ( *ptr != 0 ) {
808                                 unsigned long actionId = strtoul( ptr, &ptr, 10 );
809                                 redAct->key[pos].key = 0;
810                                 redAct->key[pos].value = cgd->allActions+actionId;
811                                 pos += 1;
812                         }
814                         /* Insert into the action table map. */
815                         cgd->redFsm->actionMap.insert( redAct );
816                 }
818                 curActionTable += 1;
819         };
822 # Conditions.
825 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
827 tag_cond_space_list_head: TAG_cond_space_list
828         final {
829                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
830                 if ( lengthAttr == 0 ) {
831                         error($1->loc) << "tag <cond_space_list> "
832                                         "requires a length attribute" << endp;
833                 }
834                 else {
835                         ulong length = readLength( lengthAttr->value );
836                         cgd->initCondSpaceList( length );
837                         curCondSpace = 0;
838                 }
839         };
841 cond_space_list: cond_space_list tag_cond_space;
842 cond_space_list: tag_cond_space;
844 tag_cond_space: TAG_cond_space '/' TAG_cond_space
845         final {
846                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
847                 Attribute *idAttr = $1->tag->findAttr( "id" );
848                 if ( lengthAttr == 0 )
849                         error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
850                 else {
851                         if ( lengthAttr == 0 )
852                                 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
853                         else {
854                                 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
855                                 ulong length = readLength( lengthAttr->value );
857                                 char *td = $3->tag->content;
858                                 Key baseKey = readKey( td, &td );
860                                 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
861                                 for ( ulong a = 0; a < length; a++ ) {
862                                         long actionOffset = readOffsetPtr( td, &td );
863                                         cgd->condSpaceItem( curCondSpace, actionOffset );
864                                 }
865                                 curCondSpace += 1;
866                         }
867                 }
868         };
873         write types;
874         write data;
877 void Parser::init()
879         %% write init;
882 int Parser::parseLangEl( int type, const Token *token )
884         %% write exec;
885         return errCount == 0 ? 0 : -1;
889 unsigned long readLength( char *td )
891         return strtoul( td, 0, 10 );
894 Key readKey( char *td, char **end )
896         if ( keyOps->isSigned )
897                 return Key( strtol( td, end, 10 ) );
898         else
899                 return Key( strtoul( td, end, 10 ) );
902 long readOffsetPtr( char *td, char **end )
904         while ( *td == ' ' || *td == '\t' )
905                 td++;
907         if ( *td == 'x' ) {
908                 if ( end != 0 )
909                         *end = td + 1;
910                 return -1;
911         }
913         return strtol( td, end, 10 );
916 ostream &Parser::warning( const InputLoc &loc )
918         cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
919         return cerr;
922 ostream &Parser::error( const InputLoc &loc )
924         gblErrorCount += 1;
925         assert( fileName != 0 );
926         cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
927         return cerr;
931 ostream &Parser::parser_error( int tokId, Token &token )
933         gblErrorCount += 1;
934         assert( fileName != 0 );
935         cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
936         if ( token.tag != 0 ) {
937                 if ( token.tag->tagId == 0 )
938                         cerr << ": at unknown tag";
939                 else
940                         cerr << ": at tag <" << token.tag->tagId->name << ">";
941         }
942         cerr << ": ";
943         
944         return cerr;
947 ostream &Parser::source_error( const InputLoc &loc )
949         gblErrorCount += 1;
950         assert( sourceFileName != 0 );
951         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
952         return cerr;
956 int Parser::token( int tokenId, Token &tok )
958         int res = parseLangEl( tokenId, &tok );
959         if ( res < 0 )
960                 parser_error( tokenId, tok ) << "parse error" << endp;
961         return res;
964 int Parser::token( int tokenId, int col, int line )
966         Token tok;
967         tok.loc.col = col;
968         tok.loc.line = line;
969         tok.tag = 0;
970         return token( tokenId, tok );
973 int Parser::token( XMLTag *tag, int col, int line )
975         Token tok;
976         tok.loc.col = col;
977         tok.loc.line = line;
978         tok.tag = tag;
979         
980         if ( tag->type == XMLTag::Close ) {
981                 int res = token( '/', tok );
982                 if ( res < 0 )
983                         return res;
984         }
986         tok.tag = tag;
987         return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );