diff options
Diffstat (limited to 'libfsm/xmlparse.kl')
-rw-r--r-- | libfsm/xmlparse.kl | 1006 |
1 files changed, 1006 insertions, 0 deletions
diff --git a/libfsm/xmlparse.kl b/libfsm/xmlparse.kl new file mode 100644 index 00000000..04d95b83 --- /dev/null +++ b/libfsm/xmlparse.kl @@ -0,0 +1,1006 @@ +/* + * Copyright 2001-2007 Adrian Thurston <thurston@colm.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "xmlparse.h" +#include "common.h" +#include "gendata.h" +#include "version.h" +#include <iostream> +#include <stdlib.h> + +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 <ragel> 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 <ragel> 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 <ragel> 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 <host> 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 <ex> 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 <alphtype> 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 <write> requires a def_name attribute" << endp; + if ( lineAttr == 0 ) + error($1->loc) << "tag <write> requires a line attribute" << endp; + if ( colAttr == 0 ) + error($1->loc) << "tag <write> 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 <entry_points>::<entry> " + "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 <state_list> 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 <state> 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 <cond_list> 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 <trans_list> 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 <action_list> 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 <action> 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 <action_table_list> 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 <at> 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 <cond_space_list> " + "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 <cond_space> requires a length attribute" << endp; + else { + if ( lengthAttr == 0 ) + error($1->loc) << "tag <cond_space> 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 ); +} |