summaryrefslogtreecommitdiff
path: root/rlcodegen/xmlparse.y
diff options
context:
space:
mode:
Diffstat (limited to 'rlcodegen/xmlparse.y')
-rw-r--r--rlcodegen/xmlparse.y978
1 files changed, 978 insertions, 0 deletions
diff --git a/rlcodegen/xmlparse.y b/rlcodegen/xmlparse.y
new file mode 100644
index 0000000..a837c87
--- /dev/null
+++ b/rlcodegen/xmlparse.y
@@ -0,0 +1,978 @@
+/*
+ * Copyright 2005-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/* 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 <iostream>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "rlcodegen.h"
+#include "vector.h"
+#include "xmlparse.h"
+#include "gendata.h"
+
+using std::cerr;
+using std::endl;
+
+char *sourceFileName;
+char *attrKey;
+char *attrValue;
+int curAction;
+int curActionTable;
+int curTrans;
+int curState;
+int curCondSpace;
+int curStateCond;
+
+Key readKey( char *td, char **end );
+long readOffsetPtr( char *td, char **end );
+unsigned long readLength( char *td );
+
+CodeGenMap codeGenMap;
+
+%}
+
+%pure-parser
+
+%union {
+ /* General data types. */
+ char c;
+ char *data;
+ int integer;
+ AttrList *attrList;
+
+ /* Inline parse tree items. */
+ InlineItem *ilitem;
+ InlineList *illist;
+}
+
+%token TAG_unknown
+%token TAG_ragel
+%token TAG_ragel_def
+%token TAG_host
+%token TAG_state_list
+%token TAG_state
+%token TAG_trans_list
+%token TAG_t
+%token TAG_machine
+%token TAG_start_state
+%token TAG_action_list
+%token TAG_action_table_list
+%token TAG_action
+%token TAG_action_table
+%token TAG_alphtype
+%token TAG_element
+%token TAG_getkey
+%token TAG_state_actions
+%token TAG_entry_points
+%token TAG_sub_action
+%token TAG_cond_space_list
+%token TAG_cond_space
+%token TAG_cond_list
+%token TAG_c
+
+/* Inline block tokens. */
+%token TAG_text
+%token TAG_goto
+%token TAG_call
+%token TAG_next
+%token TAG_goto_expr
+%token TAG_call_expr
+%token TAG_next_expr
+%token TAG_ret
+%token TAG_pchar
+%token TAG_char
+%token TAG_hold
+%token TAG_exec
+%token TAG_holdte
+%token TAG_execte
+%token TAG_curs
+%token TAG_targs
+%token TAG_entry
+%token TAG_data
+%token TAG_lm_switch
+%token TAG_init_act
+%token TAG_set_act
+%token TAG_set_tokend
+%token TAG_get_tokend
+%token TAG_init_tokstart
+%token TAG_set_tokstart
+%token TAG_write
+%token TAG_curstate
+%token TAG_access
+%token TAG_break
+%token TAG_option
+
+%token <data> XML_Word
+%token <data> XML_Literal
+%type <attrList> AttributeList
+
+%type <illist> InlineList
+%type <ilitem> InlineItem
+%type <illist> LmActionList
+
+%type <ilitem> TagText
+%type <ilitem> TagGoto
+%type <ilitem> TagCall
+%type <ilitem> TagNext
+%type <ilitem> TagGotoExpr
+%type <ilitem> TagCallExpr
+%type <ilitem> TagNextExpr
+%type <ilitem> TagRet
+%type <ilitem> TagBreak
+%type <ilitem> TagPChar
+%type <ilitem> TagChar
+%type <ilitem> TagHold
+%type <ilitem> TagExec
+%type <ilitem> TagHoldTE
+%type <ilitem> TagExecTE
+%type <ilitem> TagCurs
+%type <ilitem> TagTargs
+%type <ilitem> TagIlEntry
+%type <ilitem> TagLmSwitch
+%type <ilitem> TagLmSetActId
+%type <ilitem> TagLmGetTokEnd
+%type <ilitem> TagLmSetTokEnd
+%type <ilitem> TagLmInitTokStart
+%type <ilitem> TagLmInitAct
+%type <ilitem> TagLmSetTokStart
+%type <ilitem> TagInlineAction
+%type <ilitem> TagSubAction
+
+%%
+
+/* Input is any number of input sections. An empty file is accepted. */
+input:
+ TagRagel |
+ /* Nothing */ {
+ /* Assume the frontend died if we get no input. It will emit an error.
+ * Cause us to return an error code. */
+ gblErrorCount += 1;
+ };
+
+TagRagel:
+ TagRagelHead
+ HostOrDefList
+ '<' '/' TAG_ragel '>';
+
+TagRagelHead:
+ '<' TAG_ragel AttributeList '>' {
+ Attribute *fileNameAttr = $3->find( "filename" );
+ if ( fileNameAttr == 0 )
+ xml_error(@2) << "tag <ragel> requires a filename attribute" << endl;
+ else
+ sourceFileName = fileNameAttr->value;
+
+ Attribute *langAttr = $3->find( "lang" );
+ if ( langAttr == 0 )
+ xml_error(@2) << "tag <ragel> requires a lang attribute" << endl;
+ else {
+ if ( strcmp( langAttr->value, "C" ) == 0 ) {
+ hostLangType = CCode;
+ hostLang = &hostLangC;
+ }
+ else if ( strcmp( langAttr->value, "D" ) == 0 ) {
+ hostLangType = DCode;
+ hostLang = &hostLangD;
+ }
+ else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
+ hostLangType = JavaCode;
+ hostLang = &hostLangJava;
+ }
+ }
+
+ /* Eventually more types will be supported. */
+ if ( hostLangType == JavaCode && codeStyle != GenTables ) {
+ error() << "java: only the table code style -T0 is "
+ "currently supported" << endl;
+ }
+
+ openOutput( sourceFileName );
+ };
+
+AttributeList:
+ AttributeList Attribute {
+ $$ = $1;
+ $$->append( Attribute( attrKey, attrValue ) );
+ } |
+ /* Nothing */ {
+ $$ = new AttrList;
+ };
+
+Attribute:
+ XML_Word '=' XML_Literal {
+ attrKey = $1;
+ attrValue = $3;
+ };
+
+HostOrDefList:
+ HostOrDefList HostOrDef |
+ /* Nothing */;
+
+HostOrDef:
+ TagHost | TagRagelDef;
+
+TagHost:
+ TagHostHead
+ '<' '/' TAG_host '>' {
+ if ( outputFormat == OutCode )
+ *outStream << xmlData.data;
+ };
+
+TagHostHead:
+ '<' TAG_host AttributeList '>' {
+ Attribute *lineAttr = $3->find( "line" );
+ if ( lineAttr == 0 )
+ xml_error(@2) << "tag <host> requires a line attribute" << endl;
+ else {
+ int line = atoi( lineAttr->value );
+ if ( outputFormat == OutCode )
+ lineDirective( *outStream, sourceFileName, line );
+ }
+ };
+
+TagRagelDef:
+ RagelDefHead
+ RagelDefItemList
+ '<' '/' TAG_ragel_def '>' {
+ if ( gblErrorCount == 0 )
+ cgd->generate();
+ };
+
+RagelDefHead:
+ '<' TAG_ragel_def AttributeList '>' {
+ bool wantComplete = outputFormat != OutGraphvizDot;
+
+ char *fsmName = 0;
+ Attribute *nameAttr = $3->find( "name" );
+ if ( nameAttr != 0 ) {
+ fsmName = nameAttr->value;
+
+ CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
+ if ( mapEl != 0 )
+ cgd = mapEl->value;
+ else {
+ cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
+ codeGenMap.insert( fsmName, cgd );
+ }
+ }
+ else {
+ cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
+ }
+
+ cgd->writeOps = 0;
+ cgd->writeData = false;
+ cgd->writeInit = false;
+ cgd->writeExec = false;
+ cgd->writeEOF = false;
+ ::keyOps = &cgd->thisKeyOps;
+ };
+
+RagelDefItemList:
+ RagelDefItemList RagelDefItem |
+ /* Nothing */;
+
+RagelDefItem:
+ TagAlphType |
+ TagGetKeyExpr |
+ TagAccessExpr |
+ TagCurStateExpr |
+ TagMachine |
+ TagWrite;
+
+TagWrite:
+ '<' TAG_write AttributeList '>'
+ OptionList
+ '<' '/' TAG_write '>' {
+ Attribute *what = $3->find( "what" );
+ if ( what == 0 ) {
+ xml_error(@2) << "tag <write> requires a what attribute" << endl;
+ }
+ else {
+ if ( strcmp( what->value, "data" ) == 0 )
+ cgd->writeData = true;
+ else if ( strcmp( what->value, "init" ) == 0 )
+ cgd->writeInit = true;
+ else if ( strcmp( what->value, "exec" ) == 0 )
+ cgd->writeExec = true;
+ else if ( strcmp( what->value, "eof" ) == 0 )
+ cgd->writeEOF = true;
+ }
+ };
+
+OptionList:
+ OptionList TagOption |
+ /* Nothing */;
+
+TagOption:
+ '<' TAG_option '>'
+ '<' '/' TAG_option '>' {
+ if ( strcmp( xmlData.data, "noend" ) == 0 )
+ cgd->writeOps |= WO_NOEND;
+ else if ( strcmp( xmlData.data, "noerror" ) == 0 )
+ cgd->writeOps |= WO_NOERROR;
+ else if ( strcmp( xmlData.data, "noprefix" ) == 0 )
+ cgd->writeOps |= WO_NOPREFIX;
+ else if ( strcmp( xmlData.data, "nofinal" ) == 0 )
+ cgd->writeOps |= WO_NOFF;
+ else {
+ warning() << "unrecognized write option" << endl;
+ }
+ };
+
+
+TagAlphType:
+ '<' TAG_alphtype '>'
+ '<' '/' TAG_alphtype '>' {
+ if ( ! cgd->setAlphType( xmlData.data ) )
+ xml_error(@2) << "tag <alphtype> specifies unknown alphabet type" << endl;
+ };
+
+TagGetKeyExpr:
+ '<' TAG_getkey '>'
+ InlineList
+ '<' '/' TAG_getkey '>' {
+ cgd->getKeyExpr = $4;
+ };
+
+TagAccessExpr:
+ '<' TAG_access '>'
+ InlineList
+ '<' '/' TAG_access '>' {
+ cgd->accessExpr = $4;
+ };
+
+TagCurStateExpr:
+ '<' TAG_curstate '>'
+ InlineList
+ '<' '/' TAG_curstate '>' {
+ cgd->curStateExpr = $4;
+ };
+
+TagMachine:
+ TagMachineHead
+ MachineItemList
+ '<' '/' TAG_machine '>' {
+ cgd->finishMachine();
+ };
+
+TagMachineHead:
+ '<' TAG_machine '>' {
+ cgd->createMachine();
+ };
+
+MachineItemList:
+ MachineItemList MachineItem |
+ /* Nothing */;
+
+MachineItem:
+ TagStartState |
+ TagEntryPoints |
+ TagStateList |
+ TagActionList |
+ TagActionTableList |
+ TagCondSpaceList;
+
+TagStartState:
+ '<' TAG_start_state '>'
+ '<' '/' TAG_start_state '>' {
+ unsigned long startState = strtoul( xmlData.data, 0, 10 );
+ cgd->setStartState( startState );
+ };
+
+TagEntryPoints:
+ '<' TAG_entry_points AttributeList '>'
+ EntryPointList
+ '<' '/' TAG_entry_points '>' {
+ Attribute *errorAttr = $3->find( "error" );
+ if ( errorAttr != 0 )
+ cgd->setForcedErrorState();
+ };
+
+EntryPointList:
+ EntryPointList TagEntry |
+ /* Nothing */;
+
+TagEntry:
+ '<' TAG_entry AttributeList '>'
+ '<' '/' TAG_entry '>' {
+ Attribute *nameAttr = $3->find( "name" );
+ if ( nameAttr == 0 )
+ xml_error(@2) << "tag <entry_points>::<entry> requires a name attribute" << endl;
+ else {
+ char *data = xmlData.data;
+ unsigned long entry = strtoul( data, &data, 10 );
+ cgd->addEntryPoint( nameAttr->value, entry );
+ }
+ };
+
+TagStateList:
+ TagStateListHead
+ StateList
+ '<' '/' TAG_state_list '>';
+
+TagStateListHead:
+ '<' TAG_state_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <state_list> requires a length attribute" << endl;
+ else {
+ unsigned long length = strtoul( lengthAttr->value, 0, 10 );
+ cgd->initStateList( length );
+ curState = 0;
+ }
+ };
+
+StateList:
+ StateList TagState |
+ /* Nothing */;
+
+TagState:
+ TagStateHead
+ StateItemList
+ '<' '/' TAG_state '>' {
+ curState += 1;
+ };
+
+TagStateHead:
+ '<' TAG_state AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "final" );
+ if ( lengthAttr != 0 )
+ cgd->setFinal( curState );
+ };
+
+StateItemList:
+ StateItemList StateItem |
+ /* Nothing */;
+
+StateItem:
+ TagStateActions |
+ TagStateCondList |
+ TagTransList;
+
+TagStateActions:
+ '<' TAG_state_actions '>'
+ '<' '/' TAG_state_actions '>' {
+ char *ad = xmlData.data;
+
+ long toStateAction = readOffsetPtr( ad, &ad );
+ long fromStateAction = readOffsetPtr( ad, &ad );
+ long eofAction = readOffsetPtr( ad, &ad );
+
+ cgd->setStateActions( curState, toStateAction,
+ fromStateAction, eofAction );
+ };
+
+TagStateCondList:
+ TagStateCondListHead
+ StateCondList
+ '<' '/' TAG_cond_list '>';
+
+TagStateCondListHead:
+ '<' TAG_cond_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <cond_list> requires a length attribute" << endl;
+ else {
+ ulong length = readLength( lengthAttr->value );
+ cgd->initStateCondList( curState, length );
+ curStateCond = 0;
+ }
+ }
+
+StateCondList:
+ StateCondList StateCond |
+ /* Empty */;
+
+StateCond:
+ '<' TAG_c '>'
+ '<' '/' TAG_c '>' {
+ char *td = xmlData.data;
+ Key lowKey = readKey( td, &td );
+ Key highKey = readKey( td, &td );
+ long condId = readOffsetPtr( td, &td );
+ cgd->addStateCond( curState, lowKey, highKey, condId );
+ }
+
+TagTransList:
+ TagTransListHead
+ TransList
+ '<' '/' TAG_trans_list '>' {
+ cgd->finishTransList( curState );
+ };
+
+TagTransListHead:
+ '<' TAG_trans_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <trans_list> requires a length attribute" << endl;
+ else {
+ unsigned long length = strtoul( lengthAttr->value, 0, 10 );
+ cgd->initTransList( curState, length );
+ curTrans = 0;
+ }
+ };
+
+TransList:
+ TransList TagTrans |
+ /* Nothing */;
+
+TagTrans:
+ '<' TAG_t AttributeList '>'
+ '<' '/' TAG_t '>' {
+ char *td = xmlData.data;
+ 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 );
+ };
+
+TagActionList:
+ TagActionListHead
+ ActionList
+ '<' '/' TAG_action_list '>';
+
+TagActionListHead:
+ '<' TAG_action_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <action_list> requires a length attribute" << endl;
+ else {
+ unsigned long length = strtoul( lengthAttr->value, 0, 10 );
+ cgd->initActionList( length );
+ curAction = 0;
+ }
+ };
+
+ActionList:
+ ActionList TagAction |
+ /* Nothing */;
+
+TagAction:
+ '<' TAG_action AttributeList '>'
+ InlineList
+ '<' '/' TAG_action '>' {
+ Attribute *lineAttr = $3->find( "line" );
+ Attribute *colAttr = $3->find( "col" );
+ Attribute *nameAttr = $3->find( "name" );
+ if ( lineAttr == 0 || colAttr == 0)
+ xml_error(@2) << "tag <action> requires a line and col attributes" << endl;
+ 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, $5 );
+ }
+ };
+
+InlineList:
+ InlineList InlineItem {
+ /* Append the item to the list, return the list. */
+ $1->append( $2 );
+ $$ = $1;
+ } |
+ /* Nothing */ {
+ /* Start with empty list. */
+ $$ = new InlineList;
+ };
+
+InlineItem:
+ TagText |
+ TagGoto |
+ TagCall |
+ TagNext |
+ TagGotoExpr |
+ TagCallExpr |
+ TagNextExpr |
+ TagRet |
+ TagBreak |
+ TagPChar |
+ TagChar |
+ TagHold |
+ TagExec |
+ TagHoldTE |
+ TagExecTE |
+ TagCurs |
+ TagTargs |
+ TagIlEntry |
+ TagLmSwitch |
+ TagLmSetActId |
+ TagLmSetTokEnd |
+ TagLmGetTokEnd |
+ TagSubAction |
+ TagLmInitTokStart |
+ TagLmInitAct |
+ TagLmSetTokStart;
+
+TagText:
+ '<' TAG_text AttributeList '>'
+ '<' '/' TAG_text '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Text );
+ $$->data = strdup(xmlData.data);
+ };
+
+TagGoto:
+ '<' TAG_goto '>'
+ '<' '/' TAG_goto '>' {
+ int targ = strtol( xmlData.data, 0, 10 );
+ $$ = new InlineItem( InputLoc(), InlineItem::Goto );
+ $$->targId = targ;
+ };
+
+TagCall:
+ '<' TAG_call '>'
+ '<' '/' TAG_call '>' {
+ int targ = strtol( xmlData.data, 0, 10 );
+ $$ = new InlineItem( InputLoc(), InlineItem::Call );
+ $$->targId = targ;
+ };
+
+TagNext:
+ '<' TAG_next '>'
+ '<' '/' TAG_next '>' {
+ int targ = strtol( xmlData.data, 0, 10 );
+ $$ = new InlineItem( InputLoc(), InlineItem::Next );
+ $$->targId = targ;
+ };
+
+TagGotoExpr:
+ '<' TAG_goto_expr '>'
+ InlineList
+ '<' '/' TAG_goto_expr '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::GotoExpr );
+ $$->children = $4;
+ };
+
+TagCallExpr:
+ '<' TAG_call_expr '>'
+ InlineList
+ '<' '/' TAG_call_expr '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::CallExpr );
+ $$->children = $4;
+ };
+
+TagNextExpr:
+ '<' TAG_next_expr '>'
+ InlineList
+ '<' '/' TAG_next_expr '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::NextExpr );
+ $$->children = $4;
+ };
+
+TagRet:
+ '<' TAG_ret '>'
+ '<' '/' TAG_ret '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Ret );
+ };
+
+TagPChar:
+ '<' TAG_pchar '>'
+ '<' '/' TAG_pchar '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::PChar );
+ };
+
+TagChar:
+ '<' TAG_char '>'
+ '<' '/' TAG_char '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Char );
+ };
+
+TagHold:
+ '<' TAG_hold '>'
+ '<' '/' TAG_hold '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Hold );
+ };
+
+TagExec:
+ '<' TAG_exec '>'
+ InlineList
+ '<' '/' TAG_exec '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Exec );
+ $$->children = $4;
+ };
+
+TagHoldTE:
+ '<' TAG_holdte '>'
+ '<' '/' TAG_holdte '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::HoldTE );
+ };
+
+TagExecTE:
+ '<' TAG_execte '>'
+ InlineList
+ '<' '/' TAG_execte '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::ExecTE );
+ $$->children = $4;
+ };
+
+TagCurs:
+ '<' TAG_curs '>'
+ '<' '/' TAG_curs '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Curs );
+ };
+
+TagTargs:
+ '<' TAG_targs '>'
+ '<' '/' TAG_targs '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Targs );
+ };
+
+TagIlEntry:
+ '<' TAG_entry '>'
+ '<' '/' TAG_entry '>' {
+ int targ = strtol( xmlData.data, 0, 10 );
+ $$ = new InlineItem( InputLoc(), InlineItem::Entry );
+ $$->targId = targ;
+ };
+
+TagBreak:
+ '<' TAG_break '>'
+ '<' '/' TAG_break '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::Break );
+ };
+
+
+TagLmSwitch:
+ '<' TAG_lm_switch AttributeList '>'
+ LmActionList
+ '<' '/' TAG_lm_switch '>' {
+ bool handlesError = false;
+ Attribute *handlesErrorAttr = $3->find( "handles_error" );
+ if ( handlesErrorAttr != 0 )
+ handlesError = true;
+
+ $$ = new InlineItem( InputLoc(), InlineItem::LmSwitch );
+ $$->children = $5;
+ $$->handlesError = handlesError;
+ };
+
+LmActionList:
+ LmActionList TagInlineAction {
+ $$ = $1;
+ $$->append( $2 );
+ } |
+ /* Nothing */ {
+ $$ = new InlineList;
+ };
+
+TagInlineAction:
+ '<' TAG_sub_action AttributeList '>'
+ InlineList
+ '<' '/' TAG_sub_action '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
+ $$->children = $5;
+
+ Attribute *idAttr = $3->find( "id" );
+ if ( idAttr != 0 ) {
+ unsigned long id = strtoul( idAttr->value, 0, 10 );
+ $$->lmId = id;
+ }
+ };
+
+TagLmSetActId:
+ '<' TAG_set_act '>'
+ '<' '/' TAG_set_act '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmSetActId );
+ $$->lmId = strtol( xmlData.data, 0, 10 );
+ };
+
+TagLmGetTokEnd:
+ '<' TAG_get_tokend '>'
+ '<' '/' TAG_get_tokend '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
+ };
+
+TagLmSetTokEnd:
+ '<' TAG_set_tokend '>'
+ '<' '/' TAG_set_tokend '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
+ $$->offset = strtol( xmlData.data, 0, 10 );
+ };
+
+TagSubAction:
+ '<' TAG_sub_action '>'
+ InlineList
+ '<' '/' TAG_sub_action '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
+ $$->children = $4;
+ };
+
+TagLmInitTokStart:
+ '<' TAG_init_tokstart '>'
+ '<' '/' TAG_init_tokstart '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
+ };
+
+TagLmInitAct:
+ '<' TAG_init_act '>'
+ '<' '/' TAG_init_act '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmInitAct );
+ };
+
+TagLmSetTokStart:
+ '<' TAG_set_tokstart '>'
+ '<' '/' TAG_set_tokstart '>' {
+ $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
+ cgd->hasLongestMatch = true;
+ };
+
+TagActionTableList:
+ TagActionTableListHead
+ ActionTableList
+ '<' '/' TAG_action_table_list '>';
+
+TagActionTableListHead:
+ '<' TAG_action_table_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <action_table_list> requires a length attribute" << endl;
+ else {
+ unsigned long length = strtoul( lengthAttr->value, 0, 10 );
+ cgd->initActionTableList( length );
+ curActionTable = 0;
+ }
+ };
+
+ActionTableList:
+ ActionTableList TagActionTable |
+ /* Nothing */;
+
+TagActionTable:
+ '<' TAG_action_table AttributeList '>'
+ '<' '/' TAG_action_table '>' {
+ /* Find the length of the action table. */
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <at> requires a length attribute" << endl;
+ 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 = xmlData.data;
+ 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;
+ };
+
+TagCondSpaceList:
+ TagCondSpaceListHead
+ CondSpaceList
+ '<' '/' TAG_cond_space_list '>';
+
+TagCondSpaceListHead:
+ '<' TAG_cond_space_list AttributeList '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <cond_space_list> requires a length attribute" << endl;
+ else {
+ ulong length = readLength( lengthAttr->value );
+ cgd->initCondSpaceList( length );
+ curCondSpace = 0;
+ }
+ };
+
+CondSpaceList:
+ CondSpaceList TagCondSpace |
+ TagCondSpace;
+
+TagCondSpace:
+ '<' TAG_cond_space AttributeList '>'
+ '<' '/' TAG_cond_space '>' {
+ Attribute *lengthAttr = $3->find( "length" );
+ Attribute *idAttr = $3->find( "id" );
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <cond_space> requires a length attribute" << endl;
+ else {
+ if ( lengthAttr == 0 )
+ xml_error(@2) << "tag <cond_space> requires an id attribute" << endl;
+ else {
+ unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
+ ulong length = readLength( lengthAttr->value );
+
+ char *td = xmlData.data;
+ 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;
+ }
+ }
+ };
+
+%%
+
+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 );
+}
+
+void yyerror( char *err )
+{
+ /* Bison won't give us the location, but in the last call to the scanner we
+ * saved a pointer to the locationn variable. Use that. instead. */
+ error(::yylloc->first_line, ::yylloc->first_column) << err << endl;
+}
+