/* * Copyright 2001-2007 Adrian Thurston */ /* This file is part of Ragel. * * Ragel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Ragel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Ragel; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "xmlparse.h" #include "common.h" #include "gendata.h" #include "version.h" #include #include using std::cout; using std::ostream; using std::istream; using std::cerr; using std::endl; Key readKey( char *td, char **end ); long readOffsetPtr( char *td, char **end ); unsigned long readLength( char *td ); struct Token { XMLTag *tag; InputLoc loc; }; %%{ parser XmlParser; include "xmlparse.kh"; start: tag_ragel; start: final { /* If we get no input the assumption is that the frontend died and * emitted an error. This forces the backend to return a non-zero * exit status, but does not print an error. */ gblErrorCount += 1; }; tag_ragel: tag_ragel_head ragel_def_list host_or_write_list '/' TAG_ragel; tag_ragel_head: TAG_ragel final { /* Check version used to generated the intermediate file. */ Attribute *versionAttr = $1->tag->findAttr( "version" ); if ( versionAttr == 0 ) error($1->loc) << "tag requires a version attribute" << endp; if ( strcmp( versionAttr->value, VERSION ) != 0 ) error($1->loc) << "version mismatch between frontend and backend" << endp; /* Check for file name attribute. */ Attribute *fileNameAttr = $1->tag->findAttr( "filename" ); if ( fileNameAttr == 0 ) error($1->loc) << "tag requires a filename attribute" << endp; sourceFileName = fileNameAttr->value; /* Check for language attribute. */ Attribute *langAttr = $1->tag->findAttr( "lang" ); if ( langAttr == 0 ) error($1->loc) << "tag requires a lang attribute" << endp; if ( generateDot ) outStream = dotOpenOutput( sourceFileName ); else if ( strcmp( langAttr->value, "C" ) == 0 ) { hostLang = &hostLangC; outStream = cdOpenOutput( sourceFileName ); } else if ( strcmp( langAttr->value, "D" ) == 0 ) { hostLang = &hostLangD; outStream = cdOpenOutput( sourceFileName ); } else if ( strcmp( langAttr->value, "Java" ) == 0 ) { hostLang = &hostLangJava; outStream = javaOpenOutput( sourceFileName ); } else if ( strcmp( langAttr->value, "Ruby" ) == 0 ) { hostLang = &hostLangRuby; outStream = rubyOpenOutput( sourceFileName ); } else if ( strcmp( langAttr->value, "C#" ) == 0 ) { hostLang = &hostLangCSharp; outStream = csharpOpenOutput( sourceFileName ); } else { error($1->loc) << "expecting lang attribute to be " "one of C, D, Java, Ruby or C#" << endp; } }; ragel_def_list: ragel_def_list ragel_def; ragel_def_list: ; host_or_write_list: host_or_write_list host_or_write; host_or_write_list: ; host_or_write: tag_host; host_or_write: tag_write; tag_host: TAG_host '/' TAG_host final { Attribute *lineAttr = $1->tag->findAttr( "line" ); if ( lineAttr == 0 ) error($1->loc) << "tag requires a line attribute" << endp; else { int line = atoi( lineAttr->value ); if ( outputActive ) lineDirective( *outStream, sourceFileName, line ); } if ( outputActive ) *outStream << $3->tag->content; }; ragel_def: tag_ragel_def_head ragel_def_item_list '/' TAG_ragel_def final { /* Do this before distributing transitions out to singles and defaults * makes life easier. */ cgd->redFsm->maxKey = cgd->findMaxKey(); cgd->redFsm->assignActionLocs(); /* Find the first final state (The final state with the lowest id). */ cgd->redFsm->findFirstFinState(); /* Call the user's callback. */ cgd->finishRagelDef(); }; tag_ragel_def_head: TAG_ragel_def final { char *fsmName = 0; Attribute *nameAttr = $1->tag->findAttr( "name" ); if ( nameAttr != 0 ) { fsmName = nameAttr->value; CodeGenMapEl *mapEl = codeGenMap.find( fsmName ); if ( mapEl != 0 ) cgd = mapEl->value; else { cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete ); codeGenMap.insert( fsmName, cgd ); } } else { cgd = makeCodeGen( sourceFileName, fsmName, *outStream, wantComplete ); } ::keyOps = &cgd->thisKeyOps; }; ragel_def_item_list: ragel_def_item_list ragel_def_item; ragel_def_item_list: ; ragel_def_item: tag_alph_type; ragel_def_item: tag_getkey_expr; ragel_def_item: tag_access_expr; ragel_def_item: tag_prepush_expr; ragel_def_item: tag_postpop_expr; ragel_def_item: tag_export_list; ragel_def_item: tag_machine; ragel_def_item: tag_p_expr; ragel_def_item: tag_pe_expr; ragel_def_item: tag_eof_expr; ragel_def_item: tag_cs_expr; ragel_def_item: tag_top_expr; ragel_def_item: tag_stack_expr; ragel_def_item: tag_act_expr; ragel_def_item: tag_tokstart_expr; ragel_def_item: tag_tokend_expr; ragel_def_item: tag_data_expr; tag_export_list: TAG_exports export_list '/' TAG_exports; export_list: export_list tag_export; export_list: ; tag_export: TAG_ex '/' TAG_ex final { Attribute *nameAttr = $1->tag->findAttr( "name" ); if ( nameAttr == 0 ) error($1->loc) << "tag requires a name attribute" << endp; else { char *td = $3->tag->content; Key exportKey = readKey( td, &td ); cgd->exportList.append( new Export( nameAttr->value, exportKey ) ); } }; tag_alph_type: TAG_alphtype '/' TAG_alphtype final { if ( ! cgd->setAlphType( $3->tag->content ) ) error($1->loc) << "tag specifies unknown alphabet type" << endp; }; tag_getkey_expr: TAG_getkey inline_list '/' TAG_getkey final { cgd->getKeyExpr = $2->inlineList; }; tag_access_expr: TAG_access inline_list '/' TAG_access final { cgd->accessExpr = $2->inlineList; }; tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush final { cgd->prePushExpr = $2->inlineList; }; tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop final { cgd->postPopExpr = $2->inlineList; }; tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr final { cgd->pExpr = $2->inlineList; }; tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr final { cgd->peExpr = $2->inlineList; }; tag_eof_expr: TAG_eof_expr inline_list '/' TAG_eof_expr final { cgd->eofExpr = $2->inlineList; }; tag_cs_expr: TAG_cs_expr inline_list '/' TAG_cs_expr final { cgd->csExpr = $2->inlineList; }; tag_top_expr: TAG_top_expr inline_list '/' TAG_top_expr final { cgd->topExpr = $2->inlineList; }; tag_stack_expr: TAG_stack_expr inline_list '/' TAG_stack_expr final { cgd->stackExpr = $2->inlineList; }; tag_act_expr: TAG_act_expr inline_list '/' TAG_act_expr final { cgd->actExpr = $2->inlineList; }; tag_tokstart_expr: TAG_tokstart_expr inline_list '/' TAG_tokstart_expr final { cgd->tokstartExpr = $2->inlineList; }; tag_tokend_expr: TAG_tokend_expr inline_list '/' TAG_tokend_expr final { cgd->tokendExpr = $2->inlineList; }; tag_data_expr: TAG_data_expr inline_list '/' TAG_data_expr final { cgd->dataExpr = $2->inlineList; }; tag_write: tag_write_head write_option_list '/' TAG_write final { /* Terminate the options list and call the write statement handler. */ writeOptions.append(0); cgd->writeStatement( $1->loc, writeOptions.length()-1, writeOptions.data ); /* Clear the options in prep for the next write statement. */ writeOptions.empty(); }; nonterm tag_write_head { InputLoc loc; }; tag_write_head: TAG_write final { Attribute *nameAttr = $1->tag->findAttr( "def_name" ); Attribute *lineAttr = $1->tag->findAttr( "line" ); Attribute *colAttr = $1->tag->findAttr( "col" ); if ( nameAttr == 0 ) error($1->loc) << "tag requires a def_name attribute" << endp; if ( lineAttr == 0 ) error($1->loc) << "tag requires a line attribute" << endp; if ( colAttr == 0 ) error($1->loc) << "tag requires a col attribute" << endp; if ( nameAttr != 0 && lineAttr != 0 && colAttr != 0 ) { $$->loc.line = atoi(lineAttr->value); $$->loc.col = atoi(colAttr->value); CodeGenMapEl *mapEl = codeGenMap.find( nameAttr->value ); if ( mapEl == 0 ) { source_error($$->loc) << "write statement given " "but there are no machine instantiations" << endp; } else { cgd = mapEl->value; ::keyOps = &cgd->thisKeyOps; } } }; write_option_list: write_option_list tag_arg; write_option_list: ; nonterm tag_arg { char *option; }; tag_arg: TAG_arg '/' TAG_arg final { writeOptions.append( $3->tag->content ); }; tag_machine: tag_machine_head machine_item_list '/' TAG_machine final { cgd->closeMachine(); }; tag_machine_head: TAG_machine final { cgd->createMachine(); }; machine_item_list: machine_item_list machine_item; machine_item_list: ; machine_item: tag_start_state; machine_item: tag_error_state; machine_item: tag_entry_points; machine_item: tag_state_list; machine_item: tag_action_list; machine_item: tag_action_table_list; machine_item: tag_cond_space_list; # # States. # tag_start_state: TAG_start_state '/' TAG_start_state final { unsigned long startState = strtoul( $3->tag->content, 0, 10 ); cgd->setStartState( startState ); }; tag_error_state: TAG_error_state '/' TAG_error_state final { unsigned long errorState = strtoul( $3->tag->content, 0, 10 ); cgd->setErrorState( errorState ); }; tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points final { Attribute *errorAttr = $1->tag->findAttr( "error" ); if ( errorAttr != 0 ) cgd->setForcedErrorState(); }; entry_point_list: entry_point_list tag_entry; entry_point_list: ; tag_entry: TAG_entry '/' TAG_entry final { Attribute *nameAttr = $1->tag->findAttr( "name" ); if ( nameAttr == 0 ) { error($1->loc) << "tag :: " "requires a name attribute" << endp; } else { char *data = $3->tag->content; unsigned long entry = strtoul( data, &data, 10 ); cgd->addEntryPoint( nameAttr->value, entry ); } }; tag_state_list: tag_state_list_head state_list '/' TAG_state_list; tag_state_list_head: TAG_state_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { unsigned long length = strtoul( lengthAttr->value, 0, 10 ); cgd->initStateList( length ); curState = 0; } }; state_list: state_list tag_state; state_list: ; tag_state: TAG_state state_item_list '/' TAG_state final { Attribute *idAttr = $1->tag->findAttr( "id" ); if ( idAttr == 0 ) error($1->loc) << "tag requires an id attribute" << endp; else { int id = atoi( idAttr->value ); cgd->setId( curState, id ); } Attribute *lengthAttr = $1->tag->findAttr( "final" ); if ( lengthAttr != 0 ) cgd->setFinal( curState ); curState += 1; }; state_item_list: state_item_list state_item; state_item_list: ; state_item: tag_state_actions; state_item: tag_eof_t; state_item: tag_state_cond_list; state_item: tag_trans_list; tag_state_actions: TAG_state_actions '/' TAG_state_actions final { char *ad = $3->tag->content; long toStateAction = readOffsetPtr( ad, &ad ); long fromStateAction = readOffsetPtr( ad, &ad ); long eofAction = readOffsetPtr( ad, &ad ); cgd->setStateActions( curState, toStateAction, fromStateAction, eofAction ); }; tag_eof_t: TAG_eof_t '/' TAG_eof_t final { char *et = $3->tag->content; long targ = readOffsetPtr( et, &et ); long eofAction = readOffsetPtr( et, &et ); cgd->setEofTrans( curState, targ, eofAction ); }; tag_state_cond_list: tag_state_cond_list_head state_cond_list '/' TAG_cond_list; tag_state_cond_list_head: TAG_cond_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { ulong length = readLength( lengthAttr->value ); cgd->initStateCondList( curState, length ); curStateCond = 0; } }; state_cond_list: state_cond_list state_cond; state_cond_list: ; state_cond: TAG_c '/' TAG_c final { char *td = $3->tag->content; Key lowKey = readKey( td, &td ); Key highKey = readKey( td, &td ); long condId = readOffsetPtr( td, &td ); cgd->addStateCond( curState, lowKey, highKey, condId ); }; tag_trans_list: tag_trans_list_head trans_list '/' TAG_trans_list final { cgd->finishTransList( curState ); }; tag_trans_list_head: TAG_trans_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { unsigned long length = strtoul( lengthAttr->value, 0, 10 ); cgd->initTransList( curState, length ); curTrans = 0; } }; trans_list: trans_list tag_trans; trans_list: ; tag_trans: TAG_t '/' TAG_t final { char *td = $3->tag->content; Key lowKey = readKey( td, &td ); Key highKey = readKey( td, &td ); long targ = readOffsetPtr( td, &td ); long action = readOffsetPtr( td, &td ); cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action ); }; # # Action Lists. # tag_action_list: tag_action_list_head action_list '/' TAG_action_list; tag_action_list_head: TAG_action_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { unsigned long length = strtoul( lengthAttr->value, 0, 10 ); cgd->initActionList( length ); curAction = 0; } }; action_list: action_list tag_action; action_list: ; # # Actions. # tag_action: TAG_action inline_list '/' TAG_action final { Attribute *lineAttr = $1->tag->findAttr( "line" ); Attribute *colAttr = $1->tag->findAttr( "col" ); Attribute *nameAttr = $1->tag->findAttr( "name" ); if ( lineAttr == 0 || colAttr == 0) error($1->loc) << "tag requires a line and col attributes" << endp; else { unsigned long line = strtoul( lineAttr->value, 0, 10 ); unsigned long col = strtoul( colAttr->value, 0, 10 ); char *name = 0; if ( nameAttr != 0 ) name = nameAttr->value; cgd->newAction( curAction++, name, line, col, $2->inlineList ); } }; nonterm inline_list { GenInlineList *inlineList; }; inline_list: inline_list inline_item final { /* Append the item to the list, return the list. */ $1->inlineList->append( $2->inlineItem ); $$->inlineList = $1->inlineList; }; inline_list: final { /* Start with empty list. */ $$->inlineList = new GenInlineList; }; nonterm inline_item_type { GenInlineItem *inlineItem; }; nonterm inline_item uses inline_item_type; inline_item: tag_text final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_goto final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_call final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_next final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_goto_expr final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_call_expr final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_next_expr final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_ret final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_break final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_pchar final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_char final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_hold final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_exec final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_curs final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_targs final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_il_entry final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_init_tokstart final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_init_act final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_get_tokend final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_set_tokstart final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_set_tokend final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_set_act final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_sub_action final { $$->inlineItem = $1->inlineItem; }; inline_item: tag_lm_switch final { $$->inlineItem = $1->inlineItem; }; nonterm tag_text uses inline_item_type; nonterm tag_goto uses inline_item_type; nonterm tag_call uses inline_item_type; nonterm tag_next uses inline_item_type; nonterm tag_goto_expr uses inline_item_type; nonterm tag_call_expr uses inline_item_type; nonterm tag_next_expr uses inline_item_type; nonterm tag_ret uses inline_item_type; nonterm tag_break uses inline_item_type; nonterm tag_pchar uses inline_item_type; nonterm tag_char uses inline_item_type; nonterm tag_hold uses inline_item_type; nonterm tag_exec uses inline_item_type; nonterm tag_curs uses inline_item_type; nonterm tag_targs uses inline_item_type; nonterm tag_il_entry uses inline_item_type; nonterm tag_init_tokstart uses inline_item_type; nonterm tag_init_act uses inline_item_type; nonterm tag_get_tokend uses inline_item_type; nonterm tag_set_tokstart uses inline_item_type; nonterm tag_set_tokend uses inline_item_type; nonterm tag_set_act uses inline_item_type; nonterm tag_sub_action uses inline_item_type; nonterm tag_lm_switch uses inline_item_type; tag_text: TAG_text '/' TAG_text final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text ); $$->inlineItem->data = $3->tag->content; }; tag_goto: TAG_goto '/' TAG_goto final { int targ = strtol( $3->tag->content, 0, 10 ); $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto ); $$->inlineItem->targId = targ; }; tag_call: TAG_call '/' TAG_call final { int targ = strtol( $3->tag->content, 0, 10 ); $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Call ); $$->inlineItem->targId = targ; }; tag_next: TAG_next '/' TAG_next final { int targ = strtol( $3->tag->content, 0, 10 ); $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Next ); $$->inlineItem->targId = targ; }; tag_goto_expr: TAG_goto_expr inline_list '/' TAG_goto_expr final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::GotoExpr ); $$->inlineItem->children = $2->inlineList; }; tag_call_expr: TAG_call_expr inline_list '/' TAG_call_expr final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::CallExpr ); $$->inlineItem->children = $2->inlineList; }; tag_next_expr: TAG_next_expr inline_list '/' TAG_next_expr final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::NextExpr ); $$->inlineItem->children = $2->inlineList; }; tag_ret: TAG_ret '/' TAG_ret final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Ret ); }; tag_break: TAG_break '/' TAG_break final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Break ); }; tag_pchar: TAG_pchar '/' TAG_pchar final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::PChar ); }; tag_char: TAG_char '/' TAG_char final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Char ); }; tag_hold: TAG_hold '/' TAG_hold final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Hold ); }; tag_exec: TAG_exec inline_list '/' TAG_exec final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec ); $$->inlineItem->children = $2->inlineList; }; tag_curs: TAG_curs '/' TAG_curs final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Curs ); }; tag_targs: TAG_targs '/' TAG_targs final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Targs ); }; tag_il_entry: TAG_entry '/' TAG_entry final { int targ = strtol( $3->tag->content, 0, 10 ); $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Entry ); $$->inlineItem->targId = targ; }; tag_init_tokstart: TAG_init_tokstart '/' TAG_init_tokstart final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ); }; tag_init_act: TAG_init_act '/' TAG_init_act final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ); }; tag_get_tokend: TAG_get_tokend '/' TAG_get_tokend final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd ); }; tag_set_tokstart: TAG_set_tokstart '/' TAG_set_tokstart final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ); cgd->hasLongestMatch = true; }; tag_set_tokend: TAG_set_tokend '/' TAG_set_tokend final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd ); $$->inlineItem->offset = strtol( $3->tag->content, 0, 10 ); }; tag_set_act: TAG_set_act '/' TAG_set_act final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId ); $$->inlineItem->lmId = strtol( $3->tag->content, 0, 10 ); }; tag_sub_action: TAG_sub_action inline_list '/' TAG_sub_action final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::SubAction ); $$->inlineItem->children = $2->inlineList; }; # Action switches. tag_lm_switch: TAG_lm_switch lm_action_list '/' TAG_lm_switch final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch ); $$->inlineItem->children = $2->inlineList; }; nonterm lm_action_list { GenInlineList *inlineList; }; lm_action_list: lm_action_list tag_inline_action final { $$->inlineList = $1->inlineList; $$->inlineList->append( $2->inlineItem ); }; lm_action_list: final { $$->inlineList = new GenInlineList; }; nonterm tag_inline_action uses inline_item_type; tag_inline_action: TAG_sub_action inline_list '/' TAG_sub_action final { $$->inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::SubAction ); $$->inlineItem->children = $2->inlineList; Attribute *idAttr = $1->tag->findAttr( "id" ); if ( idAttr != 0 ) { unsigned long id = strtoul( idAttr->value, 0, 10 ); $$->inlineItem->lmId = id; } }; # # Lists of Actions. # tag_action_table_list: tag_action_table_list_head action_table_list '/' TAG_action_table_list; tag_action_table_list_head: TAG_action_table_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) { error($1->loc) << "tag requires " "a length attribute" << endp; } else { unsigned long length = strtoul( lengthAttr->value, 0, 10 ); cgd->initActionTableList( length ); curActionTable = 0; } }; action_table_list: action_table_list tag_action_table; action_table_list: ; tag_action_table: TAG_action_table '/' TAG_action_table final { /* Find the length of the action table. */ Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { unsigned long length = strtoul( lengthAttr->value, 0, 10 ); /* Collect the action table. */ RedAction *redAct = cgd->allActionTables + curActionTable; redAct->actListId = curActionTable; redAct->key.setAsNew( length ); char *ptr = $3->tag->content; int pos = 0; while ( *ptr != 0 ) { unsigned long actionId = strtoul( ptr, &ptr, 10 ); redAct->key[pos].key = 0; redAct->key[pos].value = cgd->allActions+actionId; pos += 1; } /* Insert into the action table map. */ cgd->redFsm->actionMap.insert( redAct ); } curActionTable += 1; }; # # Conditions. # tag_cond_space_list: tag_cond_space_list_head cond_space_list '/' TAG_cond_space_list; tag_cond_space_list_head: TAG_cond_space_list final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); if ( lengthAttr == 0 ) { error($1->loc) << "tag " "requires a length attribute" << endp; } else { ulong length = readLength( lengthAttr->value ); cgd->initCondSpaceList( length ); curCondSpace = 0; } }; cond_space_list: cond_space_list tag_cond_space; cond_space_list: tag_cond_space; tag_cond_space: TAG_cond_space '/' TAG_cond_space final { Attribute *lengthAttr = $1->tag->findAttr( "length" ); Attribute *idAttr = $1->tag->findAttr( "id" ); if ( lengthAttr == 0 ) error($1->loc) << "tag requires a length attribute" << endp; else { if ( lengthAttr == 0 ) error($1->loc) << "tag requires an id attribute" << endp; else { unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 ); ulong length = readLength( lengthAttr->value ); char *td = $3->tag->content; Key baseKey = readKey( td, &td ); cgd->newCondSpace( curCondSpace, condSpaceId, baseKey ); for ( ulong a = 0; a < length; a++ ) { long actionOffset = readOffsetPtr( td, &td ); cgd->condSpaceItem( curCondSpace, actionOffset ); } curCondSpace += 1; } } }; }%% %%{ write types; write data; }%% void XmlParser::init() { %% write init; } int XmlParser::parseLangEl( int type, const Token *token ) { %% write exec; return errCount == 0 ? 0 : -1; } unsigned long readLength( char *td ) { return strtoul( td, 0, 10 ); } Key readKey( char *td, char **end ) { if ( keyOps->isSigned ) return Key( strtol( td, end, 10 ) ); else return Key( strtoul( td, end, 10 ) ); } long readOffsetPtr( char *td, char **end ) { while ( *td == ' ' || *td == '\t' ) td++; if ( *td == 'x' ) { if ( end != 0 ) *end = td + 1; return -1; } return strtol( td, end, 10 ); } ostream &XmlParser::warning( const InputLoc &loc ) { cerr << fileName << ":" << loc.line << ":" << loc.col << ": warning: "; return cerr; } ostream &XmlParser::error( const InputLoc &loc ) { gblErrorCount += 1; assert( fileName != 0 ); cerr << fileName << ":" << loc.line << ":" << loc.col << ": "; return cerr; } ostream &XmlParser::parser_error( int tokId, Token &token ) { gblErrorCount += 1; assert( fileName != 0 ); cerr << fileName << ":" << token.loc.line << ":" << token.loc.col; if ( token.tag != 0 ) { if ( token.tag->tagId == 0 ) cerr << ": at unknown tag"; else cerr << ": at tag <" << token.tag->tagId->name << ">"; } cerr << ": "; return cerr; } ostream &XmlParser::source_error( const InputLoc &loc ) { gblErrorCount += 1; assert( sourceFileName != 0 ); cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": "; return cerr; } int XmlParser::token( int tokenId, Token &tok ) { int res = parseLangEl( tokenId, &tok ); if ( res < 0 ) parser_error( tokenId, tok ) << "parse error" << endp; return res; } int XmlParser::token( int tokenId, int col, int line ) { Token tok; tok.loc.col = col; tok.loc.line = line; tok.tag = 0; return token( tokenId, tok ); } int XmlParser::token( XMLTag *tag, int col, int line ) { Token tok; tok.loc.col = col; tok.loc.line = line; tok.tag = tag; if ( tag->type == XMLTag::Close ) { int res = token( '/', tok ); if ( res < 0 ) return res; } tok.tag = tag; return token( tag->tagId != 0 ? tag->tagId->id : TAG_unknown, tok ); }