summaryrefslogtreecommitdiff
path: root/libfsm/xmlparse.kl
diff options
context:
space:
mode:
Diffstat (limited to 'libfsm/xmlparse.kl')
-rw-r--r--libfsm/xmlparse.kl1006
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 );
+}