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