a837c878ae052e000b29ae9c3be953459bae606b
[external/ragel.git] / rlcodegen / xmlparse.y
1 /*
2  *  Copyright 2005-2006 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 %{
23
24 #include <iostream>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <errno.h>
28 #include "rlcodegen.h"
29 #include "vector.h"
30 #include "xmlparse.h"
31 #include "gendata.h"
32
33 using std::cerr;
34 using std::endl;
35
36 char *sourceFileName;
37 char *attrKey;
38 char *attrValue;
39 int curAction;
40 int curActionTable;
41 int curTrans;
42 int curState;
43 int curCondSpace;
44 int curStateCond;
45
46 Key readKey( char *td, char **end );
47 long readOffsetPtr( char *td, char **end );
48 unsigned long readLength( char *td );
49
50 CodeGenMap codeGenMap;
51
52 %}
53
54 %pure-parser
55
56 %union {
57         /* General data types. */
58         char c;
59         char *data;
60         int integer;
61         AttrList *attrList;
62
63         /* Inline parse tree items. */
64         InlineItem *ilitem;
65         InlineList *illist;
66 }
67
68 %token TAG_unknown
69 %token TAG_ragel
70 %token TAG_ragel_def
71 %token TAG_host
72 %token TAG_state_list
73 %token TAG_state
74 %token TAG_trans_list
75 %token TAG_t
76 %token TAG_machine
77 %token TAG_start_state
78 %token TAG_action_list
79 %token TAG_action_table_list
80 %token TAG_action
81 %token TAG_action_table
82 %token TAG_alphtype
83 %token TAG_element
84 %token TAG_getkey
85 %token TAG_state_actions
86 %token TAG_entry_points
87 %token TAG_sub_action
88 %token TAG_cond_space_list
89 %token TAG_cond_space
90 %token TAG_cond_list
91 %token TAG_c
92
93 /* Inline block tokens. */
94 %token TAG_text
95 %token TAG_goto
96 %token TAG_call
97 %token TAG_next
98 %token TAG_goto_expr
99 %token TAG_call_expr
100 %token TAG_next_expr
101 %token TAG_ret
102 %token TAG_pchar
103 %token TAG_char
104 %token TAG_hold
105 %token TAG_exec
106 %token TAG_holdte
107 %token TAG_execte
108 %token TAG_curs
109 %token TAG_targs
110 %token TAG_entry
111 %token TAG_data
112 %token TAG_lm_switch
113 %token TAG_init_act
114 %token TAG_set_act
115 %token TAG_set_tokend
116 %token TAG_get_tokend
117 %token TAG_init_tokstart
118 %token TAG_set_tokstart
119 %token TAG_write
120 %token TAG_curstate
121 %token TAG_access
122 %token TAG_break
123 %token TAG_option
124
125 %token <data> XML_Word
126 %token <data> XML_Literal
127 %type <attrList> AttributeList
128
129 %type <illist> InlineList
130 %type <ilitem> InlineItem
131 %type <illist> LmActionList
132
133 %type <ilitem> TagText
134 %type <ilitem> TagGoto
135 %type <ilitem> TagCall
136 %type <ilitem> TagNext
137 %type <ilitem> TagGotoExpr
138 %type <ilitem> TagCallExpr
139 %type <ilitem> TagNextExpr
140 %type <ilitem> TagRet
141 %type <ilitem> TagBreak
142 %type <ilitem> TagPChar
143 %type <ilitem> TagChar
144 %type <ilitem> TagHold
145 %type <ilitem> TagExec
146 %type <ilitem> TagHoldTE
147 %type <ilitem> TagExecTE
148 %type <ilitem> TagCurs
149 %type <ilitem> TagTargs
150 %type <ilitem> TagIlEntry
151 %type <ilitem> TagLmSwitch
152 %type <ilitem> TagLmSetActId
153 %type <ilitem> TagLmGetTokEnd
154 %type <ilitem> TagLmSetTokEnd
155 %type <ilitem> TagLmInitTokStart
156 %type <ilitem> TagLmInitAct
157 %type <ilitem> TagLmSetTokStart
158 %type <ilitem> TagInlineAction
159 %type <ilitem> TagSubAction
160
161 %%
162
163 /* Input is any number of input sections. An empty file is accepted. */
164 input: 
165         TagRagel |
166         /* Nothing */ {
167                 /* Assume the frontend died if we get no input. It will emit an error.
168                  * Cause us to return an error code. */
169                 gblErrorCount += 1;
170         };
171
172 TagRagel: 
173         TagRagelHead
174         HostOrDefList
175         '<' '/' TAG_ragel '>';
176
177 TagRagelHead:
178         '<' TAG_ragel AttributeList '>' {
179                 Attribute *fileNameAttr = $3->find( "filename" );
180                 if ( fileNameAttr == 0 )
181                         xml_error(@2) << "tag <ragel> requires a filename attribute" << endl;
182                 else
183                         sourceFileName = fileNameAttr->value;
184
185                 Attribute *langAttr = $3->find( "lang" );
186                 if ( langAttr == 0 )
187                         xml_error(@2) << "tag <ragel> requires a lang attribute" << endl;
188                 else {
189                         if ( strcmp( langAttr->value, "C" ) == 0 ) {
190                                 hostLangType = CCode;
191                                 hostLang = &hostLangC;
192                         }
193                         else if ( strcmp( langAttr->value, "D" ) == 0 ) {
194                                 hostLangType = DCode;
195                                 hostLang = &hostLangD;
196                         }
197                         else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
198                                 hostLangType = JavaCode;
199                                 hostLang = &hostLangJava;
200                         }
201                 }
202
203                 /* Eventually more types will be supported. */
204                 if ( hostLangType == JavaCode && codeStyle != GenTables ) {
205                         error() << "java: only the table code style -T0 is "
206                                                 "currently supported" << endl;
207                 }
208
209                 openOutput( sourceFileName );
210         };
211
212 AttributeList:
213         AttributeList Attribute {
214                 $$ = $1;
215                 $$->append( Attribute( attrKey, attrValue ) );
216         } |
217         /* Nothing */ {
218                 $$ = new AttrList;
219         };
220
221 Attribute:
222         XML_Word '=' XML_Literal {
223                 attrKey = $1;
224                 attrValue = $3;
225         };
226         
227 HostOrDefList:
228         HostOrDefList HostOrDef |
229         /* Nothing */;
230
231 HostOrDef: 
232         TagHost | TagRagelDef;
233
234 TagHost:
235         TagHostHead
236         '<' '/' TAG_host '>' {
237                 if ( outputFormat == OutCode )
238                         *outStream << xmlData.data;
239         };
240
241 TagHostHead:
242         '<' TAG_host AttributeList '>' {
243                 Attribute *lineAttr = $3->find( "line" );
244                 if ( lineAttr == 0 )
245                         xml_error(@2) << "tag <host> requires a line attribute" << endl;
246                 else {
247                         int line = atoi( lineAttr->value );
248                         if ( outputFormat == OutCode )
249                                 lineDirective( *outStream, sourceFileName, line );
250                 }
251         };
252
253 TagRagelDef:
254         RagelDefHead
255         RagelDefItemList
256         '<' '/' TAG_ragel_def '>' {
257                 if ( gblErrorCount == 0 )
258                         cgd->generate();
259         };
260
261 RagelDefHead:
262         '<' TAG_ragel_def AttributeList '>' {
263                 bool wantComplete = outputFormat != OutGraphvizDot;
264
265                 char *fsmName = 0;
266                 Attribute *nameAttr = $3->find( "name" );
267                 if ( nameAttr != 0 ) {
268                         fsmName = nameAttr->value;
269
270                         CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
271                         if ( mapEl != 0 )
272                                 cgd = mapEl->value;
273                         else {
274                                 cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
275                                 codeGenMap.insert( fsmName, cgd );
276                         }
277                 }
278                 else {
279                         cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
280                 }
281
282                 cgd->writeOps = 0;
283                 cgd->writeData = false;
284                 cgd->writeInit = false;
285                 cgd->writeExec = false;
286                 cgd->writeEOF = false;
287                 ::keyOps = &cgd->thisKeyOps;
288         };
289
290 RagelDefItemList:
291         RagelDefItemList RagelDefItem |
292         /* Nothing */;
293
294 RagelDefItem:
295         TagAlphType |
296         TagGetKeyExpr |
297         TagAccessExpr |
298         TagCurStateExpr |
299         TagMachine |
300         TagWrite;
301
302 TagWrite:
303         '<' TAG_write AttributeList '>'
304         OptionList
305         '<' '/' TAG_write '>' {
306                 Attribute *what = $3->find( "what" );
307                 if ( what == 0 ) {
308                         xml_error(@2) << "tag <write> requires a what attribute" << endl;
309                 }
310                 else {
311                         if ( strcmp( what->value, "data" ) == 0 )
312                                 cgd->writeData = true;
313                         else if ( strcmp( what->value, "init" ) == 0 )
314                                 cgd->writeInit = true;
315                         else if ( strcmp( what->value, "exec" ) == 0 )
316                                 cgd->writeExec = true;
317                         else if ( strcmp( what->value, "eof" ) == 0 )
318                                 cgd->writeEOF = true;
319                 }
320         };
321
322 OptionList:
323         OptionList TagOption |
324         /* Nothing */;
325
326 TagOption:
327         '<' TAG_option '>'
328         '<' '/' TAG_option '>' {
329                 if ( strcmp( xmlData.data, "noend" ) == 0 )
330                         cgd->writeOps |= WO_NOEND;
331                 else if ( strcmp( xmlData.data, "noerror" ) == 0 )
332                         cgd->writeOps |= WO_NOERROR;
333                 else if ( strcmp( xmlData.data, "noprefix" ) == 0 )
334                         cgd->writeOps |= WO_NOPREFIX;
335                 else if ( strcmp( xmlData.data, "nofinal" ) == 0 )
336                         cgd->writeOps |= WO_NOFF;
337                 else {
338                         warning() << "unrecognized write option" << endl;
339                 }
340         };
341
342
343 TagAlphType:
344         '<' TAG_alphtype '>'
345         '<' '/' TAG_alphtype '>' {
346                 if ( ! cgd->setAlphType( xmlData.data ) )
347                         xml_error(@2) << "tag <alphtype> specifies unknown alphabet type" << endl;
348         };
349
350 TagGetKeyExpr:
351         '<' TAG_getkey '>'
352         InlineList
353         '<' '/' TAG_getkey '>' {
354                 cgd->getKeyExpr = $4;
355         };
356
357 TagAccessExpr:
358         '<' TAG_access '>'
359         InlineList
360         '<' '/' TAG_access '>' {
361                 cgd->accessExpr = $4;
362         };
363
364 TagCurStateExpr:
365         '<' TAG_curstate '>'
366         InlineList
367         '<' '/' TAG_curstate '>' {
368                 cgd->curStateExpr = $4;
369         };
370
371 TagMachine:
372         TagMachineHead
373         MachineItemList
374         '<' '/' TAG_machine '>' {
375                 cgd->finishMachine();
376         };
377
378 TagMachineHead:
379         '<' TAG_machine '>' {
380                 cgd->createMachine();
381         };
382
383 MachineItemList:
384         MachineItemList MachineItem |
385         /* Nothing */;
386
387 MachineItem:
388         TagStartState |
389         TagEntryPoints |
390         TagStateList |
391         TagActionList |
392         TagActionTableList |
393         TagCondSpaceList;
394
395 TagStartState:
396         '<' TAG_start_state '>'
397         '<' '/' TAG_start_state '>' {
398                 unsigned long startState = strtoul( xmlData.data, 0, 10 );
399                 cgd->setStartState( startState );
400         };
401
402 TagEntryPoints:
403         '<' TAG_entry_points AttributeList '>'
404         EntryPointList
405         '<' '/' TAG_entry_points '>' {
406                 Attribute *errorAttr = $3->find( "error" );
407                 if ( errorAttr != 0 )
408                         cgd->setForcedErrorState();
409         };
410
411 EntryPointList:
412         EntryPointList TagEntry |
413         /* Nothing */;
414
415 TagEntry:
416         '<' TAG_entry AttributeList '>'
417         '<' '/' TAG_entry '>' {
418                 Attribute *nameAttr = $3->find( "name" );
419                 if ( nameAttr == 0 )
420                         xml_error(@2) << "tag <entry_points>::<entry> requires a name attribute" << endl;
421                 else {
422                         char *data = xmlData.data;
423                         unsigned long entry = strtoul( data, &data, 10 );
424                         cgd->addEntryPoint( nameAttr->value, entry );
425                 }
426         };
427
428 TagStateList:
429         TagStateListHead
430         StateList
431         '<' '/' TAG_state_list '>';
432
433 TagStateListHead:
434         '<' TAG_state_list AttributeList '>' {
435                 Attribute *lengthAttr = $3->find( "length" );
436                 if ( lengthAttr == 0 )
437                         xml_error(@2) << "tag <state_list> requires a length attribute" << endl;
438                 else {
439                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
440                         cgd->initStateList( length );
441                         curState = 0;
442                 }
443         };
444
445 StateList:
446         StateList TagState |
447         /* Nothing */;
448
449 TagState:
450         TagStateHead
451         StateItemList
452         '<' '/' TAG_state '>' {
453                 curState += 1;
454         };
455
456 TagStateHead:
457         '<' TAG_state AttributeList '>' {
458                 Attribute *lengthAttr = $3->find( "final" );
459                 if ( lengthAttr != 0 )
460                         cgd->setFinal( curState );
461         };
462
463 StateItemList:
464         StateItemList StateItem |
465         /* Nothing */;
466
467 StateItem:
468         TagStateActions |
469         TagStateCondList |
470         TagTransList;
471
472 TagStateActions:
473         '<' TAG_state_actions '>'
474         '<' '/' TAG_state_actions '>' {
475                 char *ad = xmlData.data;
476
477                 long toStateAction = readOffsetPtr( ad, &ad );
478                 long fromStateAction = readOffsetPtr( ad, &ad );
479                 long eofAction = readOffsetPtr( ad, &ad );
480
481                 cgd->setStateActions( curState, toStateAction,
482                                 fromStateAction, eofAction );
483         };
484
485 TagStateCondList:
486         TagStateCondListHead
487         StateCondList
488         '<' '/' TAG_cond_list '>';
489
490 TagStateCondListHead:
491         '<' TAG_cond_list AttributeList '>' {
492                 Attribute *lengthAttr = $3->find( "length" );
493                 if ( lengthAttr == 0 )
494                         xml_error(@2) << "tag <cond_list> requires a length attribute" << endl;
495                 else {
496                         ulong length = readLength( lengthAttr->value );
497                         cgd->initStateCondList( curState, length );
498                         curStateCond = 0;
499                 }
500         }
501
502 StateCondList:
503         StateCondList StateCond |
504         /* Empty */;
505
506 StateCond:
507         '<' TAG_c '>'
508         '<' '/' TAG_c '>' {
509                 char *td = xmlData.data;
510                 Key lowKey = readKey( td, &td );
511                 Key highKey = readKey( td, &td );
512                 long condId = readOffsetPtr( td, &td );
513                 cgd->addStateCond( curState, lowKey, highKey, condId );
514         }
515         
516 TagTransList:
517         TagTransListHead
518         TransList
519         '<' '/' TAG_trans_list '>' {
520                 cgd->finishTransList( curState );
521         };
522
523 TagTransListHead:
524         '<' TAG_trans_list AttributeList '>' {
525                 Attribute *lengthAttr = $3->find( "length" );
526                 if ( lengthAttr == 0 )
527                         xml_error(@2) << "tag <trans_list> requires a length attribute" << endl;
528                 else {
529                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
530                         cgd->initTransList( curState, length );
531                         curTrans = 0;
532                 }
533         };
534
535 TransList:
536         TransList TagTrans |
537         /* Nothing */;
538
539 TagTrans:
540         '<' TAG_t AttributeList '>'
541         '<' '/' TAG_t '>' {
542                 char *td = xmlData.data;
543                 Key lowKey = readKey( td, &td );
544                 Key highKey = readKey( td, &td );
545                 long targ = readOffsetPtr( td, &td );
546                 long action = readOffsetPtr( td, &td );
547
548                 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
549         };
550
551 TagActionList:
552         TagActionListHead
553         ActionList
554         '<' '/' TAG_action_list '>';
555
556 TagActionListHead:
557         '<' TAG_action_list AttributeList '>' {
558                 Attribute *lengthAttr = $3->find( "length" );
559                 if ( lengthAttr == 0 )
560                         xml_error(@2) << "tag <action_list> requires a length attribute" << endl;
561                 else {
562                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
563                         cgd->initActionList( length );
564                         curAction = 0;
565                 }
566         };
567
568 ActionList:
569         ActionList TagAction |
570         /* Nothing */;
571
572 TagAction:
573         '<' TAG_action AttributeList '>'
574         InlineList
575         '<' '/' TAG_action '>' {
576                 Attribute *lineAttr = $3->find( "line" );
577                 Attribute *colAttr = $3->find( "col" );
578                 Attribute *nameAttr = $3->find( "name" );
579                 if ( lineAttr == 0 || colAttr == 0)
580                         xml_error(@2) << "tag <action> requires a line and col attributes" << endl;
581                 else {
582                         unsigned long line = strtoul( lineAttr->value, 0, 10 );
583                         unsigned long col = strtoul( colAttr->value, 0, 10 );
584
585                         char *name = 0;
586                         if ( nameAttr != 0 )
587                                 name = nameAttr->value;
588
589                         cgd->newAction( curAction++, name, line, col, $5 );
590                 }
591         };
592
593 InlineList:
594         InlineList InlineItem {
595                 /* Append the item to the list, return the list. */
596                 $1->append( $2 );
597                 $$ = $1;
598         } |
599         /* Nothing */ {
600                 /* Start with empty list. */
601                 $$ = new InlineList;
602         };
603
604 InlineItem:
605         TagText |
606         TagGoto |
607         TagCall |
608         TagNext |
609         TagGotoExpr |
610         TagCallExpr |
611         TagNextExpr |
612         TagRet |
613         TagBreak |
614         TagPChar |
615         TagChar |
616         TagHold |
617         TagExec |
618         TagHoldTE |
619         TagExecTE |
620         TagCurs |
621         TagTargs |
622         TagIlEntry |
623         TagLmSwitch |
624         TagLmSetActId |
625         TagLmSetTokEnd |
626         TagLmGetTokEnd |
627         TagSubAction |
628         TagLmInitTokStart |
629         TagLmInitAct |
630         TagLmSetTokStart;
631
632 TagText:
633         '<' TAG_text AttributeList '>'
634         '<' '/' TAG_text '>' {
635                 $$ = new InlineItem( InputLoc(), InlineItem::Text );
636                 $$->data = strdup(xmlData.data);
637         };
638
639 TagGoto:
640         '<' TAG_goto '>'
641         '<' '/' TAG_goto '>' {
642                 int targ = strtol( xmlData.data, 0, 10 );
643                 $$ = new InlineItem( InputLoc(), InlineItem::Goto );
644                 $$->targId = targ;
645         };
646         
647 TagCall:
648         '<' TAG_call '>'
649         '<' '/' TAG_call '>' {
650                 int targ = strtol( xmlData.data, 0, 10 );
651                 $$ = new InlineItem( InputLoc(), InlineItem::Call );
652                 $$->targId = targ;
653         };
654
655 TagNext:
656         '<' TAG_next '>'
657         '<' '/' TAG_next '>' {
658                 int targ = strtol( xmlData.data, 0, 10 );
659                 $$ = new InlineItem( InputLoc(), InlineItem::Next );
660                 $$->targId = targ;
661         };
662
663 TagGotoExpr:
664         '<' TAG_goto_expr '>'
665         InlineList
666         '<' '/' TAG_goto_expr '>' {
667                 $$ = new InlineItem( InputLoc(), InlineItem::GotoExpr );
668                 $$->children = $4;
669         };
670         
671 TagCallExpr:
672         '<' TAG_call_expr '>'
673         InlineList
674         '<' '/' TAG_call_expr '>' {
675                 $$ = new InlineItem( InputLoc(), InlineItem::CallExpr );
676                 $$->children = $4;
677         };
678
679 TagNextExpr:
680         '<' TAG_next_expr '>'
681         InlineList
682         '<' '/' TAG_next_expr '>' {
683                 $$ = new InlineItem( InputLoc(), InlineItem::NextExpr );
684                 $$->children = $4;
685         };
686
687 TagRet:
688         '<' TAG_ret '>'
689         '<' '/' TAG_ret '>' {
690                 $$ = new InlineItem( InputLoc(), InlineItem::Ret );
691         };
692         
693 TagPChar:
694         '<' TAG_pchar '>'
695         '<' '/' TAG_pchar '>' {
696                 $$ = new InlineItem( InputLoc(), InlineItem::PChar );
697         };
698
699 TagChar:
700         '<' TAG_char '>'
701         '<' '/' TAG_char '>' {
702                 $$ = new InlineItem( InputLoc(), InlineItem::Char );
703         };
704
705 TagHold:
706         '<' TAG_hold '>'
707         '<' '/' TAG_hold '>' {
708                 $$ = new InlineItem( InputLoc(), InlineItem::Hold );
709         };
710
711 TagExec:
712         '<' TAG_exec '>'
713         InlineList
714         '<' '/' TAG_exec '>' {
715                 $$ = new InlineItem( InputLoc(), InlineItem::Exec );
716                 $$->children = $4;
717         };
718
719 TagHoldTE:
720         '<' TAG_holdte '>'
721         '<' '/' TAG_holdte '>' {
722                 $$ = new InlineItem( InputLoc(), InlineItem::HoldTE );
723         };
724
725 TagExecTE:
726         '<' TAG_execte '>'
727         InlineList
728         '<' '/' TAG_execte '>' {
729                 $$ = new InlineItem( InputLoc(), InlineItem::ExecTE );
730                 $$->children = $4;
731         };
732
733 TagCurs:
734         '<' TAG_curs '>'
735         '<' '/' TAG_curs '>' {
736                 $$ = new InlineItem( InputLoc(), InlineItem::Curs );
737         };
738
739 TagTargs:
740         '<' TAG_targs '>'
741         '<' '/' TAG_targs '>' {
742                 $$ = new InlineItem( InputLoc(), InlineItem::Targs );
743         };
744
745 TagIlEntry:
746         '<' TAG_entry '>'
747         '<' '/' TAG_entry '>' {
748                 int targ = strtol( xmlData.data, 0, 10 );
749                 $$ = new InlineItem( InputLoc(), InlineItem::Entry );
750                 $$->targId = targ;
751         };
752
753 TagBreak:
754         '<' TAG_break '>'
755         '<' '/' TAG_break '>' {
756                 $$ = new InlineItem( InputLoc(), InlineItem::Break );
757         };
758         
759
760 TagLmSwitch:
761         '<' TAG_lm_switch AttributeList '>'
762         LmActionList
763         '<' '/' TAG_lm_switch '>' {
764                 bool handlesError = false;
765                 Attribute *handlesErrorAttr = $3->find( "handles_error" );
766                 if ( handlesErrorAttr != 0 )
767                         handlesError = true;
768
769                 $$ = new InlineItem( InputLoc(), InlineItem::LmSwitch );
770                 $$->children = $5;
771                 $$->handlesError = handlesError;
772         };
773
774 LmActionList:
775         LmActionList TagInlineAction {
776                 $$ = $1;
777                 $$->append( $2 );
778         } |
779         /* Nothing */ {
780                 $$ = new InlineList;
781         };
782
783 TagInlineAction:
784         '<' TAG_sub_action AttributeList '>'
785         InlineList
786         '<' '/' TAG_sub_action '>' {
787                 $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
788                 $$->children = $5;
789
790                 Attribute *idAttr = $3->find( "id" );
791                 if ( idAttr != 0 ) {
792                         unsigned long id = strtoul( idAttr->value, 0, 10 );
793                         $$->lmId = id;
794                 }
795         };
796
797 TagLmSetActId:
798         '<' TAG_set_act '>'
799         '<' '/' TAG_set_act '>' {
800                 $$ = new InlineItem( InputLoc(), InlineItem::LmSetActId );
801                 $$->lmId = strtol( xmlData.data, 0, 10 );
802         };
803
804 TagLmGetTokEnd:
805         '<' TAG_get_tokend '>'
806         '<' '/' TAG_get_tokend '>' {
807                 $$ = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
808         };
809
810 TagLmSetTokEnd:
811         '<' TAG_set_tokend '>'
812         '<' '/' TAG_set_tokend '>' {
813                 $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
814                 $$->offset = strtol( xmlData.data, 0, 10 );
815         };
816
817 TagSubAction:
818         '<' TAG_sub_action '>'
819         InlineList
820         '<' '/' TAG_sub_action '>' {
821                 $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
822                 $$->children = $4;
823         };
824
825 TagLmInitTokStart:
826         '<' TAG_init_tokstart '>'
827         '<' '/' TAG_init_tokstart '>' {
828                 $$ = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
829         };
830
831 TagLmInitAct:
832         '<' TAG_init_act '>'
833         '<' '/' TAG_init_act '>' {
834                 $$ = new InlineItem( InputLoc(), InlineItem::LmInitAct );
835         };
836
837 TagLmSetTokStart:
838         '<' TAG_set_tokstart '>'
839         '<' '/' TAG_set_tokstart '>' {
840                 $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
841                 cgd->hasLongestMatch = true;
842         };
843
844 TagActionTableList:
845         TagActionTableListHead
846         ActionTableList
847         '<' '/' TAG_action_table_list '>';
848
849 TagActionTableListHead:
850         '<' TAG_action_table_list AttributeList '>' {
851                 Attribute *lengthAttr = $3->find( "length" );
852                 if ( lengthAttr == 0 )
853                         xml_error(@2) << "tag <action_table_list> requires a length attribute" << endl;
854                 else {
855                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
856                         cgd->initActionTableList( length );
857                         curActionTable = 0;
858                 }
859         };
860
861 ActionTableList:
862         ActionTableList TagActionTable |
863         /* Nothing */;
864
865 TagActionTable:
866         '<' TAG_action_table AttributeList '>'
867         '<' '/' TAG_action_table '>' {
868                 /* Find the length of the action table. */
869                 Attribute *lengthAttr = $3->find( "length" );
870                 if ( lengthAttr == 0 )
871                         xml_error(@2) << "tag <at> requires a length attribute" << endl;
872                 else {
873                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
874
875                         /* Collect the action table. */
876                         RedAction *redAct = cgd->allActionTables + curActionTable;
877                         redAct->actListId = curActionTable;
878                         redAct->key.setAsNew( length );
879                         char *ptr = xmlData.data;
880                         int pos = 0;
881                         while ( *ptr != 0 ) {
882                                 unsigned long actionId = strtoul( ptr, &ptr, 10 );
883                                 redAct->key[pos].key = 0;
884                                 redAct->key[pos].value = cgd->allActions+actionId;
885                                 pos += 1;
886                         }
887
888                         /* Insert into the action table map. */
889                         cgd->redFsm->actionMap.insert( redAct );
890                 }
891
892                 curActionTable += 1;
893         };
894
895 TagCondSpaceList:
896         TagCondSpaceListHead
897         CondSpaceList
898         '<' '/' TAG_cond_space_list '>';
899
900 TagCondSpaceListHead:
901         '<' TAG_cond_space_list AttributeList '>' {
902                 Attribute *lengthAttr = $3->find( "length" );
903                 if ( lengthAttr == 0 )
904                         xml_error(@2) << "tag <cond_space_list> requires a length attribute" << endl;
905                 else {
906                         ulong length = readLength( lengthAttr->value );
907                         cgd->initCondSpaceList( length );
908                         curCondSpace = 0;
909                 }
910         };
911
912 CondSpaceList: 
913         CondSpaceList TagCondSpace |
914         TagCondSpace;
915
916 TagCondSpace:
917         '<' TAG_cond_space AttributeList '>'
918         '<' '/' TAG_cond_space '>' {
919                 Attribute *lengthAttr = $3->find( "length" );
920                 Attribute *idAttr = $3->find( "id" );
921                 if ( lengthAttr == 0 )
922                         xml_error(@2) << "tag <cond_space> requires a length attribute" << endl;
923                 else {
924                         if ( lengthAttr == 0 )
925                                 xml_error(@2) << "tag <cond_space> requires an id attribute" << endl;
926                         else {
927                                 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
928                                 ulong length = readLength( lengthAttr->value );
929
930                                 char *td = xmlData.data;
931                                 Key baseKey = readKey( td, &td );
932
933                                 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
934                                 for ( ulong a = 0; a < length; a++ ) {
935                                         long actionOffset = readOffsetPtr( td, &td );
936                                         cgd->condSpaceItem( curCondSpace, actionOffset );
937                                 }
938                                 curCondSpace += 1;
939                         }
940                 }
941         };
942
943 %%
944
945 unsigned long readLength( char *td )
946 {
947         return strtoul( td, 0, 10 );
948 }
949
950 Key readKey( char *td, char **end )
951 {
952         if ( keyOps->isSigned )
953                 return Key( strtol( td, end, 10 ) );
954         else
955                 return Key( strtoul( td, end, 10 ) );
956 }
957
958 long readOffsetPtr( char *td, char **end )
959 {
960         while ( *td == ' ' || *td == '\t' )
961                 td++;
962
963         if ( *td == 'x' ) {
964                 if ( end != 0 )
965                         *end = td + 1;
966                 return -1;
967         }
968
969         return strtol( td, end, 10 );
970 }
971
972 void yyerror( char *err )
973 {
974         /* Bison won't give us the location, but in the last call to the scanner we
975          * saved a pointer to the locationn variable. Use that. instead. */
976         error(::yylloc->first_line, ::yylloc->first_column) << err << endl;
977 }
978