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