Can cleanup the xml code generation and remove the holdte and execte tags
[external/ragel.git] / redfsm / xmlparse.kl
1 /*
2  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
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  */
21
22 #include "xmlparse.h"
23 #include "common.h"
24 #include "gendata.h"
25 #include "version.h"
26 #include <iostream>
27 #include <stdlib.h>
28
29 using std::cout;
30 using std::ostream;
31 using std::istream;
32 using std::cerr;
33 using std::endl;
34
35 Key readKey( char *td, char **end );
36 long readOffsetPtr( char *td, char **end );
37 unsigned long readLength( char *td );
38
39 %%{
40
41 parser Parser;
42
43 include "xmlparse.kh";
44
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         };
53
54 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
55
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;
64
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;
70
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;
75
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                 }
88
89                 outStream = openOutput( sourceFileName );
90         };
91
92 ragel_def_list: ragel_def_list ragel_def;
93 ragel_def_list: ;
94
95 host_or_write_list: host_or_write_list host_or_write;
96 host_or_write_list: ;
97
98 host_or_write: tag_host;
99 host_or_write: tag_write;
100
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                 }
112
113                 if ( outputActive )
114                         *outStream << $3->tag->content;
115         };
116
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();
123
124                 cgd->redFsm->assignActionLocs();
125
126                 /* Find the first final state (The final state with the lowest id). */
127                 cgd->redFsm->findFirstFinState();
128
129                 /* Call the user's callback. */
130                 cgd->finishRagelDef();
131         };
132
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;
139
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                 }
152
153                 ::keyOps = &cgd->thisKeyOps;
154         };
155
156 ragel_def_item_list: ragel_def_item_list ragel_def_item;
157 ragel_def_item_list: ;
158
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_export_list;
163 ragel_def_item: tag_machine;
164 ragel_def_item: tag_p_expr;
165 ragel_def_item: tag_pe_expr;
166 ragel_def_item: tag_cs_expr;
167 ragel_def_item: tag_top_expr;
168 ragel_def_item: tag_stack_expr;
169 ragel_def_item: tag_act_expr;
170 ragel_def_item: tag_tokstart_expr;
171 ragel_def_item: tag_tokend_expr;
172
173 tag_export_list: TAG_exports export_list '/' TAG_exports;
174
175 export_list: export_list tag_export;
176 export_list: ;
177
178 tag_export: TAG_ex '/' TAG_ex
179         final {
180                 Attribute *nameAttr = $1->tag->findAttr( "name" );
181                 if ( nameAttr == 0 )
182                         error($1->loc) << "tag <ex> requires a name attribute" << endp;
183                 else {
184                         char *td = $3->tag->content;
185                         Key exportKey = readKey( td, &td );
186                         cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
187                 }
188         };
189
190 tag_alph_type: TAG_alphtype '/' TAG_alphtype
191         final {
192                 if ( ! cgd->setAlphType( $3->tag->content ) )
193                         error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
194         };
195
196 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
197         final {
198                 cgd->getKeyExpr = $2->inlineList;
199         };
200
201 tag_access_expr: TAG_access inline_list '/' TAG_access
202         final {
203                 cgd->accessExpr = $2->inlineList;
204         };
205
206 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
207         final { cgd->pExpr = $2->inlineList; };
208 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
209         final { cgd->peExpr = $2->inlineList; };
210 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
211         final { cgd->csExpr = $2->inlineList; };
212 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
213         final { cgd->topExpr = $2->inlineList; };
214 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
215         final { cgd->stackExpr = $2->inlineList; };
216 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
217         final { cgd->actExpr = $2->inlineList; };
218 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
219         final { cgd->tokstartExpr = $2->inlineList; };
220 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
221         final { cgd->tokendExpr = $2->inlineList; };
222
223
224 tag_write: tag_write_head write_option_list '/' TAG_write
225         final {
226                 /* Terminate the options list and call the write statement handler. */
227                 writeOptions.append(0);
228                 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
229
230                 /* Clear the options in prep for the next write statement. */
231                 writeOptions.empty();
232         };
233
234 nonterm tag_write_head
235 {
236         InputLoc loc;
237 };
238
239 tag_write_head: TAG_write
240         final {
241                 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
242                 Attribute *lineAttr = $1->tag->findAttr( "line" );
243                 Attribute *colAttr = $1->tag->findAttr( "col" );
244
245                 if ( nameAttr == 0 )
246                         error($1->loc) << "tag <write> requires a def_name attribute" << endp;
247                 if ( lineAttr == 0 )
248                         error($1->loc) << "tag <write> requires a line attribute" << endp;
249                 if ( colAttr == 0 )
250                         error($1->loc) << "tag <write> requires a col attribute" << endp;
251
252                 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
253                         CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
254                         if ( mapEl == 0 )
255                                 error($1->loc) << "internal error: cannot find codeGen" << endp;
256                         else {
257                                 cgd = mapEl->value;
258                                 ::keyOps = &cgd->thisKeyOps;
259                         }
260
261                         $$->loc.line = atoi(lineAttr->value);
262                         $$->loc.col = atoi(colAttr->value);
263                 }
264         };
265
266
267 write_option_list: write_option_list tag_arg;
268 write_option_list: ;
269
270 nonterm tag_arg
271 {
272         char *option;
273 };
274
275 tag_arg: TAG_arg '/' TAG_arg
276         final {
277                 writeOptions.append( $3->tag->content );
278         };
279
280 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
281         final {
282                 cgd->closeMachine();
283         };
284
285 tag_machine_head: TAG_machine
286         final {
287                 cgd->createMachine();
288         };
289
290 machine_item_list: machine_item_list machine_item;
291 machine_item_list: ;
292
293 machine_item: tag_start_state;
294 machine_item: tag_error_state;
295 machine_item: tag_entry_points;
296 machine_item: tag_state_list;
297 machine_item: tag_action_list;
298 machine_item: tag_action_table_list;
299 machine_item: tag_cond_space_list;
300
301 #
302 # States.
303 #
304
305 tag_start_state: TAG_start_state '/' TAG_start_state
306         final {
307                 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
308                 cgd->setStartState( startState );
309         };
310
311 tag_error_state: TAG_error_state '/' TAG_error_state
312         final {
313                 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
314                 cgd->setErrorState( errorState );
315         };
316
317 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
318         final {
319                 Attribute *errorAttr = $1->tag->findAttr( "error" );
320                 if ( errorAttr != 0 )
321                         cgd->setForcedErrorState();
322         };
323
324 entry_point_list: entry_point_list tag_entry;
325 entry_point_list: ;
326
327 tag_entry: TAG_entry '/' TAG_entry
328         final {
329                 Attribute *nameAttr = $1->tag->findAttr( "name" );
330                 if ( nameAttr == 0 ) {
331                         error($1->loc) << "tag <entry_points>::<entry> "
332                                         "requires a name attribute" << endp;
333                 }
334                 else {
335                         char *data = $3->tag->content;
336                         unsigned long entry = strtoul( data, &data, 10 );
337                         cgd->addEntryPoint( nameAttr->value, entry );
338                 }
339         };
340
341 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
342
343 tag_state_list_head: TAG_state_list
344         final {
345                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
346                 if ( lengthAttr == 0 )
347                         error($1->loc) << "tag <state_list> requires a length attribute" << endp;
348                 else {
349                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
350                         cgd->initStateList( length );
351                         curState = 0;
352                 }
353         };
354
355 state_list: state_list tag_state;
356 state_list: ;
357
358 tag_state: TAG_state state_item_list '/' TAG_state
359         final {
360                 Attribute *idAttr = $1->tag->findAttr( "id" );
361                 if ( idAttr == 0 )
362                         error($1->loc) << "tag <state> requires an id attribute" << endp;
363                 else {
364                         int id = atoi( idAttr->value );
365                         cgd->setId( curState, id );
366                 }
367
368                 Attribute *lengthAttr = $1->tag->findAttr( "final" );
369                 if ( lengthAttr != 0 )
370                         cgd->setFinal( curState );
371                 curState += 1;
372         };
373
374 state_item_list: state_item_list state_item;
375 state_item_list: ;
376
377 state_item: tag_state_actions;
378 state_item: tag_state_cond_list;
379 state_item: tag_trans_list;
380
381 tag_state_actions: TAG_state_actions '/' TAG_state_actions
382         final {
383                 char *ad = $3->tag->content;
384
385                 long toStateAction = readOffsetPtr( ad, &ad );
386                 long fromStateAction = readOffsetPtr( ad, &ad );
387                 long eofAction = readOffsetPtr( ad, &ad );
388
389                 cgd->setStateActions( curState, toStateAction,
390                                 fromStateAction, eofAction );
391         };
392
393 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
394
395 tag_state_cond_list_head: TAG_cond_list
396         final {
397                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
398                 if ( lengthAttr == 0 )
399                         error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
400                 else {
401                         ulong length = readLength( lengthAttr->value );
402                         cgd->initStateCondList( curState, length );
403                         curStateCond = 0;
404                 }
405         };
406
407 state_cond_list: state_cond_list state_cond;
408 state_cond_list: ;
409
410 state_cond: TAG_c '/' TAG_c
411         final {
412                 char *td = $3->tag->content;
413                 Key lowKey = readKey( td, &td );
414                 Key highKey = readKey( td, &td );
415                 long condId = readOffsetPtr( td, &td );
416                 cgd->addStateCond( curState, lowKey, highKey, condId );
417         };
418
419 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
420         final {
421                 cgd->finishTransList( curState );
422         };
423
424 tag_trans_list_head: TAG_trans_list
425         final {
426                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
427                 if ( lengthAttr == 0 )
428                         error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
429                 else {
430                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
431                         cgd->initTransList( curState, length );
432                         curTrans = 0;
433                 }
434         };
435
436 trans_list: trans_list tag_trans;
437 trans_list: ;
438
439 tag_trans: TAG_t '/' TAG_t
440         final {
441                 char *td = $3->tag->content;
442                 Key lowKey = readKey( td, &td );
443                 Key highKey = readKey( td, &td );
444                 long targ = readOffsetPtr( td, &td );
445                 long action = readOffsetPtr( td, &td );
446
447                 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
448         };
449
450 #
451 # Action Lists.
452 #
453
454 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
455
456 tag_action_list_head: TAG_action_list
457         final {
458                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
459                 if ( lengthAttr == 0 )
460                         error($1->loc) << "tag <action_list> requires a length attribute" << endp;
461                 else {
462                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
463                         cgd->initActionList( length );
464                         curAction = 0;
465                 }
466         };
467
468 action_list: action_list tag_action;
469 action_list: ;
470
471 #
472 # Actions.
473 #
474
475 tag_action: TAG_action inline_list '/' TAG_action
476         final {
477                 Attribute *lineAttr = $1->tag->findAttr( "line" );
478                 Attribute *colAttr = $1->tag->findAttr( "col" );
479                 Attribute *nameAttr = $1->tag->findAttr( "name" );
480                 if ( lineAttr == 0 || colAttr == 0)
481                         error($1->loc) << "tag <action> requires a line and col attributes" << endp;
482                 else {
483                         unsigned long line = strtoul( lineAttr->value, 0, 10 );
484                         unsigned long col = strtoul( colAttr->value, 0, 10 );
485
486                         char *name = 0;
487                         if ( nameAttr != 0 )
488                                 name = nameAttr->value;
489
490                         cgd->newAction( curAction++, name, line, col, $2->inlineList );
491                 }
492         };
493
494 nonterm inline_list
495 {
496         InlineList *inlineList;
497 };
498
499
500 inline_list: inline_list inline_item
501         final {
502                 /* Append the item to the list, return the list. */
503                 $1->inlineList->append( $2->inlineItem );
504                 $$->inlineList = $1->inlineList;
505         };
506
507 inline_list: 
508         final {
509                 /* Start with empty list. */
510                 $$->inlineList = new InlineList;
511         };
512
513 nonterm inline_item_type
514 {
515         InlineItem *inlineItem;
516 };
517
518 nonterm inline_item uses inline_item_type;
519
520 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
521 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
522 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
523 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
524 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
525 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
526 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
527 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
528 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
529 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
530 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
531 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
532 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
533 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
534 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
535 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
536 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
537 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
538 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
539 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
540 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
541 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
542 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
543 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
544
545 nonterm tag_text uses inline_item_type;
546 nonterm tag_goto uses inline_item_type;
547 nonterm tag_call uses inline_item_type;
548 nonterm tag_next uses inline_item_type;
549 nonterm tag_goto_expr uses inline_item_type;
550 nonterm tag_call_expr uses inline_item_type;
551 nonterm tag_next_expr uses inline_item_type;
552 nonterm tag_ret uses inline_item_type;
553 nonterm tag_break uses inline_item_type;
554 nonterm tag_pchar uses inline_item_type;
555 nonterm tag_char uses inline_item_type;
556 nonterm tag_hold uses inline_item_type;
557 nonterm tag_exec uses inline_item_type;
558 nonterm tag_curs uses inline_item_type;
559 nonterm tag_targs uses inline_item_type;
560 nonterm tag_il_entry uses inline_item_type;
561 nonterm tag_init_tokstart uses inline_item_type;
562 nonterm tag_init_act uses inline_item_type;
563 nonterm tag_get_tokend uses inline_item_type;
564 nonterm tag_set_tokstart uses inline_item_type;
565 nonterm tag_set_tokend uses inline_item_type;
566 nonterm tag_set_act uses inline_item_type;
567 nonterm tag_sub_action uses inline_item_type;
568 nonterm tag_lm_switch uses inline_item_type;
569
570 tag_text: TAG_text '/' TAG_text
571         final {
572                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
573                 $$->inlineItem->data = $3->tag->content;
574         };
575
576 tag_goto: TAG_goto '/' TAG_goto
577         final {
578                 int targ = strtol( $3->tag->content, 0, 10 );
579                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
580                 $$->inlineItem->targId = targ;
581         };
582
583 tag_call: TAG_call '/' TAG_call
584         final {
585                 int targ = strtol( $3->tag->content, 0, 10 );
586                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
587                 $$->inlineItem->targId = targ;
588         };
589
590 tag_next: TAG_next '/' TAG_next
591         final {
592                 int targ = strtol( $3->tag->content, 0, 10 );
593                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
594                 $$->inlineItem->targId = targ;
595         };
596
597 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
598         final {
599                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
600                 $$->inlineItem->children = $2->inlineList;
601         };
602
603 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
604         final {
605                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
606                 $$->inlineItem->children = $2->inlineList;
607         };
608
609 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
610         final {
611                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
612                 $$->inlineItem->children = $2->inlineList;
613         };
614
615 tag_ret: TAG_ret '/' TAG_ret
616         final {
617                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
618         };
619
620 tag_break: TAG_break '/' TAG_break
621         final {
622                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
623         };
624
625 tag_pchar: TAG_pchar '/' TAG_pchar
626         final {
627                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
628         };
629
630 tag_char: TAG_char '/' TAG_char
631         final {
632                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
633         };
634
635 tag_hold: TAG_hold '/' TAG_hold
636         final {
637                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
638         };
639
640 tag_exec: TAG_exec inline_list '/' TAG_exec
641         final {
642                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
643                 $$->inlineItem->children = $2->inlineList;
644         };
645
646 tag_curs: TAG_curs '/' TAG_curs
647         final {
648                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
649         };
650
651 tag_targs: TAG_targs '/' TAG_targs
652         final {
653                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
654         };
655
656 tag_il_entry: TAG_entry '/' TAG_entry
657         final {
658                 int targ = strtol( $3->tag->content, 0, 10 );
659                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
660                 $$->inlineItem->targId = targ;
661         };
662
663 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
664         final {
665                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
666         };
667
668 tag_init_act: TAG_init_act '/' TAG_init_act
669         final {
670                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
671         };
672
673 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
674         final {
675                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
676         };
677
678 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
679         final {
680                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
681                 cgd->hasLongestMatch = true;
682         };
683
684 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
685         final {
686                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
687                 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
688         };
689
690 tag_set_act: TAG_set_act '/' TAG_set_act
691         final {
692                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
693                 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
694         };
695
696 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
697         final {
698                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
699                 $$->inlineItem->children = $2->inlineList;
700         };
701
702 # Action switches.
703 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
704         final {
705                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
706                 $$->inlineItem->children = $2->inlineList;
707         };
708
709 nonterm lm_action_list
710 {
711         InlineList *inlineList;
712 };
713
714 lm_action_list: lm_action_list tag_inline_action
715         final {
716                 $$->inlineList = $1->inlineList;
717                 $$->inlineList->append( $2->inlineItem );
718         };
719 lm_action_list:
720         final {
721                 $$->inlineList = new InlineList;
722         };
723
724 nonterm tag_inline_action uses inline_item_type;
725
726 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
727         final {
728                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
729                 $$->inlineItem->children = $2->inlineList;
730
731                 Attribute *idAttr = $1->tag->findAttr( "id" );
732                 if ( idAttr != 0 ) {
733                         unsigned long id = strtoul( idAttr->value, 0, 10 );
734                         $$->inlineItem->lmId = id;
735                 }
736         };
737
738 #
739 # Lists of Actions.
740 #
741
742 tag_action_table_list: 
743         tag_action_table_list_head action_table_list '/' TAG_action_table_list;
744
745 tag_action_table_list_head: TAG_action_table_list
746         final {
747                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
748                 if ( lengthAttr == 0 ) {
749                         error($1->loc) << "tag <action_table_list> requires "
750                                         "a length attribute" << endp;
751                 }
752                 else {
753                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
754                         cgd->initActionTableList( length );
755                         curActionTable = 0;
756                 }
757         };
758
759 action_table_list: action_table_list tag_action_table;
760 action_table_list: ;
761
762 tag_action_table: TAG_action_table '/' TAG_action_table
763         final {
764                 /* Find the length of the action table. */
765                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
766                 if ( lengthAttr == 0 )
767                         error($1->loc) << "tag <at> requires a length attribute" << endp;
768                 else {
769                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
770
771                         /* Collect the action table. */
772                         RedAction *redAct = cgd->allActionTables + curActionTable;
773                         redAct->actListId = curActionTable;
774                         redAct->key.setAsNew( length );
775                         char *ptr = $3->tag->content;
776                         int pos = 0;
777                         while ( *ptr != 0 ) {
778                                 unsigned long actionId = strtoul( ptr, &ptr, 10 );
779                                 redAct->key[pos].key = 0;
780                                 redAct->key[pos].value = cgd->allActions+actionId;
781                                 pos += 1;
782                         }
783
784                         /* Insert into the action table map. */
785                         cgd->redFsm->actionMap.insert( redAct );
786                 }
787
788                 curActionTable += 1;
789         };
790
791 #
792 # Conditions.
793 #
794
795 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
796
797 tag_cond_space_list_head: TAG_cond_space_list
798         final {
799                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
800                 if ( lengthAttr == 0 ) {
801                         error($1->loc) << "tag <cond_space_list> "
802                                         "requires a length attribute" << endp;
803                 }
804                 else {
805                         ulong length = readLength( lengthAttr->value );
806                         cgd->initCondSpaceList( length );
807                         curCondSpace = 0;
808                 }
809         };
810
811 cond_space_list: cond_space_list tag_cond_space;
812 cond_space_list: tag_cond_space;
813
814 tag_cond_space: TAG_cond_space '/' TAG_cond_space
815         final {
816                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
817                 Attribute *idAttr = $1->tag->findAttr( "id" );
818                 if ( lengthAttr == 0 )
819                         error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
820                 else {
821                         if ( lengthAttr == 0 )
822                                 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
823                         else {
824                                 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
825                                 ulong length = readLength( lengthAttr->value );
826
827                                 char *td = $3->tag->content;
828                                 Key baseKey = readKey( td, &td );
829
830                                 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
831                                 for ( ulong a = 0; a < length; a++ ) {
832                                         long actionOffset = readOffsetPtr( td, &td );
833                                         cgd->condSpaceItem( curCondSpace, actionOffset );
834                                 }
835                                 curCondSpace += 1;
836                         }
837                 }
838         };
839
840 }%%
841
842 %%{
843         write types;
844         write data;
845 }%%
846
847 void Parser::init()
848 {
849         %% write init;
850 }
851
852 int Parser::parseLangEl( int type, const Token *token )
853 {
854         %% write exec;
855         return errCount == 0 ? 0 : -1;
856 }
857
858
859 unsigned long readLength( char *td )
860 {
861         return strtoul( td, 0, 10 );
862 }
863
864 Key readKey( char *td, char **end )
865 {
866         if ( keyOps->isSigned )
867                 return Key( strtol( td, end, 10 ) );
868         else
869                 return Key( strtoul( td, end, 10 ) );
870 }
871
872 long readOffsetPtr( char *td, char **end )
873 {
874         while ( *td == ' ' || *td == '\t' )
875                 td++;
876
877         if ( *td == 'x' ) {
878                 if ( end != 0 )
879                         *end = td + 1;
880                 return -1;
881         }
882
883         return strtol( td, end, 10 );
884 }
885
886 ostream &Parser::warning( const InputLoc &loc )
887 {
888         cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
889         return cerr;
890 }
891
892 ostream &Parser::error( const InputLoc &loc )
893 {
894         gblErrorCount += 1;
895         assert( fileName != 0 );
896         cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
897         return cerr;
898 }
899
900
901 ostream &Parser::parser_error( int tokId, Token &token )
902 {
903         gblErrorCount += 1;
904         assert( fileName != 0 );
905         cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
906         if ( token.tag != 0 ) {
907                 if ( token.tag->tagId == 0 )
908                         cerr << ": at unknown tag";
909                 else
910                         cerr << ": at tag <" << token.tag->tagId->name << ">";
911         }
912         cerr << ": ";
913         
914         return cerr;
915 }
916
917 int Parser::token( int tokenId, Token &tok )
918 {
919         int res = parseLangEl( tokenId, &tok );
920         if ( res < 0 )
921                 parser_error( tokenId, tok ) << "parse error" << endp;
922         return res;
923 }
924
925 int Parser::token( int tokenId, int col, int line )
926 {
927         Token tok;
928         tok.loc.col = col;
929         tok.loc.line = line;
930         tok.tag = 0;
931         return token( tokenId, tok );
932 }
933
934 int Parser::token( XMLTag *tag, int col, int line )
935 {
936         Token tok;
937         tok.loc.col = col;
938         tok.loc.line = line;
939         tok.tag = tag;
940         
941         if ( tag->type == XMLTag::Close ) {
942                 int res = token( '/', tok );
943                 if ( res < 0 )
944                         return res;
945         }
946
947         tok.tag = tag;
948         return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );
949 }