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