C# patch Daniel Tang.
[ragel.git] / redfsm / xmlparse.kl
blob424bbd268a887f724fd19330b7863862d9498895
1 /*
2  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
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  */
22 #include "xmlparse.h"
23 #include "common.h"
24 #include "gendata.h"
25 #include "version.h"
26 #include <iostream>
27 #include <stdlib.h>
29 using std::cout;
30 using std::ostream;
31 using std::istream;
32 using std::cerr;
33 using std::endl;
35 Key readKey( char *td, char **end );
36 long readOffsetPtr( char *td, char **end );
37 unsigned long readLength( char *td );
39 %%{
41 parser Parser;
43 include "xmlparse.kh";
45 start: tag_ragel;
46 start:
47         final {
48                 /* If we get no input the assumption is that the frontend died and
49                  * emitted an error. This forces the backend to return a non-zero
50                  * exit status, but does not print an error. */
51                 gblErrorCount += 1;
52         };
54 tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel;
56 tag_ragel_head: TAG_ragel
57         final {
58                 /* Check version used to generated the intermediate file. */
59                 Attribute *versionAttr = $1->tag->findAttr( "version" );
60                 if ( versionAttr == 0 )
61                         error($1->loc) << "tag <ragel> requires a version attribute" << endp;
62                 if ( strcmp( versionAttr->value, VERSION ) != 0 )
63                         error($1->loc) << "version mismatch between frontend and backend" << endp;
65                 /* Check for file name attribute. */
66                 Attribute *fileNameAttr = $1->tag->findAttr( "filename" );
67                 if ( fileNameAttr == 0 )
68                         error($1->loc) << "tag <ragel> requires a filename attribute" << endp;
69                 sourceFileName = fileNameAttr->value;
71                 /* Check for language attribute. */
72                 Attribute *langAttr = $1->tag->findAttr( "lang" );
73                 if ( langAttr == 0 )
74                         error($1->loc) << "tag <ragel> requires a lang attribute" << endp;
76                 if ( strcmp( langAttr->value, "C" ) == 0 )
77                         hostLang = &hostLangC;
78                 else if ( strcmp( langAttr->value, "D" ) == 0 )
79                         hostLang = &hostLangD;
80                 else if ( strcmp( langAttr->value, "Java" ) == 0 )
81                         hostLang = &hostLangJava;
82                 else if ( strcmp( langAttr->value, "Ruby" ) == 0 )
83                         hostLang = &hostLangRuby;
84                 else if ( strcmp( langAttr->value, "C#" ) == 0 )
85                         hostLang = &hostLangCSharp;
86                 else {
87                         error($1->loc) << "expecting lang attribute to be "
88                                         "one of C, D, Java, Ruby or C#" << endp;
89                 }
91                 outStream = openOutput( sourceFileName );
92         };
94 ragel_def_list: ragel_def_list ragel_def;
95 ragel_def_list: ;
97 host_or_write_list: host_or_write_list host_or_write;
98 host_or_write_list: ;
100 host_or_write: tag_host;
101 host_or_write: tag_write;
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" << endp;
109                 else {
110                         int line = atoi( lineAttr->value );
111                         if ( outputActive )
112                                 lineDirective( *outStream, sourceFileName, line );
113                 }
115                 if ( outputActive )
116                         *outStream << $3->tag->content;
117         };
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();
126                 cgd->redFsm->assignActionLocs();
128                 /* Find the first final state (The final state with the lowest id). */
129                 cgd->redFsm->findFirstFinState();
131                 /* Call the user's callback. */
132                 cgd->finishRagelDef();
133         };
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;
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                 }
155                 ::keyOps = &cgd->thisKeyOps;
156         };
158 ragel_def_item_list: ragel_def_item_list ragel_def_item;
159 ragel_def_item_list: ;
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_prepush_expr;
165 ragel_def_item: tag_postpop_expr;
166 ragel_def_item: tag_export_list;
167 ragel_def_item: tag_machine;
168 ragel_def_item: tag_p_expr;
169 ragel_def_item: tag_pe_expr;
170 ragel_def_item: tag_eof_expr;
171 ragel_def_item: tag_cs_expr;
172 ragel_def_item: tag_top_expr;
173 ragel_def_item: tag_stack_expr;
174 ragel_def_item: tag_act_expr;
175 ragel_def_item: tag_tokstart_expr;
176 ragel_def_item: tag_tokend_expr;
177 ragel_def_item: tag_data_expr;
179 tag_export_list: TAG_exports export_list '/' TAG_exports;
181 export_list: export_list tag_export;
182 export_list: ;
184 tag_export: TAG_ex '/' TAG_ex
185         final {
186                 Attribute *nameAttr = $1->tag->findAttr( "name" );
187                 if ( nameAttr == 0 )
188                         error($1->loc) << "tag <ex> requires a name attribute" << endp;
189                 else {
190                         char *td = $3->tag->content;
191                         Key exportKey = readKey( td, &td );
192                         cgd->exportList.append( new Export( nameAttr->value, exportKey ) );
193                 }
194         };
196 tag_alph_type: TAG_alphtype '/' TAG_alphtype
197         final {
198                 if ( ! cgd->setAlphType( $3->tag->content ) )
199                         error($1->loc) << "tag <alphtype> specifies unknown alphabet type" << endp;
200         };
202 tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey
203         final {
204                 cgd->getKeyExpr = $2->inlineList;
205         };
207 tag_access_expr: TAG_access inline_list '/' TAG_access
208         final {
209                 cgd->accessExpr = $2->inlineList;
210         };
212 tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
213         final {
214                 cgd->prePushExpr = $2->inlineList;
215         };
217 tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
218         final {
219                 cgd->postPopExpr = $2->inlineList;
220         };
222 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
223         final { cgd->pExpr = $2->inlineList; };
224 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
225         final { cgd->peExpr = $2->inlineList; };
226 tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr
227         final { cgd->eofExpr = $2->inlineList; };
228 tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr
229         final { cgd->csExpr = $2->inlineList; };
230 tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr
231         final { cgd->topExpr = $2->inlineList; };
232 tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr
233         final { cgd->stackExpr = $2->inlineList; };
234 tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr
235         final { cgd->actExpr = $2->inlineList; };
236 tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr
237         final { cgd->tokstartExpr = $2->inlineList; };
238 tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr
239         final { cgd->tokendExpr = $2->inlineList; };
240 tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr
241         final { cgd->dataExpr = $2->inlineList; };
244 tag_write: tag_write_head write_option_list '/' TAG_write
245         final {
246                 /* Terminate the options list and call the write statement handler. */
247                 writeOptions.append(0);
248                 cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data );
250                 /* Clear the options in prep for the next write statement. */
251                 writeOptions.empty();
252         };
254 nonterm tag_write_head
256         InputLoc loc;
259 tag_write_head: TAG_write
260         final {
261                 Attribute *nameAttr = $1->tag->findAttr( "def_name" );
262                 Attribute *lineAttr = $1->tag->findAttr( "line" );
263                 Attribute *colAttr = $1->tag->findAttr( "col" );
265                 if ( nameAttr == 0 )
266                         error($1->loc) << "tag <write> requires a def_name attribute" << endp;
267                 if ( lineAttr == 0 )
268                         error($1->loc) << "tag <write> requires a line attribute" << endp;
269                 if ( colAttr == 0 )
270                         error($1->loc) << "tag <write> requires a col attribute" << endp;
272                 if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) {
273                         $$->loc.line = atoi(lineAttr->value);
274                         $$->loc.col = atoi(colAttr->value);
276                         CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value );
277                         if ( mapEl == 0 ) {
278                                 source_error($$->loc) << "write statement given "
279                                                 "but there are no machine instantiations" << endp;
280                         }
281                         else {
282                                 cgd = mapEl->value;
283                                 ::keyOps = &cgd->thisKeyOps;
284                         }
285                 }
286         };
289 write_option_list: write_option_list tag_arg;
290 write_option_list: ;
292 nonterm tag_arg
294         char *option;
297 tag_arg: TAG_arg '/' TAG_arg
298         final {
299                 writeOptions.append( $3->tag->content );
300         };
302 tag_machine: tag_machine_head machine_item_list '/' TAG_machine
303         final {
304                 cgd->closeMachine();
305         };
307 tag_machine_head: TAG_machine
308         final {
309                 cgd->createMachine();
310         };
312 machine_item_list: machine_item_list machine_item;
313 machine_item_list: ;
315 machine_item: tag_start_state;
316 machine_item: tag_error_state;
317 machine_item: tag_entry_points;
318 machine_item: tag_state_list;
319 machine_item: tag_action_list;
320 machine_item: tag_action_table_list;
321 machine_item: tag_cond_space_list;
324 # States.
327 tag_start_state: TAG_start_state '/' TAG_start_state
328         final {
329                 unsigned long startState = strtoul( $3->tag->content, 0, 10 );
330                 cgd->setStartState( startState );
331         };
333 tag_error_state: TAG_error_state '/' TAG_error_state
334         final {
335                 unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
336                 cgd->setErrorState( errorState );
337         };
339 tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
340         final {
341                 Attribute *errorAttr = $1->tag->findAttr( "error" );
342                 if ( errorAttr != 0 )
343                         cgd->setForcedErrorState();
344         };
346 entry_point_list: entry_point_list tag_entry;
347 entry_point_list: ;
349 tag_entry: TAG_entry '/' TAG_entry
350         final {
351                 Attribute *nameAttr = $1->tag->findAttr( "name" );
352                 if ( nameAttr == 0 ) {
353                         error($1->loc) << "tag <entry_points>::<entry> "
354                                         "requires a name attribute" << endp;
355                 }
356                 else {
357                         char *data = $3->tag->content;
358                         unsigned long entry = strtoul( data, &data, 10 );
359                         cgd->addEntryPoint( nameAttr->value, entry );
360                 }
361         };
363 tag_state_list: tag_state_list_head state_list '/' TAG_state_list;
365 tag_state_list_head: TAG_state_list
366         final {
367                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
368                 if ( lengthAttr == 0 )
369                         error($1->loc) << "tag <state_list> requires a length attribute" << endp;
370                 else {
371                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
372                         cgd->initStateList( length );
373                         curState = 0;
374                 }
375         };
377 state_list: state_list tag_state;
378 state_list: ;
380 tag_state: TAG_state state_item_list '/' TAG_state
381         final {
382                 Attribute *idAttr = $1->tag->findAttr( "id" );
383                 if ( idAttr == 0 )
384                         error($1->loc) << "tag <state> requires an id attribute" << endp;
385                 else {
386                         int id = atoi( idAttr->value );
387                         cgd->setId( curState, id );
388                 }
390                 Attribute *lengthAttr = $1->tag->findAttr( "final" );
391                 if ( lengthAttr != 0 )
392                         cgd->setFinal( curState );
393                 curState += 1;
394         };
396 state_item_list: state_item_list state_item;
397 state_item_list: ;
399 state_item: tag_state_actions;
400 state_item: tag_eof_t;
401 state_item: tag_state_cond_list;
402 state_item: tag_trans_list;
404 tag_state_actions: TAG_state_actions '/' TAG_state_actions
405         final {
406                 char *ad = $3->tag->content;
408                 long toStateAction = readOffsetPtr( ad, &ad );
409                 long fromStateAction = readOffsetPtr( ad, &ad );
410                 long eofAction = readOffsetPtr( ad, &ad );
412                 cgd->setStateActions( curState, toStateAction,
413                                 fromStateAction, eofAction );
414         };
416 tag_eof_t: TAG_eof_t '/' TAG_eof_t
417         final {
418                 char *et = $3->tag->content;
419                 long targ = readOffsetPtr( et, &et );
420                 long eofAction = readOffsetPtr( et, &et );
422                 cgd->setEofTrans( curState, targ, eofAction );
423         };
425 tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list;
427 tag_state_cond_list_head: TAG_cond_list
428         final {
429                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
430                 if ( lengthAttr == 0 )
431                         error($1->loc) << "tag <cond_list> requires a length attribute" << endp;
432                 else {
433                         ulong length = readLength( lengthAttr->value );
434                         cgd->initStateCondList( curState, length );
435                         curStateCond = 0;
436                 }
437         };
439 state_cond_list: state_cond_list state_cond;
440 state_cond_list: ;
442 state_cond: TAG_c '/' TAG_c
443         final {
444                 char *td = $3->tag->content;
445                 Key lowKey = readKey( td, &td );
446                 Key highKey = readKey( td, &td );
447                 long condId = readOffsetPtr( td, &td );
448                 cgd->addStateCond( curState, lowKey, highKey, condId );
449         };
451 tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list
452         final {
453                 cgd->finishTransList( curState );
454         };
456 tag_trans_list_head: TAG_trans_list
457         final {
458                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
459                 if ( lengthAttr == 0 )
460                         error($1->loc) << "tag <trans_list> requires a length attribute" << endp;
461                 else {
462                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
463                         cgd->initTransList( curState, length );
464                         curTrans = 0;
465                 }
466         };
468 trans_list: trans_list tag_trans;
469 trans_list: ;
471 tag_trans: TAG_t '/' TAG_t
472         final {
473                 char *td = $3->tag->content;
474                 Key lowKey = readKey( td, &td );
475                 Key highKey = readKey( td, &td );
476                 long targ = readOffsetPtr( td, &td );
477                 long action = readOffsetPtr( td, &td );
479                 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
480         };
483 # Action Lists.
486 tag_action_list: tag_action_list_head action_list '/' TAG_action_list;
488 tag_action_list_head: TAG_action_list
489         final {
490                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
491                 if ( lengthAttr == 0 )
492                         error($1->loc) << "tag <action_list> requires a length attribute" << endp;
493                 else {
494                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
495                         cgd->initActionList( length );
496                         curAction = 0;
497                 }
498         };
500 action_list: action_list tag_action;
501 action_list: ;
504 # Actions.
507 tag_action: TAG_action inline_list '/' TAG_action
508         final {
509                 Attribute *lineAttr = $1->tag->findAttr( "line" );
510                 Attribute *colAttr = $1->tag->findAttr( "col" );
511                 Attribute *nameAttr = $1->tag->findAttr( "name" );
512                 if ( lineAttr == 0 || colAttr == 0)
513                         error($1->loc) << "tag <action> requires a line and col attributes" << endp;
514                 else {
515                         unsigned long line = strtoul( lineAttr->value, 0, 10 );
516                         unsigned long col = strtoul( colAttr->value, 0, 10 );
518                         char *name = 0;
519                         if ( nameAttr != 0 )
520                                 name = nameAttr->value;
522                         cgd->newAction( curAction++, name, line, col, $2->inlineList );
523                 }
524         };
526 nonterm inline_list
528         InlineList *inlineList;
532 inline_list: inline_list inline_item
533         final {
534                 /* Append the item to the list, return the list. */
535                 $1->inlineList->append( $2->inlineItem );
536                 $$->inlineList = $1->inlineList;
537         };
539 inline_list: 
540         final {
541                 /* Start with empty list. */
542                 $$->inlineList = new InlineList;
543         };
545 nonterm inline_item_type
547         InlineItem *inlineItem;
550 nonterm inline_item uses inline_item_type;
552 inline_item: tag_text final { $$->inlineItem = $1->inlineItem; };
553 inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; };
554 inline_item: tag_call final { $$->inlineItem = $1->inlineItem; };
555 inline_item: tag_next final { $$->inlineItem = $1->inlineItem; };
556 inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; };
557 inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; };
558 inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; };
559 inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; };
560 inline_item: tag_break final { $$->inlineItem = $1->inlineItem; };
561 inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; };
562 inline_item: tag_char final { $$->inlineItem = $1->inlineItem; };
563 inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; };
564 inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; };
565 inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; };
566 inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; };
567 inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; };
568 inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; };
569 inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; };
570 inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; };
571 inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; };
572 inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; };
573 inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; };
574 inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; };
575 inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; };
577 nonterm tag_text uses inline_item_type;
578 nonterm tag_goto uses inline_item_type;
579 nonterm tag_call uses inline_item_type;
580 nonterm tag_next uses inline_item_type;
581 nonterm tag_goto_expr uses inline_item_type;
582 nonterm tag_call_expr uses inline_item_type;
583 nonterm tag_next_expr uses inline_item_type;
584 nonterm tag_ret uses inline_item_type;
585 nonterm tag_break uses inline_item_type;
586 nonterm tag_pchar uses inline_item_type;
587 nonterm tag_char uses inline_item_type;
588 nonterm tag_hold uses inline_item_type;
589 nonterm tag_exec uses inline_item_type;
590 nonterm tag_curs uses inline_item_type;
591 nonterm tag_targs uses inline_item_type;
592 nonterm tag_il_entry uses inline_item_type;
593 nonterm tag_init_tokstart uses inline_item_type;
594 nonterm tag_init_act uses inline_item_type;
595 nonterm tag_get_tokend uses inline_item_type;
596 nonterm tag_set_tokstart uses inline_item_type;
597 nonterm tag_set_tokend uses inline_item_type;
598 nonterm tag_set_act uses inline_item_type;
599 nonterm tag_sub_action uses inline_item_type;
600 nonterm tag_lm_switch uses inline_item_type;
602 tag_text: TAG_text '/' TAG_text
603         final {
604                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Text );
605                 $$->inlineItem->data = $3->tag->content;
606         };
608 tag_goto: TAG_goto '/' TAG_goto
609         final {
610                 int targ = strtol( $3->tag->content, 0, 10 );
611                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Goto );
612                 $$->inlineItem->targId = targ;
613         };
615 tag_call: TAG_call '/' TAG_call
616         final {
617                 int targ = strtol( $3->tag->content, 0, 10 );
618                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Call );
619                 $$->inlineItem->targId = targ;
620         };
622 tag_next: TAG_next '/' TAG_next
623         final {
624                 int targ = strtol( $3->tag->content, 0, 10 );
625                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Next );
626                 $$->inlineItem->targId = targ;
627         };
629 tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr
630         final {
631                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::GotoExpr );
632                 $$->inlineItem->children = $2->inlineList;
633         };
635 tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr
636         final {
637                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::CallExpr );
638                 $$->inlineItem->children = $2->inlineList;
639         };
641 tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr
642         final {
643                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::NextExpr );
644                 $$->inlineItem->children = $2->inlineList;
645         };
647 tag_ret: TAG_ret '/' TAG_ret
648         final {
649                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Ret );
650         };
652 tag_break: TAG_break '/' TAG_break
653         final {
654                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Break );
655         };
657 tag_pchar: TAG_pchar '/' TAG_pchar
658         final {
659                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::PChar );
660         };
662 tag_char: TAG_char '/' TAG_char
663         final {
664                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Char );
665         };
667 tag_hold: TAG_hold '/' TAG_hold
668         final {
669                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Hold );
670         };
672 tag_exec: TAG_exec inline_list '/' TAG_exec
673         final {
674                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Exec );
675                 $$->inlineItem->children = $2->inlineList;
676         };
678 tag_curs: TAG_curs '/' TAG_curs
679         final {
680                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Curs );
681         };
683 tag_targs: TAG_targs '/' TAG_targs
684         final {
685                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Targs );
686         };
688 tag_il_entry: TAG_entry '/' TAG_entry
689         final {
690                 int targ = strtol( $3->tag->content, 0, 10 );
691                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::Entry );
692                 $$->inlineItem->targId = targ;
693         };
695 tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart
696         final {
697                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
698         };
700 tag_init_act: TAG_init_act '/' TAG_init_act
701         final {
702                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmInitAct );
703         };
705 tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend
706         final {
707                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
708         };
710 tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart
711         final {
712                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
713                 cgd->hasLongestMatch = true;
714         };
716 tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend
717         final {
718                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
719                 $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 );
720         };
722 tag_set_act: TAG_set_act '/' TAG_set_act
723         final {
724                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSetActId );
725                 $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 );
726         };
728 tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action
729         final {
730                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
731                 $$->inlineItem->children = $2->inlineList;
732         };
734 # Action switches.
735 tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch
736         final {
737                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::LmSwitch );
738                 $$->inlineItem->children = $2->inlineList;
739         };
741 nonterm lm_action_list
743         InlineList *inlineList;
746 lm_action_list: lm_action_list tag_inline_action
747         final {
748                 $$->inlineList = $1->inlineList;
749                 $$->inlineList->append( $2->inlineItem );
750         };
751 lm_action_list:
752         final {
753                 $$->inlineList = new InlineList;
754         };
756 nonterm tag_inline_action uses inline_item_type;
758 tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action
759         final {
760                 $$->inlineItem = new InlineItem( InputLoc(), InlineItem::SubAction );
761                 $$->inlineItem->children = $2->inlineList;
763                 Attribute *idAttr = $1->tag->findAttr( "id" );
764                 if ( idAttr != 0 ) {
765                         unsigned long id = strtoul( idAttr->value, 0, 10 );
766                         $$->inlineItem->lmId = id;
767                 }
768         };
771 # Lists of Actions.
774 tag_action_table_list: 
775         tag_action_table_list_head action_table_list '/' TAG_action_table_list;
777 tag_action_table_list_head: TAG_action_table_list
778         final {
779                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
780                 if ( lengthAttr == 0 ) {
781                         error($1->loc) << "tag <action_table_list> requires "
782                                         "a length attribute" << endp;
783                 }
784                 else {
785                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
786                         cgd->initActionTableList( length );
787                         curActionTable = 0;
788                 }
789         };
791 action_table_list: action_table_list tag_action_table;
792 action_table_list: ;
794 tag_action_table: TAG_action_table '/' TAG_action_table
795         final {
796                 /* Find the length of the action table. */
797                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
798                 if ( lengthAttr == 0 )
799                         error($1->loc) << "tag <at> requires a length attribute" << endp;
800                 else {
801                         unsigned long length = strtoul( lengthAttr->value, 0, 10 );
803                         /* Collect the action table. */
804                         RedAction *redAct = cgd->allActionTables + curActionTable;
805                         redAct->actListId = curActionTable;
806                         redAct->key.setAsNew( length );
807                         char *ptr = $3->tag->content;
808                         int pos = 0;
809                         while ( *ptr != 0 ) {
810                                 unsigned long actionId = strtoul( ptr, &ptr, 10 );
811                                 redAct->key[pos].key = 0;
812                                 redAct->key[pos].value = cgd->allActions+actionId;
813                                 pos += 1;
814                         }
816                         /* Insert into the action table map. */
817                         cgd->redFsm->actionMap.insert( redAct );
818                 }
820                 curActionTable += 1;
821         };
824 # Conditions.
827 tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list;
829 tag_cond_space_list_head: TAG_cond_space_list
830         final {
831                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
832                 if ( lengthAttr == 0 ) {
833                         error($1->loc) << "tag <cond_space_list> "
834                                         "requires a length attribute" << endp;
835                 }
836                 else {
837                         ulong length = readLength( lengthAttr->value );
838                         cgd->initCondSpaceList( length );
839                         curCondSpace = 0;
840                 }
841         };
843 cond_space_list: cond_space_list tag_cond_space;
844 cond_space_list: tag_cond_space;
846 tag_cond_space: TAG_cond_space '/' TAG_cond_space
847         final {
848                 Attribute *lengthAttr = $1->tag->findAttr( "length" );
849                 Attribute *idAttr = $1->tag->findAttr( "id" );
850                 if ( lengthAttr == 0 )
851                         error($1->loc) << "tag <cond_space> requires a length attribute" << endp;
852                 else {
853                         if ( lengthAttr == 0 )
854                                 error($1->loc) << "tag <cond_space> requires an id attribute" << endp;
855                         else {
856                                 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
857                                 ulong length = readLength( lengthAttr->value );
859                                 char *td = $3->tag->content;
860                                 Key baseKey = readKey( td, &td );
862                                 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
863                                 for ( ulong a = 0; a < length; a++ ) {
864                                         long actionOffset = readOffsetPtr( td, &td );
865                                         cgd->condSpaceItem( curCondSpace, actionOffset );
866                                 }
867                                 curCondSpace += 1;
868                         }
869                 }
870         };
875         write types;
876         write data;
879 void Parser::init()
881         %% write init;
884 int Parser::parseLangEl( int type, const Token *token )
886         %% write exec;
887         return errCount == 0 ? 0 : -1;
891 unsigned long readLength( char *td )
893         return strtoul( td, 0, 10 );
896 Key readKey( char *td, char **end )
898         if ( keyOps->isSigned )
899                 return Key( strtol( td, end, 10 ) );
900         else
901                 return Key( strtoul( td, end, 10 ) );
904 long readOffsetPtr( char *td, char **end )
906         while ( *td == ' ' || *td == '\t' )
907                 td++;
909         if ( *td == 'x' ) {
910                 if ( end != 0 )
911                         *end = td + 1;
912                 return -1;
913         }
915         return strtol( td, end, 10 );
918 ostream &Parser::warning( const InputLoc &loc )
920         cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: ";
921         return cerr;
924 ostream &Parser::error( const InputLoc &loc )
926         gblErrorCount += 1;
927         assert( fileName != 0 );
928         cerr << fileName << ":" << loc.line << ":" << loc.col << ": ";
929         return cerr;
933 ostream &Parser::parser_error( int tokId, Token &token )
935         gblErrorCount += 1;
936         assert( fileName != 0 );
937         cerr << fileName << ":" << token.loc.line << ":" << token.loc.col;
938         if ( token.tag != 0 ) {
939                 if ( token.tag->tagId == 0 )
940                         cerr << ": at unknown tag";
941                 else
942                         cerr << ": at tag <" << token.tag->tagId->name << ">";
943         }
944         cerr << ": ";
945         
946         return cerr;
949 ostream &Parser::source_error( const InputLoc &loc )
951         gblErrorCount += 1;
952         assert( sourceFileName != 0 );
953         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
954         return cerr;
958 int Parser::token( int tokenId, Token &tok )
960         int res = parseLangEl( tokenId, &tok );
961         if ( res < 0 )
962                 parser_error( tokenId, tok ) << "parse error" << endp;
963         return res;
966 int Parser::token( int tokenId, int col, int line )
968         Token tok;
969         tok.loc.col = col;
970         tok.loc.line = line;
971         tok.tag = 0;
972         return token( tokenId, tok );
975 int Parser::token( XMLTag *tag, int col, int line )
977         Token tok;
978         tok.loc.col = col;
979         tok.loc.line = line;
980         tok.tag = tag;
981         
982         if ( tag->type == XMLTag::Close ) {
983                 int res = token( '/', tok );
984                 if ( res < 0 )
985                         return res;
986         }
988         tok.tag = tag;
989         return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok );