Get ragel working again while the direct-to-backend code is being written.
[external/ragel.git] / redfsm / xmlparse.kl
1 /*
2  *  Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
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 struct Token
40 {
41         XMLTag *tag;
42         GenInputLoc loc;
43 };
44
45 CodeGenData *makeCodeGen( const char *sourceFileName, const char *fsmName, 
46                 ostream &out, bool wantComplete )
47 {
48         CodeGenData *cgd = 0;
49         if ( generateDot )
50                 cgd = dotMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
51         else if ( hostLang == &hostLangC )
52                 cgd = cdMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
53         else if ( hostLang == &hostLangD )
54                 cgd = cdMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
55         else if ( hostLang == &hostLangJava )
56                 cgd = javaMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
57         else if ( hostLang == &hostLangRuby )
58                 cgd = rubyMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
59         else if ( hostLang == &hostLangCSharp )
60                 cgd = csharpMakeCodeGen( sourceFileName, fsmName, out, wantComplete );
61         return cgd;
62 }
63
64 void lineDirective( ostream &out, const char *fileName, int line )
65 {
66         if ( !generateDot ) {
67                 if ( hostLang == &hostLangC )
68                         cdLineDirective( out, fileName, line );
69                 else if ( hostLang == &hostLangD )
70                         cdLineDirective( out, fileName, line );
71                 else if ( hostLang == &hostLangJava )
72                         javaLineDirective( out, fileName, line );
73                 else if ( hostLang == &hostLangRuby )
74                         rubyLineDirective( out, fileName, line );
75                 else if ( hostLang == &hostLangCSharp )
76                         csharpLineDirective( out, fileName, line );
77         }
78 }
79
80 void genLineDirective( ostream &out )
81 {
82         std::streambuf *sbuf = out.rdbuf();
83         output_filter *filter = static_cast<output_filter*>(sbuf);
84         lineDirective( out, filter->fileName, filter->line + 1 );
85 }
86
87 void XmlParser::open_ragel( const char *fileName )
88 {
89         /* Check for file name attribute. */
90         sourceFileName = fileName;
91
92         if ( generateDot )
93                 outStream = dotOpenOutput( sourceFileName );
94         else if ( hostLang->lang == HostLang::C ) {
95                 hostLang = &hostLangC;
96                 outStream = cdOpenOutput( sourceFileName );
97         }
98         else if ( hostLang->lang == HostLang::D ) {
99                 hostLang = &hostLangD;
100                 outStream = cdOpenOutput( sourceFileName );
101         }
102         else if ( hostLang->lang == HostLang::Java ) {
103                 hostLang = &hostLangJava;
104                 outStream = javaOpenOutput( sourceFileName );
105         }
106         else if ( hostLang->lang == HostLang::Ruby ) {
107                 hostLang = &hostLangRuby;
108                 outStream = rubyOpenOutput( sourceFileName );
109         }
110         else if ( hostLang->lang == HostLang::CSharp ) {
111                 hostLang = &hostLangCSharp;
112                 outStream = csharpOpenOutput( sourceFileName );
113         }
114         else {
115                 assert( false );
116         }
117 }
118
119 void XmlParser::open_ragel_def( char *fsmName )
120 {
121         CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
122         if ( mapEl != 0 )
123                 cgd = mapEl->value;
124         else {
125                 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
126                 codeGenMap.insert( fsmName, cgd );
127         }
128 }
129
130 %%{
131
132 parser XmlParser;
133
134 include "xmlparse.kh";
135
136 start: tag_ragel;
137 start:
138         final {
139                 /* If we get no input the assumption is that the frontend died and
140                  * emitted an error. This forces the backend to return a non-zero
141                  * exit status, but does not print an error. */
142                 gblErrorCount += 1;
143         };
144
145 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
146
147 tag_ragel_head: TAG_ragel
148         final {
149                 /* Check version used to generated the intermediate file. */
150                 Attribute *versionAttr = $1->tag->findAttr( "version" );
151                 if ( versionAttr == 0 )
152                         error($1->loc) << "tag <ragel> requires a version attribute" << endp;
153                 if ( strcmp( versionAttr->value, VERSION ) != 0 )
154                         error($1->loc) << "version mismatch between frontend and backend" << endp;
155
156                 /* Check for file name attribute. */
157                 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
158                 if ( fileNameAttr == 0 )
159                         error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
160                 sourceFileName = fileNameAttr->value;
161
162                 /* Check for language attribute. */
163                 Attribute *langAttr = $1->tag->findAttr( "lang" );
164                 if ( langAttr == 0 )
165                         error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
166
167                 if ( generateDot )
168                         outStream = dotOpenOutput( sourceFileName );
169                 else if ( strcmp( langAttr->value, "C" ) == 0 ) {
170                         hostLang = &hostLangC;
171                         outStream = cdOpenOutput( sourceFileName );
172                 }
173                 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
174                         hostLang = &hostLangD;
175                         outStream = cdOpenOutput( sourceFileName );
176                 }
177                 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
178                         hostLang = &hostLangJava;
179                         outStream = javaOpenOutput( sourceFileName );
180                 }
181                 else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) {
182                         hostLang = &hostLangRuby;
183                         outStream = rubyOpenOutput( sourceFileName );
184                 }
185                 else if ( strcmp( langAttr->value, "C#" ) == 0 ) {
186                         hostLang = &hostLangCSharp;
187                         outStream = csharpOpenOutput( sourceFileName );
188                 }
189                 else {
190                         error($1->loc) << "expecting lang attribute to be "
191                                         "one of C, D, Java, Ruby or C#" << endp;
192                 }
193         };
194
195 ragel_def_list: ragel_def_list ragel_def;
196 ragel_def_list: ;
197
198 host_or_write_list: host_or_write_list host_or_write;
199 host_or_write_list: ;
200
201 host_or_write: tag_host;
202 host_or_write: tag_write;
203
204 tag_host: 
205         TAG_host '/' TAG_host
206         final {
207                 Attribute *lineAttr = $1->tag->findAttr( "line" );
208                 if ( lineAttr == 0 )
209                         error($1->loc) << "tag <host> requires a line attribute" << endp;
210                 else {
211                         int line = atoi( lineAttr->value );
212                         if ( outputActive )
213                                 lineDirective( *outStream, sourceFileName, line );
214                 }
215
216                 if ( outputActive )
217                         *outStream << $3->tag->content;
218         };
219
220 ragel_def: 
221         tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def
222         final {
223                 /* Do this before distributing transitions out to singles and defaults
224                  * makes life easier. */
225                 cgd->redFsm->maxKey = cgd->findMaxKey();
226
227                 cgd->redFsm->assignActionLocs();
228
229                 /* Find the first final state (The final state with the lowest id). */
230                 cgd->redFsm->findFirstFinState();
231
232                 /* Call the user's callback. */
233                 cgd->finishRagelDef();
234         };
235
236 tag_ragel_def_head: TAG_ragel_def 
237         final {
238                 char *fsmName = 0;
239                 Attribute *nameAttr = $1->tag->findAttr( "name" );
240                 if ( nameAttr != 0 ) {
241                         fsmName = nameAttr->value;
242
243                         CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
244                         if ( mapEl != 0 )
245                                 cgd = mapEl->value;
246                         else {
247                                 cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete );
248                                 codeGenMap.insert( fsmName, cgd );
249                         }
250                 }
251                 else {
252                         cgd = makeCodeGen( sourceFileName, fsmName, 
253                                         *outStream, wantComplete );
254                 }
255
256                 ::keyOps = &cgd->thisKeyOps;
257         };
258
259 ragel_def_item_list: ragel_def_item_list ragel_def_item;
260 ragel_def_item_list: ;
261
262 ragel_def_item: tag_alph_type;
263 ragel_def_item: tag_getkey_expr;
264 ragel_def_item: tag_access_expr;
265 ragel_def_item: tag_prepush_expr;
266 ragel_def_item: tag_postpop_expr;
267 ragel_def_item: tag_export_list;
268 ragel_def_item: tag_machine;
269 ragel_def_item: tag_p_expr;
270 ragel_def_item: tag_pe_expr;
271 ragel_def_item: tag_eof_expr;
272 ragel_def_item: tag_cs_expr;
273 ragel_def_item: tag_top_expr;
274 ragel_def_item: tag_stack_expr;
275 ragel_def_item: tag_act_expr;
276 ragel_def_item: tag_tokstart_expr;
277 ragel_def_item: tag_tokend_expr;
278 ragel_def_item: tag_data_expr;
279
280 tag_export_list: TAG_exports export_list '/' TAG_exports;
281
282 export_list: export_list tag_export;
283 export_list: ;
284
285 tag_export: TAG_ex '/' TAG_ex
286         final {
287                 Attribute *nameAttr = $1->tag->findAttr( "name" );
288                 if ( nameAttr == 0 )
289                         error($1->loc) << "tag <ex> requires a name attribute" << endp;
290                 else {
291                         char *td = $3->tag->content;
292                         Key exportKey = readKey( td, &td );
293                         cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
294                 }
295         };
296
297 tag_alph_type: TAG_alphtype '/' TAG_alphtype
298         final {
299                 if ( ! cgd->setAlphType( $3->tag->content ) )
300                         error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
301         };
302
303 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
304         final {
305                 cgd->getKeyExpr = $2->inlineList;
306         };
307
308 tag_access_expr: TAG_access inline_list '/' TAG_access
309         final {
310                 cgd->accessExpr = $2->inlineList;
311         };
312
313 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
314         final {
315                 cgd->prePushExpr = $2->inlineList;
316         };
317
318 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
319         final {
320                 cgd->postPopExpr = $2->inlineList;
321         };
322
323 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
324         final { cgd->pExpr = $2->inlineList; };
325 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
326         final { cgd->peExpr = $2->inlineList; };
327 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
328         final { cgd->eofExpr = $2->inlineList; };
329 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
330         final { cgd->csExpr = $2->inlineList; };
331 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
332         final { cgd->topExpr = $2->inlineList; };
333 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
334         final { cgd->stackExpr = $2->inlineList; };
335 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
336         final { cgd->actExpr = $2->inlineList; };
337 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
338         final { cgd->tokstartExpr = $2->inlineList; };
339 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
340         final { cgd->tokendExpr = $2->inlineList; };
341 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
342         final { cgd->dataExpr = $2->inlineList; };
343
344
345 tag_write: tag_write_head write_option_list '/' TAG_write
346         final {
347                 /* Terminate the options list and call the write statement handler. */
348                 writeOptions.append(0);
349                 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
350
351                 /* Clear the options in prep for the next write statement. */
352                 writeOptions.empty();
353         };
354
355 nonterm tag_write_head
356 {
357         GenInputLoc loc;
358 };
359
360 tag_write_head: TAG_write
361         final {
362                 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
363                 Attribute *lineAttr = $1->tag->findAttr( "line" );
364                 Attribute *colAttr = $1->tag->findAttr( "col" );
365
366                 if ( nameAttr == 0 )
367                         error($1->loc) << "tag <write> requires a def_name attribute" << endp;
368                 if ( lineAttr == 0 )
369                         error($1->loc) << "tag <write> requires a line attribute" << endp;
370                 if ( colAttr == 0 )
371                         error($1->loc) << "tag <write> requires a col attribute" << endp;
372
373                 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
374                         $$->loc.line = atoi(lineAttr->value);
375                         $$->loc.col = atoi(colAttr->value);
376
377                         CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
378                         if ( mapEl == 0 ) {
379                                 source_error($$->loc) << "write statement given "
380                                                 "but there are no machine instantiations" << endp;
381                         }
382                         else {
383                                 cgd = mapEl->value;
384                                 ::keyOps = &cgd->thisKeyOps;
385                         }
386                 }
387         };
388
389
390 write_option_list: write_option_list tag_arg;
391 write_option_list: ;
392
393 nonterm tag_arg
394 {
395         char *option;
396 };
397
398 tag_arg: TAG_arg '/' TAG_arg
399         final {
400                 writeOptions.append( $3->tag->content );
401         };
402
403 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
404         final {
405                 cgd->closeMachine();
406         };
407
408 tag_machine_head: TAG_machine
409         final {
410                 cgd->createMachine();
411         };
412
413 machine_item_list: machine_item_list machine_item;
414 machine_item_list: ;
415
416 machine_item: tag_start_state;
417 machine_item: tag_error_state;
418 machine_item: tag_entry_points;
419 machine_item: tag_state_list;
420 machine_item: tag_action_list;
421 machine_item: tag_action_table_list;
422 machine_item: tag_cond_space_list;
423
424 #
425 # States.
426 #
427
428 tag_start_state: TAG_start_state '/' TAG_start_state
429         final {
430                 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
431                 cgd->setStartState( startState );
432         };
433
434 tag_error_state: TAG_error_state '/' TAG_error_state
435         final {
436                 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
437                 cgd->setErrorState( errorState );
438         };
439
440 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
441         final {
442                 Attribute *errorAttr = $1->tag->findAttr( "error" );
443                 if ( errorAttr != 0 )
444                         cgd->setForcedErrorState();
445         };
446
447 entry_point_list: entry_point_list tag_entry;
448 entry_point_list: ;
449
450 tag_entry: TAG_entry '/' TAG_entry
451         final {
452                 Attribute *nameAttr = $1->tag->findAttr( "name" );
453                 if ( nameAttr == 0 ) {
454                         error($1->loc) << "tag <entry_points>::<entry> "
455                                         "requires a name attribute" << endp;
456                 }
457                 else {
458                         char *data = $3->tag->content;
459                         unsigned long entry = strtoul( data, &data, 10 );
460                         cgd->addEntryPoint( nameAttr->value, entry );
461                 }
462         };
463
464 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
465
466 tag_state_list_head: TAG_state_list
467         final {
468                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
469                 if ( lengthAttr == 0 )
470                         error($1->loc) << "tag <state_list> requires a length attribute" << endp;
471                 else {
472                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
473                         cgd->initStateList( length );
474                         curState = 0;
475                 }
476         };
477
478 state_list: state_list tag_state;
479 state_list: ;
480
481 tag_state: TAG_state state_item_list '/' TAG_state
482         final {
483                 Attribute *idAttr = $1->tag->findAttr( "id" );
484                 if ( idAttr == 0 )
485                         error($1->loc) << "tag <state> requires an id attribute" << endp;
486                 else {
487                         int id = atoi( idAttr->value );
488                         cgd->setId( curState, id );
489                 }
490
491                 Attribute *lengthAttr = $1->tag->findAttr( "final" );
492                 if ( lengthAttr != 0 )
493                         cgd->setFinal( curState );
494                 curState += 1;
495         };
496
497 state_item_list: state_item_list state_item;
498 state_item_list: ;
499
500 state_item: tag_state_actions;
501 state_item: tag_eof_t;
502 state_item: tag_state_cond_list;
503 state_item: tag_trans_list;
504
505 tag_state_actions: TAG_state_actions '/' TAG_state_actions
506         final {
507                 char *ad = $3->tag->content;
508
509                 long toStateAction = readOffsetPtr( ad, &ad );
510                 long fromStateAction = readOffsetPtr( ad, &ad );
511                 long eofAction = readOffsetPtr( ad, &ad );
512
513                 cgd->setStateActions( curState, toStateAction,
514                                 fromStateAction, eofAction );
515         };
516
517 tag_eof_t: TAG_eof_t '/' TAG_eof_t
518         final {
519                 char *et = $3->tag->content;
520                 long targ = readOffsetPtr( et, &et );
521                 long eofAction = readOffsetPtr( et, &et );
522
523                 cgd->setEofTrans( curState, targ, eofAction );
524         };
525
526 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
527
528 tag_state_cond_list_head: TAG_cond_list
529         final {
530                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
531                 if ( lengthAttr == 0 )
532                         error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
533                 else {
534                         ulong length = readLength( lengthAttr->value );
535                         cgd->initStateCondList( curState, length );
536                         curStateCond = 0;
537                 }
538         };
539
540 state_cond_list: state_cond_list state_cond;
541 state_cond_list: ;
542
543 state_cond: TAG_c '/' TAG_c
544         final {
545                 char *td = $3->tag->content;
546                 Key lowKey = readKey( td, &td );
547                 Key highKey = readKey( td, &td );
548                 long condId = readOffsetPtr( td, &td );
549                 cgd->addStateCond( curState, lowKey, highKey, condId );
550         };
551
552 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
553         final {
554                 cgd->finishTransList( curState );
555         };
556
557 tag_trans_list_head: TAG_trans_list
558         final {
559                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
560                 if ( lengthAttr == 0 )
561                         error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
562                 else {
563                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
564                         cgd->initTransList( curState, length );
565                         curTrans = 0;
566                 }
567         };
568
569 trans_list: trans_list tag_trans;
570 trans_list: ;
571
572 tag_trans: TAG_t '/' TAG_t
573         final {
574                 char *td = $3->tag->content;
575                 Key lowKey = readKey( td, &td );
576                 Key highKey = readKey( td, &td );
577                 long targ = readOffsetPtr( td, &td );
578                 long action = readOffsetPtr( td, &td );
579
580                 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
581         };
582
583 #
584 # Action Lists.
585 #
586
587 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
588
589 tag_action_list_head: TAG_action_list
590         final {
591                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
592                 if ( lengthAttr == 0 )
593                         error($1->loc) << "tag <action_list> requires a length attribute" << endp;
594                 else {
595                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
596                         cgd->initActionList( length );
597                         curAction = 0;
598                 }
599         };
600
601 action_list: action_list tag_action;
602 action_list: ;
603
604 #
605 # Actions.
606 #
607
608 tag_action: TAG_action inline_list '/' TAG_action
609         final {
610                 Attribute *lineAttr = $1->tag->findAttr( "line" );
611                 Attribute *colAttr = $1->tag->findAttr( "col" );
612                 Attribute *nameAttr = $1->tag->findAttr( "name" );
613                 if ( lineAttr == 0 || colAttr == 0)
614                         error($1->loc) << "tag <action> requires a line and col attributes" << endp;
615                 else {
616                         unsigned long line = strtoul( lineAttr->value, 0, 10 );
617                         unsigned long col = strtoul( colAttr->value, 0, 10 );
618
619                         char *name = 0;
620                         if ( nameAttr != 0 )
621                                 name = nameAttr->value;
622
623                         cgd->newAction( curAction++, name, line, col, $2->inlineList );
624                 }
625         };
626
627 nonterm inline_list
628 {
629         GenInlineList *inlineList;
630 };
631
632
633 inline_list: inline_list inline_item
634         final {
635                 /* Append the item to the list, return the list. */
636                 $1->inlineList->append( $2->inlineItem );
637                 $$->inlineList = $1->inlineList;
638         };
639
640 inline_list: 
641         final {
642                 /* Start with empty list. */
643                 $$->inlineList = new GenInlineList;
644         };
645
646 nonterm inline_item_type
647 {
648         GenInlineItem *inlineItem;
649 };
650
651 nonterm inline_item uses inline_item_type;
652
653 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
654 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
655 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
656 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
657 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
658 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
659 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
660 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
661 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
662 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
663 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
664 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
665 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
666 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
667 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
668 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
669 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
670 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
671 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
672 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
673 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
674 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
675 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
676 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
677
678 nonterm tag_text uses inline_item_type;
679 nonterm tag_goto uses inline_item_type;
680 nonterm tag_call uses inline_item_type;
681 nonterm tag_next uses inline_item_type;
682 nonterm tag_goto_expr uses inline_item_type;
683 nonterm tag_call_expr uses inline_item_type;
684 nonterm tag_next_expr uses inline_item_type;
685 nonterm tag_ret uses inline_item_type;
686 nonterm tag_break uses inline_item_type;
687 nonterm tag_pchar uses inline_item_type;
688 nonterm tag_char uses inline_item_type;
689 nonterm tag_hold uses inline_item_type;
690 nonterm tag_exec uses inline_item_type;
691 nonterm tag_curs uses inline_item_type;
692 nonterm tag_targs uses inline_item_type;
693 nonterm tag_il_entry uses inline_item_type;
694 nonterm tag_init_tokstart uses inline_item_type;
695 nonterm tag_init_act uses inline_item_type;
696 nonterm tag_get_tokend uses inline_item_type;
697 nonterm tag_set_tokstart uses inline_item_type;
698 nonterm tag_set_tokend uses inline_item_type;
699 nonterm tag_set_act uses inline_item_type;
700 nonterm tag_sub_action uses inline_item_type;
701 nonterm tag_lm_switch uses inline_item_type;
702
703 tag_text: TAG_text '/' TAG_text
704         final {
705                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Text );
706                 $$->inlineItem->data = $3->tag->content;
707         };
708
709 tag_goto: TAG_goto '/' TAG_goto
710         final {
711                 int targ = strtol( $3->tag->content, 0, 10 );
712                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Goto );
713                 $$->inlineItem->targId = targ;
714         };
715
716 tag_call: TAG_call '/' TAG_call
717         final {
718                 int targ = strtol( $3->tag->content, 0, 10 );
719                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Call );
720                 $$->inlineItem->targId = targ;
721         };
722
723 tag_next: TAG_next '/' TAG_next
724         final {
725                 int targ = strtol( $3->tag->content, 0, 10 );
726                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Next );
727                 $$->inlineItem->targId = targ;
728         };
729
730 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
731         final {
732                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::GotoExpr );
733                 $$->inlineItem->children = $2->inlineList;
734         };
735
736 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
737         final {
738                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::CallExpr );
739                 $$->inlineItem->children = $2->inlineList;
740         };
741
742 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
743         final {
744                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::NextExpr );
745                 $$->inlineItem->children = $2->inlineList;
746         };
747
748 tag_ret: TAG_ret '/' TAG_ret
749         final {
750                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Ret );
751         };
752
753 tag_break: TAG_break '/' TAG_break
754         final {
755                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Break );
756         };
757
758 tag_pchar: TAG_pchar '/' TAG_pchar
759         final {
760                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::PChar );
761         };
762
763 tag_char: TAG_char '/' TAG_char
764         final {
765                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Char );
766         };
767
768 tag_hold: TAG_hold '/' TAG_hold
769         final {
770                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Hold );
771         };
772
773 tag_exec: TAG_exec inline_list '/' TAG_exec
774         final {
775                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Exec );
776                 $$->inlineItem->children = $2->inlineList;
777         };
778
779 tag_curs: TAG_curs '/' TAG_curs
780         final {
781                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Curs );
782         };
783
784 tag_targs: TAG_targs '/' TAG_targs
785         final {
786                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Targs );
787         };
788
789 tag_il_entry: TAG_entry '/' TAG_entry
790         final {
791                 int targ = strtol( $3->tag->content, 0, 10 );
792                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Entry );
793                 $$->inlineItem->targId = targ;
794         };
795
796 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
797         final {
798                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitTokStart );
799         };
800
801 tag_init_act: TAG_init_act '/' TAG_init_act
802         final {
803                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitAct );
804         };
805
806 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
807         final {
808                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmGetTokEnd );
809         };
810
811 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
812         final {
813                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokStart );
814                 cgd->hasLongestMatch = true;
815         };
816
817 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
818         final {
819                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokEnd );
820                 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
821         };
822
823 tag_set_act: TAG_set_act '/' TAG_set_act
824         final {
825                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetActId );
826                 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
827         };
828
829 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
830         final {
831                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::SubAction );
832                 $$->inlineItem->children = $2->inlineList;
833         };
834
835 # Action switches.
836 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
837         final {
838                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSwitch );
839                 $$->inlineItem->children = $2->inlineList;
840         };
841
842 nonterm lm_action_list
843 {
844         GenInlineList *inlineList;
845 };
846
847 lm_action_list: lm_action_list tag_inline_action
848         final {
849                 $$->inlineList = $1->inlineList;
850                 $$->inlineList->append( $2->inlineItem );
851         };
852 lm_action_list:
853         final {
854                 $$->inlineList = new GenInlineList;
855         };
856
857 nonterm tag_inline_action uses inline_item_type;
858
859 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
860         final {
861                 $$->inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::SubAction );
862                 $$->inlineItem->children = $2->inlineList;
863
864                 Attribute *idAttr = $1->tag->findAttr( "id" );
865                 if ( idAttr != 0 ) {
866                         unsigned long id = strtoul( idAttr->value, 0, 10 );
867                         $$->inlineItem->lmId = id;
868                 }
869         };
870
871 #
872 # Lists of Actions.
873 #
874
875 tag_action_table_list: 
876         tag_action_table_list_head action_table_list '/' TAG_action_table_list;
877
878 tag_action_table_list_head: TAG_action_table_list
879         final {
880                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
881                 if ( lengthAttr == 0 ) {
882                         error($1->loc) << "tag <action_table_list> requires "
883                                         "a length attribute" << endp;
884                 }
885                 else {
886                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
887                         cgd->initActionTableList( length );
888                         curActionTable = 0;
889                 }
890         };
891
892 action_table_list: action_table_list tag_action_table;
893 action_table_list: ;
894
895 tag_action_table: TAG_action_table '/' TAG_action_table
896         final {
897                 /* Find the length of the action table. */
898                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
899                 if ( lengthAttr == 0 )
900                         error($1->loc) << "tag <at> requires a length attribute" << endp;
901                 else {
902                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
903
904                         /* Collect the action table. */
905                         RedAction *redAct = cgd->allActionTables + curActionTable;
906                         redAct->actListId = curActionTable;
907                         redAct->key.setAsNew( length );
908                         char *ptr = $3->tag->content;
909                         int pos = 0;
910                         while ( *ptr != 0 ) {
911                                 unsigned long actionId = strtoul( ptr, &ptr, 10 );
912                                 redAct->key[pos].key = 0;
913                                 redAct->key[pos].value = cgd->allActions+actionId;
914                                 pos += 1;
915                         }
916
917                         /* Insert into the action table map. */
918                         cgd->redFsm->actionMap.insert( redAct );
919                 }
920
921                 curActionTable += 1;
922         };
923
924 #
925 # Conditions.
926 #
927
928 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
929
930 tag_cond_space_list_head: TAG_cond_space_list
931         final {
932                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
933                 if ( lengthAttr == 0 ) {
934                         error($1->loc) << "tag <cond_space_list> "
935                                         "requires a length attribute" << endp;
936                 }
937                 else {
938                         ulong length = readLength( lengthAttr->value );
939                         cgd->initCondSpaceList( length );
940                         curCondSpace = 0;
941                 }
942         };
943
944 cond_space_list: cond_space_list tag_cond_space;
945 cond_space_list: tag_cond_space;
946
947 tag_cond_space: TAG_cond_space '/' TAG_cond_space
948         final {
949                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
950                 Attribute *idAttr = $1->tag->findAttr( "id" );
951                 if ( lengthAttr == 0 )
952                         error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
953                 else {
954                         if ( lengthAttr == 0 )
955                                 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
956                         else {
957                                 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
958                                 ulong length = readLength( lengthAttr->value );
959
960                                 char *td = $3->tag->content;
961                                 Key baseKey = readKey( td, &td );
962
963                                 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
964                                 for ( ulong a = 0; a < length; a++ ) {
965                                         long actionOffset = readOffsetPtr( td, &td );
966                                         cgd->condSpaceItem( curCondSpace, actionOffset );
967                                 }
968                                 curCondSpace += 1;
969                         }
970                 }
971         };
972
973 }%%
974
975 %%{
976         write types;
977         write data;
978 }%%
979
980 void XmlParser::init()
981 {
982         %% write init;
983 }
984
985 int XmlParser::parseLangEl( int type, const Token *token )
986 {
987         %% write exec;
988         return errCount == 0 ? 0 : -1;
989 }
990
991
992 unsigned long readLength( char *td )
993 {
994         return strtoul( td, 0, 10 );
995 }
996
997 Key readKey( char *td, char **end )
998 {
999         if ( keyOps->isSigned )
1000                 return Key( strtol( td, end, 10 ) );
1001         else
1002                 return Key( strtoul( td, end, 10 ) );
1003 }
1004
1005 long readOffsetPtr( char *td, char **end )
1006 {
1007         while ( *td == ' ' || *td == '\t' )
1008                 td++;
1009
1010         if ( *td == 'x' ) {
1011                 if ( end != 0 )
1012                         *end = td + 1;
1013                 return -1;
1014         }
1015
1016         return strtol( td, end, 10 );
1017 }
1018
1019 ostream &XmlParser::warning( const GenInputLoc &loc )
1020 {
1021         cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1022         return cerr;
1023 }
1024
1025 ostream &XmlParser::error( const GenInputLoc &loc )
1026 {
1027         gblErrorCount += 1;
1028         assert( fileName != 0 );
1029         cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
1030         return cerr;
1031 }
1032
1033
1034 ostream &XmlParser::parser_error( int tokId, Token &token )
1035 {
1036         gblErrorCount += 1;
1037         assert( fileName != 0 );
1038         cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
1039         if ( token.tag != 0 ) {
1040                 if ( token.tag->tagId == 0 )
1041                         cerr << ": at unknown tag";
1042                 else
1043                         cerr << ": at tag <" << token.tag->tagId->name << ">";
1044         }
1045         cerr << ": ";
1046         
1047         return cerr;
1048 }
1049
1050 ostream &XmlParser::source_error( const GenInputLoc &loc )
1051 {
1052         gblErrorCount += 1;
1053         assert( sourceFileName != 0 );
1054         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1055         return cerr;
1056 }
1057
1058
1059 int XmlParser::token( int tokenId, Token &tok )
1060 {
1061         int res = parseLangEl( tokenId, &tok );
1062         if ( res < 0 )
1063                 parser_error( tokenId, tok ) << "parse error" << endp;
1064         return res;
1065 }
1066
1067 int XmlParser::token( int tokenId, int col, int line )
1068 {
1069         Token tok;
1070         tok.loc.col = col;
1071         tok.loc.line = line;
1072         tok.tag = 0;
1073         return token( tokenId, tok );
1074 }
1075
1076 int XmlParser::token( XMLTag *tag, int col, int line )
1077 {
1078         Token tok;
1079         tok.loc.col = col;
1080         tok.loc.line = line;
1081         tok.tag = tag;
1082         
1083         if ( tag->type == XMLTag::Close ) {
1084                 int res = token( '/', tok );
1085                 if ( res < 0 )
1086                         return res;
1087         }
1088
1089         tok.tag = tag;
1090         return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );
1091 }