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