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