diff options
author | Adrian Thurston <thurston@colm.net> | 2021-12-28 17:49:55 +0000 |
---|---|---|
committer | Adrian Thurston <thurston@colm.net> | 2021-12-28 17:49:55 +0000 |
commit | f5116edb1e8773ea21e51e5d9644dcea173c9016 (patch) | |
tree | 93e639406fda342da3c6b34b738257ac43bc1233 | |
parent | 8dc93d3b2cc730e5344ce9c047d4d595dac3dc29 (diff) | |
download | ragel-f5116edb1e8773ea21e51e5d9644dcea173c9016.tar.gz |
removed code that is unused, or that now lives in the colm package
-rw-r--r-- | src/actexp.cc | 218 | ||||
-rw-r--r-- | src/actloop.cc | 229 | ||||
-rw-r--r-- | src/asm.cc | 2047 | ||||
-rw-r--r-- | src/buffer.h | 56 | ||||
-rw-r--r-- | src/fsmap.cc | 1200 | ||||
-rw-r--r-- | src/fsmattach.cc | 857 | ||||
-rw-r--r-- | src/fsmbase.cc | 853 | ||||
-rw-r--r-- | src/fsmcond.cc | 520 | ||||
-rw-r--r-- | src/fsmgraph.cc | 1948 | ||||
-rw-r--r-- | src/fsmmin.cc | 934 | ||||
-rw-r--r-- | src/fsmnfa.cc | 660 | ||||
-rw-r--r-- | src/fsmstate.cc | 603 | ||||
-rw-r--r-- | src/gendata.cc | 1648 | ||||
-rw-r--r-- | src/idbase.cc | 422 | ||||
-rw-r--r-- | src/ipgoto.cc | 765 | ||||
-rw-r--r-- | src/libragel.h | 32 | ||||
-rw-r--r-- | src/redfsm.cc | 1192 | ||||
-rw-r--r-- | src/tabbreak.cc | 378 | ||||
-rw-r--r-- | src/tabgoto.cc | 330 | ||||
-rw-r--r-- | src/tables.cc | 81 | ||||
-rw-r--r-- | src/tabvar.cc | 332 | ||||
-rw-r--r-- | src/xml.cc | 786 | ||||
-rw-r--r-- | src/xml.h | 81 | ||||
-rw-r--r-- | src/xmlparse.kh | 211 | ||||
-rw-r--r-- | src/xmlparse.kl | 1006 | ||||
-rw-r--r-- | src/xmlscan.rl | 315 | ||||
-rw-r--r-- | src/xmltags.gperf | 95 |
27 files changed, 0 insertions, 17799 deletions
diff --git a/src/actexp.cc b/src/actexp.cc deleted file mode 100644 index 771d4623..00000000 --- a/src/actexp.cc +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2018-2018 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 "actexp.h" -#include "redfsm.h" -#include "gendata.h" - -void ActExp::FROM_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->fromStateAction != 0 ) - act = state->fromStateAction->actListId + 1; - fromStateActions.value( act ); -} - -void ActExp::COND_ACTION( RedCondPair *cond ) -{ - int action = 0; - if ( cond->action != 0 ) - action = cond->action->actListId + 1; - condActions.value( action ); -} - -void ActExp::TO_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->toStateAction != 0 ) - act = state->toStateAction->actListId + 1; - toStateActions.value( act ); -} - -void ActExp::EOF_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->eofAction != 0 ) - act = state->eofAction->actListId + 1; - eofActions.value( act ); -} - -void ActExp::NFA_PUSH_ACTION( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->push != 0 ) - act = targ->push->actListId+1; - nfaPushActions.value( act ); -} - -void ActExp::NFA_POP_TEST( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->popTest != 0 ) - act = targ->popTest->actListId+1; - nfaPopTrans.value( act ); -} - - -/* Write out the function switch. This switch is keyed on the values - * of the func index. */ -std::ostream &ActExp::FROM_STATE_ACTION_SWITCH() -{ - /* Loop the actions. */ - for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { - if ( redAct->numFromStateRefs > 0 ) { - /* Write the entry label. */ - out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; - - /* Write each action in the list of action items. */ - for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( 0, false, false ) ); - out << "\n\t"; - } - - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - -/* Write out the function switch. This switch is keyed on the values - * of the func index. */ -std::ostream &ActExp::ACTION_SWITCH() -{ - /* Loop the actions. */ - for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { - if ( redAct->numTransRefs > 0 ) { - /* Write the entry label. */ - out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; - - /* Write each action in the list of action items. */ - for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( 0, false, false ) ); - out << "\n\t"; - } - - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - -/* Write out the function switch. This switch is keyed on the values - * of the func index. */ -std::ostream &ActExp::TO_STATE_ACTION_SWITCH() -{ - /* Loop the actions. */ - for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { - if ( redAct->numToStateRefs > 0 ) { - /* Write the entry label. */ - out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; - - /* Write each action in the list of action items. */ - for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( 0, false, false ) ); - out << "\n\t"; - } - - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - -std::ostream &ActExp::EOF_ACTION_SWITCH() -{ - /* Loop the actions. */ - for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { - if ( redAct->numEofRefs > 0 ) { - /* Write the entry label. */ - out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; - - /* Write each action in the list of action items. */ - for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( 0, true, false ) ); - out << "\n\t"; - } - - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - - -void ActExp::FROM_STATE_ACTIONS() -{ - if ( redFsm->anyFromStateActions() ) { - out << - " switch ( " << ARR_REF( fromStateActions ) << "[" << vCS() << "] ) {\n"; - FROM_STATE_ACTION_SWITCH() << - " }\n" - "\n"; - } -} - -void ActExp::REG_ACTIONS( std::string cond ) -{ - out << - " switch ( " << ARR_REF( condActions ) << "[" << cond << "] ) {\n"; - ACTION_SWITCH() << - " }\n" - "\n"; -} -void ActExp::TO_STATE_ACTIONS() -{ - if ( redFsm->anyToStateActions() ) { - out << - " switch ( " << ARR_REF( toStateActions ) << "[" << vCS() << "] ) {\n"; - TO_STATE_ACTION_SWITCH() << - " }\n" - "\n"; - } -} - - -void ActExp::EOF_ACTIONS() -{ - if ( redFsm->anyEofActions() ) { - out << - " switch ( " << ARR_REF( eofActions ) << "[" << vCS() << "] ) {\n"; - EOF_ACTION_SWITCH() << - " }\n"; - } -} - -void ActExp::NFA_FROM_STATE_ACTION_EXEC() -{ - if ( redFsm->anyFromStateActions() ) { - out << - " switch ( " << ARR_REF( fromStateActions ) << "[nfa_bp[nfa_len].state] ) {\n"; - FROM_STATE_ACTION_SWITCH() << - " }\n" - "\n"; - } -} - diff --git a/src/actloop.cc b/src/actloop.cc deleted file mode 100644 index 675e78fa..00000000 --- a/src/actloop.cc +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2018-2018 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 "actloop.h" -#include "redfsm.h" -#include "gendata.h" - -void ActLoop::FROM_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->fromStateAction != 0 ) - act = state->fromStateAction->location+1; - fromStateActions.value( act ); -} - -void ActLoop::COND_ACTION( RedCondPair *cond ) -{ - int act = 0; - if ( cond->action != 0 ) - act = cond->action->location+1; - condActions.value( act ); -} - -void ActLoop::TO_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->toStateAction != 0 ) - act = state->toStateAction->location+1; - toStateActions.value( act ); -} - -void ActLoop::EOF_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->eofAction != 0 ) - act = state->eofAction->location+1; - eofActions.value( act ); -} - -void ActLoop::NFA_PUSH_ACTION( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->push != 0 ) - act = targ->push->actListId+1; - nfaPushActions.value( act ); -} - -void ActLoop::NFA_POP_TEST( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->popTest != 0 ) - act = targ->popTest->actListId+1; - nfaPopTrans.value( act ); -} - -std::ostream &ActLoop::FROM_STATE_ACTION_SWITCH() -{ - /* Walk the list of functions, printing the cases. */ - for ( GenActionList::Iter act = red->actionList; act.lte(); act++ ) { - /* Write out referenced actions. */ - if ( act->numFromStateRefs > 0 ) { - /* Write the case label, the action and the case break. */ - out << "\t " << CASE( STR( act->actionId ) ) << " {\n"; - ACTION( out, act, IlOpts( 0, false, false ) ); - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - -std::ostream &ActLoop::ACTION_SWITCH() -{ - /* Walk the list of functions, printing the cases. */ - for ( GenActionList::Iter act = red->actionList; act.lte(); act++ ) { - /* Write out referenced actions. */ - if ( act->numTransRefs > 0 ) { - /* Write the case label, the action and the case break. */ - out << "\t " << CASE( STR( act->actionId ) ) << " {\n"; - ACTION( out, act, IlOpts( 0, false, false ) ); - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - -std::ostream &ActLoop::TO_STATE_ACTION_SWITCH() -{ - /* Walk the list of functions, printing the cases. */ - for ( GenActionList::Iter act = red->actionList; act.lte(); act++ ) { - /* Write out referenced actions. */ - if ( act->numToStateRefs > 0 ) { - /* Write the case label, the action and the case break. */ - out << "\t " << CASE( STR( act->actionId ) ) << " {\n"; - ACTION( out, act, IlOpts( 0, false, false ) ); - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - - -std::ostream &ActLoop::EOF_ACTION_SWITCH() -{ - /* Walk the list of functions, printing the cases. */ - for ( GenActionList::Iter act = red->actionList; act.lte(); act++ ) { - /* Write out referenced actions. */ - if ( act->numEofRefs > 0 ) { - /* Write the case label, the action and the case break. */ - out << "\t " << CASE( STR( act->actionId ) ) << " {\n"; - ACTION( out, act, IlOpts( 0, true, false ) ); - out << "\n\t" << CEND() << "\n}\n"; - } - } - - return out; -} - - - -void ActLoop::FROM_STATE_ACTIONS() -{ - if ( redFsm->anyFromStateActions() ) { - out << - " " << acts << " = " << OFFSET( ARR_REF( actions ), ARR_REF( fromStateActions ) + "[" + vCS() + "]" ) << ";\n" - " " << nacts << " = " << CAST(UINT()) << DEREF( ARR_REF( actions ), "" + acts.ref() + "" ) << ";\n" - " " << acts << " += 1;\n" - " while ( " << nacts << " > 0 ) {\n" - " switch ( " << DEREF( ARR_REF( actions ), "" + acts.ref() + "" ) << " ) {\n"; - FROM_STATE_ACTION_SWITCH() << - " }\n" - " " << nacts << " -= 1;\n" - " " << acts << " += 1;\n" - " }\n" - "\n"; - } -} - -void ActLoop::REG_ACTIONS( std::string cond ) -{ - out << - " " << acts << " = " << OFFSET( ARR_REF( actions ), ARR_REF( condActions ) + "[" + cond + "]" ) << ";\n" - " " << nacts << " = " << CAST( UINT() ) << DEREF( ARR_REF( actions ), "" + acts.ref() + "" ) << ";\n" - " " << acts << " += 1;\n" - " while ( " << nacts << " > 0 ) {\n" - " switch ( " << DEREF( ARR_REF( actions ), "" + acts.ref() + "" ) << " )\n" - " {\n"; - ACTION_SWITCH() << - " }\n" - " " << nacts << " -= 1;\n" - " " << acts << " += 1;\n" - " }\n" - "\n"; -} - -void ActLoop::TO_STATE_ACTIONS() -{ - if ( redFsm->anyToStateActions() ) { - out << - " " << acts << " = " << OFFSET( ARR_REF( actions ), ARR_REF( toStateActions ) + "[" + vCS() + "]" ) << ";\n" - " " << nacts << " = " << CAST(UINT()) << DEREF( ARR_REF( actions ), acts.ref() ) << ";\n" - " " << acts << " += 1;\n" - " while ( " << nacts << " > 0 ) {\n" - " switch ( " << DEREF( ARR_REF( actions ), acts.ref() ) << " ) {\n"; - TO_STATE_ACTION_SWITCH() << - " }\n" - " " << nacts << " -= 1;\n" - " " << acts << " += 1;\n" - " }\n" - "\n"; - } -} - -void ActLoop::EOF_ACTIONS() -{ - if ( redFsm->anyEofActions() ) { - out << - " " << acts << " = " << OFFSET( ARR_REF( actions ), ARR_REF( eofActions ) + "[" + vCS() + "]" ) << ";\n" - " " << nacts << " = " << CAST(UINT()) << DEREF( ARR_REF( actions ), acts.ref() ) << ";\n" - " " << acts << " += 1;\n" - " while ( " << nacts << " > 0 ) {\n" - " switch ( " << DEREF( ARR_REF( actions ), acts.ref() ) << " ) {\n"; - EOF_ACTION_SWITCH() << - " }\n" - " " << nacts << " -= 1;\n" - " " << acts << " += 1;\n" - " }\n"; - } -} - -void ActLoop::NFA_FROM_STATE_ACTION_EXEC() -{ - if ( redFsm->anyFromStateActions() ) { - out << - " " << acts << " = " << OFFSET( ARR_REF( actions ), ARR_REF( fromStateActions ) + "[nfa_bp[nfa_len].state]" ) << ";\n" - " " << nacts << " = " << CAST( UINT() ) << DEREF( ARR_REF( actions ), acts.ref() ) << ";\n" - " " << acts << " += 1;\n" - " while ( " << nacts << " > 0 ) {\n" - " switch ( " << DEREF( ARR_REF( actions ), acts.ref() ) << " ) {\n"; - FROM_STATE_ACTION_SWITCH() << - " }\n" - " " << nacts << " -= 1;\n" - " " << acts << " += 1;\n" - " }\n" - "\n"; - } -} - diff --git a/src/asm.cc b/src/asm.cc deleted file mode 100644 index ca9f5d65..00000000 --- a/src/asm.cc +++ /dev/null @@ -1,2047 +0,0 @@ -/* - * Copyright 2014-2018 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 "ragel.h" -#include "asm.h" -#include "redfsm.h" -#include "gendata.h" -#include "bstmap.h" -#include "ragel.h" -#include "redfsm.h" -#include "bstmap.h" -#include "gendata.h" -#include "parsedata.h" -#include "inputdata.h" -#include <sstream> - -using std::ostream; -using std::ostringstream; -using std::string; -using std::endl; -using std::istream; -using std::ifstream; -using std::ostream; -using std::ios; -using std::cin; -using std::endl; - -extern int numSplitPartitions; -bool printStatistics = false; - -/* Enables transition logging in the form that score-based state sorting can - * processes. This bit of code is intended to increase locality and reduce - * cache misses. Gains are minimal, 1-2%. */ -// #define LOG_TRANS 1 - -void asmLineDirective( ostream &out, const char *fileName, int line ) -{ - /* Write the preprocessor line info for to the input file. */ - out << "#line " << line << " \""; - for ( const char *pc = fileName; *pc != 0; pc++ ) { - if ( *pc == '\\' ) - out << "\\\\"; - else - out << *pc; - } - out << '"'; - - out << '\n'; -} - -/* Init code gen with in parameters. */ -AsmCodeGen::AsmCodeGen( const CodeGenArgs &args ) -: - CodeGenData( args ), - nextLmSwitchLabel( 1 ), - stackCS( false ) -{ -} - -void AsmCodeGen::genAnalysis() -{ - /* For directly executable machines there is no required state - * ordering. Choose a depth-first ordering to increase the - * potential for fall-throughs. */ - redFsm->depthFirstOrdering(); - - /* Choose default transitions and make the flat transitions by character class. */ - redFsm->chooseDefaultSpan(); - redFsm->makeFlatClass(); - - /* If any errors have occured in the input file then don't write anything. */ - if ( red->id->errorCount > 0 ) - return; - - redFsm->setInTrans(); - - /* Anlayze Machine will find the final action reference counts, among other - * things. We will use these in reporting the usage of fsm directives in - * action code. */ - red->analyzeMachine(); -} - -/* Write out the fsm name. */ -string AsmCodeGen::FSM_NAME() -{ - return fsmName; -} - -/* Emit the offset of the start state as a decimal integer. */ -string AsmCodeGen::START_STATE_ID() -{ - ostringstream ret; - ret << redFsm->startState->id; - return ret.str(); -}; - -string AsmCodeGen::ACCESS() -{ - ostringstream ret; - if ( red->accessExpr != 0 ) - INLINE_LIST( ret, red->accessExpr, 0, false, false ); - return ret.str(); -} - - -string AsmCodeGen::P() -{ - ostringstream ret; - if ( red->pExpr == 0 ) - ret << "%r12"; - else { - INLINE_LIST( ret, red->pExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::PE() -{ - ostringstream ret; - if ( red->peExpr == 0 ) - ret << "%r13"; - else { - INLINE_LIST( ret, red->peExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::vCS() -{ - ostringstream ret; - if ( red->csExpr == 0 ) { - if ( stackCS ) - ret << "-48(%rbp)"; - else - ret << "%r11"; - } - else { - INLINE_LIST( ret, red->csExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::TOP() -{ - ostringstream ret; - if ( red->topExpr == 0 ) - ret << "-64(%rbp)"; - else { - ret << "("; - INLINE_LIST( ret, red->topExpr, 0, false, false ); - ret << ")"; - } - return ret.str(); -} - -string AsmCodeGen::NFA_STACK() -{ - return string( "-80(%rbp)" ); -} - -string AsmCodeGen::NFA_TOP() -{ - return string( "-88(%rbp)" ); -} - -string AsmCodeGen::NFA_SZ() -{ - return string( "-96(%rbp)" ); -} - -string AsmCodeGen::STACK() -{ - ostringstream ret; - if ( red->stackExpr == 0 ) - ret << "-56(%rbp)"; - else { - ret << "("; - INLINE_LIST( ret, red->stackExpr, 0, false, false ); - ret << ")"; - } - return ret.str(); -} - -string AsmCodeGen::vEOF() -{ - ostringstream ret; - if ( red->eofExpr == 0 ) - ret << "-8(%rbp)"; - else { - INLINE_LIST( ret, red->eofExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::TOKSTART() -{ - ostringstream ret; - if ( red->tokstartExpr == 0 ) - ret << "-16(%rbp)"; - else { - INLINE_LIST( ret, red->tokstartExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::TOKEND() -{ - ostringstream ret; - if ( red->tokendExpr == 0 ) - ret << "-24(%rbp)"; - else { - INLINE_LIST( ret, red->tokendExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::ACT() -{ - ostringstream ret; - if ( red->actExpr == 0 ) - ret << "-32(%rbp)"; - else { - INLINE_LIST( ret, red->actExpr, 0, false, false ); - } - return ret.str(); -} - -string AsmCodeGen::NBREAK() -{ - return string("-33(%rbp)"); -} - -string AsmCodeGen::GET_KEY() -{ - ostringstream ret; - if ( red->getKeyExpr != 0 ) { - /* Emit the user supplied method of retrieving the key. */ - ret << "("; - INLINE_LIST( ret, red->getKeyExpr, 0, false, false ); - ret << ")"; - } - else { - /* Expression for retrieving the key, use simple dereference. */ - ret << "(" << P() << ")"; - } - return ret.str(); -} - -string AsmCodeGen::COND_KEY( CondKey key ) -{ - ostringstream ret; - ret << "$" << key.getVal(); - return ret.str(); -} - - -/* Write out a key from the fsm code gen. Depends on wether or not the key is - * signed. */ -string AsmCodeGen::KEY( Key key ) -{ - ostringstream ret; - ret << "$" << key.getVal(); - return ret.str(); -} - -bool AsmCodeGen::isAlphTypeSigned() -{ - return keyOps->isSigned; -} - -void AsmCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish ) -{ - /* The parser gives fexec two children. The double brackets are for D - * code. If the inline list is a single word it will get interpreted as a - * C-style cast by the D compiler. */ - - ret << - " subq $1, "; - INLINE_LIST( ret, item->children, targState, inFinish, false ); - ret << - "\n" - " movq "; - INLINE_LIST( ret, item->children, targState, inFinish, false ); - ret << ", " << P() << "\n"; -} - -void AsmCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, - int targState, int inFinish, bool csForced ) -{ - long done = nextLmSwitchLabel++; - - ret << - " movq " << ACT() << ", %rax\n"; - - for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) { - long l = nextLmSwitchLabel++; - - /* Write the case label, the action and the case break. */ - if ( lma->lmId < 0 ) { - } - else { - ret << - " cmpq $" << lma->lmId << ", %rax\n" - " jne " << LABEL( "lm_switch_next", l ) << "\n"; - } - - INLINE_LIST( ret, lma->children, targState, inFinish, csForced ); - - ret << - " jmp " << LABEL( "lm_done", done ) << "\n" - "" << LABEL( "lm_switch_next", l ) << ":\n"; - } - - ret << - "" << LABEL( "lm_done", done ) << ":\n"; -} - -void AsmCodeGen::SET_ACT( ostream &ret, GenInlineItem *item ) -{ - ret << - " movq $" << item->lmId << ", " << ACT() << "\n"; -} - -void AsmCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item ) -{ - /* Sets tokend, there may be an offset. */ - ret << - " movq " << P() << ", %rax\n"; - - if ( item->offset != 0 ) { - out << - " addq $" << item->offset << ", %rax\n"; - } - - out << - " movq %rax, " << TOKEND() << "\n"; -} - -void AsmCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item ) -{ - ret << - " movq " << TOKEND() << ", " << "%rax\n"; -} - -void AsmCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item ) -{ - ret << - " movq $0, " << TOKSTART() << "\n"; -} - -void AsmCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item ) -{ - ret << - " movq $0, " << ACT() << "\n"; -} - -void AsmCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item ) -{ - ret << - " movq " << P() << ", " << TOKSTART() << "\n"; -} - -void AsmCodeGen::HOST_STMT( ostream &ret, GenInlineItem *item, - int targState, bool inFinish, bool csForced ) -{ - if ( item->children->length() > 0 ) { - /* Write the block and close it off. */ - INLINE_LIST( ret, item->children, targState, inFinish, csForced ); - } -} - -void AsmCodeGen::HOST_EXPR( ostream &ret, GenInlineItem *item, - int targState, bool inFinish, bool csForced ) -{ - if ( item->children->length() > 0 ) { - /* Write the block and close it off. */ - INLINE_LIST( ret, item->children, targState, inFinish, csForced ); - } -} - -void AsmCodeGen::HOST_TEXT( ostream &ret, GenInlineItem *item, - int targState, bool inFinish, bool csForced ) -{ - if ( item->children->length() > 0 ) { - /* Write the block and close it off. */ - INLINE_LIST( ret, item->children, targState, inFinish, csForced ); - } -} - -void AsmCodeGen::GEN_STMT( ostream &ret, GenInlineItem *item, - int targState, bool inFinish, bool csForced ) -{ - if ( item->children->length() > 0 ) { - /* Write the block and close it off. */ - INLINE_LIST( ret, item->children, targState, inFinish, csForced ); - } -} - -void AsmCodeGen::GEN_EXPR( ostream &ret, GenInlineItem *item, - int targState, bool inFinish, bool csForced ) -{ - if ( item->children->length() > 0 ) { - /* Write the block and close it off. */ - INLINE_LIST( ret, item->children, targState, inFinish, csForced ); - } -} - -void AsmCodeGen::LM_EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish ) -{ - /* The parser gives fexec two children. The double brackets are for D code. - * If the inline list is a single word it will get interpreted as a C-style - * cast by the D compiler. This should be in the D code generator. */ - INLINE_LIST( ret, item->children, targState, inFinish, false ); - - ret << - " movq %rax, " << P() << "\n" - " subq $1, " << P() << "\n"; -} - -void AsmCodeGen::NBREAK( ostream &ret, int targState, bool csForced ) -{ - outLabelUsed = true; - ret << - " addq $1, " << P() << "\n"; - - if ( !csForced ) { - ret << - " movq $" << targState << ", " << vCS() << "\n"; - } - - ret << - " movb $1, " << NBREAK() << "\n" - " jmp " << LABEL( "pop" ) << "\n"; -} - -/* Write out an inline tree structure. Walks the list and possibly calls out - * to virtual functions than handle language specific items in the tree. */ -void AsmCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList, - int targState, bool inFinish, bool csForced ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - switch ( item->type ) { - case GenInlineItem::Text: - ret << item->data; - break; - case GenInlineItem::Goto: - GOTO( ret, item->targState->id, inFinish ); - break; - case GenInlineItem::Call: - CALL( ret, item->targState->id, targState, inFinish ); - break; - case GenInlineItem::Next: - NEXT( ret, item->targState->id, inFinish ); - break; - case GenInlineItem::Ret: - RET( ret, inFinish ); - break; - case GenInlineItem::PChar: - ret << P(); - break; - case GenInlineItem::Char: - ret << GET_KEY(); - break; - case GenInlineItem::Hold: - ret << - " subq $1, " << P() << "\n"; - break; - case GenInlineItem::Exec: - EXEC( ret, item, targState, inFinish ); - break; - case GenInlineItem::Curs: - CURS( ret, inFinish ); - break; - case GenInlineItem::Targs: - TARGS( ret, inFinish, targState ); - break; - case GenInlineItem::Entry: - ret << item->targState->id; - break; - case GenInlineItem::GotoExpr: - GOTO_EXPR( ret, item, inFinish ); - break; - case GenInlineItem::CallExpr: - CALL_EXPR( ret, item, targState, inFinish ); - break; - case GenInlineItem::NextExpr: - NEXT_EXPR( ret, item, inFinish ); - break; - case GenInlineItem::LmSwitch: - LM_SWITCH( ret, item, targState, inFinish, csForced ); - break; - case GenInlineItem::LmSetActId: - SET_ACT( ret, item ); - break; - case GenInlineItem::LmSetTokEnd: - SET_TOKEND( ret, item ); - break; - case GenInlineItem::LmGetTokEnd: - GET_TOKEND( ret, item ); - break; - case GenInlineItem::LmInitTokStart: - INIT_TOKSTART( ret, item ); - break; - case GenInlineItem::LmInitAct: - INIT_ACT( ret, item ); - break; - case GenInlineItem::LmSetTokStart: - SET_TOKSTART( ret, item ); - break; - case GenInlineItem::Break: - BREAK( ret, targState, csForced ); - break; - /* Stubbed. */ - case GenInlineItem::Ncall: - NCALL( ret, item->targState->id, targState, inFinish ); - break; - case GenInlineItem::NcallExpr: - NCALL_EXPR( ret, item, targState, inFinish ); - break; - case GenInlineItem::Nret: - NRET( ret, inFinish ); - break; - case GenInlineItem::Nbreak: - NBREAK( ret, targState, csForced ); - break; - case GenInlineItem::LmCase: - break; - - case GenInlineItem::LmExec: - LM_EXEC( ret, item, targState, inFinish ); - break; - - case GenInlineItem::LmHold: - ret << - " subq $1, " << P() << "\n"; - break; - case GenInlineItem::NfaClear: - ret << - " movq $0, " << NFA_TOP() << "\n"; - break; - - case GenInlineItem::HostStmt: - HOST_STMT( ret, item, targState, inFinish, csForced ); - break; - case GenInlineItem::HostExpr: - HOST_EXPR( ret, item, targState, inFinish, csForced ); - break; - case GenInlineItem::HostText: - HOST_TEXT( ret, item, targState, inFinish, csForced ); - break; - case GenInlineItem::GenStmt: - GEN_STMT( ret, item, targState, inFinish, csForced ); - break; - case GenInlineItem::GenExpr: - GEN_EXPR( ret, item, targState, inFinish, csForced ); - break; - /* Handled at the top level. */ - case GenInlineItem::NfaWrapAction: - case GenInlineItem::NfaWrapConds: - break; - } - } -} -/* Write out paths in line directives. Escapes any special characters. */ -string AsmCodeGen::LDIR_PATH( char *path ) -{ - ostringstream ret; - for ( char *pc = path; *pc != 0; pc++ ) { - if ( *pc == '\\' ) - ret << "\\\\"; - else - ret << *pc; - } - return ret.str(); -} - -void AsmCodeGen::ACTION( ostream &ret, GenAction *action, int targState, - bool inFinish, bool csForced ) -{ - /* Write the preprocessor line info for going into the source file. */ - asmLineDirective( ret, action->loc.fileName, action->loc.line ); - - /* Write the block and close it off. */ - INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced ); -} - -void AsmCodeGen::CONDITION( ostream &ret, GenAction *condition ) -{ - ret << "\n"; - asmLineDirective( ret, condition->loc.fileName, condition->loc.line ); - INLINE_LIST( ret, condition->inlineList, 0, false, false ); -} - -bool singleItem( GenAction *action, GenInlineItem::Type type ) -{ - return action->inlineList->length() == 1 && - action->inlineList->head->type == type; -} - -void AsmCodeGen::NFA_CONDITION( ostream &ret, GenAction *condition, bool last ) -{ - if ( singleItem( condition, GenInlineItem::NfaWrapAction ) ) - { - GenAction *action = condition->inlineList->head->wrappedAction; - ACTION( out, action, 0, false, false ); - } - else if ( singleItem( condition, GenInlineItem::NfaWrapConds ) ) - { - GenCondSpace *condSpace = condition->inlineList->head->condSpace; - const CondKeySet &condKeySet = condition->inlineList->head->condKeySet; - - out << " movq $0, %r9\n"; - for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { - out << - " pushq %r9\n"; - - CONDITION( out, *csi ); - out << - "\n" - " test %eax, %eax\n" - " setne %cl\n" - " movsbq %cl, %rcx\n" - " salq $" << csi.pos() << ", %rcx\n" - " popq %r9\n" - " addq %rcx, %r9\n"; - } - - for ( int c = 0; c < condKeySet.length(); c++ ) { - CondKey key = condKeySet[c]; - out << - " cmpq " << COND_KEY( key ) << ", %r9\n" - " je 102f\n"; - } - - out << - " jmp " << LABEL( "pop_fail" ) << "\n" - "102:\n"; - } - else { - CONDITION( ret, condition ); - out << - " test %eax, %eax\n" - " jz " << LABEL( "pop_fail" ) << "\n"; - } -} - -string AsmCodeGen::ERROR_STATE() -{ - ostringstream ret; - if ( redFsm->errState != 0 ) - ret << redFsm->errState->id; - else - ret << "-1"; - return ret.str(); -} - -string AsmCodeGen::FIRST_FINAL_STATE() -{ - ostringstream ret; - if ( redFsm->firstFinState != 0 ) - ret << redFsm->firstFinState->id; - else - ret << redFsm->nextStateId; - return ret.str(); -} - -void AsmCodeGen::writeInit() -{ - if ( !noCS ) { - /* Don't use vCS here. vCS may assumes CS needs to be on the stack. - * Just use the interface register. */ - out << - " movq $" << redFsm->startState->id << ", %r11\n"; - } - - if ( redFsm->anyNfaStates() ) { - out << - " movq $0, " << NFA_TOP() << "\n"; - } - - /* If there are any calls, then the stack top needs initialization. */ - if ( redFsm->anyActionCalls() || redFsm->anyActionRets() ) { - out << - " movq $0, " << TOP() << "\n"; - } - - if ( red->hasLongestMatch ) { - out << - " movq $0, " << TOKSTART() << "\n" - " movq $0, " << TOKEND() << "\n" - " movq $0, " << ACT() << "\n"; - } -} - -string AsmCodeGen::DATA_PREFIX() -{ - if ( !noPrefix ) - return FSM_NAME() + "_"; - return ""; -} - -/* Emit the alphabet data type. */ -string AsmCodeGen::ALPH_TYPE() -{ - string ret = alphType->data1; - if ( alphType->data2 != 0 ) { - ret += " "; - ret += + alphType->data2; - } - return ret; -} - -void AsmCodeGen::STATIC_CONST_INT( const string &name, const string &value ) -{ - out << - " .align 8\n" - " .type " << name << ", @object\n" - " .size " << name << ", 8\n" << - name << ":\n" - " .long " << value << "\n"; -} - -void AsmCodeGen::STATE_IDS() -{ - if ( redFsm->startState != 0 ) - STATIC_CONST_INT( START(), START_STATE_ID() ); - - if ( !noFinal ) - STATIC_CONST_INT( FIRST_FINAL(), FIRST_FINAL_STATE() ); - - if ( !noError ) - STATIC_CONST_INT( ERROR(), ERROR_STATE() ); - - out << "\n"; - - if ( red->entryPointNames.length() > 0 ) { - for ( EntryNameVect::Iter en = red->entryPointNames; en.lte(); en++ ) { - ostringstream ret; - ret << redFsm->startState->id; - - STATIC_CONST_INT( string( DATA_PREFIX() + "en_" + *en ), - ret.str() ); - } - out << "\n"; - } -} - -void AsmCodeGen::writeStart() -{ - out << START_STATE_ID(); -} - -void AsmCodeGen::writeFirstFinal() -{ - out << FIRST_FINAL_STATE(); -} - -void AsmCodeGen::writeError() -{ - out << ERROR_STATE(); -} - -string AsmCodeGen::PTR_CONST() -{ - return "const "; -} - -string AsmCodeGen::PTR_CONST_END() -{ - return ""; -} - -std::ostream &AsmCodeGen::OPEN_ARRAY( string type, string name ) -{ - out << "static const " << type << " " << name << "[] = {\n"; - return out; -} - -std::ostream &AsmCodeGen::CLOSE_ARRAY() -{ - return out << "};\n"; -} - -std::ostream &AsmCodeGen::STATIC_VAR( string type, string name ) -{ - out << "static const " << type << " " << name; - return out; -} - -string AsmCodeGen::UINT( ) -{ - return "unsigned int"; -} - -string AsmCodeGen::ARR_OFF( string ptr, string offset ) -{ - return ptr + " + " + offset; -} - -string AsmCodeGen::CAST( string type ) -{ - return "(" + type + ")"; -} - -string AsmCodeGen::NULL_ITEM() -{ - return "0"; -} - -string AsmCodeGen::POINTER() -{ - return " *"; -} - -std::ostream &AsmCodeGen::SWITCH_DEFAULT() -{ - return out; -} - -string AsmCodeGen::CTRL_FLOW() -{ - return ""; -} - -void AsmCodeGen::writeExports() -{ - if ( red->exportList.length() > 0 ) { - for ( ExportList::Iter ex = red->exportList; ex.lte(); ex++ ) { - out << "#define " << DATA_PREFIX() << "ex_" << ex->name << " " << - KEY(ex->key) << "\n"; - } - out << "\n"; - } -} - -string AsmCodeGen::LABEL( const char *type, long i ) -{ - std::stringstream s; - s << ".L" << red->machineId << "_" << type << "_" << i; - return s.str(); -} - -string AsmCodeGen::LABEL( const char *name ) -{ - std::stringstream s; - s << ".L" << red->machineId << "_" << name; - return s.str(); -} - -void AsmCodeGen::emitSingleIfElseIf( RedStateAp *state ) -{ - /* Load up the singles. */ - int numSingles = state->outSingle.length(); - RedTransEl *data = state->outSingle.data; - - /* Write out the single indices. */ - for ( int j = 0; j < numSingles; j++ ) { - out << - " cmpb " << KEY( data[j].lowKey ) << ", %r10b\n" - " je " << TRANS_GOTO_TARG( data[j].value ) << "\n"; - } -} - -void AsmCodeGen::emitSingleJumpTable( RedStateAp *state, string def ) -{ - int numSingles = state->outSingle.length(); - RedTransEl *data = state->outSingle.data; - - long long low = data[0].lowKey.getVal(); - long long high = data[numSingles-1].lowKey.getVal(); - - if ( def.size() == 0 ) - def = LABEL( "sjf", state->id ); - - out << - " movzbq %r10b, %rax\n" - " subq $" << low << ", %rax\n" - " cmpq $" << (high - low) << ", %rax\n" - " ja " << def << "\n" - " leaq " << LABEL( "sjt", state->id ) << "(%rip), %rcx\n" - " movslq (%rcx,%rax,4), %rdx\n" - " addq %rcx, %rdx\n" - " jmp *%rdx\n" - " .section .rodata\n" - " .align 4\n" - << LABEL( "sjt", state->id ) << ":\n"; - - for ( long long j = 0; j < numSingles; j++ ) { - /* Fill in gap between prev and this. */ - if ( j > 0 ) { - long long span = keyOps->span( data[j-1].lowKey, data[j].lowKey ) - 2; - for ( long long k = 0; k < span; k++ ) { - out << " .long " << def << " - " << - LABEL( "sjt", state->id ) << "\n"; - } - } - - out << " .long " << TRANS_GOTO_TARG( data[j].value ) << " - " << - LABEL( "sjt", state->id ) << "\n"; - } - - out << - " .text\n" - "" << LABEL( "sjf", state->id ) << ":\n"; -} - - -void AsmCodeGen::emitRangeBSearch( RedStateAp *state, int low, int high ) -{ - static int nl = 1; - - /* Get the mid position, staying on the lower end of the range. */ - int mid = (low + high) >> 1; - RedTransEl *data = state->outRange.data; - - /* Determine if we need to look higher or lower. */ - bool anyLower = mid > low; - bool anyHigher = mid < high; - - /* Determine if the keys at mid are the limits of the alphabet. */ - bool limitLow = keyOps->eq( data[mid].lowKey, keyOps->minKey ); - bool limitHigh = keyOps->eq( data[mid].highKey, keyOps->maxKey ); - -// string nf = TRANS_GOTO_TARG( state->defTrans ); - - /* For some reason the hop is faster and results in smaller code. Not sure - * why. */ - string nf = LABEL( "nf", state->id ); - - if ( anyLower && anyHigher ) { - int l1 = nl++; - string targ = TRANS_GOTO_TARG( data[mid].value ); - - /* Can go lower and higher than mid. */ - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n" - " jge " << LABEL( "nl", l1 ) << "\n"; - - - emitRangeBSearch( state, low, mid-1 ); - - out << - LABEL( "nl", l1 ) << ":\n"; - - if ( !keyOps->eq( data[mid].lowKey, data[mid].highKey ) ) { - out << - " cmpb " << KEY ( data[mid].highKey ) << ", %r10b\n"; - } - - out << - " jle " << targ << "\n"; - - emitRangeBSearch( state, mid+1, high ); - } - else if ( anyLower && !anyHigher ) { - - string targ; - if ( limitHigh ) - targ = TRANS_GOTO_TARG( data[mid].value ); - else - targ = LABEL( "nl", nl++ ); - - /* Can go lower than mid but not higher. */ - - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n" - " jge " << targ << "\n"; - - emitRangeBSearch( state, low, mid-1 ); - - /* If the higher is the highest in the alphabet then there is no sense - * testing it. */ - if ( !limitHigh ) { - - out << - targ << ":\n"; - - if ( ! keyOps->eq( data[mid].lowKey, data[mid].highKey ) ) { - out << - " cmpb " << KEY ( data[mid].highKey ) << ", %r10b\n"; - } - - out << - " jg " << nf << "\n"; - - TRANS_GOTO( data[mid].value ); - } - } - else if ( !anyLower && anyHigher ) { - string targ; - if ( limitLow ) - targ = TRANS_GOTO_TARG( data[mid].value ); - else - targ = LABEL( "nl", nl++ ); - - /* Can go higher than mid but not lower. */ - - out << - " cmpb " << KEY( data[mid].highKey ) << ", %r10b\n" - " jle " << targ << "\n"; - - emitRangeBSearch( state, mid+1, high ); - - /* If the lower end is the lowest in the alphabet then there is no - * sense testing it. */ - if ( !limitLow ) { - - out << - targ << ":\n"; - - if ( !keyOps->eq( data[mid].lowKey, data[mid].highKey ) ) { - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n"; - } - - out << - " jl " << nf << "\n"; - - TRANS_GOTO( data[mid].value ); - } - } - else { - /* Cannot go higher or lower than mid. It's mid or bust. What - * tests to do depends on limits of alphabet. */ - if ( !limitLow && !limitHigh ) { - - if ( !keyOps->eq( data[mid].lowKey, data[mid].highKey ) ) { - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n" - " jl " << nf << "\n" - " cmpb " << KEY( data[mid].highKey ) << ", %r10b\n" - " jg " << nf << "\n"; - } - else { - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n" - " jne " << nf << "\n"; - } - - TRANS_GOTO( data[mid].value ); - } - else if ( limitLow && !limitHigh ) { - - out << - " cmpb " << KEY( data[mid].highKey ) << ", %r10b\n" - " jg " << nf << "\n"; - - TRANS_GOTO( data[mid].value ); - } - else if ( !limitLow && limitHigh ) { - - out << - " cmpb " << KEY( data[mid].lowKey ) << ", %r10b\n" - " jl " << nf << "\n"; - - TRANS_GOTO( data[mid].value ); - } - else { - /* Both high and low are at the limit. No tests to do. */ - TRANS_GOTO( data[mid].value ); - } - } -} - -void AsmCodeGen::emitCharClassIfElseIf( RedStateAp *st ) -{ - long long span = st->high - st->low + 1; - for ( long long pos = 0; pos < span; pos++ ) { - out << - " cmpb " << KEY( st->low + pos ) << ", %r10b\n" - " je " << TRANS_GOTO_TARG( st->transList[pos] ) << "\n"; - } -} - -void AsmCodeGen::emitCharClassJumpTable( RedStateAp *st, string def ) -{ - long long low = st->low; - long long high = st->high; - - if ( def.size() == 0 ) - def = LABEL( "ccf", st->id ); - - out << - " movzbq %r10b, %rax\n" - " subq $" << low << ", %rax\n" - " cmpq $" << (high - low) << ", %rax\n" - " ja " << def << "\n" - " leaq " << LABEL( "cct", st->id ) << "(%rip), %rcx\n" - " movslq (%rcx,%rax,4), %rdx\n" - " addq %rcx, %rdx\n" - " jmp *%rdx\n" - " .section .rodata\n" - " .align 4\n" - << LABEL( "cct", st->id ) << ":\n"; - - long long span = st->high - st->low + 1; - for ( long long pos = 0; pos < span; pos++ ) { - out << " .long " << TRANS_GOTO_TARG( st->transList[pos] ) << " - " << - LABEL( "cct", st->id ) << "\n"; - } - - out << - " .text\n" - "" << LABEL( "ccf", st->id ) << ":\n"; -} - -void AsmCodeGen::NFA_PUSH( RedStateAp *st ) -{ - if ( st->nfaTargs != 0 && st->nfaTargs->length() > 0 ) { - if ( red->nfaPrePushExpr != 0 ) { - out << " movq $" << st->nfaTargs->length() << ", %rdi\n"; - INLINE_LIST( out, red->nfaPrePushExpr->inlineList, 0, false, false ); - } - - for ( RedNfaTargs::Iter t = *st->nfaTargs; t.lte(); t++ ) { - out << - " movq " << NFA_STACK() << ", %rax\n" - " movq " << NFA_TOP() << ", %rcx\n" - " imulq $24, %rcx\n" - " movq $" << t->state->id << ", 0(%rax,%rcx,)\n" - " movq " << P() << ", 8(%rax,%rcx,)\n"; - - out << - " # pop action id " << t->id << "\n" - " movq $" << t->id << ", 16(%rax,%rcx,)\n"; - - if ( t->push ) { - for ( GenActionTable::Iter item = t->push->key; item.lte(); item++ ) { - ACTION( out, item->value, st->id, false, - t->push->anyNextStmt() ); - out << "\n"; - } - } - - out << - " movq " << NFA_TOP() << ", %rcx\n" - " addq $1, %rcx\n" - " movq %rcx, " << NFA_TOP() << "\n"; - } - } -} - -void AsmCodeGen::STATE_GOTOS() -{ - bool eof = redFsm->anyEofActivity() || redFsm->anyNfaStates(); - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - /* Writing code above state gotos. */ - IN_TRANS_ACTIONS( st ); - - if ( st->labelNeeded ) - out << LABEL( "st", st->id ) << ":\n"; - - - /* need to do this if the transition is an eof transition, or if the action - * contains fexec. Otherwise, no need. */ - if ( eof ) { - out << - " cmpq " << P() << ", " << vEOF() << "\n"; - - if ( st->isFinal ) - out << " je " << LABEL( "out", st->id ) << "\n"; - else - out << " je " << LABEL( "pop", st->id ) << "\n"; - } - - if ( st->toStateAction != 0 ) { - /* Remember that we wrote an action. Write every action in the list. */ - for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ ) { - ACTION( out, item->value, st->id, false, - st->toStateAction->anyNextStmt() ); - out << "\n"; - } - } - - if ( st == redFsm->errState ) { - out << LABEL( "en", st->id ) << ":\n"; - - /* Break out here. */ - outLabelUsed = true; - - out << - " movq $" << st->id << ", " << vCS() << "\n" - " jmp " << LABEL( "pop" ) << "\n"; - } - else { - /* Advance and test buffer pos. */ - if ( st->labelNeeded ) { - out << - " addq $1, " << P() << "\n"; - - } - - /* This is the entry label for starting a run. */ - out << LABEL( "en", st->id ) << ":\n"; - - if ( !noEnd ) { - if ( eof ) { - out << - " cmpq " << P() << ", " << PE() << "\n" - " jne " << LABEL( "nope", st->id ) << "\n" << - " cmpq " << P() << ", " << vEOF() << "\n" - " jne " << LABEL( "out", st->id ) << "\n" << - LABEL( "nope", st->id ) << ":\n"; - } - else { - out << - " cmpq " << P() << ", " << PE() << "\n" - " je " << LABEL( "out", st->id ) << "\n"; - } - } - - NFA_PUSH( st ); - - if ( st->fromStateAction != 0 ) { - /* Remember that we wrote an action. Write every action in the list. */ - for ( GenActionTable::Iter item = st->fromStateAction->key; - item.lte(); item++ ) - { - ACTION( out, item->value, st->id, false, - st->fromStateAction->anyNextStmt() ); - out << "\n"; - } - } - - if ( !noEnd && eof ) { - out << - " cmpq " << P() << ", " << vEOF() << "\n" - " jne " << LABEL( "neofd", st->id ) << "\n"; - - if ( st->eofTrans != 0 ) - TRANS_GOTO( st->eofTrans ); - else { - if ( st->isFinal || !redFsm->anyNfaStates() ) - out << "jmp " << LABEL( "out", st->id ) << "\n"; - else - out << "jmp " << LABEL( "pop", st->id ) << "\n"; - } - - out << - " jmp " << LABEL( "deofd", st->id ) << "\n"; - - out << LABEL( "neofd", st->id ) << ":\n"; - } - - /* Record the prev state if necessary. */ - if ( st->anyRegCurStateRef() ) { - out << - " movq $" << st->id << ", -72(%rbp)\n"; - } - - -#ifdef LOG_TRANS - out << - " movzbl (" << P() << "), %r10d\n" - " movq $" << machineId << ", %rdi\n" - " movq $" << st->id << ", %rsi\n" - " movslq %r10d, %rdx\n" - " call " << LABEL( "log_trans" ) << "\n" - ; -#endif - - /* Load *p. */ - if ( st->transList != 0 ) { - long lowKey = redFsm->lowKey.getVal(); - long highKey = redFsm->highKey.getVal(); - - out << - " movzbl (" << P() << "), %r10d\n" - " cmpl $" << lowKey << ", %r10d\n" - " jl " << LABEL( "nf", st->id ) << "\n" - " cmpl $" << highKey << ", %r10d\n" - " jg " << LABEL( "nf", st->id ) << "\n" - " subl " << KEY( lowKey ) << ", %r10d\n" - " leaq " << LABEL( "char_class" ) << "(%rip), %rcx\n" - " movslq %r10d, %rax\n" - " movb (%rcx, %rax), %r10b\n" - ; - - - long len = ( st->high - st->low + 1 ); - - if ( len < 8 ) - emitCharClassIfElseIf( st ); - else { - string def; - if ( st->outRange.length() == 0 ) - def = TRANS_GOTO_TARG( st->defTrans ); - emitCharClassJumpTable( st, def ); - } - } - - /* Write the default transition. */ - out << LABEL( "nf", st->id ) << ":\n"; - TRANS_GOTO( st->defTrans ); - - if ( !noEnd && eof ) { - out << LABEL( "deofd", st->id) << ":\n"; - } - } - } -} - -unsigned int AsmCodeGen::TO_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->toStateAction != 0 ) - act = state->toStateAction->location+1; - return act; -} - -unsigned int AsmCodeGen::FROM_STATE_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->fromStateAction != 0 ) - act = state->fromStateAction->location+1; - return act; -} - -unsigned int AsmCodeGen::EOF_ACTION( RedStateAp *state ) -{ - int act = 0; - if ( state->eofAction != 0 ) - act = state->eofAction->location+1; - return act; -} - -bool AsmCodeGen::useAgainLabel() -{ - return redFsm->anyActionRets() || - redFsm->anyActionByValControl() || - redFsm->anyRegNextStmt(); -} - -void AsmCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish ) -{ - ret << - " jmp " << LABEL( "st", gotoDest ) << "\n"; -} - -void AsmCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - if ( red->prePushExpr != 0 ) - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - - ret << - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " movq $" << targState << ", (%rax, %rcx, 8)\n" - " addq $1, %rcx\n" - " movq %rcx, " << TOP() << "\n" - ; - - ret << - " jmp " << LABEL( "st", callDest ) << "\n"; - ; -} - -void AsmCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - if ( red->prePushExpr != 0 ) - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - - ret << - "\n" - " movq "; - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << ", %rdx\n" - "\n" - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " movq $" << targState << ", (%rax, %rcx, 8)\n" - " addq $1, %rcx\n" - " movq %rcx, " << TOP() << "\n" - " movq %rdx, " << vCS() << "\n" - ; - - ret << - " jmp " << LABEL( "again" ) << "\n"; -} - -void AsmCodeGen::RET( ostream &ret, bool inFinish ) -{ - ret << - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " subq $1, %rcx\n" - " movq (%rax, %rcx, 8), %rax\n" - " movq %rax, " << vCS() << "\n" - " movq %rcx, " << TOP() << "\n"; - - if ( red->postPopExpr != 0 ) - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - - ret << - " jmp " << LABEL("again") << "\n"; -} - -void AsmCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << " movq "; - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << ", " << vCS() << "\n"; - - ret << - " jmp " << LABEL("again") << "\n"; -} - -void AsmCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish ) -{ - ret << - " movq $" << nextDest << ", " << vCS() << "\n"; -} - -void AsmCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << " movq "; - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << ", " << vCS() << "\n"; -} - -void AsmCodeGen::NCALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - if ( red->prePushExpr != 0 ) - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - - ret << - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " movq $" << targState << ", (%rax, %rcx, 8)\n" - " addq $1, %rcx\n" - " movq %rcx, " << TOP() << "\n" - " movq $" << callDest << ", " << vCS() << "\n"; -} - -void AsmCodeGen::NCALL_EXPR( ostream &ret, GenInlineItem *ilItem, - int targState, bool inFinish ) -{ - if ( red->prePushExpr != 0 ) - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - - ret << - "\n" - " movq "; - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << ", %rdx\n" - "\n" - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " movq $" << targState << ", (%rax, %rcx, 8)\n" - " addq $1, %rcx\n" - " movq %rcx, " << TOP() << "\n" - " movq %rdx, " << vCS() << "\n"; -} - -void AsmCodeGen::NRET( ostream &ret, bool inFinish ) -{ - ret << - " movq " << STACK() << ", %rax\n" - " movq " << TOP() << ", %rcx\n" - " subq $1, %rcx\n" - " movq (%rax, %rcx, 8), %rax\n" - " movq %rax, " << vCS() << "\n" - " movq %rcx, " << TOP() << "\n"; - - if ( red->postPopExpr != 0 ) - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); -} - -void AsmCodeGen::CURS( ostream &ret, bool inFinish ) -{ - ret << - " movq -72(%rbp), %rax\n"; -} - -void AsmCodeGen::TARGS( ostream &ret, bool inFinish, int targState ) -{ - ret << - " movq $" << targState << ", %rax\n"; -} - -void AsmCodeGen::BREAK( ostream &ret, int targState, bool csForced ) -{ - outLabelUsed = true; - ret << "{" << P() << "++; "; - if ( !csForced ) - ret << vCS() << " = " << targState << "; "; - ret << CTRL_FLOW() << "goto _out;}"; -} - -bool AsmCodeGen::IN_TRANS_ACTIONS( RedStateAp *state ) -{ - bool anyWritten = false; - - /* Emit any transitions that have actions and that go to this state. */ - for ( int it = 0; it < state->numInCondTests; it++ ) { - /* Write the label for the transition so it can be jumped to. */ - RedTransAp *trans = state->inCondTests[it]; - out << LABEL( "ctr", trans->id ) << ":\n"; - - if ( trans->condSpace->condSet.length() == 1 ) { - RedCondPair *tp, *fp; - if ( trans->numConds() == 1 ) { - /* The single condition is either false or true, errCond is the - * opposite. */ - if ( trans->outCondKey(0) == 0 ) { - fp = trans->outCond(0); - tp = trans->errCond(); - } - else { - tp = trans->outCond(0); - fp = trans->errCond(); - } - } - else { - /* Full list, goes false, then true. */ - fp = trans->outCond(0); - tp = trans->outCond(1); - } - - GenCondSet::Iter csi = trans->condSpace->condSet; - CONDITION( out, *csi ); - - out << - " test %eax, %eax\n" - " je " << TRANS_GOTO_TARG( fp ) << "\n" - " jmp " << TRANS_GOTO_TARG( tp ) << "\n"; - } - else { - out << " movq $0, %r9\n"; - - for ( GenCondSet::Iter csi = trans->condSpace->condSet; csi.lte(); csi++ ) { - out << - " pushq %r9\n"; - - CONDITION( out, *csi ); - out << - "\n" - " test %eax, %eax\n" - " setne %cl\n" - " movsbq %cl, %rcx\n" - " salq $" << csi.pos() << ", %rcx\n" - " popq %r9\n" - " addq %rcx, %r9\n"; - } - - for ( int c = 0; c < trans->numConds(); c++ ) { - CondKey key = trans->outCondKey( c ); - RedCondPair *pair = trans->outCond( c ); - out << - " cmpq " << COND_KEY( key ) << ", %r9\n" - " je " << TRANS_GOTO_TARG( pair ) << "\n"; - - } - - RedCondPair *err = trans->errCond(); - if ( err != 0 ) { - out << - " jmp " << TRANS_GOTO_TARG( err ) << "\n"; - } - } - } - - /* Emit any transitions that have actions and that go to this state. */ - for ( int it = 0; it < state->numInConds; it++ ) { - RedCondPair *pair = state->inConds[it]; - if ( pair->action != 0 /* && pair->labelNeeded */ ) { - /* Remember that we wrote an action so we know to write the - * line directive for going back to the output. */ - anyWritten = true; - - /* Write the label for the transition so it can be jumped to. */ - out << LABEL( "tr", pair->id ) << ":\n"; - - /* If the action contains a next, then we must preload the current - * state since the action may or may not set it. */ - if ( pair->action->anyNextStmt() ) { - out << - " movq $" << pair->targ->id << ", " << vCS() << "\n"; - } - - if ( redFsm->anyRegNbreak() ) { - out << - " movb $0, " << NBREAK() << "\n"; - } - - /* Write each action in the list. */ - for ( GenActionTable::Iter item = pair->action->key; item.lte(); item++ ) { - ACTION( out, item->value, pair->targ->id, false, - pair->action->anyNextStmt() ); - out << "\n"; - } - - if ( redFsm->anyRegNbreak() ) { - out << - " cmpb $0, " << NBREAK() << "\n" - " jne " << LABEL( "pop" ) << "\n"; - outLabelUsed = true; - } - - - /* If the action contains a next then we need to reload, otherwise - * jump directly to the target state. */ - if ( pair->action->anyNextStmt() ) - out << " jmp " << LABEL( "again" ) << "\n"; - else - out << " jmp " << LABEL( "st", pair->targ->id ) << "\n"; - } - } - - return anyWritten; -} - -std::string AsmCodeGen::TRANS_GOTO_TARG( RedCondPair *pair ) -{ - std::stringstream s; - if ( pair->action != 0 ) { - /* Go to the transition which will go to the state. */ - s << LABEL( "tr", pair->id ); - } - else { - /* Go directly to the target state. */ - s << LABEL( "st", pair->targ->id ); - } - return s.str(); -} - -std::string AsmCodeGen::TRANS_GOTO_TARG( RedTransAp *trans ) -{ - if ( trans->condSpace != 0 ) { - /* Need to jump to the trans since there are conditions. */ - return LABEL( "ctr", trans->id ); - } - else { - return TRANS_GOTO_TARG( &trans->p ); - } -} - -/* Emit the goto to take for a given transition. */ -std::ostream &AsmCodeGen::TRANS_GOTO( RedTransAp *trans ) -{ - out << " jmp " << TRANS_GOTO_TARG( trans ) << "\n"; - return out; -} - -std::ostream &AsmCodeGen::EXIT_STATES() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - out << - LABEL( "out", st->id ) << ":\n" - " movq $" << st->id << ", " << vCS() << "\n" - " jmp " << LABEL( "out" ) << "\n"; - - out << - LABEL( "pop", st->id ) << ":\n" - " movq $" << st->id << ", " << vCS() << "\n" - " jmp " << LABEL( "pop" ) << "\n"; - } - return out; -} - -std::ostream &AsmCodeGen::AGAIN_CASES() -{ - /* Jump into the machine based on the current state. */ - out << - " leaq " << LABEL( "again_jmp" ) << "(%rip), %rcx\n"; - - if ( stackCS ) { - out << - " movq " << vCS() << ", %r11\n"; - } - - out << - " movq (%rcx,%r11,8), %rcx\n" - " jmp *%rcx\n" - " .section .rodata\n" - " .align 8\n" - << LABEL( "again_jmp" ) << ":\n"; - - for ( int stId = 0; stId < redFsm->stateList.length(); stId++ ) { - out << - " .quad " << LABEL( "st", stId ) << "\n"; - } - - out << - " .text\n"; - - return out; -} - -std::ostream &AsmCodeGen::ENTRY_CASES() -{ - out << - " movq (%rcx,%r11,8), %rcx\n" - " jmp *%rcx\n" - " .section .rodata\n" - " .align 8\n" - << LABEL( "entry_jmp" ) << ":\n"; - - for ( int stId = 0; stId < redFsm->stateList.length(); stId++ ) { - out << - " .quad " << LABEL( "en", stId ) << "\n"; - } - - out << - " .text\n"; - return out; -} - - -std::ostream &AsmCodeGen::FINISH_CASES() -{ - /* The current state is in %rax. */ - /*long done = */ nextLmSwitchLabel++; - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofTrans != 0 ) { - out << - " cmpq $" << st->id << ", %rax\n" - " jne " << LABEL( "fc", st->id ) << "\n"; - - if ( st->fromStateAction != 0 ) { - /* Remember that we wrote an action. Write every action in the list. */ - for ( GenActionTable::Iter item = st->fromStateAction->key; - item.lte(); item++ ) - { - ACTION( out, item->value, st->id, false, - st->fromStateAction->anyNextStmt() ); - out << "\n"; - } - } - - out << - " jmp " << TRANS_GOTO_TARG( st->eofTrans ) << "\n" << - LABEL( "fc", st->id ) << ":\n"; - } - } - - return out; -} - -void AsmCodeGen::setLabelsNeeded( GenInlineList *inlineList ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - switch ( item->type ) { - case GenInlineItem::Goto: case GenInlineItem::Call: { - /* Mark the target as needing a label. */ - item->targState->labelNeeded = true; - break; - } - default: break; - } - - if ( item->children != 0 ) - setLabelsNeeded( item->children ); - } -} - -void AsmCodeGen::setLabelsNeeded( RedCondPair *pair ) -{ - /* If there is no action with a next statement, then the label will be - * needed. */ - if ( pair->action == 0 || !pair->action->anyNextStmt() ) - pair->targ->labelNeeded = true; - - /* Need labels for states that have goto or calls in action code - * invoked on characters (ie, not from out action code). */ - if ( pair->action != 0 ) { - /* Loop the actions. */ - for ( GenActionTable::Iter act = pair->action->key; act.lte(); act++ ) { - /* Get the action and walk it's tree. */ - setLabelsNeeded( act->value->inlineList ); - } - } -} - -/* Set up labelNeeded flag for each state. */ -void AsmCodeGen::setLabelsNeeded() -{ - /* If we use the _again label, then we the _again switch, which uses all - * labels. */ - if ( useAgainLabel() ) { - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) - st->labelNeeded = true; - } - else { - /* Do not use all labels by default, init all labelNeeded vars to false. */ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) - st->labelNeeded = false; - - for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) - setLabelsNeeded( &trans->p ); - } - - for ( CondApSet::Iter cond = redFsm->condSet; cond.lte(); cond++ ) - setLabelsNeeded( &cond->p ); - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofAction != 0 ) { - for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ ) - setLabelsNeeded( item->value->inlineList ); - } - } - } - - if ( !noEnd ) { - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) - st->outNeeded = st->labelNeeded; - } -} - -void AsmCodeGen::writeData() -{ - STATE_IDS(); - - long long maxSpan = keyOps->span( redFsm->lowKey, redFsm->highKey ); - - out << - " .type " << LABEL( "char_class" ) << ", @object\n" << - LABEL( "char_class" ) << ":\n"; - - for ( long long pos = 0; pos < maxSpan; pos++ ) { - out << - " .byte " << redFsm->classMap[pos] << "\n"; - } - -#ifdef LOG_TRANS - out << - LABEL( "fmt_log_trans" ) << ":\n" - " .string \"%i %i %i\\n\"\n"; -#endif -} - -void AsmCodeGen::setNfaIds() -{ - long nextId = 1; - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->nfaTargs != 0 ) { - for ( RedNfaTargs::Iter targ = *st->nfaTargs; targ.lte(); targ++ ) { - targ->id = nextId; - nextId += 1; - } - } - } -} - -void AsmCodeGen::writeExec() -{ - /* Must set labels immediately before writing because we may depend on the - * noend write option. */ - setLabelsNeeded(); - testEofUsed = false; - outLabelUsed = false; - - setNfaIds(); - - /* If there are eof actions then we need to run code after exporting the - * final state to vCS. Since the interface register is calee-save, we need - * it to live on the stack. */ - stackCS = redFsm->anyEofActivity(); - - /* - * This code needs 88 bytes of stack (offset 0 from %rbp). - * - * cv : %r9 -- caller-save, used internally, condition char, undefined in - * conditions and actions, can use - * - * pc : %r10b -- caller-save, used internally, undefined in conditions - * actions, can use - * - * cs : %r11 -- caller-save, written by write init, read and - * written by exec, undefined in conditions and actions - * - * p : %r12 -- callee-save, interface, persistent - * - * pe : %r13 -- callee-save, interface, persistent - * - * eof: -8(%rbp) - * - * ts: -16(%rbp) - * - * te: -24(%rbp) - * - * act: -32(%rbp) - * - * _nbreak: -40(%rbp) - * - * stackCS: -48(%rbp) - * - * stack: -56(%rbp) - * top: -64(%rbp) - * - * _ps: -72(%rbp) - * - * nfa_stack -80(%rbp) - * nfa_top -88(%rbp) - * nfa_sz -96(%rbp) - */ - - if ( redFsm->anyRegCurStateRef() ) { - out << - " movq $0, -72(%rbp)\n"; - } - - if ( stackCS ) { - /* Only need a persistent cs in the case of eof actions when exiting the - * block. Where CS lives is a matter of performance though, so we should - * only do this if necessary. */ - out << - " movq %r11, " << vCS() << "\n"; - } - - if ( useAgainLabel() ) { - out << - " jmp " << LABEL( "resume" ) << "\n" - << LABEL( "again" ) << ":\n"; - - AGAIN_CASES(); - } - - if ( useAgainLabel() || redFsm->anyNfaStates() ) - out << LABEL( "resume" ) << ":\n"; - - /* Jump into the machine based on the current state. */ - out << - " leaq " << LABEL( "entry_jmp" ) << "(%rip), %rcx\n"; - - if ( stackCS ) { - out << - " movq " << vCS() << ", %r11\n"; - } - - ENTRY_CASES(); - - STATE_GOTOS(); - - EXIT_STATES(); - - out << LABEL( "pop" ) << ":\n"; - - if ( redFsm->anyNfaStates() ) { - out << - " movq " << NFA_TOP() << ", %rcx\n" - " cmpq $0, %rcx\n" - " je " << LABEL( "nfa_stack_empty" ) << "\n" - " movq " << NFA_TOP() << ", %rcx\n" - " subq $1, %rcx\n" - " movq %rcx, " << NFA_TOP() << "\n" - " movq " << NFA_STACK() << ", %rax\n" - " imulq $24, %rcx\n" - " movq 0(%rax,%rcx,), %r11\n" - " movq 8(%rax,%rcx,), " << P() << "\n" - " movq %r11, " << vCS() << "\n" - ; - - if ( redFsm->bAnyNfaPops ) { - out << - " movq %r11, %r14\n" - " movq 16(%rax,%rcx,), %rax\n"; - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->nfaTargs != 0 ) { - for ( RedNfaTargs::Iter targ = *st->nfaTargs; targ.lte(); targ++ ) { - - /* Write the entry label. */ - out << - " # pop action select\n" - " cmp $" << targ->id << ", %rax\n" - " jne 100f\n"; - - if ( targ->popTest != 0 ) { - /* Write each action in the list of action items. */ - for ( GenActionTable::Iter item = targ->popTest->key; item.lte(); item++ ) - NFA_CONDITION( out, item->value, item.last() ); - } - - out << - " jmp 101f\n" - "100:\n"; - - } - } - } - - out << - "101:\n" - " movq %r14, %r11\n"; - } - - out << - " jmp " << LABEL( "resume" ) << "\n" << - LABEL( "pop_fail" ) << ":\n" - " movq $" << ERROR_STATE() << ", " << vCS() << "\n" - " jmp " << LABEL( "resume" ) << "\n" << - LABEL( "nfa_stack_empty" ) << ":\n"; - } - - if ( stackCS ) { - out << - " movq " << vCS() << ", %r11\n"; - } - - out << - "# WRITE EXEC END\n"; - - out << LABEL( "out" ) << ":\n"; - - if ( stackCS ) { - out << - " movq " << vCS() << ", %r11\n"; - } - -#ifdef LOG_TRANS - out << - " jmp " << LABEL( "skip" ) << "\n" << - LABEL( "log_trans" ) << ":\n" - " movq %rdx, %rcx\n" - " movq %rsi, %rdx\n" - " movq %rdi, %rsi\n" - " movq " << LABEL( "fmt_log_trans" ) << "@GOTPCREL(%rip), %rdi\n" - " movq $0, %rax\n" - " call printf@PLT\n" - " ret\n" << - LABEL( "skip" ) << ":\n" - "\n"; -#endif -} diff --git a/src/buffer.h b/src/buffer.h deleted file mode 100644 index 72bcd5f9..00000000 --- a/src/buffer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2003-2018 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. - */ - -#ifndef _BUFFER_H -#define _BUFFER_H - -#define BUFFER_INITIAL_SIZE 4096 - -/* An automatically grown buffer for collecting tokens. Always reuses space; - * never down resizes. */ -struct Buffer -{ - Buffer() - { - data = (char*) malloc( BUFFER_INITIAL_SIZE ); - allocated = BUFFER_INITIAL_SIZE; - length = 0; - } - ~Buffer() { free(data); } - - void append( char p ) - { - if ( length == allocated ) { - allocated *= 2; - data = (char*) realloc( data, allocated ); - } - data[length++] = p; - } - - void clear() { length = 0; } - - char *data; - int allocated; - int length; -}; - -#endif diff --git a/src/fsmap.cc b/src/fsmap.cc deleted file mode 100644 index e38680f3..00000000 --- a/src/fsmap.cc +++ /dev/null @@ -1,1200 +0,0 @@ -/* - * Copyright 2002-2018 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 "fsmgraph.h" -#include <iostream> -using std::endl; - -/* Insert an action into an action table. */ -void ActionTable::setAction( int ordering, Action *action ) -{ - /* Multi-insert in case specific instances of an action appear in a - * transition more than once. */ - insertMulti( ordering, action ); -} - -/* Set all the action from another action table in this table. */ -void ActionTable::setActions( const ActionTable &other ) -{ - for ( ActionTable::Iter action = other; action.lte(); action++ ) - insertMulti( action->key, action->value ); -} - -void ActionTable::setActions( int *orderings, Action **actions, int nActs ) -{ - for ( int a = 0; a < nActs; a++ ) - insertMulti( orderings[a], actions[a] ); -} - -bool ActionTable::hasAction( Action *action ) -{ - for ( int a = 0; a < length(); a++ ) { - if ( data[a].value == action ) - return true; - } - return false; -} - -/* Insert an action into an action table. */ -void LmActionTable::setAction( int ordering, LongestMatchPart *action ) -{ - /* Multi-insert in case specific instances of an action appear in a - * transition more than once. */ - insertMulti( ordering, action ); -} - -/* Set all the action from another action table in this table. */ -void LmActionTable::setActions( const LmActionTable &other ) -{ - for ( LmActionTable::Iter action = other; action.lte(); action++ ) - insertMulti( action->key, action->value ); -} - -void ErrActionTable::setAction( int ordering, Action *action, int transferPoint ) -{ - insertMulti( ErrActionTableEl( action, ordering, transferPoint ) ); -} - -void ErrActionTable::setActions( const ErrActionTable &other ) -{ - for ( ErrActionTable::Iter act = other; act.lte(); act++ ) - insertMulti( ErrActionTableEl( act->action, act->ordering, act->transferPoint ) ); -} - -/* Insert a priority into this priority table. Looks out for priorities on - * duplicate keys. */ -void PriorTable::setPrior( int ordering, PriorDesc *desc ) -{ - PriorEl *lastHit = 0; - PriorEl *insed = insert( PriorEl(ordering, desc), &lastHit ); - if ( insed == 0 ) { - /* This already has a priority on the same key as desc. Overwrite the - * priority if the ordering is larger (later in time). */ - if ( ordering >= lastHit->ordering ) - *lastHit = PriorEl( ordering, desc ); - } -} - -/* Set all the priorities from a priorTable in this table. */ -void PriorTable::setPriors( const PriorTable &other ) -{ - /* Loop src priorities once to overwrite duplicates. */ - PriorTable::Iter priorIt = other; - for ( ; priorIt.lte(); priorIt++ ) - setPrior( priorIt->ordering, priorIt->desc ); -} - -/* Set the priority of starting transitions. Isolates the start state so it has - * no other entry points, then sets the priorities of all the transitions out - * of the start state. If the start state is final, then the outPrior of the - * start state is also set. The idea is that a machine that accepts the null - * string can still specify the starting trans prior for when it accepts the - * null word. */ -void FsmAp::startFsmPrior( int ordering, PriorDesc *prior ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - /* Walk all transitions out of the start state. */ - for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - trans->tdap()->priorTable.setPrior( ordering, prior ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - cond->priorTable.setPrior( ordering, prior ); - } - } - } - - if ( startState->nfaOut != 0 ) { - for ( NfaTransList::Iter na = *startState->nfaOut; na.lte(); na++ ) - na->priorTable.setPrior( ordering, prior ); - } - - /* If the new start state is final then set the out priority. This follows - * the same convention as setting start action in the out action table of - * a final start state. */ - if ( startState->stateBits & STB_ISFINAL ) - startState->outPriorTable.setPrior( ordering, prior ); - - /* Start fsm priorities are a special case that may require - * minimization afterwards. */ - afterOpMinimize( true ); -} - -/* Set the priority of all transitions in a graph. Walks all transition lists - * and all def transitions. */ -void FsmAp::allTransPrior( int ordering, PriorDesc *prior ) -{ - /* Walk the list of all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Walk the out list of the state. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - trans->tdap()->priorTable.setPrior( ordering, prior ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - cond->priorTable.setPrior( ordering, prior ); - } - } - } - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter na = *state->nfaOut; na.lte(); na++ ) - na->priorTable.setPrior( ordering, prior ); - } - } -} - -/* Set the priority of all transitions that go into a final state. Note that if - * any entry states are final, we will not be setting the priority of any - * transitions that may go into those states in the future. The graph does not - * support pending in transitions in the same way pending out transitions are - * supported. */ -void FsmAp::finishFsmPrior( int ordering, PriorDesc *prior ) -{ - /* Walk all final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) { - /* Walk all in transitions of the final state. */ - for ( TransInList::Iter t = (*state)->inTrans; t.lte(); t++ ) - t->priorTable.setPrior( ordering, prior ); - for ( CondInList::Iter t = (*state)->inCond; t.lte(); t++ ) - t->priorTable.setPrior( ordering, prior ); - - if ( (*state)->nfaIn != 0 ) { - for ( NfaInList::Iter na = *(*state)->nfaIn; na.lte(); na++ ) - na->priorTable.setPrior( ordering, prior ); - } - } -} - -/* Set the priority of any future out transitions that may be made going out of - * this state machine. */ -void FsmAp::leaveFsmPrior( int ordering, PriorDesc *prior ) -{ - /* Set priority in all final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->outPriorTable.setPrior( ordering, prior ); -} - - -/* Set actions to execute on starting transitions. Isolates the start state - * so it has no other entry points, then adds to the transition functions - * of all the transitions out of the start state. If the start state is final, - * then the func is also added to the start state's out func list. The idea is - * that a machine that accepts the null string can execute a start func when it - * matches the null word, which can only be done when leaving the start/final - * state. */ -void FsmAp::startFsmAction( int ordering, Action *action ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - /* Walk the start state's transitions, setting functions. */ - for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - trans->tdap()->actionTable.setAction( ordering, action ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - cond->actionTable.setAction( ordering, action ); - } - } - } - - /* If start state is final then add the action to the out action table. - * This means that when the null string is accepted the start action will - * not be bypassed. */ - if ( startState->stateBits & STB_ISFINAL ) - startState->outActionTable.setAction( ordering, action ); - - if ( startState->nfaOut != 0 ) { - for ( NfaTransList::Iter na = *startState->nfaOut; na.lte(); na++ ) { - - StateAp *state = na->toState; - - /* Walk the start state's transitions, setting functions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - trans->tdap()->actionTable.setAction( ordering, action ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - cond->actionTable.setAction( ordering, action ); - } - } - } - - /* If start state is final then add the action to the out action table. - * This means that when the null string is accepted the start action will - * not be bypassed. */ - if ( state->stateBits & STB_ISFINAL ) - state->outActionTable.setAction( ordering, action ); - - } - } - - afterOpMinimize( true ); -} - -/* Set functions to execute on all transitions. Walks the out lists of all - * states. */ -void FsmAp::allTransAction( int ordering, Action *action ) -{ - /* Walk all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Walk the out list of the state. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - trans->tdap()->actionTable.setAction( ordering, action ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - cond->actionTable.setAction( ordering, action ); - } - } - } - } -} - -/* Specify functions to execute upon entering final states. If the start state - * is final we can't really specify a function to execute upon entering that - * final state the first time. So function really means whenever entering a - * final state from within the same fsm. */ -void FsmAp::finishFsmAction( int ordering, Action *action ) -{ - /* Walk all final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) { - /* Walk the final state's in list. */ - for ( TransInList::Iter t = (*state)->inTrans; t.lte(); t++ ) - t->actionTable.setAction( ordering, action ); - for ( CondInList::Iter t = (*state)->inCond; t.lte(); t++ ) - t->actionTable.setAction( ordering, action ); - } -} - -/* Add functions to any future out transitions that may be made going out of - * this state machine. */ -void FsmAp::leaveFsmAction( int ordering, Action *action ) -{ - /* Insert the action in the outActionTable of all final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->outActionTable.setAction( ordering, action ); -} - -/* Add functions to the longest match action table for constructing scanners. */ -void FsmAp::longMatchAction( int ordering, LongestMatchPart *lmPart ) -{ - /* Walk all final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) { - /* Walk the final state's in list. */ - for ( TransInList::Iter t = (*state)->inTrans; t.lte(); t++ ) - t->lmActionTable.setAction( ordering, lmPart ); - for ( CondInList::Iter t = (*state)->inCond; t.lte(); t++ ) - t->lmActionTable.setAction( ordering, lmPart ); - } -} - -void FsmAp::fillGaps( StateAp *state ) -{ - /* - * First pass fills in the the caps between transitions. - */ - if ( state->outList.length() == 0 ) { - /* Add the range on the lower and upper bound. */ - attachNewTrans( state, 0, ctx->keyOps->minKey, ctx->keyOps->maxKey ); - } - else { - TransList srcList; - srcList.transfer( state->outList ); - - /* Check for a gap at the beginning. */ - TransList::Iter trans = srcList, next; - if ( ctx->keyOps->lt( ctx->keyOps->minKey, trans->lowKey ) ) { - /* Make the high key and append. */ - Key highKey = trans->lowKey; - ctx->keyOps->decrement( highKey ); - - attachNewTrans( state, 0, ctx->keyOps->minKey, highKey ); - } - - /* Write the transition. */ - next = trans.next(); - state->outList.append( trans ); - - /* Keep the last high end. */ - Key lastHigh = trans->highKey; - - /* Loop each source range. */ - for ( trans = next; trans.lte(); trans = next ) { - /* Make the next key following the last range. */ - Key nextKey = lastHigh; - ctx->keyOps->increment( nextKey ); - - /* Check for a gap from last up to here. */ - if ( ctx->keyOps->lt( nextKey, trans->lowKey ) ) { - /* Make the high end of the range that fills the gap. */ - Key highKey = trans->lowKey; - ctx->keyOps->decrement( highKey ); - - attachNewTrans( state, 0, nextKey, highKey ); - } - - /* Reduce the transition. If it reduced to anything then add it. */ - next = trans.next(); - state->outList.append( trans ); - - /* Keep the last high end. */ - lastHigh = trans->highKey; - } - - /* Now check for a gap on the end to fill. */ - if ( ctx->keyOps->lt( lastHigh, ctx->keyOps->maxKey ) ) { - /* Get a copy of the default. */ - ctx->keyOps->increment( lastHigh ); - - attachNewTrans( state, 0, lastHigh, ctx->keyOps->maxKey ); - } - } - - /* - * Second pass fills in gaps in condition lists. - */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) - continue; - - CondList srcList; - srcList.transfer( trans->tcap()->condList ); - - CondList::Iter cond = srcList, next; - - /* Check for gap at the beginning. */ - if ( cond->key > 0 ) { - for ( CondKey key = 0; key < cond->key; key.increment() ) - attachNewCond( trans, state, 0, key ); - } - - next = cond.next(); - trans->tcap()->condList.append( cond ); - - CondKey lastKey = cond->key; - - for ( cond = next; cond.lte(); cond = next ) { - /* Make the next key following the last range. */ - CondKey nextKey = lastKey; - nextKey.increment(); - - /* Check for a gap from last up to here. */ - if ( nextKey < cond->key ) { - for ( CondKey key = nextKey; key < cond->key; key.increment() ) - attachNewCond( trans, state, 0, key ); - } - - next = cond.next(); - trans->tcap()->condList.append( cond ); - - lastKey = cond->key; - } - - CondKey high = (trans->condSpace == 0) ? - 0 : (1 << trans->condSpace->condSet.length()); - - /* Now check for a gap on the end to fill. */ - if ( lastKey < high ) { - /* Get a copy of the default. */ - lastKey.increment(); - - for ( CondKey key = lastKey; key < high; key.increment() ) - attachNewCond( trans, state, 0, key ); - } - } -} - -void FsmAp::setErrorActions( StateAp *state, const ActionTable &other ) -{ - /* Fill any gaps in the out list with an error transition. */ - fillGaps( state ); - - /* Set error transitions in the transitions that go to error. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState == 0 ) - trans->tdap()->actionTable.setActions( other ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState == 0 ) - cond->actionTable.setActions( other ); - } - } - } -} - -void FsmAp::setErrorAction( StateAp *state, int ordering, Action *action ) -{ - /* Fill any gaps in the out list with an error transition. */ - fillGaps( state ); - - /* Set error transitions in the transitions that go to error. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState == 0 ) - trans->tdap()->actionTable.setAction( ordering, action ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState == 0 ) - cond->actionTable.setAction( ordering, action ); - } - } - } -} - - -/* Give a target state for error transitions. */ -void FsmAp::setErrorTarget( StateAp *state, StateAp *target, int *orderings, - Action **actions, int nActs ) -{ - /* Fill any gaps in the out list with an error transition. */ - fillGaps( state ); - - /* Set error target in the transitions that go to error. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState == 0 ) { - /* The trans goes to error, redirect it. */ - redirectErrorTrans( trans->tdap()->fromState, target, trans->tdap() ); - trans->tdap()->actionTable.setActions( orderings, actions, nActs ); - } - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState == 0 ) { - /* The trans goes to error, redirect it. */ - redirectErrorTrans( cond->fromState, target, cond ); - cond->actionTable.setActions( orderings, actions, nActs ); - } - } - } - } -} - -void FsmAp::transferOutActions( StateAp *state ) -{ - for ( ActionTable::Iter act = state->outActionTable; act.lte(); act++ ) - state->eofActionTable.setAction( act->key, act->value ); - state->outActionTable.empty(); -} - -void FsmAp::transferErrorActions( StateAp *state, int transferPoint ) -{ - for ( int i = 0; i < state->errActionTable.length(); ) { - ErrActionTableEl *act = state->errActionTable.data + i; - if ( act->transferPoint == transferPoint ) { - /* Transfer the error action and remove it. */ - setErrorAction( state, act->ordering, act->action ); - if ( ! state->isFinState() ) - state->eofActionTable.setAction( act->ordering, act->action ); - state->errActionTable.vremove( i ); - } - else { - /* Not transfering and deleting, skip over the item. */ - i += 1; - } - } -} - -/* Set error actions in the start state. */ -void FsmAp::startErrorAction( int ordering, Action *action, int transferPoint ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - /* Add the actions. */ - startState->errActionTable.setAction( ordering, action, transferPoint ); - - afterOpMinimize( true ); -} - -/* Set error actions in all states where there is a transition out. */ -void FsmAp::allErrorAction( int ordering, Action *action, int transferPoint ) -{ - /* Insert actions in the error action table of all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - state->errActionTable.setAction( ordering, action, transferPoint ); -} - -/* Set error actions in final states. */ -void FsmAp::finalErrorAction( int ordering, Action *action, int transferPoint ) -{ - /* Add the action to the error table of final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->errActionTable.setAction( ordering, action, transferPoint ); -} - -void FsmAp::notStartErrorAction( int ordering, Action *action, int transferPoint ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState ) - state->errActionTable.setAction( ordering, action, transferPoint ); - } -} - -void FsmAp::notFinalErrorAction( int ordering, Action *action, int transferPoint ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( ! state->isFinState() ) - state->errActionTable.setAction( ordering, action, transferPoint ); - } -} - -/* Set error actions in the states that have transitions into a final state. */ -void FsmAp::middleErrorAction( int ordering, Action *action, int transferPoint ) -{ - /* Isolate the start state in case it is reachable from in inside the - * machine, in which case we don't want it set. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState && ! state->isFinState() ) - state->errActionTable.setAction( ordering, action, transferPoint ); - } -} - -/* Set EOF actions in the start state. */ -void FsmAp::startEOFAction( int ordering, Action *action ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - /* Add the actions. */ - startState->eofActionTable.setAction( ordering, action ); - - afterOpMinimize( true ); -} - -/* Set EOF actions in all states where there is a transition out. */ -void FsmAp::allEOFAction( int ordering, Action *action ) -{ - /* Insert actions in the EOF action table of all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - state->eofActionTable.setAction( ordering, action ); -} - -/* Set EOF actions in final states. */ -void FsmAp::finalEOFAction( int ordering, Action *action ) -{ - /* Add the action to the error table of final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->eofActionTable.setAction( ordering, action ); -} - -void FsmAp::notStartEOFAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState ) - state->eofActionTable.setAction( ordering, action ); - } -} - -void FsmAp::notFinalEOFAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( ! state->isFinState() ) - state->eofActionTable.setAction( ordering, action ); - } -} - -/* Set EOF actions in the states that have transitions into a final state. */ -void FsmAp::middleEOFAction( int ordering, Action *action ) -{ - /* Set the actions in all states that are not the start state and not final. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState && ! state->isFinState() ) - state->eofActionTable.setAction( ordering, action ); - } -} - -/* - * Set To State Actions. - */ - -/* Set to state actions in the start state. */ -void FsmAp::startToStateAction( int ordering, Action *action ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - startState->toStateActionTable.setAction( ordering, action ); - - afterOpMinimize( true ); -} - -/* Set to state actions in all states. */ -void FsmAp::allToStateAction( int ordering, Action *action ) -{ - /* Insert the action on all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - state->toStateActionTable.setAction( ordering, action ); -} - -/* Set to state actions in final states. */ -void FsmAp::finalToStateAction( int ordering, Action *action ) -{ - /* Add the action to the error table of final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->toStateActionTable.setAction( ordering, action ); -} - -void FsmAp::notStartToStateAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState ) - state->toStateActionTable.setAction( ordering, action ); - } -} - -void FsmAp::notFinalToStateAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( ! state->isFinState() ) - state->toStateActionTable.setAction( ordering, action ); - } -} - -/* Set to state actions in states that are not final and not the start state. */ -void FsmAp::middleToStateAction( int ordering, Action *action ) -{ - /* Set the action in all states that are not the start state and not final. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState && ! state->isFinState() ) - state->toStateActionTable.setAction( ordering, action ); - } -} - -/* - * Set From State Actions. - */ - -void FsmAp::startFromStateAction( int ordering, Action *action ) -{ - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - startState->fromStateActionTable.setAction( ordering, action ); - - afterOpMinimize( true ); -} - -void FsmAp::allFromStateAction( int ordering, Action *action ) -{ - /* Insert the action on all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - state->fromStateActionTable.setAction( ordering, action ); -} - -void FsmAp::finalFromStateAction( int ordering, Action *action ) -{ - /* Add the action to the error table of final states. */ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - (*state)->fromStateActionTable.setAction( ordering, action ); -} - -void FsmAp::notStartFromStateAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState ) - state->fromStateActionTable.setAction( ordering, action ); - } -} - -void FsmAp::notFinalFromStateAction( int ordering, Action *action ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( ! state->isFinState() ) - state->fromStateActionTable.setAction( ordering, action ); - } -} - -void FsmAp::middleFromStateAction( int ordering, Action *action ) -{ - /* Set the action in all states that are not the start state and not final. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - if ( state != startState && ! state->isFinState() ) - state->fromStateActionTable.setAction( ordering, action ); - } -} - -/* Shift the function ordering of the start transitions to start - * at fromOrder and increase in units of 1. Useful before staring. - * Returns the maximum number of order numbers used. */ -int FsmAp::shiftStartActionOrder( int fromOrder ) -{ - int maxUsed = 0; - - /* Walk the start state's transitions, shifting function ordering. */ - for ( TransList::Iter trans = startState->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - int curFromOrder = fromOrder; - ActionTable::Iter action = trans->tdap()->actionTable; - for ( ; action.lte(); action++ ) - action->key = curFromOrder++; - - /* Keep track of the max number of orders used. */ - if ( curFromOrder - fromOrder > maxUsed ) - maxUsed = curFromOrder - fromOrder; - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - /* Walk the function data for the transition and set the keys to - * increasing values starting at fromOrder. */ - int curFromOrder = fromOrder; - ActionTable::Iter action = cond->actionTable; - for ( ; action.lte(); action++ ) - action->key = curFromOrder++; - - /* Keep track of the max number of orders used. */ - if ( curFromOrder - fromOrder > maxUsed ) - maxUsed = curFromOrder - fromOrder; - } - } - } - - return maxUsed; -} - -/* Remove all priorities. */ -void FsmAp::clearAllPriorities() -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Clear out priority data. */ - state->outPriorTable.empty(); - - /* Clear transition data from the out transitions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) - trans->tdap()->priorTable.empty(); - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) - cond->priorTable.empty(); - } - } - - if ( state->nfaIn != 0 ) { - for ( NfaInList::Iter na = *state->nfaIn; na.lte(); na++ ) - na->priorTable.empty(); - } - } -} - -/* Zeros out the function ordering keys. This may be called before minimization - * when it is known that no more fsm operations are going to be done. This - * will achieve greater reduction as states will not be separated on the basis - * of function ordering. */ -void FsmAp::nullActionKeys( ) -{ - /* For each state... */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Walk the transitions for the state. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - /* Walk the action table for the transition. */ - for ( ActionTable::Iter action = trans->tdap()->actionTable; - action.lte(); action++ ) - action->key = 0; - - /* Walk the action table for the transition. */ - for ( LmActionTable::Iter action = trans->tdap()->lmActionTable; - action.lte(); action++ ) - action->key = 0; - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - /* Walk the action table for the transition. */ - for ( ActionTable::Iter action = cond->actionTable; - action.lte(); action++ ) - action->key = 0; - - /* Walk the action table for the transition. */ - for ( LmActionTable::Iter action = cond->lmActionTable; - action.lte(); action++ ) - action->key = 0; - } - } - } - - /* Null the action keys of the to state action table. */ - for ( ActionTable::Iter action = state->toStateActionTable; - action.lte(); action++ ) - action->key = 0; - - /* Null the action keys of the from state action table. */ - for ( ActionTable::Iter action = state->fromStateActionTable; - action.lte(); action++ ) - action->key = 0; - - /* Null the action keys of the out transtions. */ - for ( ActionTable::Iter action = state->outActionTable; - action.lte(); action++ ) - action->key = 0; - - /* Null the action keys of the error action table. */ - for ( ErrActionTable::Iter action = state->errActionTable; - action.lte(); action++ ) - action->ordering = 0; - - /* Null the action keys eof action table. */ - for ( ActionTable::Iter action = state->eofActionTable; - action.lte(); action++ ) - action->key = 0; - } -} - -/* Walk the list of states and verify that non final states do not have out - * data, that all stateBits are cleared, and that there are no states with - * zero foreign in transitions. */ -void FsmAp::verifyStates() -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Non final states should not have leaving data. */ - if ( ! (state->stateBits & STB_ISFINAL) ) { - assert( state->outActionTable.length() == 0 ); - assert( state->outCondSpace == 0 ); - assert( state->outCondKeys.length() == 0 ); - assert( state->outPriorTable.length() == 0 ); - } - - /* Data used in algorithms should be cleared. */ - assert( (state->stateBits & STB_BOTH) == 0 ); - assert( state->foreignInTrans > 0 ); - } -} - -/* Compare two transitions according to their relative priority. Since the - * base transition has no priority associated with it, the default is to - * return equal. */ -int FsmAp::comparePrior( const PriorTable &priorTable1, const PriorTable &priorTable2 ) -{ - /* Looking for differing priorities on same keys. Need to concurrently - * scan the priority lists. */ - PriorTable::Iter pd1 = priorTable1; - PriorTable::Iter pd2 = priorTable2; - while ( pd1.lte() && pd2.lte() ) { - /* Check keys. */ - if ( pd1->desc->key < pd2->desc->key ) - pd1.increment(); - else if ( pd1->desc->key > pd2->desc->key ) - pd2.increment(); - /* Keys are the same, check priorities. */ - else if ( pd1->desc->priority < pd2->desc->priority ) { - if ( ctx->checkPriorInteraction && pd1->desc->guarded ) { - if ( ! priorInteraction ) { - priorInteraction = true; - guardId = pd1->desc->guardId; - } - } - return -1; - } - else if ( pd1->desc->priority > pd2->desc->priority ) { - if ( ctx->checkPriorInteraction && pd1->desc->guarded ) { - if ( ! priorInteraction ) { - priorInteraction = true; - guardId = pd1->desc->guardId; - } - } - return 1; - } - else { - /* Keys and priorities are equal, advance both. */ - pd1.increment(); - pd2.increment(); - } - } - - /* No differing priorities on the same key. */ - return 0; -} - -int FsmAp::compareCondListBitElim( const CondList &condList1, const CondList &condList2 ) -{ - typedef ValPairIter< PiList<CondAp> > ValPairIterPiListCondAp; - ValPairIterPiListCondAp outPair( condList1, condList2 ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - case ValPairIterPiListCondAp::RangeInS1: { - int compareRes = FsmAp::compareCondBitElimPtr<CondAp>( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - } - case ValPairIterPiListCondAp::RangeInS2: { - int compareRes = FsmAp::compareCondBitElimPtr<CondAp>( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - } - case ValPairIterPiListCondAp::RangeOverlap: { - int compareRes = FsmAp::compareCondBitElimPtr<CondAp>( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - }} - } - return 0; -} - -/* Compares two transitions according to priority and functions. Pointers - * should not be null. Does not consider to state or from state. Compare two - * transitions according to the data contained in the transitions. Data means - * any properties added to user transitions that may differentiate them. Since - * the base transition has no data, the default is to return equal. */ -int FsmAp::compareTransData( TransAp *trans1, TransAp *trans2 ) -{ - if ( trans1->condSpace < trans2->condSpace ) - return -1; - else if ( trans2->condSpace < trans1->condSpace ) - return 1; - - if ( trans1->plain() ) { - int compareRes = FsmAp::compareCondDataPtr( trans1->tdap(), trans2->tdap() ); - if ( compareRes != 0 ) - return compareRes; - } - else { - typedef ValPairIter< PiList<CondAp> > ValPairIterPiListCondAp; - ValPairIterPiListCondAp outPair( trans1->tcap()->condList, - trans2->tcap()->condList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - case ValPairIterPiListCondAp::RangeInS1: { - int compareRes = FsmAp::compareCondDataPtr<CondAp>( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - } - case ValPairIterPiListCondAp::RangeInS2: { - int compareRes = FsmAp::compareCondDataPtr<CondAp>( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - } - case ValPairIterPiListCondAp::RangeOverlap: { - int compareRes = FsmAp::compareCondDataPtr<CondAp>( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - }} - } - } - return 0; -} - -/* Compares two transitions according to priority and functions. Pointers - * should not be null. Does not consider to state or from state. Compare two - * transitions according to the data contained in the transitions. Data means - * any properties added to user transitions that may differentiate them. Since - * the base transition has no data, the default is to return equal. */ -template< class Trans > int FsmAp::compareCondData( Trans *trans1, Trans *trans2 ) -{ - /* Compare the prior table. */ - int cmpRes = CmpPriorTable::compare( trans1->priorTable, - trans2->priorTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Compare longest match action tables. */ - cmpRes = CmpLmActionTable::compare(trans1->lmActionTable, - trans2->lmActionTable); - if ( cmpRes != 0 ) - return cmpRes; - - /* Compare action tables. */ - return CmpActionTable::compare(trans1->actionTable, - trans2->actionTable); -} - -/* Compares two transitions according to priority and functions. Pointers - * should not be null. Does not consider to state or from state. Compare two - * transitions according to the data contained in the transitions. Data means - * any properties added to user transitions that may differentiate them. Since - * the base transition has no data, the default is to return equal. */ -template< class Trans > int FsmAp::compareCondBitElim( Trans *trans1, Trans *trans2 ) -{ - if ( trans1->toState < trans2->toState ) - return -1; - else if ( trans1->toState > trans2->toState ) - return 1; - - /* Compare the prior table. */ - int cmpRes = CmpPriorTable::compare( trans1->priorTable, - trans2->priorTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Compare longest match action tables. */ - cmpRes = CmpLmActionTable::compare(trans1->lmActionTable, - trans2->lmActionTable); - if ( cmpRes != 0 ) - return cmpRes; - - /* Compare action tables. */ - return CmpActionTable::compare(trans1->actionTable, - trans2->actionTable); -} - -/* Compare the properties of states that are embedded by users. Compares out - * priorities, out transitions, to, from, out, error and eof action tables. */ -int FsmAp::compareStateData( const StateAp *state1, const StateAp *state2 ) -{ - /* Compare the out priority table. */ - int cmpRes = CmpPriorTable:: - compare( state1->outPriorTable, state2->outPriorTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Test to state action tables. */ - cmpRes = CmpActionTable::compare( state1->toStateActionTable, - state2->toStateActionTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Test from state action tables. */ - cmpRes = CmpActionTable::compare( state1->fromStateActionTable, - state2->fromStateActionTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Test out action tables. */ - cmpRes = CmpActionTable::compare( state1->outActionTable, - state2->outActionTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Out condition space and set of vals. */ - if ( state1->outCondSpace < state2->outCondSpace ) - return -1; - else if ( state1->outCondSpace > state2->outCondSpace ) - return 1; - - cmpRes = CmpTable<int>::compare( state1->outCondKeys, - state2->outCondKeys ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Test out error action tables. */ - cmpRes = CmpErrActionTable::compare( state1->errActionTable, - state2->errActionTable ); - if ( cmpRes != 0 ) - return cmpRes; - - /* Test eof action tables. */ - cmpRes = CmpActionTable::compare( state1->eofActionTable, - state2->eofActionTable ); - if ( cmpRes != 0 ) - return cmpRes; - - return CmpTable<LongestMatchPart*>::compare( - state1->lmNfaParts, state2->lmNfaParts ); -} - - -/* Invoked when a state looses its final state status and the leaving - * transition embedding data should be deleted. */ -void FsmAp::clearOutData( StateAp *state ) -{ - /* Kill the out actions and priorities. */ - state->outCondSpace = 0; - state->outCondKeys.empty(); - state->outActionTable.empty(); - state->outPriorTable.empty(); -} - -bool FsmAp::hasOutData( StateAp *state ) -{ - return ( state->outActionTable.length() > 0 || - state->outCondSpace != 0 || - state->outCondKeys.length() > 0 || - state->outPriorTable.length() > 0 || - state->outCondSpace != 0 ); -} - -/* - * Setting Conditions. - */ - -FsmRes FsmAp::startFsmCondition( Action *condAction, bool sense ) -{ - CondSet set; - CondKeySet vals; - set.insert( condAction ); - vals.append( sense ? 1 : 0 ); - - /* Make sure the start state has no other entry points. */ - isolateStartState( this ); - - FsmRes res = embedCondition( this, startState, set, vals ); - if ( !res.success() ) - return res; - - if ( startState->nfaOut != 0 ) { - /* Only one level. */ - for ( NfaTransList::Iter na = *startState->nfaOut; na.lte(); na++ ) { - res = embedCondition( this, startState, set, vals ); - if ( !res.success() ) - return res; - } - } - - afterOpMinimize( true ); - - return FsmRes( FsmRes::Fsm(), this ); -} - -void FsmAp::allTransCondition( Action *condAction, bool sense ) -{ - CondSet set; - CondKeySet vals; - set.insert( condAction ); - vals.append( sense ? 1 : 0 ); - - for ( StateList::Iter state = stateList; state.lte(); state++ ) - embedCondition( this, state, set, vals ); -} - -void FsmAp::leaveFsmCondition( Action *condAction, bool sense ) -{ - for ( StateSet::Iter state = finStateSet; state.lte(); state++ ) - addOutCondition( *state, condAction, sense ); -} diff --git a/src/fsmattach.cc b/src/fsmattach.cc deleted file mode 100644 index 5e7e5e7c..00000000 --- a/src/fsmattach.cc +++ /dev/null @@ -1,857 +0,0 @@ -/* - * Copyright 2001-2018 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 <string.h> -#include <assert.h> -#include "fsmgraph.h" - -#include <iostream> -using namespace std; - -void FsmAp::attachStateDict( StateAp *from, StateAp *to ) -{ - if ( to->stateDictIn == 0 ) - to->stateDictIn = new StateSet; - - bool inserted = to->stateDictIn->insert( from ); - assert( inserted ); - - if ( from != to ) { - if ( misfitAccounting ) { - if ( to->foreignInTrans == 0 ) - stateList.append( misfitList.detach( to ) ); - } - - to->foreignInTrans += 1; - } -} - -void FsmAp::detachStateDict( StateAp *from, StateAp *to ) -{ - bool removed = to->stateDictIn->remove( from ); - assert( removed ); - - to->foreignInTrans -= 1; - - if ( from != to ) { - if ( misfitAccounting ) { - if ( to->foreignInTrans == 0 ) - misfitList.append( stateList.detach( to ) ); - } - } -} - -void FsmAp::attachToNfa( StateAp *from, StateAp *to, NfaTrans *nfaTrans ) -{ - if ( to->nfaIn == 0 ) - to->nfaIn = new NfaInList; - - nfaTrans->fromState = from; - nfaTrans->toState = to; - - attachToInList( from, to, to->nfaIn->head, nfaTrans ); -} - -void FsmAp::detachFromNfa( StateAp *from, StateAp *to, NfaTrans *nfaTrans ) -{ - nfaTrans->fromState = 0; - nfaTrans->toState = 0; - - detachFromInList( from, to, to->nfaIn->head, nfaTrans ); -} - -template< class Head > void FsmAp::attachToInList( StateAp *from, - StateAp *to, Head *&head, Head *trans ) -{ - trans->ilnext = head; - trans->ilprev = 0; - - /* If in trans list is not empty, set the head->prev to trans. */ - if ( head != 0 ) - head->ilprev = trans; - - /* Now insert ourselves at the front of the list. */ - head = trans; - - /* Keep track of foreign transitions for from and to. */ - if ( from != to ) { - if ( misfitAccounting ) { - /* If the number of foreign in transitions is about to go up to 1 then - * move it from the misfit list to the main list. */ - if ( to->foreignInTrans == 0 ) - stateList.append( misfitList.detach( to ) ); - } - - to->foreignInTrans += 1; - } -}; - -/* Detach a transition from an inlist. The head of the inlist must be supplied. */ -template< class Head > void FsmAp::detachFromInList( StateAp *from, StateAp *to, - Head *&head, Head *trans ) -{ - if ( trans->ilprev == 0 ) - head = trans->ilnext; - else - trans->ilprev->ilnext = trans->ilnext; - - if ( trans->ilnext != 0 ) - trans->ilnext->ilprev = trans->ilprev; - - /* Keep track of foreign transitions for from and to. */ - if ( from != to ) { - to->foreignInTrans -= 1; - - if ( misfitAccounting ) { - /* If the number of foreign in transitions goes down to 0 then move it - * from the main list to the misfit list. */ - if ( to->foreignInTrans == 0 ) - misfitList.append( stateList.detach( to ) ); - } - } -} - -CondAp *FsmAp::attachNewCond( TransAp *trans, StateAp *from, StateAp *to, CondKey onChar ) -{ - /* Sub-transition for conditions. */ - CondAp *condAp = new CondAp( trans ); - condAp->key = onChar; - trans->tcap()->condList.append( condAp ); - - condAp->fromState = from; - condAp->toState = to; - - /* Attach in list. */ - if ( to != 0 ) - attachToInList( from, to, to->inCond.head, condAp ); - - return condAp; -} - -TransAp *FsmAp::attachNewTrans( StateAp *from, StateAp *to, Key lowKey, Key highKey ) -{ - /* Make the new transition. */ - TransDataAp *retVal = new TransDataAp(); - - /* Make the entry in the out list for the transitions. */ - from->outList.append( retVal ); - - /* Set the the keys of the new trans. */ - retVal->lowKey = lowKey; - retVal->highKey = highKey; - - retVal->fromState = from; - retVal->toState = to; - - /* Attach in list. */ - if ( to != 0 ) - attachToInList( from, to, to->inTrans.head, retVal ); - - return retVal; -} - -/* Attach for range lists or for the default transition. This attach should - * be used when a transition already is allocated and must be attached to a - * target state. Does not handle adding the transition into the out list. */ -void FsmAp::attachTrans( StateAp *from, StateAp *to, TransDataAp *trans ) -{ - assert( trans->fromState == 0 && trans->toState == 0 ); - - trans->fromState = from; - trans->toState = to; - - if ( to != 0 ) { - /* For now always attache the one and only condList element. */ - attachToInList( from, to, to->inTrans.head, trans ); - } -} - -void FsmAp::attachTrans( StateAp *from, StateAp *to, CondAp *trans ) -{ - assert( trans->fromState == 0 && trans->toState == 0 ); - - trans->fromState = from; - trans->toState = to; - - if ( to != 0 ) { - /* For now always attache the one and only condList element. */ - attachToInList( from, to, to->inCond.head, trans ); - } -} - -/* Redirect a transition away from error and towards some state. This is just - * like attachTrans except it requires fromState to be set and does not touch - * it. */ -void FsmAp::redirectErrorTrans( StateAp *from, StateAp *to, TransDataAp *trans ) -{ - assert( trans->fromState != 0 && trans->toState == 0 ); - trans->toState = to; - - if ( to != 0 ) { - /* Attach using the inList pointer as the head pointer. */ - attachToInList( from, to, to->inTrans.head, trans ); - } -} - -void FsmAp::redirectErrorTrans( StateAp *from, StateAp *to, CondAp *trans ) -{ - assert( trans->fromState != 0 && trans->toState == 0 ); - trans->toState = to; - - if ( to != 0 ) { - /* Attach using the inList pointer as the head pointer. */ - attachToInList( from, to, to->inCond.head, trans ); - } -} - -/* Detach for out/in lists or for default transition. */ -void FsmAp::detachTrans( StateAp *from, StateAp *to, TransDataAp *trans ) -{ - assert( trans->fromState == from && trans->toState == to ); - - trans->fromState = 0; - trans->toState = 0; - - if ( to != 0 ) { - detachFromInList( from, to, to->inTrans.head, trans ); - } -} - -void FsmAp::detachTrans( StateAp *from, StateAp *to, CondAp *trans ) -{ - assert( trans->fromState == from && trans->toState == to ); - - trans->fromState = 0; - trans->toState = 0; - - if ( to != 0 ) { - detachFromInList( from, to, to->inCond.head, trans ); - } -} - - -/* Detach a state from the graph. Detaches and deletes transitions in and out - * of the state. Empties inList and outList. Removes the state from the final - * state set. A detached state becomes useless and should be deleted. */ -void FsmAp::detachState( StateAp *state ) -{ - while ( state->inTrans.head != 0 ) { - /* Get pointers to the trans and the state. */ - TransDataAp *trans = state->inTrans.head; - - StateAp *fromState = trans->fromState; - - /* Detach the transitions from the source state. */ - detachTrans( fromState, state, trans ); - fromState->outList.detach( trans ); - delete trans->tdap(); - } - - /* Detach the in transitions from the inList list of transitions. */ - while ( state->inCond.head != 0 ) { - /* Get pointers to the trans and the state. */ - CondAp *condAp = state->inCond.head; - TransAp *trans = condAp->transAp; - - StateAp *fromState = condAp->fromState; - - /* Detach the transitions from the source state. */ - detachTrans( fromState, state, condAp ); - - trans->tcap()->condList.detach( condAp ); - delete condAp; - - if ( trans->tcap()->condList.length() == 0 ) { - /* Ok to delete the transition. */ - fromState->outList.detach( trans ); - delete trans->tcap(); - } - } - - /* Remove the entry points in on the machine. */ - while ( state->entryIds.length() > 0 ) - unsetEntry( state->entryIds[0], state ); - - /* Detach out range transitions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); ) { - TransList::Iter next = trans.next(); - if ( trans->plain() ) { - detachTrans( state, trans->tdap()->toState, trans->tdap() ); - delete trans->tdap(); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); ) { - CondList::Iter next = cond.next(); - detachTrans( state, cond->toState, cond ); - delete cond; - cond = next; - } - trans->tcap()->condList.abandon(); - delete trans->tcap(); - } - trans = next; - } - - /* Delete all of the out range pointers. */ - state->outList.abandon(); - - /* Unset final stateness before detaching from graph. */ - if ( state->stateBits & STB_ISFINAL ) - finStateSet.remove( state ); - - if ( state->nfaIn != 0 ) { - while ( state->nfaIn->head != 0 ) { - NfaTrans *trans = state->nfaIn->head; - StateAp *fromState = trans->fromState; - - detachFromNfa( fromState, state, trans ); - fromState->nfaOut->detach( trans ); - delete trans; - } - delete state->nfaIn; - state->nfaIn = 0; - } - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter t = *state->nfaOut; t.lte(); ) { - NfaTransList::Iter next = t.next(); - detachFromNfa( t->fromState, t->toState, t ); - state->nfaOut->detach( t ); - delete t; - t = next; - } - state->nfaOut->abandon(); - delete state->nfaOut; - state->nfaOut = 0; - } - - if ( state->stateDictIn != 0 ) { - for ( StateSet::Iter s = *state->stateDictIn; s.lte(); s++ ) { - bool removed = (*s)->stateDictEl->stateSet.remove( state ); - assert( removed ); - } - - delete state->stateDictIn; - state->stateDictIn = 0; - } - - if ( state->stateDictEl != 0 ) { - for ( StateSet::Iter s = state->stateDictEl->stateSet; s.lte(); s++ ) - detachStateDict( state, *s ); - - stateDict.detach( state->stateDictEl ); - delete state->stateDictEl; - state->stateDictEl = 0; - - nfaList.detach( state ); - } -} - -TransDataAp *FsmAp::dupTransData( StateAp *from, TransDataAp *srcTrans ) -{ - /* Make a new transition. */ - TransDataAp *newTrans = new TransDataAp(); - newTrans->condSpace = srcTrans->condSpace; - - attachTrans( from, srcTrans->tdap()->toState, newTrans ); - addInTrans( newTrans, srcTrans->tdap() ); - - return newTrans; -} - - -/* Duplicate a transition. Makes a new transition that is attached to the same - * dest as srcTrans. The new transition has functions and priority taken from - * srcTrans. Used for merging a transition in to a free spot. The trans can - * just be dropped in. It does not conflict with an existing trans and need - * not be crossed. Returns the new transition. */ -TransAp *FsmAp::dupTrans( StateAp *from, TransAp *srcTrans ) -{ - if ( srcTrans->plain() ) { - /* Make a new transition. */ - TransDataAp *newTrans = new TransDataAp(); - newTrans->condSpace = srcTrans->condSpace; - - attachTrans( from, srcTrans->tdap()->toState, newTrans ); - addInTrans( newTrans, srcTrans->tdap() ); - - return newTrans; - } - else { - /* Make a new transition. */ - TransAp *newTrans = new TransCondAp(); - newTrans->condSpace = srcTrans->condSpace; - - for ( CondList::Iter sc = srcTrans->tcap()->condList; sc.lte(); sc++ ) { - /* Sub-transition for conditions. */ - CondAp *newCond = new CondAp( newTrans ); - newCond->key = sc->key; - newTrans->tcap()->condList.append( newCond ); - - /* We can attach the transition, one does not exist. */ - attachTrans( from, sc->toState, newCond ); - - /* Call the user callback to add in the original source transition. */ - addInTrans( newCond, sc.ptr ); - } - - return newTrans; - } -} - -/* Duplicate a transition. Makes a new transition that is attached to the same - * dest as srcTrans. The new transition has functions and priority taken from - * srcTrans. Used for merging a transition in to a free spot. The trans can - * just be dropped in. It does not conflict with an existing trans and need - * not be crossed. Returns the new transition. */ -CondAp *FsmAp::dupCondTrans( StateAp *from, TransAp *destParent, CondAp *srcTrans ) -{ - /* Sub-transition for conditions. */ - CondAp *newCond = new CondAp( destParent ); - - /* We can attach the transition, one does not exist. */ - attachTrans( from, srcTrans->toState, newCond ); - - /* Call the user callback to add in the original source transition. */ - addInTrans( newCond, srcTrans ); - - return newCond; -} - -/* In crossing, src trans and dest trans both go to existing states. Make one - * state from the sets of states that src and dest trans go to. */ -template< class Trans > Trans *FsmAp::fsmAttachStates( StateAp *from, - Trans *destTrans, Trans *srcTrans ) -{ - /* The priorities are equal. We must merge the transitions. Does the - * existing trans go to the state we are to attach to? ie, are we to - * simply double up the transition? */ - StateAp *toState = srcTrans->toState; - StateAp *existingState = destTrans->toState; - - if ( existingState == toState ) { - /* The transition is a double up to the same state. Copy the src - * trans into itself. We don't need to merge in the from out trans - * data, that was done already. */ - addInTrans( destTrans, srcTrans ); - } - else { - /* The trans is not a double up. Dest trans cannot be the same as src - * trans. Set up the state set. */ - StateSet stateSet; - - /* We go to all the states the existing trans goes to, plus... */ - if ( existingState->stateDictEl == 0 ) - stateSet.insert( existingState ); - else - stateSet.insert( existingState->stateDictEl->stateSet ); - - /* ... all the states that we have been told to go to. */ - if ( toState->stateDictEl == 0 ) - stateSet.insert( toState ); - else - stateSet.insert( toState->stateDictEl->stateSet ); - - /* Look for the state. If it is not there already, make it. */ - StateDictEl *lastFound; - if ( stateDict.insert( stateSet, &lastFound ) ) { - /* Make a new state representing the combination of states in - * stateSet. It gets added to the fill list. This means that we - * need to fill in it's transitions sometime in the future. We - * don't do that now (ie, do not recurse). */ - StateAp *combinState = addState(); - - /* Link up the dict element and the state. */ - lastFound->targState = combinState; - combinState->stateDictEl = lastFound; - - /* Setup the in links. */ - for ( StateSet::Iter s = stateSet; s.lte(); s++ ) - attachStateDict( combinState, *s ); - - /* Add to the fill list. */ - nfaList.append( combinState ); - } - - /* Get the state insertted/deleted. */ - StateAp *targ = lastFound->targState; - - /* Detach the state from existing state. */ - detachTrans( from, existingState, destTrans ); - - /* Re-attach to the new target. */ - attachTrans( from, targ, destTrans ); - - /* Add in src trans to the existing transition that we redirected to - * the new state. We don't need to merge in the from out trans data, - * that was done already. */ - addInTrans( destTrans, srcTrans ); - } - - return destTrans; -} - -/* Two transitions are to be crossed, handle the possibility of either going - * to the error state. */ -template < class Trans > Trans *FsmAp::mergeTrans( StateAp *from, - Trans *destTrans, Trans *srcTrans ) -{ - Trans *retTrans = 0; - if ( destTrans->toState == 0 && srcTrans->toState == 0 ) { - /* Error added into error. */ - addInTrans( destTrans, srcTrans ); - retTrans = destTrans; - } - else if ( destTrans->toState == 0 && srcTrans->toState != 0 ) { - /* Non error added into error we need to detach and reattach, */ - detachTrans( from, destTrans->toState, destTrans ); - attachTrans( from, srcTrans->toState, destTrans ); - addInTrans( destTrans, srcTrans ); - retTrans = destTrans; - } - else if ( srcTrans->toState == 0 ) { - /* Dest goes somewhere but src doesn't, just add it it in. */ - addInTrans( destTrans, srcTrans ); - retTrans = destTrans; - } - else { - /* Both go somewhere, run the actual cross. */ - retTrans = fsmAttachStates( from, destTrans, srcTrans ); - } - - return retTrans; -} - -/* Find the trans with the higher priority. If src is lower priority then dest then - * src is ignored. If src is higher priority than dest, then src overwrites dest. If - * the priorities are equal, then they are merged. */ -CondAp *FsmAp::crossCondTransitions( StateAp *from, TransAp *destParent, - CondAp *destTrans, CondAp *srcTrans ) -{ - CondAp *retTrans; - - /* Compare the priority of the dest and src transitions. */ - int compareRes = comparePrior( destTrans->priorTable, srcTrans->priorTable ); - if ( compareRes < 0 ) { - /* Src trans has a higher priority than dest, src overwrites dest. - * Detach dest and return a copy of src. */ - detachTrans( from, destTrans->toState, destTrans ); - delete destTrans; - retTrans = dupCondTrans( from, destParent, srcTrans ); - } - else if ( compareRes > 0 ) { - /* The dest trans has a higher priority, use dest. */ - retTrans = destTrans; - } - else { - /* Src trans and dest trans have the same priority, they must be merged. */ - retTrans = mergeTrans( from, destTrans, srcTrans ); - } - - /* Return the transition that resulted from the cross. */ - return retTrans; -} - -TransAp *FsmAp::copyTransForExpansion( StateAp *from, TransAp *srcTrans ) -{ - /* This is the dup without the attach. */ - TransCondAp *newTrans = new TransCondAp(); - newTrans->condSpace = srcTrans->condSpace; - - if ( srcTrans->plain() ) { - TransDataAp *srcData = srcTrans->tdap(); - CondAp *newCond = new CondAp( newTrans ); - newCond->key = 0; - - attachTrans( srcData->fromState, srcData->toState, newCond ); - - /* Call the user callback to add in the original source transition. */ - //addInTrans( newCond, srcData ); - - /* Not a copy of ourself, get the functions and priorities. */ - newCond->lmActionTable.setActions( srcData->lmActionTable ); - newCond->actionTable.setActions( srcData->actionTable ); - newCond->priorTable.setPriors( srcData->priorTable ); - - newTrans->condList.append( newCond ); - } - else { - for ( CondList::Iter sc = srcTrans->tcap()->condList; sc.lte(); sc++ ) { - /* Sub-transition for conditions. */ - CondAp *newCond = new CondAp( newTrans ); - newCond->key = sc->key; - - attachTrans( sc->fromState, sc->toState, newCond ); - - /* Call the user callback to add in the original source transition. */ - addInTrans( newCond, sc.ptr ); - - newTrans->condList.append( newCond ); - } - } - - /* Set up the transition's keys and append to the dest list. */ - newTrans->lowKey = srcTrans->lowKey; - newTrans->highKey = srcTrans->highKey; - - return newTrans; -} - -void FsmAp::freeEffectiveTrans( TransAp *trans ) -{ - for ( CondList::Iter sc = trans->tcap()->condList; sc.lte(); ) { - CondList::Iter next = sc.next(); - detachTrans( sc->fromState, sc->toState, sc ); - delete sc; - sc = next; - } - trans->tcap()->condList.abandon(); - delete trans->tcap(); -} - -TransDataAp *FsmAp::crossTransitionsBothPlain( StateAp *from, - TransDataAp *destTrans, TransDataAp *srcTrans ) -{ - /* Neither have cond space and no expansion took place. Cross them. */ - TransDataAp *retTrans; - - /* Compare the priority of the dest and src transitions. */ - int compareRes = comparePrior( destTrans->priorTable, srcTrans->priorTable ); - if ( compareRes < 0 ) { - /* Src trans has a higher priority than dest, src overwrites dest. - * Detach dest and return a copy of src. */ - detachTrans( from, destTrans->toState, destTrans ); - delete destTrans; - retTrans = dupTransData( from, srcTrans ); - } - else if ( compareRes > 0 ) { - /* The dest trans has a higher priority, use dest. */ - retTrans = destTrans; - } - else { - /* Src trans and dest trans have the same priority, they must be merged. */ - retTrans = mergeTrans( from, destTrans, srcTrans ); - } - - /* Return the transition that resulted from the cross. */ - return retTrans; -} - -/* Find the trans with the higher priority. If src is lower priority then dest then - * src is ignored. If src is higher priority than dest, then src overwrites dest. If - * the priorities are equal, then they are merged. */ -TransAp *FsmAp::crossTransitions( StateAp *from, - TransAp *destTrans, TransAp *srcTrans ) -{ - if ( destTrans->plain() && srcTrans->plain() ) { - /* Return the transition that resulted from the cross. */ - return crossTransitionsBothPlain( from, - destTrans->tdap(), srcTrans->tdap() ); - } - else { - /* At least one is non-empty. Target is non-empty. Need to work in - * condition spaced. */ - CondSpace *mergedSpace = expandCondSpace( destTrans, srcTrans ); - - /* If the dest state cond space does not equal the merged, we have to - * rewrite it. If the src state cond space does not equal, we have to - * copy it. */ - - TransAp *effSrcTrans = srcTrans; - - if ( srcTrans->condSpace != mergedSpace ) { - effSrcTrans = copyTransForExpansion( from, srcTrans ); - CondSpace *orig = effSrcTrans->condSpace; - effSrcTrans->condSpace = mergedSpace; - expandConds( from, effSrcTrans, orig, mergedSpace ); - } - - if ( destTrans->condSpace != mergedSpace ) { - /* Make the transition into a conds transition. If dest is a plain - * transition, we have to replace it with a conds transition. */ - if ( destTrans->plain() ) - destTrans = convertToCondAp( from, destTrans->tdap() ); - - /* Now expand the dest. */ - CondSpace *orig = destTrans->condSpace; - destTrans->condSpace = mergedSpace; - expandConds( from, destTrans, orig, mergedSpace ); - } - - /* The destination list. */ - CondList destList; - - /* Set up an iterator to stop at breaks. */ - typedef ValPairIter< PiList<CondAp> > ValPairIterPiListCondAp; - ValPairIterPiListCondAp outPair( destTrans->tcap()->condList, - effSrcTrans->tcap()->condList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - case ValPairIterPiListCondAp::RangeInS1: { - /* The pair iter is the authority on the keys. It may have needed - * to break the dest range. */ - CondAp *destCond = outPair.s1Tel.trans; - destCond->key = outPair.s1Tel.key; - destList.append( destCond ); - break; - } - case ValPairIterPiListCondAp::RangeInS2: { - /* Src range may get crossed with dest's default transition. */ - CondAp *newCond = dupCondTrans( from, destTrans, outPair.s2Tel.trans ); - - /* Set up the transition's keys and append to the dest list. */ - newCond->key = outPair.s2Tel.key; - destList.append( newCond ); - break; - } - case ValPairIterPiListCondAp::RangeOverlap: { - /* Exact overlap, cross them. */ - CondAp *newTrans = crossCondTransitions( from, destTrans, - outPair.s1Tel.trans, outPair.s2Tel.trans ); - - /* Set up the transition's keys and append to the dest list. */ - newTrans->key = outPair.s1Tel.key; - destList.append( newTrans ); - break; - }} - } - - /* Abandon the old outList and transfer destList into it. */ - destTrans->tcap()->condList.transfer( destList ); - - /* Delete the duplicate. Don't detach anything. */ - if ( srcTrans != effSrcTrans ) - freeEffectiveTrans( effSrcTrans ); - - return destTrans; - } -} - -/* Copy the transitions in srcList to the outlist of dest. The srcList should - * not be the outList of dest, otherwise you would be copying the contents of - * srcList into itself as it's iterated: bad news. */ -void FsmAp::outTransCopy( StateAp *dest, TransAp *srcList ) -{ - /* The destination list. */ - TransList destList; - - /* Set up an iterator to stop at breaks. */ - typedef RangePairIter< PiList<TransAp> > RangePairIterPiListTransAp; - RangePairIterPiListTransAp outPair( ctx, dest->outList, srcList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - case RangePairIterPiListTransAp::RangeInS1: { - /* The pair iter is the authority on the keys. It may have needed - * to break the dest range. */ - TransAp *destTrans = outPair.s1Tel.trans; - destTrans->lowKey = outPair.s1Tel.lowKey; - destTrans->highKey = outPair.s1Tel.highKey; - destList.append( destTrans ); - break; - } - case RangePairIterPiListTransAp::RangeInS2: { - /* Src range may get crossed with dest's default transition. */ - TransAp *newTrans = dupTrans( dest, outPair.s2Tel.trans ); - - /* Set up the transition's keys and append to the dest list. */ - newTrans->lowKey = outPair.s2Tel.lowKey; - newTrans->highKey = outPair.s2Tel.highKey; - destList.append( newTrans ); - break; - } - case RangePairIterPiListTransAp::RangeOverlap: { - /* Exact overlap, cross them. */ - TransAp *newTrans = crossTransitions( dest, - outPair.s1Tel.trans, outPair.s2Tel.trans ); - - /* Set up the transition's keys and append to the dest list. */ - newTrans->lowKey = outPair.s1Tel.lowKey; - newTrans->highKey = outPair.s1Tel.highKey; - destList.append( newTrans ); - break; - } - case RangePairIterPiListTransAp::BreakS1: { - /* Since we are always writing to the dest trans, the dest needs - * to be copied when it is broken. The copy goes into the first - * half of the break to "break it off". */ - outPair.s1Tel.trans = dupTrans( dest, outPair.s1Tel.trans ); - break; - } - case RangePairIterPiListTransAp::BreakS2: - break; - } - } - - /* Abandon the old outList and transfer destList into it. */ - dest->outList.transfer( destList ); -} - -/* Move all the transitions that go into src so that they go into dest. */ -void FsmAp::moveInwardTrans( StateAp *dest, StateAp *src ) -{ - /* Do not try to move in trans to and from the same state. */ - assert( dest != src ); - - /* If src is the start state, dest becomes the start state. */ - if ( src == startState ) { - unsetStartState(); - setStartState( dest ); - } - - /* For each entry point into, create an entry point into dest, when the - * state is detached, the entry points to src will be removed. */ - for ( EntryIdSet::Iter enId = src->entryIds; enId.lte(); enId++ ) - changeEntry( *enId, dest, src ); - - /* Move the transitions in inList. */ - while ( src->inTrans.head != 0 ) { - /* Get trans and from state. */ - TransDataAp *trans = src->inTrans.head; - StateAp *fromState = trans->fromState; - - /* Detach from src, reattach to dest. */ - detachTrans( fromState, src, trans ); - attachTrans( fromState, dest, trans ); - } - - /* Move the transitions in inList. */ - while ( src->inCond.head != 0 ) { - /* Get trans and from state. */ - CondAp *trans = src->inCond.head; - StateAp *fromState = trans->fromState; - - /* Detach from src, reattach to dest. */ - detachTrans( fromState, src, trans ); - attachTrans( fromState, dest, trans ); - } - - /* Move inward nfa links. */ - if ( src->nfaIn != 0 ) { - while ( src->nfaIn->head != 0 ) { - NfaTrans *trans = src->nfaIn->head; - StateAp *fromState = trans->fromState; - - detachFromNfa( fromState, src, trans ); - attachToNfa( fromState, dest, trans ); - } - } -} diff --git a/src/fsmbase.cc b/src/fsmbase.cc deleted file mode 100644 index bdf40279..00000000 --- a/src/fsmbase.cc +++ /dev/null @@ -1,853 +0,0 @@ -/* - * Copyright 2001-2018 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 "fsmgraph.h" -#include "parsedata.h" - -#include <string.h> -#include <assert.h> -#include <iostream> - -FsmCtx::FsmCtx( FsmGbl *fsmGbl ) -: - minimizeLevel(fsmGbl->minimizeLevel), - minimizeOpt(fsmGbl->minimizeOpt), - - /* No limit. */ - stateLimit(STATE_UNLIMITED), - - printStatistics(fsmGbl->printStatistics), - - checkPriorInteraction(fsmGbl->checkPriorInteraction), - - unionOp(false), - - condsCheckDepth(0), - - curActionOrd(0), - curPriorOrd(0), - - nextPriorKey(0), - nextCondId(0), - - fsmGbl(fsmGbl), - generatingSectionSubset(false), - lmRequiresErrorState(false), - nameIndex(0), - - getKeyExpr(0), - accessExpr(0), - prePushExpr(0), - postPopExpr(0), - nfaPrePushExpr(0), - nfaPostPopExpr(0), - pExpr(0), - peExpr(0), - eofExpr(0), - csExpr(0), - topExpr(0), - stackExpr(0), - actExpr(0), - tokstartExpr(0), - tokendExpr(0), - dataExpr(0) -{ - keyOps = new KeyOps; - condData = new CondData; -} - -FsmCtx::~FsmCtx() -{ - delete keyOps; - delete condData; - priorDescList.empty(); - - actionList.empty(); - - if ( getKeyExpr != 0 ) - delete getKeyExpr; - if ( accessExpr != 0 ) - delete accessExpr; - if ( prePushExpr != 0 ) - delete prePushExpr; - if ( postPopExpr != 0 ) - delete postPopExpr; - if ( nfaPrePushExpr != 0 ) - delete nfaPrePushExpr; - if ( nfaPostPopExpr != 0 ) - delete nfaPostPopExpr; - if ( pExpr != 0 ) - delete pExpr; - if ( peExpr != 0 ) - delete peExpr; - if ( eofExpr != 0 ) - delete eofExpr; - if ( csExpr != 0 ) - delete csExpr; - if ( topExpr != 0 ) - delete topExpr; - if ( stackExpr != 0 ) - delete stackExpr; - if ( actExpr != 0 ) - delete actExpr; - if ( tokstartExpr != 0 ) - delete tokstartExpr; - if ( tokendExpr != 0 ) - delete tokendExpr; - if ( dataExpr != 0 ) - delete dataExpr; -} - -/* Graph constructor. */ -FsmAp::FsmAp( FsmCtx *ctx ) -: - ctx( ctx ), - - priorInteraction(false), - - /* No start state. */ - startState(0), - errState(0), - - /* Misfit accounting is a switch, turned on only at specific times. It - * controls what happens when states have no way in from the outside - * world.. */ - misfitAccounting(false) -{ -} - -/* Copy all graph data including transitions. */ -FsmAp::FsmAp( const FsmAp &graph ) -: - ctx( graph.ctx ), - - priorInteraction(false), - - /* Lists start empty. Will be filled by copy. */ - stateList(), - misfitList(), - - /* Copy in the entry points, - * pointers will be resolved later. */ - entryPoints(graph.entryPoints), - startState(graph.startState), - errState(0), - - /* Will be filled by copy. */ - finStateSet(), - - /* Misfit accounting is only on during merging. */ - misfitAccounting(false) -{ - /* Create the states and record their map in the original state. */ - StateList::Iter origState = graph.stateList; - for ( ; origState.lte(); origState++ ) { - /* Make the new state. */ - StateAp *newState = new StateAp( *origState ); - - /* Add the state to the list. */ - stateList.append( newState ); - - /* Set the mapsTo item of the old state. */ - origState->alg.stateMap = newState; - } - - /* Derefernce all the state maps. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - /* The points to the original in the src machine. The taget's duplicate - * is in the statemap. */ - StateAp *toState = trans->tdap()->toState != 0 ? - trans->tdap()->toState->alg.stateMap : 0; - - /* Attach The transition to the duplicate. */ - trans->tdap()->toState = 0; - attachTrans( state, toState, trans->tdap() ); - - } - else { - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++ ) { - /* The points to the original in the src machine. The taget's duplicate - * is in the statemap. */ - StateAp *toState = cti->toState != 0 ? cti->toState->alg.stateMap : 0; - - /* Attach The transition to the duplicate. */ - cti->toState = 0; - attachTrans( state, toState, cti ); - } - } - } - - /* Fix the eofTarg, if set. */ - if ( state->eofTarget != 0 ) - state->eofTarget = state->eofTarget->alg.stateMap; - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *state->nfaOut; n.lte(); n++ ) { - StateAp *targ = n->toState->alg.stateMap; - n->toState = 0; - attachToNfa( state, targ, n ); - } - } - } - - /* Fix the state pointers in the entry points array. */ - EntryMapEl *eel = entryPoints.data; - for ( int e = 0; e < entryPoints.length(); e++, eel++ ) { - /* Get the duplicate of the state. */ - eel->value = eel->value->alg.stateMap; - - /* Foreign in transitions must be built up when duping machines so - * increment it here. */ - eel->value->foreignInTrans += 1; - } - - /* Fix the start state pointer and the new start state's count of in - * transiions. */ - startState = startState->alg.stateMap; - startState->foreignInTrans += 1; - - /* Build the final state set. */ - StateSet::Iter st = graph.finStateSet; - for ( ; st.lte(); st++ ) - finStateSet.insert((*st)->alg.stateMap); -} - -/* Deletes all transition data then deletes each state. */ -FsmAp::~FsmAp() -{ - /* Delete all the transitions. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Iterate the out transitions, deleting them. */ - for ( TransList::Iter n, t = state->outList; t.lte(); ) { - n = t.next(); - if ( t->plain() ) - delete t->tdap(); - else - delete t->tcap(); - t = n; - } - state->outList.abandon(); - - if ( state->nfaIn != 0 ) { - delete state->nfaIn; - state->nfaIn = 0; - } - - if ( state->nfaOut != 0 ) { - state->nfaOut->empty(); - delete state->nfaOut; - state->nfaOut = 0; - } - } - - /* Delete all the states. */ - stateList.empty(); -} - -/* Set a state final. The state has its isFinState set to true and the state - * is added to the finStateSet. */ -void FsmAp::setFinState( StateAp *state ) -{ - /* Is it already a fin state. */ - if ( state->stateBits & STB_ISFINAL ) - return; - - state->stateBits |= STB_ISFINAL; - finStateSet.insert( state ); -} - -/* Set a state non-final. The has its isFinState flag set false and the state - * is removed from the final state set. */ -void FsmAp::unsetFinState( StateAp *state ) -{ - /* Is it already a non-final state? */ - if ( ! (state->stateBits & STB_ISFINAL) ) - return; - - /* When a state looses its final state status it must relinquish all the - * properties that are allowed only for final states. */ - clearOutData( state ); - - state->stateBits &= ~ STB_ISFINAL; - finStateSet.remove( state ); -} - -/* Set and unset a state as the start state. */ -void FsmAp::setStartState( StateAp *state ) -{ - /* Sould change from unset to set. */ - assert( startState == 0 ); - startState = state; - - if ( misfitAccounting ) { - /* If the number of foreign in transitions is about to go up to 1 then - * take it off the misfit list and put it on the head list. */ - if ( state->foreignInTrans == 0 ) - stateList.append( misfitList.detach( state ) ); - } - - /* Up the foreign in transitions to the state. */ - state->foreignInTrans += 1; -} - -void FsmAp::unsetStartState() -{ - /* Should change from set to unset. */ - assert( startState != 0 ); - - /* Decrement the entry's count of foreign entries. */ - startState->foreignInTrans -= 1; - - if ( misfitAccounting ) { - /* If the number of foreign in transitions just went down to 0 then take - * it off the main list and put it on the misfit list. */ - if ( startState->foreignInTrans == 0 ) - misfitList.append( stateList.detach( startState ) ); - } - - startState = 0; -} - -/* Associate an id with a state. Makes the state a named entry point. Has no - * effect if the entry point is already mapped to the state. */ -void FsmAp::setEntry( int id, StateAp *state ) -{ - /* Insert the id into the state. If the state is already labelled with id, - * nothing to do. */ - if ( state->entryIds.insert( id ) ) { - /* Insert the entry and assert that it succeeds. */ - entryPoints.insertMulti( id, state ); - - if ( misfitAccounting ) { - /* If the number of foreign in transitions is about to go up to 1 then - * take it off the misfit list and put it on the head list. */ - if ( state->foreignInTrans == 0 ) - stateList.append( misfitList.detach( state ) ); - } - - /* Up the foreign in transitions to the state. */ - state->foreignInTrans += 1; - } -} - -/* Remove the association of an id with a state. The state looses it's entry - * point status. Assumes that the id is indeed mapped to state. */ -void FsmAp::unsetEntry( int id, StateAp *state ) -{ - /* Find the entry point in on id. */ - EntryMapEl *enLow = 0, *enHigh = 0; - entryPoints.findMulti( id, enLow, enHigh ); - while ( enLow->value != state ) - enLow += 1; - - /* Remove the record from the map. */ - entryPoints.remove( enLow ); - - /* Remove the state's sense of the link. */ - state->entryIds.remove( id ); - state->foreignInTrans -= 1; - if ( misfitAccounting ) { - /* If the number of foreign in transitions just went down to 0 then take - * it off the main list and put it on the misfit list. */ - if ( state->foreignInTrans == 0 ) - misfitList.append( stateList.detach( state ) ); - } -} - -/* Remove all association of an id with states. Assumes that the id is indeed - * mapped to a state. */ -void FsmAp::unsetEntry( int id ) -{ - /* Find the entry point in on id. */ - EntryMapEl *enLow = 0, *enHigh = 0; - entryPoints.findMulti( id, enLow, enHigh ); - for ( EntryMapEl *mel = enLow; mel <= enHigh; mel++ ) { - /* Remove the state's sense of the link. */ - mel->value->entryIds.remove( id ); - mel->value->foreignInTrans -= 1; - if ( misfitAccounting ) { - /* If the number of foreign in transitions just went down to 0 - * then take it off the main list and put it on the misfit list. */ - if ( mel->value->foreignInTrans == 0 ) - misfitList.append( stateList.detach( mel->value ) ); - } - } - - /* Remove the records from the entry points map. */ - entryPoints.removeMulti( enLow, enHigh ); -} - - -void FsmAp::changeEntry( int id, StateAp *to, StateAp *from ) -{ - /* Find the entry in the entry map. */ - EntryMapEl *enLow = 0, *enHigh = 0; - entryPoints.findMulti( id, enLow, enHigh ); - while ( enLow->value != from ) - enLow += 1; - - /* Change it to the new target. */ - enLow->value = to; - - /* Remove from's sense of the link. */ - from->entryIds.remove( id ); - from->foreignInTrans -= 1; - if ( misfitAccounting ) { - /* If the number of foreign in transitions just went down to 0 then take - * it off the main list and put it on the misfit list. */ - if ( from->foreignInTrans == 0 ) - misfitList.append( stateList.detach( from ) ); - } - - /* Add to's sense of the link. */ - if ( to->entryIds.insert( id ) != 0 ) { - if ( misfitAccounting ) { - /* If the number of foreign in transitions is about to go up to 1 then - * take it off the misfit list and put it on the head list. */ - if ( to->foreignInTrans == 0 ) - stateList.append( misfitList.detach( to ) ); - } - - /* Up the foreign in transitions to the state. */ - to->foreignInTrans += 1; - } -} - - -/* Clear all entry points from a machine. */ -void FsmAp::unsetAllEntryPoints() -{ - for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) { - /* Kill all the state's entry points at once. */ - if ( en->value->entryIds.length() > 0 ) { - en->value->foreignInTrans -= en->value->entryIds.length(); - - if ( misfitAccounting ) { - /* If the number of foreign in transitions just went down to 0 - * then take it off the main list and put it on the misfit - * list. */ - if ( en->value->foreignInTrans == 0 ) - misfitList.append( stateList.detach( en->value ) ); - } - - /* Clear the set of ids out all at once. */ - en->value->entryIds.empty(); - } - } - - /* Now clear out the entry map all at once. */ - entryPoints.empty(); -} - -/* Assigning an epsilon transition into final states. */ -void FsmAp::epsilonTrans( int id ) -{ - for ( StateSet::Iter fs = finStateSet; fs.lte(); fs++ ) - (*fs)->epsilonTrans.append( id ); -} - -/* Mark all states reachable from state. Traverses transitions forward. Used - * for removing states that have no path into them. */ -void FsmAp::markReachableFromHere( StateAp *state ) -{ - /* Base case: return; */ - if ( state->stateBits & STB_ISMARKED ) - return; - - /* Set this state as processed. We are going to visit all states that this - * state has a transition to. */ - state->stateBits |= STB_ISMARKED; - - /* Recurse on all out transitions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - markReachableFromHere( trans->tdap()->toState ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - markReachableFromHere( cond->toState ); - } - } - } - - /* Recurse on all states that compose us. */ - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter st = *state->nfaOut; st.lte(); st++ ) - markReachableFromHere( st->toState ); - } - - if ( state->stateDictEl != 0 ) { - for ( StateSet::Iter ss = state->stateDictEl->stateSet; ss.lte(); ss++ ) - markReachableFromHere( *ss ); - } -} - -/* Any transitions to another state? */ -bool FsmAp::anyRegularTransitions( StateAp *state ) -{ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - StateAp *toState = trans->tdap()->toState; - if ( toState != 0 ) - return true; - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - StateAp *toState = cond->toState; - if ( toState != 0 ) - return true; - } - } - } - return false; -} - -void FsmAp::markReachableFromHereStopFinal( StateAp *state ) -{ - /* Base case: return; */ - if ( state->stateBits & STB_ISMARKED ) - return; - - /* Set this state as processed. We are going to visit all states that this - * state has a transition to. */ - state->stateBits |= STB_ISMARKED; - - /* Recurse on all out transitions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - StateAp *toState = trans->tdap()->toState; - if ( toState != 0 && !toState->isFinState() ) - markReachableFromHereStopFinal( toState ); - - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - StateAp *toState = cond->toState; - if ( toState != 0 && !toState->isFinState() ) - markReachableFromHereStopFinal( toState ); - } - } - } - - /* Recurse on all states that compose us. */ - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter st = *state->nfaOut; st.lte(); st++ ) - markReachableFromHereStopFinal( st->toState ); - } - - if ( state->stateDictEl != 0 ) { - for ( StateSet::Iter ss = state->stateDictEl->stateSet; ss.lte(); ss++ ) - markReachableFromHereStopFinal( *ss ); - } -} - -/* Mark all states reachable from state. Traverse transitions backwards. Used - * for removing dead end paths in graphs. */ -void FsmAp::markReachableFromHereReverse( StateAp *state ) -{ - /* Base case: return; */ - if ( state->stateBits & STB_ISMARKED ) - return; - - /* Set this state as processed. We are going to visit all states with - * transitions into this state. */ - state->stateBits |= STB_ISMARKED; - - /* Recurse on all items in transitions. */ - for ( TransInList::Iter t = state->inTrans; t.lte(); t++ ) - markReachableFromHereReverse( t->fromState ); - for ( CondInList::Iter t = state->inCond; t.lte(); t++ ) - markReachableFromHereReverse( t->fromState ); -} - -/* Determine if there are any entry points into a start state other than the - * start state. Setting starting transitions requires that the start state be - * isolated. In most cases a start state will already be isolated. */ -bool FsmAp::isStartStateIsolated() -{ - /* If there are any in transitions then the state is not isolated. */ - if ( startState->inTrans.head != 0 ) - return false; - if ( startState->inCond.head != 0 ) - return false; - - /* If there are any entry points then isolated. */ - if ( startState->entryIds.length() > 0 ) - return false; - - return true; -} - -/* Bring in other's entry points. Assumes others states are going to be - * copied into this machine. */ -void FsmAp::copyInEntryPoints( FsmAp *other ) -{ - /* Use insert multi because names are not unique. */ - for ( EntryMap::Iter en = other->entryPoints; en.lte(); en++ ) - entryPoints.insertMulti( en->key, en->value ); -} - - -void FsmAp::unsetAllFinStates() -{ - for ( StateSet::Iter st = finStateSet; st.lte(); st++ ) - (*st)->stateBits &= ~ STB_ISFINAL; - finStateSet.empty(); -} - -void FsmAp::setFinBits( int finStateBits ) -{ - for ( int s = 0; s < finStateSet.length(); s++ ) - finStateSet.data[s]->stateBits |= finStateBits; -} - -void FsmAp::unsetFinBits( int finStateBits ) -{ - for ( int s = 0; s < finStateSet.length(); s++ ) - finStateSet.data[s]->stateBits &= ~ finStateBits; -} - - -/* Tests the integrity of the transition lists and the fromStates. */ -void FsmAp::verifyIntegrity() -{ - int count = 0; - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Walk the out transitions and assert fromState is correct. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - assert( trans->tdap()->fromState == state ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - assert( cond->fromState == state ); - } - } - } - - /* Walk the inlist and assert toState is correct. */ - for ( TransInList::Iter t = state->inTrans; t.lte(); t++ ) { - assert( t->toState == state ); - } - for ( CondInList::Iter t = state->inCond; t.lte(); t++ ) { - assert( t->toState == state ); - } - - count += 1; - } - - assert( stateList.length() == count ); -} - -void FsmAp::verifyReachability() -{ - /* Mark all the states that can be reached - * through the set of entry points. */ - markReachableFromHere( startState ); - for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) - markReachableFromHere( en->value ); - - /* Check that everything got marked. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - /* Assert it got marked and then clear the mark. */ - assert( st->stateBits & STB_ISMARKED ); - st->stateBits &= ~ STB_ISMARKED; - } -} - -void FsmAp::verifyNoDeadEndStates() -{ - /* Mark all states that have paths to the final states. */ - for ( StateSet::Iter pst = finStateSet; pst.lte(); pst++ ) - markReachableFromHereReverse( *pst ); - - /* Start state gets honorary marking. Must be done AFTER recursive call. */ - startState->stateBits |= STB_ISMARKED; - - /* Make sure everything got marked. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - /* Assert the state got marked and unmark it. */ - assert( st->stateBits & STB_ISMARKED ); - st->stateBits &= ~ STB_ISMARKED; - } -} - -void FsmAp::depthFirstOrdering( StateAp *state ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->stateBits & STB_ONLIST ) - return; - - /* Doing depth first, put state on the list. */ - state->stateBits |= STB_ONLIST; - stateList.append( state ); - - /* Recurse on everything ranges. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) - depthFirstOrdering( trans->tdap()->toState ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) - depthFirstOrdering( cond->toState ); - } - } - } - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter s = *state->nfaOut; s.lte(); s++ ) - depthFirstOrdering( s->toState ); - } -} - -/* Ordering states by transition connections. */ -void FsmAp::depthFirstOrdering() -{ - /* Init on state list flags. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) - st->stateBits &= ~STB_ONLIST; - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - /* Add back to the state list from the start state and all other entry - * points. */ - if ( errState != 0 ) - depthFirstOrdering( errState ); - - depthFirstOrdering( startState ); - for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) - depthFirstOrdering( en->value ); - - /* Make sure we put everything back on. */ - assert( stateListLen == stateList.length() ); -} - -/* Stable sort the states by final state status. */ -void FsmAp::sortStatesByFinal() -{ - /* Move forward through the list and move final states onto the end. */ - StateAp *state = 0; - StateAp *next = stateList.head; - StateAp *last = stateList.tail; - while ( state != last ) { - /* Move forward and load up the next. */ - state = next; - next = state->next; - - /* Throw to the end? */ - if ( state->isFinState() ) { - stateList.detach( state ); - stateList.append( state ); - } - } -} - -void FsmAp::setStateNumbers( int base ) -{ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - state->alg.stateNum = base++; -} - -bool FsmAp::checkErrTrans( StateAp *state, CondAp *trans ) -{ - /* Might go directly to error state. */ - if ( trans->toState == 0 ) - return true; - - return false; -} - -bool FsmAp::checkErrTrans( StateAp *state, TransAp *trans ) -{ - /* - * Look for a gap between this transition and the previous. - */ - if ( trans->prev == 0 ) { - /* If this is the first transition. */ - if ( ctx->keyOps->lt( ctx->keyOps->minKey, trans->lowKey ) ) - return true; - } - else { - /* Not the first transition. Compare against the prev. */ - TransAp *prev = trans->prev; - Key nextKey = prev->highKey; - ctx->keyOps->increment( nextKey ); - if ( ctx->keyOps->lt( nextKey, trans->lowKey ) ) - return true; - } - - if ( trans->plain() ) { - if ( trans->tdap()->toState == 0 ) - return true; - } - else { - /* Check for gaps in the condition list. */ - if ( trans->tcap()->condList.length() < trans->condFullSize() ) - return true; - - /* Check all destinations. */ - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++ ) { - if ( checkErrTrans( state, cti ) ) - return true; - } - } - - return false; -} - -bool FsmAp::checkErrTransFinish( StateAp *state ) -{ - /* Check if there are any ranges already. */ - if ( state->outList.length() == 0 ) - return true; - else { - /* Get the last and check for a gap on the end. */ - TransAp *last = state->outList.tail; - if ( ctx->keyOps->lt( last->highKey, ctx->keyOps->maxKey ) ) - return true; - } - return 0; -} - -bool FsmAp::hasErrorTrans() -{ - bool result; - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - for ( TransList::Iter tr = st->outList; tr.lte(); tr++ ) { - result = checkErrTrans( st, tr ); - if ( result ) - return true; - } - result = checkErrTransFinish( st ); - if ( result ) - return true; - } - return false; -} diff --git a/src/fsmcond.cc b/src/fsmcond.cc deleted file mode 100644 index b2339c12..00000000 --- a/src/fsmcond.cc +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright 2001-2018 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. - */ - -/* - * Setting conditions and merging states with conditions are similar activities - * when expressed in code. The critical difference is that a merge is a union - * of multiple paths. We have to take both paths. Setting a condition, however, - * is a restriction. We have to expand the transition to follow both values of - * the condition, then remove the one that is not set. - */ - -#include "fsmgraph.h" -#include "mergesort.h" -#include "parsedata.h" - -#include <assert.h> -#include <iostream> - -long TransAp::condFullSize() - { return condSpace == 0 ? 1 : condSpace->fullSize(); } - -void FsmAp::expandCondKeys( CondKeySet &condKeys, CondSpace *fromSpace, - CondSpace *mergedSpace ) -{ - CondSet fromCS, mergedCS; - - if ( fromSpace != 0 ) - fromCS.insert( fromSpace->condSet ); - - if ( mergedSpace != 0 ) - mergedCS.insert( mergedSpace->condSet ); - - /* Need to transform condition element to the merged set. */ - for ( int cti = 0; cti < condKeys.length(); cti++ ) { - long origVal = condKeys[cti]; - long newVal = 0; - - /* Iterate the bit positions in the from set. */ - for ( CondSet::Iter csi = fromCS; csi.lte(); csi++ ) { - /* If set, find it in the merged set and flip the bit to 1. */ - if ( origVal & (1 << csi.pos()) ) { - /* The condition is set. Find the bit position in the merged - * set. */ - Action **cim = mergedCS.find( *csi ); - long bitPos = (cim - mergedCS.data); - newVal |= 1 << bitPos; - } - } - - if ( origVal != newVal ) - condKeys[cti] = newVal; - } - - /* Need to double up the whole transition list for each condition test in - * merged that is not in from. The one we add has the bit in question set. - * */ - for ( CondSet::Iter csi = mergedCS; csi.lte(); csi++ ) { - Action **cim = fromCS.find( *csi ); - if ( cim == 0 ) { - CondKeySet newItems; - newItems.append( condKeys ); - for ( int cti = 0; cti < condKeys.length(); cti++ ) { - int key = condKeys[cti] | (1 << csi.pos()); - newItems.insert( key ); - } - - condKeys.setAs( newItems ); - } - } -} - -void FsmAp::expandConds( StateAp *fromState, TransAp *trans, - CondSpace *fromSpace, CondSpace *mergedSpace ) -{ - CondSet fromCS, mergedCS; - - if ( fromSpace != 0 ) - fromCS.insert( fromSpace->condSet ); - - if ( mergedSpace != 0 ) - mergedCS.insert( mergedSpace->condSet ); - - /* Need to transform condition element to the merged set. */ - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++ ) { - long origVal = cti->key.getVal(); - long newVal = 0; - - /* Iterate the bit positions in the from set. */ - for ( CondSet::Iter csi = fromCS; csi.lte(); csi++ ) { - /* If set, find it in the merged set and flip the bit to 1. */ - if ( origVal & (1 << csi.pos()) ) { - /* The condition is set. Find the bit position in the merged - * set. */ - Action **cim = mergedCS.find( *csi ); - long bitPos = (cim - mergedCS.data); - newVal |= 1 << bitPos; - } - } - - if ( origVal != newVal ) - cti->key = newVal; - } - - /* Need to double up the whole transition list for each condition test in - * merged that is not in from. The one we add has the bit in question set. - * */ - for ( CondSet::Iter csi = mergedCS; csi.lte(); csi++ ) { - Action **cim = fromCS.find( *csi ); - if ( cim == 0 ) { - CondList newItems; - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++ ) { - /* Sub-transition for conditions. */ - CondAp *cond = new CondAp( trans ); - - /* Attach only if our caller wants the expanded transitions - * attached. */ - attachTrans( fromState, cti->toState, cond ); - - /* Call the user callback to add in the original source transition. */ - addInTrans( cond, cti.ptr ); - - cond->key = cti->key.getVal() | (1 << csi.pos()); - - newItems.append( cond ); - } - - /* Merge newItems in. Both the condList and newItems are sorted. Make - * a sorted list out of them. */ - CondAp *dest = trans->tcap()->condList.head; - while ( dest != 0 && newItems.head != 0 ) { - if ( newItems.head->key.getVal() > dest->key.getVal() ) { - dest = dest->next; - } - else { - /* Pop the item for insertion. */ - CondAp *ins = newItems.detachFirst(); - trans->tcap()->condList.addBefore( dest, ins ); - } - } - - /* Append the rest of the items. */ - trans->tcap()->condList.append( newItems ); - } - } -} - -CondSpace *FsmAp::expandCondSpace( TransAp *destTrans, TransAp *srcTrans ) -{ - CondSet destCS, srcCS; - CondSet mergedCS; - - if ( destTrans->condSpace != 0 ) - destCS.insert( destTrans->condSpace->condSet ); - - if ( srcTrans->condSpace != 0 ) - srcCS.insert( srcTrans->condSpace->condSet ); - - mergedCS.insert( destCS ); - mergedCS.insert( srcCS ); - - return addCondSpace( mergedCS ); -} - -StateAp *FsmAp::copyStateForExpansion( StateAp *srcState ) -{ - StateAp *newState = new StateAp(); - newState->outCondSpace = srcState->outCondSpace; - newState->outCondKeys = srcState->outCondKeys; - return newState; -} - -void FsmAp::mergeOutConds( StateAp *destState, StateAp *srcState, bool leaving ) -{ - if ( destState == srcState ) - return; - - bool bothFinal = destState->isFinState() && srcState->isFinState(); - bool unionOp = !leaving; - - CondSet destCS, srcCS; - CondSet mergedCS; - - if ( destState->outCondSpace != 0 ) - destCS.insert( destState->outCondSpace->condSet ); - - if ( srcState->outCondSpace != 0 ) - srcCS.insert( srcState->outCondSpace->condSet ); - - mergedCS.insert( destCS ); - mergedCS.insert( srcCS ); - - if ( mergedCS.length() > 0 ) { - CondSpace *mergedSpace = addCondSpace( mergedCS ); - - CondSpace *srcSpace = srcState->outCondSpace; - CondKeySet srcKeys = srcState->outCondKeys; - - if ( srcSpace != mergedSpace ) { - /* Prep the key list with zero item if necessary. */ - if ( srcSpace == 0 ) - srcKeys.append( 0 ); - - expandCondKeys( srcKeys, srcSpace, mergedSpace ); - } - - if ( destState->outCondSpace != mergedSpace ) { - /* Prep the key list with zero item if necessary. */ - if ( destState->outCondSpace == 0 ) - destState->outCondKeys.append( 0 ); - - /* Now expand the dest. */ - expandCondKeys( destState->outCondKeys, destState->outCondSpace, mergedSpace ); - } - - destState->outCondSpace = mergedSpace; - - if ( unionOp && bothFinal ) { - /* Keys can come from either. */ - for ( CondKeySet::Iter c = srcKeys; c.lte(); c++ ) - destState->outCondKeys.insert( *c ); - } - else { - /* Keys need to be in both sets. */ - for ( long c = 0; c < destState->outCondKeys.length(); ) { - if ( !srcKeys.find( destState->outCondKeys[c] ) ) - destState->outCondKeys.CondKeyVect::remove( c, 1 ); - else - c++; - } - } - } -} - -CondSpace *FsmAp::addCondSpace( const CondSet &condSet ) -{ - CondSpace *condSpace = ctx->condData->condSpaceMap.find( condSet ); - if ( condSpace == 0 ) { - condSpace = new CondSpace( condSet ); - ctx->condData->condSpaceMap.insert( condSpace ); - } - return condSpace; -} - -TransDataAp *FsmAp::convertToTransAp( StateAp *from, CondAp *cond ) -{ - TransDataAp *newTrans = new TransDataAp(); - newTrans->lowKey = cond->transAp->lowKey; - newTrans->highKey = cond->transAp->highKey; - - newTrans->lmActionTable.setActions( cond->lmActionTable ); - newTrans->actionTable.setActions( cond->actionTable ); - newTrans->priorTable.setPriors( cond->priorTable ); - - attachTrans( from, cond->toState, newTrans ); - - /* Detach in list. */ - detachTrans( from, cond->toState, cond ); - delete cond->transAp; - delete cond; - - return newTrans; -} - -TransCondAp *FsmAp::convertToCondAp( StateAp *from, TransDataAp *trans ) -{ - TransCondAp *newTrans = new TransCondAp(); - newTrans->lowKey = trans->lowKey; - newTrans->highKey = trans->highKey; - newTrans->condSpace = trans->condSpace; - - CondAp *newCond = new CondAp( newTrans ); - newCond->key = 0; - newTrans->condList.append( newCond ); - - newCond->lmActionTable.setActions( trans->lmActionTable ); - newCond->actionTable.setActions( trans->actionTable ); - newCond->priorTable.setPriors( trans->priorTable ); - - attachTrans( from, trans->toState, newCond ); - - /* Detach in list. */ - detachTrans( from, trans->toState, trans ); - delete trans; - - return newTrans; -} - -void FsmAp::convertToCondAp( StateAp *state ) -{ - /* First replace TransDataAp with cond versions. */ - TransList destList; - for ( TransList::Iter tr = state->outList; tr.lte(); ) { - TransList::Iter next = tr.next(); - if ( tr->plain() ) { - TransCondAp *newTrans = convertToCondAp( state, tr->tdap() ); - destList.append( newTrans ); - } - else { - destList.append( tr ); - } - - tr = next; - } - - state->outList.abandon(); - state->outList.transfer( destList ); -} - -void FsmAp::doEmbedCondition( StateAp *state, - const CondSet &set, const CondKeySet &vals ) -{ - convertToCondAp( state ); - - for ( TransList::Iter tr = state->outList; tr.lte(); tr++ ) { - - /* The source (being embedded). */ - CondSpace *srcSpace = addCondSpace( set ); - CondKeySet srcVals = vals; - - /* Extract cond key set from the condition list. We will use this to - * compute the intersection of the cond keys. */ - CondSpace *trSpace = tr->condSpace; - CondKeySet trVals; - if ( tr->condSpace == 0 ) - trVals.append( 0 ); - else { - for ( CondList::Iter cti = tr->tcap()->condList; cti.lte(); cti++ ) { - long key = cti->key.getVal(); - trVals.append( key ); - } - } - - /* Construct merged. */ - CondSet mergedCS; - if ( tr->condSpace != 0 ) - mergedCS.insert( tr->condSpace->condSet ); - mergedCS.insert( set ); - - CondSpace *mergedSpace = addCondSpace( mergedCS ); - - if ( srcSpace != mergedSpace ) { - /* Prep the key list with zero item if necessary. */ - if ( srcSpace == 0 ) - srcVals.append( 0 ); - - expandCondKeys( srcVals, srcSpace, mergedSpace ); - } - - if ( trSpace != mergedSpace ) { - /* Don't need to prep the key list with zero item, will be there - * (see above). */ - expandCondKeys( trVals, trSpace, mergedSpace ); - } - - /* Implement AND, in two parts. */ - CondKeySet newItems; - for ( CondKeySet::Iter c = srcVals; c.lte(); c++ ) { - if ( trVals.find( *c ) ) - newItems.insert( *c ); - } - - for ( CondKeySet::Iter c = trVals; c.lte(); c++ ) { - if ( srcVals.find( *c ) ) - newItems.insert( *c ); - } - - /* Expand the transitions, then we remove anything not in the computed - * list of keys. This approach allows us to embed combinations of - * senses, rather than cond-sense pairs. Necessary for out conditions. */ - CondSpace *orig = tr->condSpace; - tr->condSpace = mergedSpace; - expandConds( state, tr, orig, mergedSpace ); - - /* After expansion, remove anything not in newItems. */ - for ( CondList::Iter cti = tr->tcap()->condList; cti.lte(); ) { - long key = cti->key.getVal(); - - if ( !newItems.find( key ) ) { - /* Delete. */ - CondList::Iter next = cti.next(); - - CondAp *cond = cti; - detachTrans( state, cond->toState, cond ); - tr->tcap()->condList.detach( cond ); - delete cond; - - cti = next; - } - else { - /* Leave alone. */ - cti++; - } - } - } -} - -FsmRes FsmAp::embedCondition( FsmAp *fsm, StateAp *state, const CondSet &set, const CondKeySet &vals ) -{ - /* Turn on misfit accounting to possibly catch the old start state. */ - fsm->setMisfitAccounting( true ); - - /* Worker. */ - fsm->doEmbedCondition( state, set, vals ); - - /* Fill in any states that were newed up as combinations of others. */ - FsmRes res = fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - return res; -} - -void FsmAp::addOutCondition( StateAp *state, Action *condAction, bool sense ) -{ - CondSet origCS; - if ( state->outCondSpace != 0 ) - origCS.insert( state->outCondSpace->condSet ); - - CondSet mergedCS; - mergedCS.insert( origCS ); - - bool added = mergedCS.insert( condAction ); - if ( !added ) { - - /* Already exists in the cond set. For every transition, if the - * sense is identical to what we are embedding, leave it alone. If - * the sense is opposite, delete it. */ - - /* Find the position. */ - long pos = 0; - for ( CondSet::Iter csi = mergedCS; csi.lte(); csi++ ) { - if ( *csi == condAction ) - pos = csi.pos(); - } - - for ( int cti = 0; cti < state->outCondKeys.length(); ) { - long key = state->outCondKeys[cti]; - - bool set = ( key & ( 1 << pos ) ) != 0; - if ( sense xor set ) { - /* Delete. */ - state->outCondKeys.CondKeyVect::remove( cti, 1 ); - } - else { - /* Leave alone. */ - cti++; - } - } - } - else { - /* Does not exist in the cond set. We will add it. */ - - if ( state->outCondSpace == 0 ) { - /* Note that unlike transitions, we start here with an empty key - * list. Add the item */ - state->outCondKeys.append( 0 ); - } - - /* Allocate a cond space for the merged set. */ - CondSpace *mergedCondSpace = addCondSpace( mergedCS ); - state->outCondSpace = mergedCondSpace; - - /* FIXME: assumes one item always. */ - - /* Translate original condition values, making space for the new bit - * (possibly) introduced by the condition embedding. */ - for ( int cti = 0; cti < state->outCondKeys.length(); cti++ ) { - long origVal = state->outCondKeys[cti]; - long newVal = 0; - - /* For every set bit in the orig, find it's position in the merged - * and set the bit appropriately. */ - for ( CondSet::Iter csi = origCS; csi.lte(); csi++ ) { - /* If set, find it in the merged set and flip the bit to 1. If - * not set, there is nothing to do (convenient eh?) */ - if ( origVal & (1 << csi.pos()) ) { - /* The condition is set. Find the bit position in the - * merged set. */ - Action **cim = mergedCS.find( *csi ); - long bitPos = (cim - mergedCS.data); - newVal |= 1 << bitPos; - } - } - - if ( origVal != newVal ) - state->outCondKeys[cti] = newVal; - - /* Now set the new bit appropriately. Since it defaults to zero we - * only take action if sense is positive. */ - if ( sense ) { - Action **cim = mergedCS.find( condAction ); - int pos = cim - mergedCS.data; - state->outCondKeys[cti] = state->outCondKeys[cti] | (1 << pos); - } - } - } -} diff --git a/src/fsmgraph.cc b/src/fsmgraph.cc deleted file mode 100644 index 819bfa96..00000000 --- a/src/fsmgraph.cc +++ /dev/null @@ -1,1948 +0,0 @@ -/* - * Copyright 2001-2018 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 <assert.h> -#include <iostream> - -#include "fsmgraph.h" -#include "mergesort.h" -#include "action.h" - -using std::endl; - -Action::~Action() -{ - /* If we were created by substitution of another action then we don't own the inline list. */ - if ( substOf == 0 && inlineList != 0 ) { - inlineList->empty(); - delete inlineList; - inlineList = 0; - } -} - -InlineItem::~InlineItem() -{ - if ( children != 0 ) { - children->empty(); - delete children; - } -} - -/* Make a new state. The new state will be put on the graph's - * list of state. The new state can be created final or non final. */ -StateAp *FsmAp::addState() -{ - /* Make the new state to return. */ - StateAp *state = new StateAp(); - - if ( misfitAccounting ) { - /* Create the new state on the misfit list. All states are created - * with no foreign in transitions. */ - misfitList.append( state ); - } - else { - /* Create the new state. */ - stateList.append( state ); - } - - return state; -} - -/* Construct an FSM that is the concatenation of an array of characters. A new - * machine will be made that has len+1 states with one transition between each - * state for each integer in str. IsSigned determines if the integers are to - * be considered as signed or unsigned ints. */ -FsmAp *FsmAp::concatFsm( FsmCtx *ctx, Key *str, int len ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Make the first state and set it as the start state. */ - StateAp *last = fsm->addState(); - fsm->setStartState( last ); - - /* Attach subsequent states. */ - for ( int i = 0; i < len; i++ ) { - StateAp *newState = fsm->addState(); - fsm->attachNewTrans( last, newState, str[i], str[i] ); - last = newState; - } - - /* Make the last state the final state. */ - fsm->setFinState( last ); - - return fsm; -} - -/* Case insensitive version of concatFsm. */ -FsmAp *FsmAp::concatFsmCI( FsmCtx *ctx, Key *str, int len ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Make the first state and set it as the start state. */ - StateAp *last = fsm->addState(); - fsm->setStartState( last ); - - /* Attach subsequent states. */ - for ( int i = 0; i < len; i++ ) { - StateAp *newState = fsm->addState(); - - KeySet keySet( ctx->keyOps ); - if ( str[i].isLower() ) - keySet.insert( str[i].toUpper() ); - if ( str[i].isUpper() ) - keySet.insert( str[i].toLower() ); - keySet.insert( str[i] ); - - for ( int i = 0; i < keySet.length(); i++ ) - fsm->attachNewTrans( last, newState, keySet[i], keySet[i] ); - - last = newState; - } - - /* Make the last state the final state. */ - fsm->setFinState( last ); - - return fsm; -} - - -/* Construct a machine that matches one character. A new machine will be made - * that has two states with a single transition between the states. */ -FsmAp *FsmAp::concatFsm( FsmCtx *ctx, Key chr ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Two states first start, second final. */ - fsm->setStartState( fsm->addState() ); - - StateAp *end = fsm->addState(); - fsm->setFinState( end ); - - /* Attach on the character. */ - fsm->attachNewTrans( fsm->startState, end, chr, chr ); - - return fsm; -} - -/* Case insensitive version of single-char concat FSM. */ -FsmAp *FsmAp::concatFsmCI( FsmCtx *ctx, Key chr ) -{ - return concatFsmCI( ctx, &chr, 1 ); -} - - -/* Construct a machine that matches any character in set. A new machine will - * be made that has two states and len transitions between the them. The set - * should be ordered correctly accroding to KeyOps and should not contain - * any duplicates. */ -FsmAp *FsmAp::orFsm( FsmCtx *ctx, Key *set, int len ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Two states first start, second final. */ - fsm->setStartState( fsm->addState() ); - - StateAp *end = fsm->addState(); - fsm->setFinState( end ); - - for ( int i = 1; i < len; i++ ) - assert( ctx->keyOps->lt( set[i-1], set[i] ) ); - - /* Attach on all the integers in the given string of ints. */ - for ( int i = 0; i < len; i++ ) - fsm->attachNewTrans( fsm->startState, end, set[i], set[i] ); - - return fsm; -} - -FsmAp *FsmAp::dotFsm( FsmCtx *ctx ) -{ - FsmAp *retFsm = FsmAp::rangeFsm( ctx, - ctx->keyOps->minKey, ctx->keyOps->maxKey ); - return retFsm; -} - -FsmAp *FsmAp::dotStarFsm( FsmCtx *ctx ) -{ - FsmAp *retFsm = FsmAp::rangeStarFsm( ctx, - ctx->keyOps->minKey, ctx->keyOps->maxKey ); - return retFsm; -} - -/* Construct a machine that matches a range of characters. A new machine will - * be made with two states and a range transition between them. The range will - * match any characters from low to high inclusive. Low should be less than or - * equal to high otherwise undefined behaviour results. IsSigned determines - * if the integers are to be considered as signed or unsigned ints. */ -FsmAp *FsmAp::rangeFsm( FsmCtx *ctx, Key low, Key high ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Two states first start, second final. */ - fsm->setStartState( fsm->addState() ); - - StateAp *end = fsm->addState(); - fsm->setFinState( end ); - - /* Attach using the range of characters. */ - fsm->attachNewTrans( fsm->startState, end, low, high ); - - return fsm; -} - -FsmAp *FsmAp::notRangeFsm( FsmCtx *ctx, Key low, Key high ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Two states first start, second final. */ - fsm->setStartState( fsm->addState() ); - - StateAp *end = fsm->addState(); - fsm->setFinState( end ); - - /* Attach using the range of characters. */ - if ( ctx->keyOps->lt( ctx->keyOps->minKey, low ) ) { - ctx->keyOps->decrement( low ); - fsm->attachNewTrans( fsm->startState, end, ctx->keyOps->minKey, low ); - } - - if ( ctx->keyOps->lt( high, ctx->keyOps->maxKey ) ) { - ctx->keyOps->increment( high ); - fsm->attachNewTrans( fsm->startState, end, high, ctx->keyOps->maxKey ); - } - - return fsm; -} - - -FsmAp *FsmAp::rangeFsmCI( FsmCtx *ctx, Key lowKey, Key highKey ) -{ - FsmAp *retFsm = rangeFsm( ctx, lowKey, highKey ); - - /* Union the portion that covers alphas. */ - if ( lowKey.getVal() <= 'z' ) { - int low, high; - if ( lowKey.getVal() <= 'a' ) - low = 'a'; - else - low = lowKey.getVal(); - - if ( highKey.getVal() >= 'a' ) { - if ( highKey.getVal() >= 'z' ) - high = 'z'; - else - high = highKey.getVal(); - - /* Add in upper(low) .. upper(high) */ - - FsmAp *addFsm = FsmAp::rangeFsm( ctx, toupper(low), toupper(high) ); - FsmRes res = FsmAp::unionOp( retFsm, addFsm ); - retFsm = res.fsm; - } - } - - if ( lowKey.getVal() <= 'Z' ) { - int low, high; - if ( lowKey.getVal() <= 'A' ) - low = 'A'; - else - low = lowKey.getVal(); - - if ( highKey.getVal() >= 'A' ) { - if ( highKey.getVal() >= 'Z' ) - high = 'Z'; - else - high = highKey.getVal(); - - /* Add in lower(low) .. lower(high) */ - FsmAp *addFsm = FsmAp::rangeFsm( ctx, tolower(low), tolower(high) ); - FsmRes res = FsmAp::unionOp( retFsm, addFsm ); - retFsm = res.fsm; - } - } - - return retFsm; -} - -/* Construct a machine that a repeated range of characters. */ -FsmAp *FsmAp::rangeStarFsm( FsmCtx *ctx, Key low, Key high ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* One state which is final and is the start state. */ - fsm->setStartState( fsm->addState() ); - fsm->setFinState( fsm->startState ); - - /* Attach start to start using range of characters. */ - fsm->attachNewTrans( fsm->startState, fsm->startState, low, high ); - - return fsm; -} - -/* Construct a machine that matches the empty string. A new machine will be - * made with only one state. The new state will be both a start and final - * state. IsSigned determines if the machine has a signed or unsigned - * alphabet. Fsm operations must be done on machines with the same alphabet - * signedness. */ -FsmAp *FsmAp::lambdaFsm( FsmCtx *ctx ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Give it one state with no transitions making it - * the start state and final state. */ - fsm->setStartState( fsm->addState() ); - fsm->setFinState( fsm->startState ); - - return fsm; -} - -/* Construct a machine that matches nothing at all. A new machine will be - * made with only one state. It will not be final. */ -FsmAp *FsmAp::emptyFsm( FsmCtx *ctx ) -{ - FsmAp *fsm = new FsmAp( ctx ); - - /* Give it one state with no transitions making it - * the start state and final state. */ - fsm->setStartState( fsm->addState() ); - - return fsm; -} - -void FsmAp::transferOutData( StateAp *destState, StateAp *srcState ) -{ - for ( TransList::Iter trans = destState->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) { - /* Get the actions data from the outActionTable. */ - trans->tdap()->actionTable.setActions( srcState->outActionTable ); - - /* Get the priorities from the outPriorTable. */ - trans->tdap()->priorTable.setPriors( srcState->outPriorTable ); - } - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) { - /* Get the actions data from the outActionTable. */ - cond->actionTable.setActions( srcState->outActionTable ); - - /* Get the priorities from the outPriorTable. */ - cond->priorTable.setPriors( srcState->outPriorTable ); - } - } - } - } - - if ( destState->nfaOut != 0 ) { - for ( NfaTransList::Iter na = *destState->nfaOut; na.lte(); na++ ) - transferOutToNfaTrans( na, srcState ); - } -} - -/* Union worker used by union, set diff (subtract) and intersection. */ -FsmRes FsmAp::doUnion( FsmAp *fsm, FsmAp *other ) -{ - /* Build a state set consisting of both start states */ - StateSet startStateSet; - startStateSet.insert( fsm->startState ); - startStateSet.insert( other->startState ); - - /* Both of the original start states loose their start state status. */ - fsm->unsetStartState(); - other->unsetStartState(); - - /* Bring in the rest of other's entry points. */ - fsm->copyInEntryPoints( other ); - other->entryPoints.empty(); - - /* Merge the lists. This will move all the states from other - * into this. No states will be deleted. */ - fsm->stateList.append( other->stateList ); - fsm->misfitList.append( other->misfitList ); - - /* Move the final set data from other into this. */ - fsm->finStateSet.insert(other->finStateSet); - other->finStateSet.empty(); - - /* Since other's list is empty, we can delete the fsm without - * affecting any states. */ - delete other; - - /* Create a new start state. */ - fsm->setStartState( fsm->addState() ); - - /* Merge the start states. */ - fsm->mergeStateList( fsm->startState, startStateSet.data, startStateSet.length() ); - - /* Fill in any new states made from merging. */ - return fillInStates( fsm ); -} - -bool FsmAp::inEptVect( EptVect *eptVect, StateAp *state ) -{ - if ( eptVect != 0 ) { - /* Vect is there, walk it looking for state. */ - for ( int i = 0; i < eptVect->length(); i++ ) { - if ( eptVect->data[i].targ == state ) - return true; - } - } - return false; -} - -/* Fill epsilon vectors in a root state from a given starting point. Epmploys - * a depth first search through the graph of epsilon transitions. */ -void FsmAp::epsilonFillEptVectFrom( StateAp *root, StateAp *from, bool parentLeaving ) -{ - /* Walk the epsilon transitions out of the state. */ - for ( EpsilonTrans::Iter ep = from->epsilonTrans; ep.lte(); ep++ ) { - /* Find the entry point, if the it does not resove, ignore it. */ - EntryMapEl *enLow, *enHigh; - if ( entryPoints.findMulti( *ep, enLow, enHigh ) ) { - /* Loop the targets. */ - for ( EntryMapEl *en = enLow; en <= enHigh; en++ ) { - /* Do not add the root or states already in eptVect. */ - StateAp *targ = en->value; - if ( targ != from && !inEptVect(root->eptVect, targ) ) { - /* Maybe need to create the eptVect. */ - if ( root->eptVect == 0 ) - root->eptVect = new EptVect(); - - /* If moving to a different graph or if any parent is - * leaving then we are leaving. */ - bool leaving = parentLeaving || - root->owningGraph != targ->owningGraph; - - /* All ok, add the target epsilon and recurse. */ - root->eptVect->append( EptVectEl(targ, leaving) ); - epsilonFillEptVectFrom( root, targ, leaving ); - } - } - } - } -} - -void FsmAp::shadowReadWriteStates() -{ - /* Init isolatedShadow algorithm data. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) - st->isolatedShadow = 0; - - /* Any states that may be both read from and written to must - * be shadowed. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - /* Find such states by looping through stateVect lists, which give us - * the states that will be read from. May cause us to visit the states - * that we are interested in more than once. */ - if ( st->eptVect != 0 ) { - /* For all states that will be read from. */ - for ( EptVect::Iter ept = *st->eptVect; ept.lte(); ept++ ) { - /* Check for read and write to the same state. */ - StateAp *targ = ept->targ; - if ( targ->eptVect != 0 ) { - /* State is to be written to, if the shadow is not already - * there, create it. */ - if ( targ->isolatedShadow == 0 ) { - StateAp *shadow = addState(); - mergeStates( shadow, targ ); - targ->isolatedShadow = shadow; - } - - /* Write shadow into the state vector so that it is the - * state that the epsilon transition will read from. */ - ept->targ = targ->isolatedShadow; - } - } - } - } -} - -void FsmAp::resolveEpsilonTrans() -{ - /* Walk the state list and invoke recursive worker on each state. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) - epsilonFillEptVectFrom( st, st, false ); - - /* Prevent reading from and writing to of the same state. */ - shadowReadWriteStates(); - - /* For all states that have epsilon transitions out, draw the transitions, - * clear the epsilon transitions. */ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - /* If there is a state vector, then create the pre-merge state. */ - if ( st->eptVect != 0 ) { - /* Merge all the epsilon targets into the state. */ - for ( EptVect::Iter ept = *st->eptVect; ept.lte(); ept++ ) { - if ( ept->leaving ) - mergeStatesLeaving( st, ept->targ ); - else - mergeStates( st, ept->targ ); - } - - /* Clean up the target list. */ - delete st->eptVect; - st->eptVect = 0; - } - - /* Clear the epsilon transitions vector. */ - st->epsilonTrans.empty(); - } -} - -FsmRes FsmAp::applyNfaTrans( FsmAp *fsm, StateAp *fromState, StateAp *toState, NfaTrans *nfaTrans ) -{ - fsm->setMisfitAccounting( true ); - - fsm->mergeStates( fromState, toState, false ); - - /* Epsilons can caused merges which leave behind unreachable states. */ - FsmRes res = FsmAp::fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Can nuke the epsilon transition that we will never - * follow. */ - fsm->detachFromNfa( fromState, toState, nfaTrans ); - fromState->nfaOut->detach( nfaTrans ); - delete nfaTrans; - - if ( fromState->nfaOut->length() == 0 ) { - delete fromState->nfaOut; - fromState->nfaOut = 0; - } - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - return FsmRes( FsmRes::Fsm(), fsm ); -} - -void FsmAp::globOp( FsmAp **others, int numOthers ) -{ - for ( int m = 0; m < numOthers; m++ ) { - assert( ctx == others[m]->ctx ); - } - - /* All other machines loose start states status. */ - for ( int m = 0; m < numOthers; m++ ) - others[m]->unsetStartState(); - - /* Bring the other machines into this. */ - for ( int m = 0; m < numOthers; m++ ) { - /* Bring in the rest of other's entry points. */ - copyInEntryPoints( others[m] ); - others[m]->entryPoints.empty(); - - /* Merge the lists. This will move all the states from other into - * this. No states will be deleted. */ - stateList.append( others[m]->stateList ); - assert( others[m]->misfitList.length() == 0 ); - - /* Move the final set data from other into this. */ - finStateSet.insert( others[m]->finStateSet ); - others[m]->finStateSet.empty(); - - /* Since other's list is empty, we can delete the fsm without - * affecting any states. */ - delete others[m]; - } -} - -/* Used near the end of an fsm construction. Any labels that are still around - * are referenced only by gotos and calls and they need to be made into - * deterministic entry points. */ -void FsmAp::deterministicEntry() -{ - /* States may loose their entry points, turn on misfit accounting. */ - setMisfitAccounting( true ); - - /* Get a copy of the entry map then clear all the entry points. As we - * iterate the old entry map finding duplicates we will add the entry - * points for the new states that we create. */ - EntryMap prevEntry = entryPoints; - unsetAllEntryPoints(); - - for ( int enId = 0; enId < prevEntry.length(); ) { - /* Count the number of states on this entry key. */ - int highId = enId; - while ( highId < prevEntry.length() && prevEntry[enId].key == prevEntry[highId].key ) - highId += 1; - - int numIds = highId - enId; - if ( numIds == 1 ) { - /* Only a single entry point, just set the entry. */ - setEntry( prevEntry[enId].key, prevEntry[enId].value ); - } - else { - /* Multiple entry points, need to create a new state and merge in - * all the targets of entry points. */ - StateAp *newEntry = addState(); - for ( int en = enId; en < highId; en++ ) - mergeStates( newEntry, prevEntry[en].value ); - - /* Add the new state as the single entry point. */ - setEntry( prevEntry[enId].key, newEntry ); - } - - enId += numIds; - } - - /* The old start state may be unreachable. Remove the misfits and turn off - * misfit accounting. */ - removeMisfits(); - setMisfitAccounting( false ); -} - -/* Unset any final states that are no longer to be final due to final bits. */ -void FsmAp::unsetKilledFinals() -{ - /* Duplicate the final state set before we begin modifying it. */ - StateSet fin( finStateSet ); - - for ( int s = 0; s < fin.length(); s++ ) { - /* Check for killing bit. */ - StateAp *state = fin.data[s]; - if ( state->stateBits & STB_GRAPH1 ) { - /* One final state is a killer, set to non-final. */ - unsetFinState( state ); - } - - /* Clear all killing bits. Non final states should never have had those - * state bits set in the first place. */ - state->stateBits &= ~STB_GRAPH1; - } -} - -/* Unset any final states that are no longer to be final due to final bits. */ -void FsmAp::unsetIncompleteFinals() -{ - /* Duplicate the final state set before we begin modifying it. */ - StateSet fin( finStateSet ); - - for ( int s = 0; s < fin.length(); s++ ) { - /* Check for one set but not the other. */ - StateAp *state = fin.data[s]; - if ( state->stateBits & STB_BOTH && - (state->stateBits & STB_BOTH) != STB_BOTH ) - { - /* One state wants the other but it is not there. */ - unsetFinState( state ); - } - - /* Clear wanting bits. Non final states should never have had those - * state bits set in the first place. */ - state->stateBits &= ~STB_BOTH; - } -} - -/* Kleene star operator. Makes this machine the kleene star of itself. Any - * transitions made going out of the machine and back into itself will be - * notified that they are leaving transitions by having the leavingFromState - * callback invoked. */ -FsmRes FsmAp::starOp( FsmAp *fsm ) -{ - /* The start func orders need to be shifted before doing the star. */ - fsm->ctx->curActionOrd += fsm->shiftStartActionOrder( fsm->ctx->curActionOrd ); - - /* Turn on misfit accounting to possibly catch the old start state. */ - fsm->setMisfitAccounting( true ); - - /* Create the new new start state. It will be set final after the merging - * of the final states with the start state is complete. */ - StateAp *prevStartState = fsm->startState; - fsm->unsetStartState(); - fsm->setStartState( fsm->addState() ); - - /* Merge the new start state with the old one to isolate it. */ - fsm->mergeStates( fsm->startState, prevStartState ); - - if ( !fsm->startState->isFinState() ) { - /* Common case, safe to merge. */ - for ( StateSet::Iter st = fsm->finStateSet; st.lte(); st++ ) - fsm->mergeStatesLeaving( *st, fsm->startState ); - } - else { - /* Merge the start state into all final states. Except the start state on - * the first pass. If the start state is set final we will be doubling up - * its transitions, which will get transfered to any final states that - * follow it in the final state set. This will be determined by the order - * of items in the final state set. To prevent this we just merge with the - * start on a second pass. */ - StateSet origFin = fsm->finStateSet; - for ( StateSet::Iter st = origFin; st.lte(); st++ ) { - if ( *st != fsm->startState ) - fsm->mergeStatesLeaving( *st, fsm->startState ); - } - - /* Now it is safe to merge the start state with itself (provided it - * is set final). */ - if ( fsm->startState->isFinState() ) - fsm->mergeStatesLeaving( fsm->startState, fsm->startState ); - } - - /* Now ensure the new start state is a final state. */ - fsm->setFinState( fsm->startState ); - - /* Fill in any states that were newed up as combinations of others. */ - FsmRes res = FsmAp::fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - fsm->afterOpMinimize(); - - return res; -} - -FsmRes FsmAp::plusOp( FsmAp *fsm ) -{ - /* Need a duplicate for the star end. */ - FsmAp *factorDup = new FsmAp( *fsm ); - - /* Star the duplicate. */ - FsmRes res1 = FsmAp::starOp( factorDup ); - if ( !res1.success() ) - return res1; - - FsmRes res2 = FsmAp::concatOp( fsm, res1.fsm ); - if ( !res2.success() ) - return res2; - - return res2; -} - -FsmRes FsmAp::questionOp( FsmAp *fsm ) -{ - /* Make the null fsm. */ - FsmAp *nu = FsmAp::lambdaFsm( fsm->ctx ); - - /* Perform the question operator. */ - FsmRes res = FsmAp::unionOp( fsm, nu ); - if ( !res.success() ) - return res; - - return res; -} - -FsmRes FsmAp::exactRepeatOp( FsmAp *fsm, int times ) -{ - /* Zero repetitions produces lambda machine. */ - if ( times == 0 ) { - FsmCtx *fsmCtx = fsm->ctx; - delete fsm; - return FsmRes( FsmRes::Fsm(), FsmAp::lambdaFsm( fsmCtx ) ); - } - - /* The start func orders need to be shifted before doing the - * repetition. */ - fsm->ctx->curActionOrd += fsm->shiftStartActionOrder( fsm->ctx->curActionOrd ); - - /* A repeat of one does absolutely nothing. */ - if ( times == 1 ) - return FsmRes( FsmRes::Fsm(), fsm ); - - /* Make a machine to make copies from. */ - FsmAp *copyFrom = new FsmAp( *fsm ); - - /* Concatentate duplicates onto the end up until before the last. */ - for ( int i = 1; i < times-1; i++ ) { - FsmAp *dup = new FsmAp( *copyFrom ); - FsmRes res = concatOp( fsm, dup ); - if ( !res.success() ) { - delete copyFrom; - return res; - } - } - - /* Now use the copyFrom on the end. */ - FsmRes res = concatOp( fsm, copyFrom ); - if ( !res.success()) - return res; - - res.fsm->afterOpMinimize(); - - return res; -} - -FsmRes FsmAp::maxRepeatOp( FsmAp *fsm, int times ) -{ - /* Zero repetitions produces lambda machine. */ - if ( times == 0 ) { - FsmCtx *fsmCtx = fsm->ctx; - delete fsm; - return FsmRes( FsmRes::Fsm(), FsmAp::lambdaFsm( fsmCtx ) ); - } - - fsm->ctx->curActionOrd += fsm->shiftStartActionOrder( fsm->ctx->curActionOrd ); - - /* A repeat of one optional merely allows zero string. */ - if ( times == 1 ) { - isolateStartState( fsm ); - fsm->setFinState( fsm->startState ); - return FsmRes( FsmRes::Fsm(), fsm ); - } - - /* Make a machine to make copies from. */ - FsmAp *copyFrom = new FsmAp( *fsm ); - - /* The state set used in the from end of the concatentation. Starts with - * the initial final state set, then after each concatenation, gets set to - * the the final states that come from the the duplicate. */ - StateSet lastFinSet( fsm->finStateSet ); - - /* Set the initial state to zero to allow zero copies. */ - isolateStartState( fsm ); - fsm->setFinState( fsm->startState ); - - /* Concatentate duplicates onto the end up until before the last. */ - for ( int i = 1; i < times-1; i++ ) { - /* Make a duplicate for concating and set the fin bits to graph 2 so we - * can pick out it's final states after the optional style concat. */ - FsmAp *dup = new FsmAp( *copyFrom ); - dup->setFinBits( STB_GRAPH2 ); - FsmRes res = concatOp( fsm, dup, false, &lastFinSet, true ); - if ( !res.success() ) { - delete copyFrom; - return res; - } - - /* Clear the last final state set and make the new one by taking only - * the final states that come from graph 2.*/ - lastFinSet.empty(); - for ( int i = 0; i < fsm->finStateSet.length(); i++ ) { - /* If the state came from graph 2, add it to the last set and clear - * the bits. */ - StateAp *fs = fsm->finStateSet[i]; - if ( fs->stateBits & STB_GRAPH2 ) { - lastFinSet.insert( fs ); - fs->stateBits &= ~STB_GRAPH2; - } - } - } - - /* Now use the copyFrom on the end, no bits set, no bits to clear. */ - FsmRes res = concatOp( fsm, copyFrom, false, &lastFinSet, true ); - if ( !res.success() ) - return res; - - res.fsm->afterOpMinimize(); - - return res; -} - -FsmRes FsmAp::minRepeatOp( FsmAp *fsm, int times ) -{ - if ( times == 0 ) { - /* Acts just like a star op on the machine to return. */ - return FsmAp::starOp( fsm ); - } - else { - /* Take a duplicate for the star below. */ - FsmAp *dup = new FsmAp( *fsm ); - - /* Do repetition on the first half. */ - FsmRes exact = FsmAp::exactRepeatOp( fsm, times ); - if ( !exact.success() ) { - delete dup; - return exact; - } - - /* Star the duplicate. */ - FsmRes star = FsmAp::starOp( dup ); - if ( !star.success() ) { - delete exact.fsm; - return star; - } - - /* Tack on the kleene star. */ - return FsmAp::concatOp( exact.fsm, star.fsm ); - } -} - -FsmRes FsmAp::rangeRepeatOp( FsmAp *fsm, int lowerRep, int upperRep ) -{ - if ( lowerRep == 0 && upperRep == 0 ) { - FsmCtx *fsmCtx = fsm->ctx; - delete fsm; - return FsmRes( FsmRes::Fsm(), FsmAp::lambdaFsm( fsmCtx ) ); - } - else if ( lowerRep == 0 ) { - /* Just doing max repetition. Already guarded against n == 0. */ - return FsmAp::maxRepeatOp( fsm, upperRep ); - } - else if ( lowerRep == upperRep ) { - /* Just doing exact repetition. Already guarded against n == 0. */ - return FsmAp::exactRepeatOp( fsm, lowerRep ); - } - else { - /* This is the case that 0 < lowerRep < upperRep. Take a - * duplicate for the optional repeat. */ - FsmAp *dup = new FsmAp( *fsm ); - - /* Do repetition on the first half. */ - FsmRes exact = FsmAp::exactRepeatOp( fsm, lowerRep ); - if ( !exact.success() ) { - delete dup; - return exact; - } - - /* Do optional repetition on the second half. */ - FsmRes optional = FsmAp::maxRepeatOp( dup, upperRep - lowerRep ); - if ( !optional.success() ) { - delete exact.fsm; - return optional; - } - - /* Concat two halves. */ - return FsmAp::concatOp( exact.fsm, optional.fsm ); - } -} - -/* Concatenates other to the end of this machine. Other is deleted. Any - * transitions made leaving this machine and entering into other are notified - * that they are leaving transitions by having the leavingFromState callback - * invoked. Supports specifying the fromStates (istead of first final state - * set). This is useful for a max-repeat schenario, where from states are not - * all of first's final states. Also supports treating the concatentation as - * optional, which leaves the final states of the first machine as final. */ -FsmRes FsmAp::concatOp( FsmAp *fsm, FsmAp *other, bool lastInSeq, StateSet *fromStates, bool optional ) -{ - for ( PriorTable::Iter g = other->startState->guardedInTable; g.lte(); g++ ) { - fsm->allTransPrior( 0, g->desc ); - other->allTransPrior( 0, g->desc->other ); - } - - /* Assert same signedness and return graph concatenation op. */ - assert( fsm->ctx == other->ctx ); - - /* For the merging process. */ - StateSet finStateSetCopy, startStateSet; - - /* Turn on misfit accounting for both graphs. */ - fsm->setMisfitAccounting( true ); - other->setMisfitAccounting( true ); - - /* Get the other's start state. */ - StateAp *otherStartState = other->startState; - - /* Unset other's start state before bringing in the entry points. */ - other->unsetStartState(); - - /* Bring in the rest of other's entry points. */ - fsm->copyInEntryPoints( other ); - other->entryPoints.empty(); - - /* Bring in other's states into our state lists. */ - fsm->stateList.append( other->stateList ); - fsm->misfitList.append( other->misfitList ); - - /* If from states is not set, then get a copy of our final state set before - * we clobber it and use it instead. */ - if ( fromStates == 0 ) { - finStateSetCopy = fsm->finStateSet; - fromStates = &finStateSetCopy; - } - - /* Unset all of our final states and get the final states from other. */ - if ( !optional ) - fsm->unsetAllFinStates(); - fsm->finStateSet.insert( other->finStateSet ); - - /* Since other's lists are empty, we can delete the fsm without - * affecting any states. */ - delete other; - - /* Merge our former final states with the start state of other. */ - for ( int i = 0; i < fromStates->length(); i++ ) { - StateAp *state = fromStates->data[i]; - - /* Merge the former final state with other's start state. */ - fsm->mergeStatesLeaving( state, otherStartState ); - - /* If the former final state was not reset final then we must clear - * the state's out trans data. If it got reset final then it gets to - * keep its out trans data. This must be done before fillInStates gets - * called to prevent the data from being sourced. */ - if ( ! state->isFinState() ) - fsm->clearOutData( state ); - } - - /* Fill in any new states made from merging. */ - FsmRes res = fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - res.fsm->afterOpMinimize( lastInSeq ); - - return res; -} - -FsmRes FsmAp::rightStartConcatOp( FsmAp *fsm, FsmAp *other, bool lastInSeq ) -{ - PriorDesc *priorDesc0 = fsm->ctx->allocPriorDesc(); - PriorDesc *priorDesc1 = fsm->ctx->allocPriorDesc(); - - /* Set up the priority descriptors. The left machine gets the - * lower priority where as the right get the higher start priority. */ - priorDesc0->key = fsm->ctx->nextPriorKey++; - priorDesc0->priority = 0; - fsm->allTransPrior( fsm->ctx->curPriorOrd++, priorDesc0 ); - - /* The start transitions of the right machine gets the higher - * priority. Use the same unique key. */ - priorDesc1->key = priorDesc0->key; - priorDesc1->priority = 1; - other->startFsmPrior( fsm->ctx->curPriorOrd++, priorDesc1 ); - - return concatOp( fsm, other, lastInSeq ); -} - -/* Returns union of fsm and other. Other is deleted. */ -FsmRes FsmAp::unionOp( FsmAp *fsm, FsmAp *other, bool lastInSeq ) -{ - assert( fsm->ctx == other->ctx ); - - fsm->ctx->unionOp = true; - - fsm->setFinBits( STB_GRAPH1 ); - other->setFinBits( STB_GRAPH2 ); - - /* Turn on misfit accounting for both graphs. */ - fsm->setMisfitAccounting( true ); - other->setMisfitAccounting( true ); - - /* Call Worker routine. */ - FsmRes res = doUnion( fsm, other ); - if ( !res.success() ) - return res; - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - fsm->ctx->unionOp = false; - fsm->unsetFinBits( STB_BOTH ); - - fsm->afterOpMinimize( lastInSeq ); - - return res; -} - -/* Intersects other with this machine. Other is deleted. */ -FsmRes FsmAp::intersectOp( FsmAp *fsm, FsmAp *other, bool lastInSeq ) -{ - assert( fsm->ctx == other->ctx ); - - /* Turn on misfit accounting for both graphs. */ - fsm->setMisfitAccounting( true ); - other->setMisfitAccounting( true ); - - /* Set the fin bits on this and other to want each other. */ - fsm->setFinBits( STB_GRAPH1 ); - other->setFinBits( STB_GRAPH2 ); - - /* Call worker Or routine. */ - FsmRes res = doUnion( fsm, other ); - if ( !res.success() ) - return res; - - /* Unset any final states that are no longer to - * be final due to final bits. */ - fsm->unsetIncompleteFinals(); - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - /* Remove states that have no path to a final state. */ - fsm->removeDeadEndStates(); - - fsm->afterOpMinimize( lastInSeq ); - - return res; -} - -/* Set subtracts other machine from this machine. Other is deleted. */ -FsmRes FsmAp::subtractOp( FsmAp *fsm, FsmAp *other, bool lastInSeq ) -{ - assert( fsm->ctx == other->ctx ); - - /* Turn on misfit accounting for both graphs. */ - fsm->setMisfitAccounting( true ); - other->setMisfitAccounting( true ); - - /* Set the fin bits of other to be killers. */ - other->setFinBits( STB_GRAPH1 ); - - /* Call worker Or routine. */ - FsmRes res = doUnion( fsm, other ); - if ( !res.success() ) - return res; - - /* Unset any final states that are no longer to - * be final due to final bits. */ - fsm->unsetKilledFinals(); - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - /* Remove states that have no path to a final state. */ - fsm->removeDeadEndStates(); - - fsm->afterOpMinimize( lastInSeq ); - - return res; -} - -FsmRes FsmAp::epsilonOp( FsmAp *fsm ) -{ - fsm->setMisfitAccounting( true ); - - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) - st->owningGraph = 0; - - /* Perform merges. */ - fsm->resolveEpsilonTrans(); - - /* Epsilons can caused merges which leave behind unreachable states. */ - FsmRes res = FsmAp::fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Remove the misfits and turn off misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - return res; -} - -/* Make a new maching by joining together a bunch of machines without making - * any transitions between them. A negative finalId results in there being no - * final id. */ -FsmRes FsmAp::joinOp( FsmAp *fsm, int startId, int finalId, FsmAp **others, int numOthers ) -{ - for ( int m = 0; m < numOthers; m++ ) { - assert( fsm->ctx == others[m]->ctx ); - } - - /* Set the owning machines. Start at one. Zero is reserved for the start - * and final states. */ - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) - st->owningGraph = 1; - for ( int m = 0; m < numOthers; m++ ) { - for ( StateList::Iter st = others[m]->stateList; st.lte(); st++ ) - st->owningGraph = 2+m; - } - - /* All machines loose start state status. */ - fsm->unsetStartState(); - for ( int m = 0; m < numOthers; m++ ) - others[m]->unsetStartState(); - - /* Bring the other machines into this. */ - for ( int m = 0; m < numOthers; m++ ) { - /* Bring in the rest of other's entry points. */ - fsm->copyInEntryPoints( others[m] ); - others[m]->entryPoints.empty(); - - /* Merge the lists. This will move all the states from other into - * this. No states will be deleted. */ - fsm->stateList.append( others[m]->stateList ); - assert( others[m]->misfitList.length() == 0 ); - - /* Move the final set data from other into this. */ - fsm->finStateSet.insert( others[m]->finStateSet ); - others[m]->finStateSet.empty(); - - /* Since other's list is empty, we can delete the fsm without - * affecting any states. */ - delete others[m]; - } - - /* Look up the start entry point. */ - EntryMapEl *enLow = 0, *enHigh = 0; - bool findRes = fsm->entryPoints.findMulti( startId, enLow, enHigh ); - if ( ! findRes ) { - /* No start state. Set a default one and proceed with the join. Note - * that the result of the join will be a very uninteresting machine. */ - fsm->setStartState( fsm->addState() ); - } - else { - /* There is at least one start state, create a state that will become - * the new start state. */ - StateAp *newStart = fsm->addState(); - fsm->setStartState( newStart ); - - /* The start state is in an owning machine class all it's own. */ - newStart->owningGraph = 0; - - /* Create the set of states to merge from. */ - StateSet stateSet; - for ( EntryMapEl *en = enLow; en <= enHigh; en++ ) - stateSet.insert( en->value ); - - /* Merge in the set of start states into the new start state. */ - fsm->mergeStateList( newStart, stateSet.data, stateSet.length() ); - } - - /* Take a copy of the final state set, before unsetting them all. This - * will allow us to call clearOutData on the states that don't get - * final state status back back. */ - StateSet finStateSetCopy = fsm->finStateSet; - - /* Now all final states are unset. */ - fsm->unsetAllFinStates(); - - if ( finalId >= 0 ) { - /* Create the implicit final state. */ - StateAp *finState = fsm->addState(); - fsm->setFinState( finState ); - - /* Assign an entry into the final state on the final state entry id. Note - * that there may already be an entry on this id. That's ok. Also set the - * final state owning machine id. It's in a class all it's own. */ - fsm->setEntry( finalId, finState ); - finState->owningGraph = 0; - } - - /* Hand over to workers for resolving epsilon trans. This will merge states - * with the targets of their epsilon transitions. */ - fsm->resolveEpsilonTrans(); - - /* Invoke the relinquish final callback on any states that did not get - * final state status back. */ - for ( StateSet::Iter st = finStateSetCopy; st.lte(); st++ ) { - if ( !((*st)->stateBits & STB_ISFINAL) ) - fsm->clearOutData( *st ); - } - - /* Fill in any new states made from merging. */ - FsmRes res = FsmAp::fillInStates( fsm ); - if ( !res.success() ) - return res; - - /* Joining can be messy. Instead of having misfit accounting on (which is - * tricky here) do a full cleaning. */ - fsm->removeUnreachableStates(); - - return res; -} - -/* Ensure that the start state is free of entry points (aside from the fact - * that it is the start state). If the start state has entry points then Make a - * new start state by merging with the old one. Useful before modifying start - * transitions. If the existing start state has any entry points other than the - * start state entry then modifying its transitions changes more than the start - * transitions. So isolate the start state by separating it out such that it - * only has start stateness as it's entry point. */ -FsmRes FsmAp::isolateStartState( FsmAp *fsm ) -{ - /* Do nothing if the start state is already isolated. */ - if ( fsm->isStartStateIsolated() ) - return FsmRes( FsmRes::Fsm(), fsm ); - - /* Turn on misfit accounting to possibly catch the old start state. */ - fsm->setMisfitAccounting( true ); - - /* This will be the new start state. The existing start - * state is merged with it. */ - StateAp *prevStartState = fsm->startState; - fsm->unsetStartState(); - fsm->setStartState( fsm->addState() ); - - /* Merge the new start state with the old one to isolate it. */ - fsm->mergeStates( fsm->startState, prevStartState ); - - /* Stfil and stateDict will be empty because the merging of the old start - * state into the new one will not have any conflicting transitions. */ - assert( fsm->stateDict.treeSize == 0 ); - assert( fsm->nfaList.length() == 0 ); - - /* The old start state may be unreachable. Remove the misfits and turn off - * misfit accounting. */ - fsm->removeMisfits(); - fsm->setMisfitAccounting( false ); - - return FsmRes( FsmRes::Fsm(), fsm ); -} - -StateAp *FsmAp::dupStartState() -{ - StateAp *dup = addState(); - mergeStates( dup, startState ); - return dup; -} - -/* A state merge which represents the drawing in of leaving transitions. If - * there is any out data then we duplicate the source state, transfer the out - * data, then merge in the state. The new state will be reaped because it will - * not be given any in transitions. */ -void FsmAp::mergeStatesLeaving( StateAp *destState, StateAp *srcState ) -{ - if ( !hasOutData( destState ) ) { - /* Perform the merge, indicating we are leaving, which will affect how - * out conds are merged. */ - mergeStates( destState, srcState, true ); - } - else { - /* Dup the source state. */ - StateAp *ssMutable = addState(); - mergeStates( ssMutable, srcState ); - - /* Do out data transfer (and out condition embedding). */ - transferOutData( ssMutable, destState ); - - if ( destState->outCondSpace != 0 ) { - - doEmbedCondition( ssMutable, destState->outCondSpace->condSet, - destState->outCondKeys ); - } - - /* Now we merge with dest, setting leaving = true. This dictates how - * out conditions should be merged. */ - mergeStates( destState, ssMutable, true ); - } -} - -void FsmAp::checkEpsilonRegularInteraction( const PriorTable &t1, const PriorTable &t2 ) -{ - for ( PriorTable::Iter pd1 = t1; pd1.lte(); pd1++ ) { - for ( PriorTable::Iter pd2 = t2; pd2.lte(); pd2++ ) { - /* Looking for unequal guarded priorities with the same key. */ - if ( pd1->desc->key == pd2->desc->key ) { - if ( pd1->desc->priority < pd2->desc->priority || - pd1->desc->priority > pd2->desc->priority ) - { - if ( ctx->checkPriorInteraction && pd1->desc->guarded ) { - if ( ! priorInteraction ) { - priorInteraction = true; - guardId = pd1->desc->guardId; - } - } - } - } - } - } -} - -void FsmAp::mergeStateProperties( StateAp *destState, StateAp *srcState ) -{ - /* Draw in any properties of srcState into destState. */ - if ( srcState == destState ) { - /* Duplicate the list to protect against write to source. The - * priorities sets are not copied in because that would have no - * effect. */ - destState->epsilonTrans.append( EpsilonTrans( srcState->epsilonTrans ) ); - - /* Get all actions, duplicating to protect against write to source. */ - destState->toStateActionTable.setActions( - ActionTable( srcState->toStateActionTable ) ); - destState->fromStateActionTable.setActions( - ActionTable( srcState->fromStateActionTable ) ); - destState->outActionTable.setActions( ActionTable( srcState->outActionTable ) ); - destState->errActionTable.setActions( ErrActionTable( srcState->errActionTable ) ); - destState->eofActionTable.setActions( ActionTable( srcState->eofActionTable ) ); - - /* Not touching guarded-in table or out conditions. Probably should - * leave some of the above alone as well. */ - } - else { - /* Get the epsilons, out priorities. */ - destState->epsilonTrans.append( srcState->epsilonTrans ); - destState->outPriorTable.setPriors( srcState->outPriorTable ); - - /* Get all actions. */ - destState->toStateActionTable.setActions( srcState->toStateActionTable ); - destState->fromStateActionTable.setActions( srcState->fromStateActionTable ); - destState->outActionTable.setActions( srcState->outActionTable ); - destState->errActionTable.setActions( srcState->errActionTable ); - destState->eofActionTable.setActions( srcState->eofActionTable ); - destState->lmNfaParts.insert( srcState->lmNfaParts ); - destState->guardedInTable.setPriors( srcState->guardedInTable ); - } -} - -void FsmAp::mergeStateBits( StateAp *destState, StateAp *srcState ) -{ - /* Get bits and final state status. Note in the above code we depend on the - * original final state status being present. */ - destState->stateBits |= ( srcState->stateBits & ~STB_ISFINAL ); - if ( srcState->isFinState() ) - setFinState( destState ); -} - -void FsmAp::mergeNfaTransitions( StateAp *destState, StateAp *srcState ) -{ - /* Copy in any NFA transitions. */ - if ( srcState->nfaOut != 0 ) { - if ( destState->nfaOut == 0 ) - destState->nfaOut = new NfaTransList; - - for ( NfaTransList::Iter nt = *srcState->nfaOut; nt.lte(); nt++ ) { - NfaTrans *trans = new NfaTrans( - nt->pushTable, nt->restoreTable, - nt->popFrom, nt->popCondSpace, nt->popCondKeys, - nt->popAction, nt->popTest, nt->order ); - - destState->nfaOut->append( trans ); - attachToNfa( destState, nt->toState, trans ); - } - } -} - -void FsmAp::checkPriorInteractions( StateAp *destState, StateAp *srcState ) -{ - /* Run a check on priority interactions between epsilon transitions and - * regular transitions. This can't be used to affect machine construction, - * only to check for priority guards. */ - if ( destState->nfaOut != 0 ) { - for ( NfaTransList::Iter nt = *destState->nfaOut; nt.lte(); nt++ ) { - for ( TransList::Iter trans = destState->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - checkEpsilonRegularInteraction( - trans->tdap()->priorTable, nt->priorTable ); - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; - cond.lte(); cond++ ) - { - checkEpsilonRegularInteraction( - cond->priorTable, nt->priorTable ); - - } - } - } - } - } -} - -void FsmAp::mergeStates( StateAp *destState, StateAp *srcState, bool leaving ) -{ - /* Transitions. */ - outTransCopy( destState, srcState->outList.head ); - - /* Properties such as out data, to/from actions. */ - mergeStateProperties( destState, srcState ); - - /* Merge out conditions, depends on the operation (leaving or not). */ - mergeOutConds( destState, srcState, leaving ); - - /* State bits, including final state stats. Out conds depnds on this - * happening after. */ - mergeStateBits( destState, srcState ); - - /* Draw in the NFA transitions. */ - mergeNfaTransitions( destState, srcState ); - - /* Hacked in check for priority interactions, allowing detection of some - * bad situations. */ - checkPriorInteractions( destState, srcState ); -} - -void FsmAp::mergeStateList( StateAp *destState, - StateAp **srcStates, int numSrc ) -{ - for ( int s = 0; s < numSrc; s++ ) - mergeStates( destState, srcStates[s] ); -} - -void FsmAp::cleanAbortedFill( StateAp *state ) -{ - /* Iterate the out transitions, deleting them. */ - for ( TransList::Iter n, t = state->outList; t.lte(); ) { - n = t.next(); - if ( t->plain() ) - delete t->tdap(); - else - delete t->tcap(); - t = n; - } - - state->outList.abandon(); - - if ( state->nfaIn != 0 ) { - delete state->nfaIn; - state->nfaIn = 0; - } - - if ( state->nfaOut != 0 ) { - state->nfaOut->empty(); - delete state->nfaOut; - state->nfaOut = 0; - } -} - -void FsmAp::cleanAbortedFill() -{ - while ( nfaList.length() > 0 ) { - StateAp *state = nfaList.head; - - StateSet *stateSet = &state->stateDictEl->stateSet; - //mergeStateList( state, stateSet->data, stateSet->length() ); - - for ( StateSet::Iter s = *stateSet; s.lte(); s++ ) - detachStateDict( state, *s ); - - nfaList.detach( state ); - } - - /* Disassociated state dict elements from states. */ - for ( StateDict::Iter sdi = stateDict; sdi.lte(); sdi++ ) - sdi->targState->stateDictEl = 0; - - /* Delete all the state dict elements. */ - stateDict.empty(); - - /* Delete all the transitions. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) - cleanAbortedFill( state ); - - /* Delete all the states. */ - stateList.empty(); - - /* Delete all the transitions. */ - for ( StateList::Iter state = misfitList; state.lte(); state++ ) - cleanAbortedFill( state ); - - /* Delete all the states. */ - misfitList.empty(); -} - -bool FsmAp::overStateLimit() -{ - if ( ctx->stateLimit > FsmCtx::STATE_UNLIMITED ) { - long states = misfitList.length() + stateList.length(); - if ( states > ctx->stateLimit ) - return true; - } - return false; -} - -bool FsmAp::fillAbort( FsmRes &res, FsmAp *fsm ) -{ - if ( fsm->priorInteraction ) { - fsm->cleanAbortedFill(); - int guardId = fsm->guardId; - delete fsm; - res = FsmRes( FsmRes::PriorInteraction(), guardId ); - return true; - } - - if ( fsm->overStateLimit() ) { - fsm->cleanAbortedFill(); - delete fsm; - res = FsmRes( FsmRes::TooManyStates() ); - return true; - } - - return false; -} - -FsmRes FsmAp::fillInStates( FsmAp *fsm ) -{ - /* Used as return value on success. Filled in with error on abort. */ - FsmRes res( FsmRes::Fsm(), fsm ); - - /* Merge any states that are awaiting merging. This will likey cause other - * states to be added to the NFA list. */ - while ( true ) { - if ( fillAbort( res, fsm ) ) - return res; - - if ( fsm->nfaList.length() == 0 ) - break; - - StateAp *state = fsm->nfaList.head; - - StateSet *stateSet = &state->stateDictEl->stateSet; - fsm->mergeStateList( state, stateSet->data, stateSet->length() ); - - for ( StateSet::Iter s = *stateSet; s.lte(); s++ ) - fsm->detachStateDict( state, *s ); - - fsm->nfaList.detach( state ); - } - - /* The NFA list is empty at this point. There are no state sets we need to - * preserve. */ - - /* Disassociated state dict elements from states. */ - for ( StateDict::Iter sdi = fsm->stateDict; sdi.lte(); sdi++ ) - sdi->targState->stateDictEl = 0; - - /* Delete all the state dict elements. */ - fsm->stateDict.empty(); - - return res; -} - -/* Check if a machine defines a single character. This is useful in validating - * ranges and machines to export. */ -bool FsmAp::checkSingleCharMachine() -{ - /* Must have two states. */ - if ( stateList.length() != 2 ) - return false; - /* The start state cannot be final. */ - if ( startState->isFinState() ) - return false; - /* There should be only one final state. */ - if ( finStateSet.length() != 1 ) - return false; - /* The final state cannot have any transitions out. */ - if ( finStateSet[0]->outList.length() != 0 ) - return false; - /* The start state should have only one transition out. */ - if ( startState->outList.length() != 1 ) - return false; - /* The singe transition out of the start state should not be a range. */ - TransAp *startTrans = startState->outList.head; - if ( ctx->keyOps->ne( startTrans->lowKey, startTrans->highKey ) ) - return false; - return true; -} - -FsmRes FsmAp::condCostFromState( FsmAp *fsm, StateAp *state, long depth ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->stateBits & STB_ONLIST ) - return FsmRes( FsmRes::Fsm(), fsm ); - - if ( depth > fsm->ctx->condsCheckDepth ) - return FsmRes( FsmRes::Fsm(), fsm ); - - /* Doing depth first, put state on the list. */ - state->stateBits |= STB_ONLIST; - - /* Recurse on everything ranges. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) { - FsmRes res = condCostFromState( fsm, trans->tdap()->toState, depth + 1 ); - if ( !res.success() ) - return res; - } - } - else { - for ( CondSet::Iter csi = trans->condSpace->condSet; csi.lte(); csi++ ) { - if ( (*csi)->costMark ) - return FsmRes( FsmRes::CondCostTooHigh(), (*csi)->costId ); - } - - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) { - FsmRes res = condCostFromState( fsm, cond->toState, depth + 1 ); - if ( !res.success() ) - return res; - } - } - } - } - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *state->nfaOut; n.lte(); n++ ) { - /* We do not increment depth here since this is an epsilon transition. */ - FsmRes res = condCostFromState( fsm, n->toState, depth ); - if ( !res.success() ) - return res; - } - } - - for ( ActionTable::Iter a = state->fromStateActionTable; a.lte(); a++ ) { - if ( a->value->costMark ) - return FsmRes( FsmRes::CondCostTooHigh(), a->value->costId ); - } - - return FsmRes( FsmRes::Fsm(), fsm ); -} - - -/* Returns either success (using supplied fsm), or some error condition. */ -FsmRes FsmAp::condCostSearch( FsmAp *fsm ) -{ - /* Init on state list flags. */ - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) - st->stateBits &= ~STB_ONLIST; - - FsmRes res = condCostFromState( fsm, fsm->startState, 1 ); - if ( !res.success() ) - delete fsm; - return res; -} - -void FsmAp::condCost( Action *action, long repId ) -{ - action->costMark = true; - action->costId = repId; -} - -/* - * This algorithm assigns a price to each state visit, then adds that to a - * running total. Note that we do not guard against multiple visits to a state, - * since we are estimating runtime cost. - * - * We rely on a character histogram and are looking for a probability of being - * in any given state, given that histogram, simple and very effective. - */ -void FsmAp::breadthFromState( double &total, int &minDepth, double *histogram, - FsmAp *fsm, StateAp *state, long depth, int maxDepth, double stateScore ) -{ - if ( depth > maxDepth ) - return; - - /* Recurse on everything ranges. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - - /* Compute target state score. */ - double span = 0; - for ( int i = trans->lowKey.getVal(); i <= trans->highKey.getVal(); i++ ) - span += histogram[i]; - - double targetStateScore = stateScore * ( span ); - - /* Add to the level. */ - total += targetStateScore; - - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 ) { - if ( trans->tdap()->toState->isFinState() && ( minDepth < 0 || depth < minDepth ) ) - minDepth = depth; - - breadthFromState( total, minDepth, histogram, fsm, trans->tdap()->toState, - depth + 1, maxDepth, targetStateScore ); - } - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 ) { - if ( cond->toState->isFinState() && ( minDepth < 0 || depth < minDepth ) ) - minDepth = depth; - - breadthFromState( total, minDepth, histogram, fsm, cond->toState, - depth + 1, maxDepth, targetStateScore ); - } - } - } - } - - if ( state->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *state->nfaOut; n.lte(); n++ ) { - if ( n->toState->isFinState() && ( minDepth < 0 || depth < minDepth ) ) - minDepth = depth; - - /* We do not increment depth here since this is an epsilon transition. */ - breadthFromState( total, minDepth, histogram, fsm, n->toState, depth, maxDepth, stateScore ); - } - } -} - -void FsmAp::breadthFromEntry( double &total, int &minDepth, double *histogram, FsmAp *fsm, StateAp *state ) -{ - long depth = 1; - int maxDepth = 5; - double stateScore = 1.0; - - FsmAp::breadthFromState( total, minDepth, histogram, fsm, state, depth, maxDepth, stateScore ); -} - - -void FsmAp::applyEntryPriorGuard( FsmAp *fsm, long repId ) -{ - PriorDesc *priorDesc0 = fsm->ctx->allocPriorDesc(); - PriorDesc *priorDesc1 = fsm->ctx->allocPriorDesc(); - - priorDesc0->key = fsm->ctx->nextPriorKey; - priorDesc0->priority = 0; - priorDesc0->guarded = true; - priorDesc0->guardId = repId; - priorDesc0->other = priorDesc1; - - priorDesc1->key = fsm->ctx->nextPriorKey; - priorDesc1->priority = 1; - priorDesc1->guarded = true; - priorDesc1->guardId = repId; - priorDesc1->other = priorDesc0; - - /* Roll over for next allocation. */ - fsm->ctx->nextPriorKey += 1; - - /* Only need to set the first. Second is referenced using 'other' field. */ - fsm->startState->guardedInTable.setPrior( 0, priorDesc0 ); -} - -void FsmAp::applyRepeatPriorGuard( FsmAp *fsm, long repId ) -{ - PriorDesc *priorDesc2 = fsm->ctx->allocPriorDesc(); - PriorDesc *priorDesc3 = fsm->ctx->allocPriorDesc(); - - priorDesc2->key = fsm->ctx->nextPriorKey; - priorDesc2->priority = 0; - priorDesc2->guarded = true; - priorDesc2->guardId = repId; - priorDesc2->other = priorDesc3; - - priorDesc3->key = fsm->ctx->nextPriorKey; - priorDesc3->guarded = true; - priorDesc3->priority = 1; - priorDesc3->guardId = repId; - priorDesc3->other = priorDesc2; - - /* Roll over for next allocation. */ - fsm->ctx->nextPriorKey += 1; - - /* Only need to set the first. Second is referenced using 'other' field. */ - fsm->startState->guardedInTable.setPrior( 0, priorDesc2 ); - - fsm->allTransPrior( fsm->ctx->curPriorOrd++, priorDesc3 ); - fsm->leaveFsmPrior( fsm->ctx->curPriorOrd++, priorDesc2 ); -} - -FsmRes FsmAp::condPlus( FsmAp *fsm, long repId, Action *ini, Action *inc, Action *min, Action *max ) -{ - condCost( ini, repId ); - condCost( inc, repId ); - condCost( min, repId ); - if ( max != 0 ) - condCost( max, repId ); - - fsm->startFsmAction( 0, inc ); - - if ( max != 0 ) { - FsmRes res = fsm->startFsmCondition( max, true ); - if ( !res.success() ) - return res; - } - - /* Need a duplicated for the star end. */ - FsmAp *dup = new FsmAp( *fsm ); - - applyRepeatPriorGuard( dup, repId ); - - /* Star the duplicate. */ - FsmRes dupStar = FsmAp::starOp( dup ); - if ( !dupStar.success() ) { - delete fsm; - return dupStar; - } - - FsmRes res = FsmAp::concatOp( fsm, dupStar.fsm ); - if ( !res.success() ) - return res; - - /* End plus operation. */ - - res.fsm->leaveFsmCondition( min, true ); - - /* Init action. */ - res.fsm->startFromStateAction( 0, ini ); - - /* Leading priority guard. */ - applyEntryPriorGuard( res.fsm, repId ); - - return res; -} - -FsmRes FsmAp::condStar( FsmAp *fsm, long repId, Action *ini, Action *inc, Action *min, Action *max ) -{ - condCost( ini, repId ); - condCost( inc, repId ); - condCost( min, repId ); - if ( max != 0 ) - condCost( max, repId ); - - /* Increment. */ - fsm->startFsmAction( 0, inc ); - - /* Max (optional). */ - if ( max != 0 ) { - FsmRes res = fsm->startFsmCondition( max, true ); - if ( !res.success() ) - return res; - } - - applyRepeatPriorGuard( fsm, repId ); - - /* Star. */ - FsmRes res = FsmAp::starOp( fsm ); - if ( !res.success() ) - return res; - - /* Restrict leaving. */ - res.fsm->leaveFsmCondition( min, true ); - - /* Init action. */ - res.fsm->startFromStateAction( 0, ini ); - - /* Leading priority guard. */ - applyEntryPriorGuard( res.fsm, repId ); - - return res; -} - -/* Remove duplicates of unique actions from an action table. */ -void FsmAp::removeDups( ActionTable &table ) -{ - /* Scan through the table looking for unique actions to - * remove duplicates of. */ - for ( int i = 0; i < table.length(); i++ ) { - /* Remove any duplicates ahead of i. */ - for ( int r = i+1; r < table.length(); ) { - if ( table[r].value == table[i].value ) - table.vremove(r); - else - r += 1; - } - } -} - -/* Remove duplicates from action lists. This operates only on transition and - * eof action lists and so should be called once all actions have been - * transfered to their final resting place. */ -void FsmAp::removeActionDups() -{ - /* Loop all states. */ - for ( StateList::Iter state = stateList; state.lte(); state++ ) { - /* Loop all transitions. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) - removeDups( trans->tdap()->actionTable ); - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) - removeDups( cond->actionTable ); - } - } - removeDups( state->toStateActionTable ); - removeDups( state->fromStateActionTable ); - removeDups( state->eofActionTable ); - } -} - diff --git a/src/fsmmin.cc b/src/fsmmin.cc deleted file mode 100644 index cabe3968..00000000 --- a/src/fsmmin.cc +++ /dev/null @@ -1,934 +0,0 @@ -/* - * Copyright 2002-2018 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 "fsmgraph.h" -#include "mergesort.h" - -struct MergeSortInitPartition - : public MergeSort<StateAp*, InitPartitionCompare> -{ - MergeSortInitPartition( FsmCtx *ctx ) - { - InitPartitionCompare::ctx = ctx; - } -}; - -struct MergeSortPartition - : public MergeSort<StateAp*, PartitionCompare> -{ - MergeSortPartition( FsmCtx *ctx ) - { - PartitionCompare::ctx = ctx; - } -}; - -struct MergeSortApprox - : public MergeSort<StateAp*, ApproxCompare> -{ - MergeSortApprox( FsmCtx *ctx ) - { - ApproxCompare::ctx = ctx; - } -}; - -int FsmAp::partitionRound( StateAp **statePtrs, MinPartition *parts, int numParts ) -{ - /* Need a mergesort object and a single partition compare. */ - MergeSortPartition mergeSort( ctx ); - PartitionCompare partCompare; - - /* For each partition. */ - for ( int p = 0; p < numParts; p++ ) { - /* Fill the pointer array with the states in the partition. */ - StateList::Iter state = parts[p].list; - for ( int s = 0; state.lte(); state++, s++ ) - statePtrs[s] = state; - - /* Sort the states using the partitioning compare. */ - int numStates = parts[p].list.length(); - mergeSort.sort( statePtrs, numStates ); - - /* Assign the states into partitions based on the results of the sort. */ - int destPart = p, firstNewPart = numParts; - for ( int s = 1; s < numStates; s++ ) { - /* If this state differs from the last then move to the next partition. */ - if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) { - /* The new partition is the next avail spot. */ - destPart = numParts; - numParts += 1; - } - - /* If the state is not staying in the first partition, then - * transfer it to its destination partition. */ - if ( destPart != p ) { - StateAp *state = parts[p].list.detach( statePtrs[s] ); - parts[destPart].list.append( state ); - } - } - - /* Fix the partition pointer for all the states that got moved to a new - * partition. This must be done after the states are transfered so the - * result of the sort is not altered. */ - for ( int newPart = firstNewPart; newPart < numParts; newPart++ ) { - StateList::Iter state = parts[newPart].list; - for ( ; state.lte(); state++ ) - state->alg.partition = &parts[newPart]; - } - } - - return numParts; -} - -/** - * \brief Minimize by partitioning version 1. - * - * Repeatedly tries to split partitions until all partitions are unsplittable. - * Produces the most minimal FSM possible. - */ -void FsmAp::minimizePartition1() -{ - /* Need one mergesort object and partition compares. */ - MergeSortInitPartition mergeSort( ctx ); - InitPartitionCompare initPartCompare( ctx ); - - /* Nothing to do if there are no states. */ - if ( stateList.length() == 0 ) - return; - - /* - * First thing is to partition the states by final state status and - * transition functions. This gives us an initial partitioning to work - * with. - */ - - /* Make a array of pointers to states. */ - int numStates = stateList.length(); - StateAp** statePtrs = new StateAp*[numStates]; - - /* Fill up an array of pointers to the states for easy sorting. */ - StateList::Iter state = stateList; - for ( int s = 0; state.lte(); state++, s++ ) - statePtrs[s] = state; - - /* Sort the states using the array of states. */ - mergeSort.sort( statePtrs, numStates ); - - /* An array of lists of states is used to partition the states. */ - MinPartition *parts = new MinPartition[numStates]; - - /* Assign the states into partitions. */ - int destPart = 0; - for ( int s = 0; s < numStates; s++ ) { - /* If this state differs from the last then move to the next partition. */ - if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) { - /* Move to the next partition. */ - destPart += 1; - } - - /* Put the state into its partition. */ - statePtrs[s]->alg.partition = &parts[destPart]; - parts[destPart].list.append( statePtrs[s] ); - } - - /* We just moved all the states from the main list into partitions without - * taking them off the main list. So clean up the main list now. */ - stateList.abandon(); - - /* Split partitions. */ - int numParts = destPart + 1; - while ( true ) { - /* Test all partitions for splitting. */ - int newNum = partitionRound( statePtrs, parts, numParts ); - - /* When no partitions can be split, stop. */ - if ( newNum == numParts ) - break; - - numParts = newNum; - } - - /* Fuse states in the same partition. The states will end up back on the - * main list. */ - fusePartitions( parts, numParts ); - - /* Cleanup. */ - delete[] statePtrs; - delete[] parts; -} - -/* Split partitions that need splittting, decide which partitions might need - * to be split as a result, continue until there are no more that might need - * to be split. */ -int FsmAp::splitCandidates( StateAp **statePtrs, MinPartition *parts, int numParts ) -{ - /* Need a mergesort and a partition compare. */ - MergeSortPartition mergeSort( ctx ); - PartitionCompare partCompare( ctx ); - - /* The lists of unsplitable (partList) and splitable partitions. - * Only partitions in the splitable list are check for needing splitting. */ - PartitionList partList, splittable; - - /* Initially, all partitions are born from a split (the initial - * partitioning) and can cause other partitions to be split. So any - * partition with a state with a transition out to another partition is a - * candidate for splitting. This will make every partition except possibly - * partitions of final states split candidates. */ - for ( int p = 0; p < numParts; p++ ) { - /* Assume not active. */ - parts[p].active = false; - - /* Look for a trans out of any state in the partition. */ - for ( StateList::Iter state = parts[p].list; state.lte(); state++ ) { - /* If there is at least one transition out to another state then - * the partition becomes splittable. */ - if ( state->outList.length() > 0 ) { - parts[p].active = true; - break; - } - } - - /* If it was found active then it goes on the splittable list. */ - if ( parts[p].active ) - splittable.append( &parts[p] ); - else - partList.append( &parts[p] ); - } - - /* While there are partitions that are splittable, pull one off and try - * to split it. If it splits, determine which partitions may now be split - * as a result of the newly split partition. */ - while ( splittable.length() > 0 ) { - MinPartition *partition = splittable.detachFirst(); - - /* Fill the pointer array with the states in the partition. */ - StateList::Iter state = partition->list; - for ( int s = 0; state.lte(); state++, s++ ) - statePtrs[s] = state; - - /* Sort the states using the partitioning compare. */ - int numStates = partition->list.length(); - mergeSort.sort( statePtrs, numStates ); - - /* Assign the states into partitions based on the results of the sort. */ - MinPartition *destPart = partition; - int firstNewPart = numParts; - for ( int s = 1; s < numStates; s++ ) { - /* If this state differs from the last then move to the next partition. */ - if ( partCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) { - /* The new partition is the next avail spot. */ - destPart = &parts[numParts]; - numParts += 1; - } - - /* If the state is not staying in the first partition, then - * transfer it to its destination partition. */ - if ( destPart != partition ) { - StateAp *state = partition->list.detach( statePtrs[s] ); - destPart->list.append( state ); - } - } - - /* Fix the partition pointer for all the states that got moved to a new - * partition. This must be done after the states are transfered so the - * result of the sort is not altered. */ - int newPart; - for ( newPart = firstNewPart; newPart < numParts; newPart++ ) { - StateList::Iter state = parts[newPart].list; - for ( ; state.lte(); state++ ) - state->alg.partition = &parts[newPart]; - } - - /* Put the partition we just split and any new partitions that came out - * of the split onto the inactive list. */ - partition->active = false; - partList.append( partition ); - for ( newPart = firstNewPart; newPart < numParts; newPart++ ) { - parts[newPart].active = false; - partList.append( &parts[newPart] ); - } - - if ( destPart == partition ) - continue; - - /* Now determine which partitions are splittable as a result of - * splitting partition by walking the in lists of the states in - * partitions that got split. Partition is the faked first item in the - * loop. */ - MinPartition *causalPart = partition; - newPart = firstNewPart - 1; - while ( newPart < numParts ) { - /* Loop all states in the causal partition. */ - StateList::Iter state = causalPart->list; - for ( ; state.lte(); state++ ) { - /* Walk all transition into the state and put the partition - * that the from state is in onto the splittable list. */ - for ( TransInList::Iter t = state->inTrans; t.lte(); t++ ) { - MinPartition *fromPart = t->fromState->alg.partition; - if ( ! fromPart->active ) { - fromPart->active = true; - partList.detach( fromPart ); - splittable.append( fromPart ); - } - } - for ( CondInList::Iter t = state->inCond; t.lte(); t++ ) { - MinPartition *fromPart = t->fromState->alg.partition; - if ( ! fromPart->active ) { - fromPart->active = true; - partList.detach( fromPart ); - splittable.append( fromPart ); - } - } - } - - newPart += 1; - causalPart = &parts[newPart]; - } - } - return numParts; -} - - -/** - * \brief Minimize by partitioning version 2 (best alg). - * - * Repeatedly tries to split partitions that may splittable until there are no - * more partitions that might possibly need splitting. Runs faster than - * version 1. Produces the most minimal fsm possible. - */ -void FsmAp::minimizePartition2() -{ - /* Need a mergesort and an initial partition compare. */ - MergeSortInitPartition mergeSort( ctx ); - InitPartitionCompare initPartCompare( ctx ); - - /* Nothing to do if there are no states. */ - if ( stateList.length() == 0 ) - return; - - /* - * First thing is to partition the states by final state status and - * transition functions. This gives us an initial partitioning to work - * with. - */ - - /* Make a array of pointers to states. */ - int numStates = stateList.length(); - StateAp** statePtrs = new StateAp*[numStates]; - - /* Fill up an array of pointers to the states for easy sorting. */ - StateList::Iter state = stateList; - for ( int s = 0; state.lte(); state++, s++ ) - statePtrs[s] = state; - - /* Sort the states using the array of states. */ - mergeSort.sort( statePtrs, numStates ); - - /* An array of lists of states is used to partition the states. */ - MinPartition *parts = new MinPartition[numStates]; - - /* Assign the states into partitions. */ - int destPart = 0; - for ( int s = 0; s < numStates; s++ ) { - /* If this state differs from the last then move to the next partition. */ - if ( s > 0 && initPartCompare.compare( statePtrs[s-1], statePtrs[s] ) < 0 ) { - /* Move to the next partition. */ - destPart += 1; - } - - /* Put the state into its partition. */ - statePtrs[s]->alg.partition = &parts[destPart]; - parts[destPart].list.append( statePtrs[s] ); - } - - /* We just moved all the states from the main list into partitions without - * taking them off the main list. So clean up the main list now. */ - stateList.abandon(); - - /* Split partitions. */ - int numParts = splitCandidates( statePtrs, parts, destPart+1 ); - - /* Fuse states in the same partition. The states will end up back on the - * main list. */ - fusePartitions( parts, numParts ); - - /* Cleanup. */ - delete[] statePtrs; - delete[] parts; -} - -void FsmAp::initialMarkRound( MarkIndex &markIndex ) -{ - /* P and q for walking pairs. */ - StateAp *p = stateList.head, *q; - - /* Need an initial partition compare. */ - InitPartitionCompare initPartCompare( ctx ); - - /* Walk all unordered pairs of (p, q) where p != q. - * The second depth of the walk stops before reaching p. This - * gives us all unordered pairs of states (p, q) where p != q. */ - while ( p != 0 ) { - q = stateList.head; - while ( q != p ) { - /* If the states differ on final state status, out transitions or - * any transition data then they should be separated on the initial - * round. */ - if ( initPartCompare.compare( p, q ) != 0 ) - markIndex.markPair( p->alg.stateNum, q->alg.stateNum ); - - q = q->next; - } - p = p->next; - } -} - -#ifdef TO_UPGRADE_CONDS -bool FsmAp::markRound( MarkIndex &markIndex ) -{ - /* P an q for walking pairs. Take note if any pair gets marked. */ - StateAp *p = stateList.head, *q; - bool pairWasMarked = false; - - /* Need a mark comparison. */ - MarkCompare markCompare( ctx ); - - /* Walk all unordered pairs of (p, q) where p != q. - * The second depth of the walk stops before reaching p. This - * gives us all unordered pairs of states (p, q) where p != q. */ - while ( p != 0 ) { - q = stateList.head; - while ( q != p ) { - /* Should we mark the pair? */ - if ( !markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) { - if ( markCompare.shouldMark( markIndex, p, q ) ) { - markIndex.markPair( p->alg.stateNum, q->alg.stateNum ); - pairWasMarked = true; - } - } - q = q->next; - } - p = p->next; - } - - return pairWasMarked; -} -#endif - -#ifdef TO_UPGRADE_CONDS -/** - * \brief Minimize by pair marking. - * - * Decides if each pair of states is distinct or not. Uses O(n^2) memory and - * should only be used on small graphs. Produces the most minmimal FSM - * possible. - */ -void FsmAp::minimizeStable() -{ - /* Set the state numbers. */ - setStateNumbers( 0 ); - - /* This keeps track of which pairs have been marked. */ - MarkIndex markIndex( stateList.length() ); - - /* Mark pairs where final stateness, out trans, or trans data differ. */ - initialMarkRound( markIndex ); - - /* While the last round of marking succeeded in marking a state - * continue to do another round. */ - int modified = markRound( markIndex ); - while (modified) - modified = markRound( markIndex ); - - /* Merge pairs that are unmarked. */ - fuseUnmarkedPairs( markIndex ); -} -#endif - -#ifdef TO_UPGRADE_CONDS -bool FsmAp::minimizeRound() -{ - /* Nothing to do if there are no states. */ - if ( stateList.length() == 0 ) - return false; - - /* Need a mergesort on approx compare and an approx compare. */ - MergeSortApprox mergeSort( ctx ); - ApproxCompare approxCompare( ctx ); - - /* Fill up an array of pointers to the states. */ - StateAp **statePtrs = new StateAp*[stateList.length()]; - StateList::Iter state = stateList; - for ( int s = 0; state.lte(); state++, s++ ) - statePtrs[s] = state; - - bool modified = false; - - /* Sort The list. */ - mergeSort.sort( statePtrs, stateList.length() ); - - /* Walk the list looking for duplicates next to each other, - * merge in any duplicates. */ - StateAp **pLast = statePtrs; - StateAp **pState = statePtrs + 1; - for ( int i = 1; i < stateList.length(); i++, pState++ ) { - if ( approxCompare.compare( *pLast, *pState ) == 0 ) { - /* Last and pState are the same, so fuse together. Move forward - * with pState but not with pLast. If any more are identical, we - * must */ - fuseEquivStates( *pLast, *pState ); - modified = true; - } - else { - /* Last and this are different, do not set to merge them. Move - * pLast to the current (it may be way behind from merging many - * states) and pState forward one to consider the next pair. */ - pLast = pState; - } - } - delete[] statePtrs; - return modified; -} -#endif - -#ifdef TO_UPGRADE_CONDS -/** - * \brief Minmimize by an approximation. - * - * Repeatedly tries to find states with transitions out to the same set of - * states on the same set of keys until no more identical states can be found. - * Does not produce the most minimial FSM possible. - */ -void FsmAp::minimizeApproximate() -{ - /* While the last minimization round succeeded in compacting states, - * continue to try to compact states. */ - while ( true ) { - bool modified = minimizeRound(); - if ( ! modified ) - break; - } -} -#endif - - -/* Remove states that have no path to them from the start state. Recursively - * traverses the graph marking states that have paths into them. Then removes - * all states that did not get marked. */ -long FsmAp::removeUnreachableStates() -{ - long origLen = stateList.length(); - - /* Misfit accounting should be off and there should be no states on the - * misfit list. */ - assert( !misfitAccounting && misfitList.length() == 0 ); - - /* Mark all the states that can be reached - * through the existing set of entry points. */ - markReachableFromHere( startState ); - for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) - markReachableFromHere( en->value ); - - /* Delete all states that are not marked - * and unmark the ones that are marked. */ - StateAp *state = stateList.head; - while ( state ) { - StateAp *next = state->next; - - if ( state->stateBits & STB_ISMARKED ) - state->stateBits &= ~ STB_ISMARKED; - else { - detachState( state ); - stateList.detach( state ); - delete state; - } - - state = next; - } - - return origLen - stateList.length(); -} - -bool FsmAp::outListCovers( StateAp *state ) -{ - /* Must be at least one range to cover. */ - if ( state->outList.length() == 0 ) - return false; - - /* The first must start at the lower bound. */ - TransList::Iter trans = state->outList.first(); - if ( ctx->keyOps->lt( ctx->keyOps->minKey, trans->lowKey ) ) - return false; - - /* Loop starts at second el. */ - trans.increment(); - - /* Loop checks lower against prev upper. */ - for ( ; trans.lte(); trans++ ) { - /* Lower end of the trans must be one greater than the - * previous' high end. */ - Key lowKey = trans->lowKey; - ctx->keyOps->decrement( lowKey ); - if ( ctx->keyOps->lt( trans->prev->highKey, lowKey ) ) - return false; - } - - /* Require that the last range extends to the upper bound. */ - trans = state->outList.last(); - if ( ctx->keyOps->lt( trans->highKey, ctx->keyOps->maxKey ) ) - return false; - - return true; -} - -/* Remove states that that do not lead to a final states. Works recursivly traversing - * the graph in reverse (starting from all final states) and marking seen states. Then - * removes states that did not get marked. */ -void FsmAp::removeDeadEndStates() -{ - /* Misfit accounting should be off and there should be no states on the - * misfit list. */ - assert( !misfitAccounting && misfitList.length() == 0 ); - - /* Mark all states that have paths to the final states. */ - StateAp **st = finStateSet.data; - int nst = finStateSet.length(); - for ( int i = 0; i < nst; i++, st++ ) - markReachableFromHereReverse( *st ); - - /* Start state gets honorary marking. If the machine accepts nothing we - * still want the start state to hang around. This must be done after the - * recursive call on all the final states so that it does not cause the - * start state in transitions to be skipped when the start state is - * visited by the traversal. */ - startState->stateBits |= STB_ISMARKED; - - /* Delete all states that are not marked - * and unmark the ones that are marked. */ - StateAp *state = stateList.head; - while ( state != 0 ) { - StateAp *next = state->next; - - if ( state->stateBits & STB_ISMARKED ) - state->stateBits &= ~ STB_ISMARKED; - else { - detachState( state ); - stateList.detach( state ); - delete state; - } - - state = next; - } -} - -/* Remove states on the misfit list. To work properly misfit accounting should - * be on when this is called. The detaching of a state will likely cause - * another misfit to be collected and it can then be removed. */ -void FsmAp::removeMisfits() -{ - while ( misfitList.length() > 0 ) { - /* Get the first state. */ - StateAp *state = misfitList.head; - - /* Detach and delete. */ - detachState( state ); - - /* The state was previously on the misfit list and detaching can only - * remove in transitions so the state must still be on the misfit - * list. */ - misfitList.detach( state ); - delete state; - } -} - -/* Fuse src into dest because they have been deemed equivalent states. - * Involves moving transitions into src to go into dest and invoking - * callbacks. Src is deleted detached from the graph and deleted. */ -void FsmAp::fuseEquivStates( StateAp *dest, StateAp *src ) -{ - /* This would get ugly. */ - assert( dest != src ); - - /* Cur is a duplicate. We can merge it with trail. */ - moveInwardTrans( dest, src ); - - detachState( src ); - stateList.detach( src ); - delete src; -} - -void FsmAp::fuseUnmarkedPairs( MarkIndex &markIndex ) -{ - StateAp *p = stateList.head, *nextP, *q; - - /* Definition: The primary state of an equivalence class is the first state - * encounterd that belongs to the equivalence class. All equivalence - * classes have primary state including equivalence classes with one state - * in it. */ - - /* For each unmarked pair merge p into q and delete p. q is always the - * primary state of it's equivalence class. We wouldn't have landed on it - * here if it were not, because it would have been deleted. - * - * Proof that q is the primaray state of it's equivalence class: Assume q - * is not the primary state of it's equivalence class, then it would be - * merged into some state that came before it and thus p would be - * equivalent to that state. But q is the first state that p is equivalent - * to so we have a contradiction. */ - - /* Walk all unordered pairs of (p, q) where p != q. - * The second depth of the walk stops before reaching p. This - * gives us all unordered pairs of states (p, q) where p != q. */ - while ( p != 0 ) { - nextP = p->next; - - q = stateList.head; - while ( q != p ) { - /* If one of p or q is a final state then mark. */ - if ( ! markIndex.isPairMarked( p->alg.stateNum, q->alg.stateNum ) ) { - fuseEquivStates( q, p ); - break; - } - q = q->next; - } - p = nextP; - } -} - -void FsmAp::fusePartitions( MinPartition *parts, int numParts ) -{ - /* For each partition, fuse state 2, 3, ... into state 1. */ - for ( int p = 0; p < numParts; p++ ) { - /* Assume that there will always be at least one state. */ - StateAp *first = parts[p].list.head, *toFuse = first->next; - - /* Put the first state back onto the main state list. Don't bother - * removing it from the partition list first. */ - stateList.append( first ); - - /* Fuse the rest of the state into the first. */ - while ( toFuse != 0 ) { - /* Save the next. We will trash it before it is needed. */ - StateAp *next = toFuse->next; - - /* Put the state to be fused in to the first back onto the main - * list before it is fuse. the graph. The state needs to be on - * the main list for the detach from the graph to work. Don't - * bother removing the state from the partition list first. We - * need not maintain it. */ - stateList.append( toFuse ); - - /* Now fuse to the first. */ - fuseEquivStates( first, toFuse ); - - /* Go to the next that we saved before trashing the next pointer. */ - toFuse = next; - } - - /* We transfered the states from the partition list into the main list without - * removing the states from the partition list first. Clean it up. */ - parts[p].list.abandon(); - } -} - -/* Merge neighboring transitions that go to the same state and have the same - * transitions data. */ -void FsmAp::compressTransitions() -{ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outList.length() > 1 ) { - for ( TransList::Iter trans = st->outList, next = trans.next(); next.lte(); ) { - Key nextLow = next->lowKey; - ctx->keyOps->decrement( nextLow ); - - /* Require there be no conditions in either of the merge - * candidates. */ - bool merge = false; - TransDataAp *td; - TransDataAp *tn; - - if ( trans->plain() && - next->plain() && - ctx->keyOps->eq( trans->highKey, nextLow ) ) - { - td = trans->tdap(); - tn = next->tdap(); - - /* Check the condition target and action data. */ - if ( td->toState == tn->toState && CmpActionTable::compare( - td->actionTable, tn->actionTable ) == 0 ) - { - merge = true; - } - } - - if ( merge ) { - trans->highKey = next->highKey; - st->outList.detach( tn ); - detachTrans( tn->fromState, tn->toState, tn ); - delete tn; - next = trans.next(); - } - else { - trans.increment(); - next.increment(); - } - } - } - } -} - -bool FsmAp::elimCondBits() -{ - bool modified = false; - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - restart: - for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) { - if ( !trans->plain() ) { - CondSpace *cs = trans->condSpace; - - for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ ) { - long bit = 1 << csi.pos(); - - /* Sort into on and off lists. */ - CondList on; - CondList off; - TransCondAp *tcap = trans->tcap(); - while ( tcap->condList.length() > 0 ) { - CondAp *cond = tcap->condList.detachFirst(); - if ( cond->key.getVal() & bit ) { - cond->key = CondKey( cond->key.getVal() & ~bit ); - on.append( cond ); - } - else { - off.append( cond ); - } - } - - bool merge = false; - if ( on.length() > 0 && on.length() == off.length() ) { - /* test if the same */ - int cmpRes = compareCondListBitElim( on, off ); - if ( cmpRes == 0 ) - merge = true; - } - - if ( merge ) { - if ( cs->condSet.length() == 1 ) { - /* clear out the on-list. */ - while ( on.length() > 0 ) { - CondAp *cond = on.detachFirst(); - detachTrans( st, cond->toState, cond ); - } - - /* turn back into a plain transition. */ - CondAp *cond = off.detachFirst(); - TransAp *n = convertToTransAp( st, cond ); - TransAp *before = trans->prev; - st->outList.detach( trans ); - st->outList.addAfter( before, n ); - modified = true; - goto restart; - } - else - { - CondSet newSet = cs->condSet; - newSet.Vector<Action*>::remove( csi.pos(), 1 ); - trans->condSpace = addCondSpace( newSet ); - - /* clear out the on-list. */ - while ( on.length() > 0 ) { - CondAp *cond = on.detachFirst(); - detachTrans( st, cond->toState, cond ); - } - } - } - - /* Turn back into a single list. */ - while ( on.length() > 0 || off.length() > 0 ) { - if ( on.length() == 0 ) { - while ( off.length() > 0 ) - tcap->condList.append( off.detachFirst() ); - } - else if ( off.length() == 0 ) { - while ( on.length() > 0 ) { - CondAp *cond = on.detachFirst(); - cond->key = CondKey( cond->key.getVal() | bit ); - tcap->condList.append( cond ); - } - } - else { - if ( off.head->key.getVal() < ( on.head->key.getVal() | bit ) ) { - tcap->condList.append( off.detachFirst() ); - } - else { - CondAp *cond = on.detachFirst(); - cond->key = CondKey( cond->key.getVal() | bit ); - tcap->condList.append( cond ); - } - } - } - - if ( merge ) { - modified = true; - goto restart; - } - } - } - } - } - return modified; -} - -/* Perform minimization after an operation according - * to the command line args. */ -void FsmAp::afterOpMinimize( bool lastInSeq ) -{ - /* Switch on the prefered minimization algorithm. */ - if ( ctx->minimizeOpt == MinimizeEveryOp || ( ctx->minimizeOpt == MinimizeMostOps && lastInSeq ) ) { - /* First clean up the graph. FsmAp operations may leave these - * lying around. There should be no dead end states. The subtract - * intersection operators are the only places where they may be - * created and those operators clean them up. */ - removeUnreachableStates(); - - switch ( ctx->minimizeLevel ) { - #ifdef TO_UPGRADE_CONDS - case MinimizeApprox: - minimizeApproximate(); - break; - #endif - case MinimizePartition1: - minimizePartition1(); - break; - case MinimizePartition2: - minimizePartition2(); - break; - #ifdef TO_UPGRADE_CONDS - case MinimizeStable: - minimizeStable(); - break; - #endif - } - } -} - diff --git a/src/fsmnfa.cc b/src/fsmnfa.cc deleted file mode 100644 index cde4f82d..00000000 --- a/src/fsmnfa.cc +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Copyright 2015-2018 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 <assert.h> -#include <iostream> - -#include "fsmgraph.h" -#include "mergesort.h" -#include "parsedata.h" - -using std::endl; - -void FsmAp::nfaFillInStates() -{ - long count = nfaList.length(); - - /* Can this lead to too many DFAs? Since the nfa merge is removing misfits, - * it is possible we remove a state that is on the nfa list, but we don't - * adjust count. */ - - /* Merge any states that are awaiting merging. This will likey cause - * other states to be added to the stfil list. */ - while ( nfaList.length() > 0 && count-- ) { - StateAp *state = nfaList.head; - - StateSet *stateSet = &state->stateDictEl->stateSet; - nfaMergeStates( state, stateSet->data, stateSet->length() ); - - for ( StateSet::Iter s = *stateSet; s.lte(); s++ ) - detachStateDict( state, *s ); - - nfaList.detach( state ); - } -} - -void FsmAp::prepareNfaRound() -{ - for ( StateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->nfaOut != 0 && ! (st->stateBits & STB_NFA_REP) ) { - StateSet set; - for ( NfaTransList::Iter to = *st->nfaOut; to.lte(); to++ ) - set.insert( to->toState ); - - st->stateDictEl = new StateDictEl( set ); - st->stateDictEl->targState = st; - stateDict.insert( st->stateDictEl ); - delete st->nfaOut; - st->nfaOut = 0; - - nfaList.append( st ); - } - } -} - -void FsmAp::finalizeNfaRound() -{ - /* For any remaining NFA states, remove from the state dict. We need to - * keep the state sets. */ - for ( NfaStateList::Iter ns = nfaList; ns.lte(); ns++ ) - stateDict.detach( ns->stateDictEl ); - - /* Disassociate non-nfa states from their state dicts. */ - for ( StateDict::Iter sdi = stateDict; sdi.lte(); sdi++ ) - sdi->targState->stateDictEl = 0; - - /* Delete the state dict elements for non-nfa states. */ - stateDict.empty(); - - /* Transfer remaining stateDictEl sets to nfaOut. */ - while ( nfaList.length() > 0 ) { - StateAp *state = nfaList.head; - state->nfaOut = new NfaTransList; - for ( StateSet::Iter ss = state->stateDictEl->stateSet; ss.lte(); ss++ ) { - /* Attach it using the NFA transitions data structure (propigates - * to output). */ - NfaTrans *trans = new NfaTrans( /* 0, 0, */ 1 ); - state->nfaOut->append( trans ); - attachToNfa( state, *ss, trans ); - - detachStateDict( state, *ss ); - } - delete state->stateDictEl; - state->stateDictEl = 0; - nfaList.detach( state ); - } -} - -void FsmAp::nfaMergeStates( StateAp *destState, - StateAp **srcStates, int numSrc ) -{ - for ( int s = 0; s < numSrc; s++ ) { - mergeStates( destState, srcStates[s] ); - - while ( misfitList.length() > 0 ) { - StateAp *state = misfitList.head; - - /* Detach and delete. */ - detachState( state ); - misfitList.detach( state ); - delete state; - } - } -} - - -/* - * WRT action ordering. - * - * All the pop restore actions get an ordering of -2 to cause them to always - * execute first. This is the action that restores the state and we need that - * to happen before any user actions. - */ -const int ORD_PUSH = 0; -const int ORD_RESTORE = -3; -const int ORD_COND = -1; -const int ORD_COND2 = -2; -const int ORD_TEST = 1073741824; - -void FsmAp::transferOutToNfaTrans( NfaTrans *trans, StateAp *state ) -{ - trans->popFrom = state->fromStateActionTable; - trans->popCondSpace = state->outCondSpace; - trans->popCondKeys = state->outCondKeys; - trans->priorTable.setPriors( state->outPriorTable ); - trans->popAction.setActions( state->outActionTable ); -} - -FsmRes FsmAp::nfaWrap( FsmAp *fsm, Action *push, Action *pop, Action *init, - Action *stay, Action *exit, NfaRepeatMode mode ) -{ - /* - * First Concat. - */ - StateSet origFinals = fsm->finStateSet; - - /* Get the orig start state. */ - StateAp *origStartState = fsm->startState; - - /* New start state. */ - StateAp *newStart = fsm->addState(); - - newStart->nfaOut = new NfaTransList; - - const int orderInit = 0; - const int orderStay = mode == NfaGreedy ? 3 : 1; - const int orderExit = mode == NfaGreedy ? 1 : 3; - - NfaTrans *trans; - if ( init ) { - /* Transition into the repetition. Doesn't make much sense to flip this - * statically false, but provided for consistency of interface. Allows - * an init so we can have only local state manipulation. */ - trans = new NfaTrans( orderInit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, init ); - - newStart->nfaOut->append( trans ); - fsm->attachToNfa( newStart, origStartState, trans ); - } - - StateAp *newFinal = fsm->addState(); - - for ( StateSet::Iter orig = origFinals; orig.lte(); orig++ ) { - /* For every final state, we place a new final state in front of it, - * with an NFA transition to the original. This is the "stay" choice. */ - StateAp *repl = fsm->addState(); - fsm->moveInwardTrans( repl, *orig ); - - repl->nfaOut = new NfaTransList; - - if ( stay != 0 ) { - /* Transition to original final state. Represents staying. */ - trans = new NfaTrans( orderStay ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, stay ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, *orig, trans ); - } - - if ( exit != 0 ) { - /* Transition to thew new final. Represents exiting. */ - trans = new NfaTrans( orderExit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, exit ); - - fsm->transferOutToNfaTrans( trans, *orig ); - repl->fromStateActionTable.setActions( (*orig)->fromStateActionTable ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, newFinal, trans ); - } - - fsm->unsetFinState( *orig ); - } - - fsm->unsetStartState(); - fsm->setStartState( newStart ); - fsm->setFinState( newFinal ); - - return FsmRes( FsmRes::Fsm(), fsm ); -} - - -FsmRes FsmAp::nfaRepeatOp2( FsmAp *fsm, Action *push, Action *pop, Action *init, - Action *stay, Action *repeat, Action *exit, NfaRepeatMode mode ) -{ - /* - * First Concat. - */ - StateSet origFinals = fsm->finStateSet; - - /* Get the orig start state. */ - StateAp *origStartState = fsm->startState; - StateAp *repStartState = fsm->dupStartState(); - - /* New start state. */ - StateAp *newStart1 = fsm->addState(); - StateAp *newStart2 = fsm->addState(); - - newStart1->nfaOut = new NfaTransList; - newStart2->nfaOut = new NfaTransList; - - const int orderInit = 0; - const int orderStay = mode == NfaGreedy ? 3 : 1; - const int orderRepeat = mode == NfaGreedy ? 2 : 2; - const int orderExit = mode == NfaGreedy ? 1 : 3; - - NfaTrans *trans; - if ( init ) { - /* Transition into the repetition. Doesn't make much sense to flip this - * statically false, but provided for consistency of interface. Allows - * an init so we can have only local state manipulation. */ - trans = new NfaTrans( orderInit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, init ); - - newStart1->nfaOut->append( trans ); - fsm->attachToNfa( newStart1, newStart2, trans ); - } - - StateAp *newFinal = fsm->addState(); - - if ( exit ) { - trans = new NfaTrans( orderExit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, exit ); - - newStart2->nfaOut->append( trans ); - fsm->attachToNfa( newStart1, newFinal, trans ); - } - - if ( repeat ) { - trans = new NfaTrans( orderRepeat ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, repeat ); - - newStart2->nfaOut->append( trans ); - fsm->attachToNfa( newStart1, origStartState, trans ); - } - - for ( StateSet::Iter orig = origFinals; orig.lte(); orig++ ) { - /* For every final state, we place a new final state in front of it, - * with an NFA transition to the original. This is the "stay" choice. */ - StateAp *repl = fsm->addState(); - fsm->moveInwardTrans( repl, *orig ); - - repl->nfaOut = new NfaTransList; - - if ( stay != 0 ) { - /* Transition to original final state. Represents staying. */ - trans = new NfaTrans( orderStay ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, stay ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, *orig, trans ); - } - - /* Transition back to the start. Represents repeat. */ - if ( repeat != 0 ) { - trans = new NfaTrans( orderRepeat ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, repeat ); - - fsm->transferOutToNfaTrans( trans, *orig ); - repl->fromStateActionTable.setActions( (*orig)->fromStateActionTable ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, repStartState, trans ); - } - - if ( exit != 0 ) { - /* Transition to thew new final. Represents exiting. */ - trans = new NfaTrans( orderExit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, exit ); - - fsm->transferOutToNfaTrans( trans, *orig ); - repl->fromStateActionTable.setActions( (*orig)->fromStateActionTable ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, newFinal, trans ); - } - - fsm->unsetFinState( *orig ); - } - - fsm->unsetStartState(); - fsm->setStartState( newStart1 ); - fsm->setFinState( newFinal ); - - return FsmRes( FsmRes::Fsm(), fsm ); -} - - -/* This version contains the init, increment and test in the nfa pop actions. - * This is a compositional operator since it doesn't leave any actions to - * trailing characters, where they may interact with other actions that use the - * same variables. */ -FsmRes FsmAp::nfaRepeatOp( FsmAp *fsm, Action *push, Action *pop, Action *init, - Action *stay, Action *repeat, Action *exit ) -{ - /* - * First Concat. - */ - StateSet origFinals = fsm->finStateSet; - - /* Get the orig start state. */ - StateAp *origStartState = fsm->startState; - StateAp *repStartState = fsm->dupStartState(); - - /* New start state. */ - StateAp *newStart = fsm->addState(); - - newStart->nfaOut = new NfaTransList; - - NfaTrans *trans; - if ( init ) { - /* Transition into the repetition. Doesn't make much sense to flip this - * statically false, but provided for consistency of interface. Allows - * an init so we can have only local state manipulation. */ - trans = new NfaTrans( 1 ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, init ); - - newStart->nfaOut->append( trans ); - fsm->attachToNfa( newStart, origStartState, trans ); - } - - StateAp *newFinal = fsm->addState(); - - for ( StateSet::Iter orig = origFinals; orig.lte(); orig++ ) { - /* For every final state, we place a new final state in front of it, - * with an NFA transition to the original. This is the "stay" choice. */ - StateAp *repl = fsm->addState(); - fsm->moveInwardTrans( repl, *orig ); - - repl->nfaOut = new NfaTransList; - - const int orderStay = 3; - const int orderRepeat = 2; - const int orderExit = 1; - - if ( stay != 0 ) { - /* Transition to original final state. Represents staying. */ - trans = new NfaTrans( orderStay ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, stay ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, *orig, trans ); - } - - /* Transition back to the start. Represents repeat. */ - if ( repeat != 0 ) { - trans = new NfaTrans( orderRepeat ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, repeat ); - - fsm->transferOutToNfaTrans( trans, *orig ); - repl->fromStateActionTable.setActions( (*orig)->fromStateActionTable ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, repStartState, trans ); - } - - if ( exit != 0 ) { - /* Transition to thew new final. Represents exiting. */ - trans = new NfaTrans( orderExit ); - - trans->pushTable.setAction( ORD_PUSH, push ); - trans->restoreTable.setAction( ORD_RESTORE, pop ); - trans->popTest.setAction( ORD_TEST, exit ); - - fsm->transferOutToNfaTrans( trans, *orig ); - repl->fromStateActionTable.setActions( (*orig)->fromStateActionTable ); - - repl->nfaOut->append( trans ); - fsm->attachToNfa( repl, newFinal, trans ); - } - - fsm->unsetFinState( *orig ); - } - - fsm->unsetStartState(); - fsm->setStartState( newStart ); - fsm->setFinState( newFinal ); - - return FsmRes( FsmRes::Fsm(), fsm ); -} - - -/* Unions others with fsm. Others are deleted. */ -FsmRes FsmAp::nfaUnionOp( FsmAp *fsm, FsmAp **others, int n, int depth, ostream &stats ) -{ - /* Mark existing NFA states as NFA_REP states, which excludes them from the - * prepare NFA round. We must treat them as final NFA states and not try to - * make them deterministic. */ - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) { - if ( st->nfaOut != 0 ) - st->stateBits |= STB_NFA_REP; - } - - for ( int o = 0; o < n; o++ ) { - for ( StateList::Iter st = others[o]->stateList; st.lte(); st++ ) { - if ( st->nfaOut != 0 ) - st->stateBits |= STB_NFA_REP; - } - } - - for ( int o = 0; o < n; o++ ) - assert( fsm->ctx == others[o]->ctx ); - - /* Not doing misfit accounting here. If we wanted to, it would need to be - * made nfa-compatibile. */ - - /* Build a state set consisting of both start states */ - StateSet startStateSet; - startStateSet.insert( fsm->startState ); - for ( int o = 0; o < n; o++ ) - startStateSet.insert( others[o]->startState ); - - /* Both of the original start states loose their start state status. */ - fsm->unsetStartState(); - for ( int o = 0; o < n; o++ ) - others[o]->unsetStartState(); - - /* Bring in the rest of other's entry points. */ - for ( int o = 0; o < n; o++ ) { - fsm->copyInEntryPoints( others[o] ); - others[o]->entryPoints.empty(); - } - - for ( int o = 0; o < n; o++ ) { - /* Merge the lists. This will move all the states from other - * into this. No states will be deleted. */ - fsm->stateList.append( others[o]->stateList ); - fsm->misfitList.append( others[o]->misfitList ); - // nfaList.append( others[o]->nfaList ); - } - - for ( int o = 0; o < n; o++ ) { - /* Move the final set data from other into this. */ - fsm->finStateSet.insert( others[o]->finStateSet ); - others[o]->finStateSet.empty(); - } - - for ( int o = 0; o < n; o++ ) { - /* Since other's list is empty, we can delete the fsm without - * affecting any states. */ - delete others[o]; - } - - /* Create a new start state. */ - fsm->setStartState( fsm->addState() ); - - if ( depth == 0 ) { - fsm->startState->stateDictEl = new StateDictEl( startStateSet ); - fsm->nfaList.append( fsm->startState ); - - for ( StateSet::Iter s = startStateSet; s.lte(); s++ ) { - NfaTrans *trans = new NfaTrans( /* 0, 0, */ 0 ); - - if ( fsm->startState->nfaOut == 0 ) - fsm->startState->nfaOut = new NfaTransList; - - fsm->startState->nfaOut->append( trans ); - fsm->attachToNfa( fsm->startState, *s, trans ); - } - } - else { - /* Merge the start states. */ - if ( fsm->ctx->printStatistics ) - stats << "nfa-fill-round\t0" << endl; - - fsm->nfaMergeStates( fsm->startState, startStateSet.data, startStateSet.length() ); - - long removed = fsm->removeUnreachableStates(); - if ( fsm->ctx->printStatistics ) - stats << "round-unreach\t" << removed << endl; - - /* Fill in any new states made from merging. */ - for ( long i = 1; i < depth; i++ ) { - if ( fsm->ctx->printStatistics ) - stats << "nfa-fill-round\t" << i << endl; - - if ( fsm->nfaList.length() == 0 ) - break; - - fsm->nfaFillInStates( ); - - long removed = fsm->removeUnreachableStates(); - if ( fsm->ctx->printStatistics ) - stats << "round-unreach\t" << removed << endl; - } - - fsm->finalizeNfaRound(); - - long maxStateSetSize = 0; - long count = 0; - for ( StateList::Iter s = fsm->stateList; s.lte(); s++ ) { - if ( s->nfaOut != 0 && s->nfaOut->length() > 0 ) { - count += 1; - if ( s->nfaOut->length() > maxStateSetSize ) - maxStateSetSize = s->nfaOut->length(); - } - } - - if ( fsm->ctx->printStatistics ) { - stats << "fill-list\t" << count << endl; - stats << "state-dict\t" << fsm->stateDict.length() << endl; - stats << "states\t" << fsm->stateList.length() << endl; - stats << "max-ss\t" << maxStateSetSize << endl; - } - - fsm->removeUnreachableStates(); - - if ( fsm->ctx->printStatistics ) - stats << "post-unreachable\t" << fsm->stateList.length() << endl; - - fsm->minimizePartition2(); - - if ( fsm->ctx->printStatistics ) { - stats << "post-min\t" << fsm->stateList.length() << std::endl; - stats << std::endl; - } - } - - return FsmRes( FsmRes::Fsm(), fsm ); -} - -FsmRes FsmAp::nfaUnion( const NfaRoundVect &roundsList, - FsmAp **machines, int numMachines, - std::ostream &stats, bool printStatistics ) -{ - long sumPlain = 0, sumMin = 0; - for ( int i = 0; i < numMachines; i++ ) { - sumPlain += machines[i]->stateList.length(); - - machines[i]->removeUnreachableStates(); - machines[i]->minimizePartition2(); - - sumMin += machines[i]->stateList.length(); - } - - if ( printStatistics ) { - stats << "sum-plain\t" << sumPlain << endl; - stats << "sum-minimized\t" << sumMin << endl; - } - - /* For each round. */ - for ( NfaRoundVect::Iter r = roundsList; r.lte(); r++ ) { - - if ( printStatistics ) { - stats << "depth\t" << r->depth << endl; - stats << "grouping\t" << r->groups << endl; - } - - int numGroups = 0; - int start = 0; - while ( start < numMachines ) { - /* If nfa-group-max is zero, don't group, put all terms into a single - * n-depth NFA. */ - int amount = r->groups == 0 ? numMachines : r->groups; - if ( ( start + amount ) > numMachines ) - amount = numMachines - start; - - FsmAp **others = machines + start + 1; - FsmRes res = FsmAp::nfaUnionOp( machines[start], others, (amount - 1), r->depth, stats ); - machines[start] = res.fsm; - - start += amount; - numGroups++; - } - - if ( numGroups == 1 ) - break; - - /* Move the group starts into the groups array. */ - FsmAp **groups = new FsmAp*[numGroups]; - int g = 0; - start = 0; - while ( start < numMachines ) { - groups[g] = machines[start]; - start += r->groups == 0 ? numMachines : r->groups; - g++; - } - - delete[] machines; - machines = groups; - numMachines = numGroups; - } - - FsmAp *ret = machines[0]; - return FsmRes( FsmRes::Fsm(), ret ); -} diff --git a/src/fsmstate.cc b/src/fsmstate.cc deleted file mode 100644 index 03a4df34..00000000 --- a/src/fsmstate.cc +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright 2002-2018 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 "fsmgraph.h" - -#include <string.h> -#include <assert.h> -#include <iostream> - -/* Construct a mark index for a specified number of states. Must new up - * an array that is states^2 in size. */ -MarkIndex::MarkIndex( int states ) : numStates(states) -{ - /* Total pairs is states^2. Actually only use half of these, but we allocate - * them all to make indexing into the array easier. */ - int total = states * states; - - /* New up chars so that individual DListEl constructors are - * not called. Zero out the mem manually. */ - array = new bool[total]; - memset( array, 0, sizeof(bool) * total ); -} - -/* Free the array used to store state pairs. */ -MarkIndex::~MarkIndex() -{ - delete[] array; -} - -/* Mark a pair of states. States are specified by their number. The - * marked states are moved from the unmarked list to the marked list. */ -void MarkIndex::markPair(int state1, int state2) -{ - int pos = ( state1 >= state2 ) ? - ( state1 * numStates ) + state2 : - ( state2 * numStates ) + state1; - - array[pos] = true; -} - -/* Returns true if the pair of states are marked. Returns false otherwise. - * Ordering of states given does not matter. */ -bool MarkIndex::isPairMarked(int state1, int state2) -{ - int pos = ( state1 >= state2 ) ? - ( state1 * numStates ) + state2 : - ( state2 * numStates ) + state1; - - return array[pos]; -} - -/* Create a new fsm state. State has not out transitions or in transitions, not - * out out transition data and not number. */ -StateAp::StateAp() -: - /* No out or in transitions. */ - outList(), - inTrans(), - inCond(), - - /* No EOF target. */ - eofTarget(0), - - /* No entry points, or epsilon trans. */ - entryIds(), - epsilonTrans(), - - /* No transitions in from other states. */ - foreignInTrans(0), - - /* Only used during merging. Normally null. */ - stateDictEl(0), - stateDictIn(0), - - nfaOut(0), - nfaIn(0), - - eptVect(0), - - /* No state identification bits. */ - stateBits(0), - - /* No Priority data. */ - outPriorTable(), - - /* No Action data. */ - toStateActionTable(), - fromStateActionTable(), - outActionTable(), - outCondSpace(0), - outCondKeys(), - errActionTable(), - eofActionTable(), - guardedInTable(), - lmNfaParts() -{ -} - -/* Copy everything except actual the transitions. That is left up to the - * FsmAp copy constructor. */ -StateAp::StateAp(const StateAp &other) -: - /* All lists are cleared. They will be filled in when the - * individual transitions are duplicated and attached. */ - outList(), - inTrans(), - inCond(), - - /* Set this using the original state's eofTarget. It will get mapped back - * to the new machine in the Fsm copy constructor. */ - eofTarget(other.eofTarget), - - /* Duplicate the entry id set and epsilon transitions. These - * are sets of integers and as such need no fixing. */ - entryIds(other.entryIds), - epsilonTrans(other.epsilonTrans), - - /* No transitions in from other states. */ - foreignInTrans(0), - - /* This is only used during merging. Normally null. */ - stateDictEl(0), - stateDictIn(0), - - nfaOut(0), - nfaIn(0), - - eptVect(0), - - /* Fsm state data. */ - stateBits(other.stateBits), - - /* Copy in priority data. */ - outPriorTable(other.outPriorTable), - - /* Copy in action data. */ - toStateActionTable(other.toStateActionTable), - fromStateActionTable(other.fromStateActionTable), - outActionTable(other.outActionTable), - outCondSpace(other.outCondSpace), - outCondKeys(other.outCondKeys), - errActionTable(other.errActionTable), - eofActionTable(other.eofActionTable), - - guardedInTable(other.guardedInTable), - lmNfaParts(other.lmNfaParts) -{ - /* Duplicate all the transitions. */ - for ( TransList::Iter trans = other.outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - /* Duplicate and store the orginal target in the transition. This will - * be corrected once all the states have been created. */ - TransDataAp *newTrans = new TransDataAp( *trans->tdap() ); - assert( trans->tdap()->lmActionTable.length() == 0 ); - newTrans->toState = trans->tdap()->toState; - outList.append( newTrans ); - } - else { - /* Duplicate and store the orginal target in the transition. This will - * be corrected once all the states have been created. */ - TransAp *newTrans = new TransCondAp( *trans->tcap() ); - - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++ ) { - CondAp *newCondTrans = new CondAp( *cti, newTrans ); - newCondTrans->key = cti->key; - - newTrans->tcap()->condList.append( newCondTrans ); - - assert( cti->lmActionTable.length() == 0 ); - - newCondTrans->toState = cti->toState; - } - - outList.append( newTrans ); - } - } - - /* Dup the nfa trans. */ - if ( other.nfaOut != 0 ) { - nfaOut = new NfaTransList; - for ( NfaTransList::Iter trans = *other.nfaOut; trans.lte(); trans++ ) { - NfaTrans *newtrans = new NfaTrans( *trans ); - newtrans->toState = trans->toState; - - nfaOut->append( newtrans ); - } - } -} - -/* If there is a state dict element, then delete it. Everything else is left - * up to the FsmGraph destructor. */ -StateAp::~StateAp() -{ - if ( stateDictEl != 0 ) - delete stateDictEl; - - if ( stateDictIn != 0 ) - delete stateDictIn; - - if ( nfaIn != 0 ) - delete nfaIn; - - if ( nfaOut != 0 ) { - nfaOut->empty(); - delete nfaOut; - } -} - -#ifdef TO_UPGRADE_CONDS -/* Compare two states using pointers to the states. With the approximate - * compare, the idea is that if the compare finds them the same, they can - * immediately be merged. */ -int ApproxCompare::compare( const StateAp *state1, const StateAp *state2 ) -{ - int compareRes; - - /* Test final state status. */ - if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) ) - return -1; - else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) ) - return 1; - - /* Test epsilon transition sets. */ - compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans, - state2->epsilonTrans ); - if ( compareRes != 0 ) - return compareRes; - - /* Compare the out transitions. */ - compareRes = FsmAp::compareStateData( state1, state2 ); - if ( compareRes != 0 ) - return compareRes; - - /* Use a pair iterator to get the transition pairs. */ - RangePairIter<TransAp> outPair( ctx, state1->outList.head, state2->outList.head ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - - case RangePairIter<TransAp>::RangeInS1: - compareRes = FsmAp::compareFullPtr( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIter<TransAp>::RangeInS2: - compareRes = FsmAp::compareFullPtr( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIter<TransAp>::RangeOverlap: - compareRes = FsmAp::compareFullPtr( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIter<TransAp>::BreakS1: - case RangePairIter<TransAp>::BreakS2: - break; - } - } - - /* Check EOF targets. */ - if ( state1->eofTarget < state2->eofTarget ) - return -1; - else if ( state1->eofTarget > state2->eofTarget ) - return 1; - - if ( state1->guardedIn || !state2->guardedIn ) - return -1; - else if ( !state1->guardedIn || state2->guardedIn ) - return 1; - - /* Got through the entire state comparison, deem them equal. */ - return 0; -} -#endif - - -/* Compare class used in the initial partition. */ -int InitPartitionCompare::compare( const StateAp *state1, const StateAp *state2 ) -{ - int compareRes; - - if ( state1->nfaOut == 0 && state2->nfaOut != 0 ) - return -1; - else if ( state1->nfaOut != 0 && state2->nfaOut == 0 ) - return 1; - else if ( state1->nfaOut != 0 ) { - compareRes = CmpNfaTransList::compare( - *state1->nfaOut, *state2->nfaOut ); - if ( compareRes != 0 ) - return compareRes; - } - - /* Test final state status. */ - if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) ) - return -1; - else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) ) - return 1; - - /* Test epsilon transition sets. */ - compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans, - state2->epsilonTrans ); - if ( compareRes != 0 ) - return compareRes; - - /* Compare the out transitions. */ - compareRes = FsmAp::compareStateData( state1, state2 ); - if ( compareRes != 0 ) - return compareRes; - - /* Use a pair iterator to test the transition pairs. */ - typedef RangePairIter< PiList<TransAp> > RangePairIterPiListTransAp; - RangePairIterPiListTransAp - outPair( ctx, state1->outList, state2->outList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - - case RangePairIterPiListTransAp::RangeInS1: - compareRes = FsmAp::compareTransDataPtr( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::RangeInS2: - compareRes = FsmAp::compareTransDataPtr( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::RangeOverlap: - compareRes = FsmAp::compareTransDataPtr( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::BreakS1: - case RangePairIterPiListTransAp::BreakS2: - break; - } - } - - return 0; -} - -/* Compare class for the sort that does the partitioning. */ -int PartitionCompare::compare( const StateAp *state1, const StateAp *state2 ) -{ - int compareRes; - - /* Use a pair iterator to get the transition pairs. */ - typedef RangePairIter< PiList<TransAp> > RangePairIterPiListTransAp; - RangePairIterPiListTransAp outPair( ctx, state1->outList, state2->outList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - - case RangePairIterPiListTransAp::RangeInS1: - compareRes = FsmAp::compareTransPartPtr( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::RangeInS2: - compareRes = FsmAp::compareTransPartPtr( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::RangeOverlap: - compareRes = FsmAp::compareTransPartPtr( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - - case RangePairIterPiListTransAp::BreakS1: - case RangePairIterPiListTransAp::BreakS2: - break; - } - } - - /* Test eof targets. */ - if ( state1->eofTarget == 0 && state2->eofTarget != 0 ) - return -1; - else if ( state1->eofTarget != 0 && state2->eofTarget == 0 ) - return 1; - else if ( state1->eofTarget != 0 ) { - /* Both eof targets are set. */ - compareRes = CmpOrd< MinPartition* >::compare( - state1->eofTarget->alg.partition, state2->eofTarget->alg.partition ); - if ( compareRes != 0 ) - return compareRes; - } - - return 0; -} - -#ifdef TO_UPGRADE_CONDS -/* Compare class for the sort that does the partitioning. */ -bool MarkCompare::shouldMark( MarkIndex &markIndex, const StateAp *state1, - const StateAp *state2 ) -{ - /* Use a pair iterator to get the transition pairs. */ - RangePairIter<TransAp> outPair( ctx, state1->outList.head, state2->outList.head ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - - case RangePairIter<TransAp>::RangeInS1: - if ( FsmAp::shouldMarkPtr( markIndex, outPair.s1Tel.trans, 0 ) ) - return true; - break; - - case RangePairIter<TransAp>::RangeInS2: - if ( FsmAp::shouldMarkPtr( markIndex, 0, outPair.s2Tel.trans ) ) - return true; - break; - - case RangePairIter<TransAp>::RangeOverlap: - if ( FsmAp::shouldMarkPtr( markIndex, - outPair.s1Tel.trans, outPair.s2Tel.trans ) ) - return true; - break; - - case RangePairIter<TransAp>::BreakS1: - case RangePairIter<TransAp>::BreakS2: - break; - } - } - - return false; -} -#endif - -/* - * Transition Comparison. - */ - -int FsmAp::comparePart( TransAp *trans1, TransAp *trans2 ) -{ - if ( trans1->plain() ) { - int compareRes = FsmAp::compareCondPartPtr( trans1->tdap(), trans2->tdap() ); - if ( compareRes != 0 ) - return compareRes; - } - else { - /* Use a pair iterator to get the transition pairs. */ - typedef ValPairIter< PiList<CondAp> > ValPairIterPiListCondAp; - ValPairIterPiListCondAp outPair( trans1->tcap()->condList, - trans2->tcap()->condList ); - for ( ; !outPair.end(); outPair++ ) { - switch ( outPair.userState ) { - - case ValPairIterPiListCondAp::RangeInS1: { - int compareRes = FsmAp::compareCondPartPtr<CondAp>( outPair.s1Tel.trans, 0 ); - if ( compareRes != 0 ) - return compareRes; - break; - } - - case ValPairIterPiListCondAp::RangeInS2: { - int compareRes = FsmAp::compareCondPartPtr<CondAp>( 0, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - } - - case ValPairIterPiListCondAp::RangeOverlap: { - int compareRes = FsmAp::compareCondPartPtr<CondAp>( - outPair.s1Tel.trans, outPair.s2Tel.trans ); - if ( compareRes != 0 ) - return compareRes; - break; - }} - } - } - - return 0; -} - -/* Compare target partitions. Either pointer may be null. */ -int FsmAp::compareTransPartPtr( TransAp *trans1, TransAp *trans2 ) -{ - if ( trans1 != 0 ) { - /* If trans1 is set then so should trans2. The initial partitioning - * guarantees this for us. */ - return comparePart( trans1, trans2 ); - } - - return 0; -} - -template< class Trans > int FsmAp::compareCondPartPtr( Trans *trans1, Trans *trans2 ) -{ - if ( trans1 != 0 ) { - /* If trans1 is set then so should trans2. The initial partitioning - * guarantees this for us. */ - if ( trans1->toState == 0 && trans2->toState != 0 ) - return -1; - else if ( trans1->toState != 0 && trans2->toState == 0 ) - return 1; - else if ( trans1->toState != 0 ) { - /* Both of targets are set. */ - return CmpOrd< MinPartition* >::compare( - trans1->toState->alg.partition, trans2->toState->alg.partition ); - } - } - return 0; -} - - -/* Compares two transition pointers according to priority and functions. - * Either pointer may be null. Does not consider to state or from state. */ -int FsmAp::compareTransDataPtr( TransAp *trans1, TransAp *trans2 ) -{ - if ( trans1 == 0 && trans2 != 0 ) - return -1; - else if ( trans1 != 0 && trans2 == 0 ) - return 1; - else if ( trans1 != 0 ) { - /* Both of the transition pointers are set. */ - int compareRes = compareTransData( trans1, trans2 ); - if ( compareRes != 0 ) - return compareRes; - } - return 0; -} - -#ifdef TO_UPGRADE_CONDS -/* Compares two transitions according to target state, priority and functions. - * Does not consider from state. Either of the pointers may be null. */ -int FsmAp::compareFullPtr( TransAp *trans1, TransAp *trans2 ) -{ - /* << "FIXME: " << __PRETTY_FUNCTION__ << std::endl; */ - - if ( (trans1 != 0) ^ (trans2 != 0) ) { - /* Exactly one of the transitions is set. */ - if ( trans1 != 0 ) - return -1; - else - return 1; - } - else if ( trans1 != 0 ) { - /* Both of the transition pointers are set. Test target state, - * priority and funcs. */ - if ( tai(trans1)->tcap()->condList.head->toState < tai(trans2)->tcap()->condList.head->toState ) - return -1; - else if ( tai(trans1)->tcap()->condList.head->toState > tai(trans2)->tcap()->condList.head->toState ) - return 1; - else if ( tai(trans1)->tcap()->condList.head->toState != 0 ) { - /* Test transition data. */ - int compareRes = compareTransData( trans1, trans2 ); - if ( compareRes != 0 ) - return compareRes; - } - } - return 0; -} -#endif - -#ifdef TO_UPGRADE_CONDS -bool FsmAp::shouldMarkPtr( MarkIndex &markIndex, TransAp *trans1, - TransAp *trans2 ) -{ - /* << "FIXME: " << __PRETTY_FUNCTION__ << std::endl; */ - - if ( (trans1 != 0) ^ (trans2 != 0) ) { - /* Exactly one of the transitions is set. The initial mark round - * should rule out this case. */ - assert( false ); - } - else if ( trans1 != 0 ) { - /* Both of the transitions are set. If the target pair is marked, then - * the pair we are considering gets marked. */ - return markIndex.isPairMarked( tai(trans1)->tcap()->condList.head->toState->alg.stateNum, - tai(trans2)->tcap()->condList.head->toState->alg.stateNum ); - } - - /* Neither of the transitiosn are set. */ - return false; -} -#endif diff --git a/src/gendata.cc b/src/gendata.cc deleted file mode 100644 index 10420f09..00000000 --- a/src/gendata.cc +++ /dev/null @@ -1,1648 +0,0 @@ -/* - * Copyright 2005-2018 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 "gendata.h" -#include "ragel.h" -#include "parsedata.h" -#include "fsmgraph.h" -#include "inputdata.h" -#include "version.h" - -#include <string.h> -#include <iostream> - -string itoa( int i ) -{ - char buf[16]; - sprintf( buf, "%i", i ); - return buf; -} - -void openHostBlock( char opener, InputData *id, ostream &out, const char *fileName, int line ) -{ - out << "host( \""; - for ( const char *pc = fileName; *pc != 0; pc++ ) { - if ( *pc == '\\' ) - out << "\\\\"; - else - out << *pc; - } - out << "\", " << line << " ) " << opener << "{"; -} - -void Reducer::appendTrans( TransListVect &outList, Key lowKey, - Key highKey, TransAp *trans ) -{ - if ( trans->plain() ) { - if ( trans->tdap()->toState != 0 || trans->tdap()->actionTable.length() > 0 ) - outList.append( TransEl( lowKey, highKey, trans ) ); - } - else { - /* Add once if any cond has a to-state or an action table. */ - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->toState != 0 || cond->actionTable.length() > 0 ) { - outList.append( TransEl( lowKey, highKey, trans ) ); - break; - } - } - } -} - -void Reducer::reduceActionTables() -{ - /* Reduce the actions tables to a set. */ - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) { - RedActionTable *actionTable = 0; - - /* Reduce To State Actions. */ - if ( st->toStateActionTable.length() > 0 ) { - if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - - /* Reduce From State Actions. */ - if ( st->fromStateActionTable.length() > 0 ) { - if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - - /* Reduce EOF actions. */ - if ( st->eofActionTable.length() > 0 ) { - if ( actionTableMap.insert( st->eofActionTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - - /* Loop the transitions and reduce their actions. */ - for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) { - if ( trans->plain() ) { - if ( trans->tdap()->actionTable.length() > 0 ) { - if ( actionTableMap.insert( trans->tdap()->actionTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - if ( cond->actionTable.length() > 0 ) { - if ( actionTableMap.insert( cond->actionTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - } - } - } - - if ( st->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *st->nfaOut; n.lte(); n++ ) { - if ( actionTableMap.insert( n->pushTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - - if ( actionTableMap.insert( n->restoreTable, &actionTable ) ) - actionTable->id = nextActionTableId++; - - if ( actionTableMap.insert( n->popAction, &actionTable ) ) - actionTable->id = nextActionTableId++; - - if ( actionTableMap.insert( n->popTest, &actionTable ) ) - actionTable->id = nextActionTableId++; - } - } - } -} - - -void Reducer::makeText( GenInlineList *outList, InlineItem *item ) -{ - GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text ); - inlineItem->data = item->data; - - outList->append( inlineItem ); -} - -void Reducer::makeTargetItem( GenInlineList *outList, NameInst *nameTarg, - GenInlineItem::Type type ) -{ - long targetState; - if ( fsmCtx->generatingSectionSubset ) - targetState = -1; - else { - EntryMapEl *targ = fsm->entryPoints.find( nameTarg->id ); - targetState = targ->value->alg.stateNum; - } - - /* Make the item. */ - GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type ); - inlineItem->targId = targetState; - outList->append( inlineItem ); -} - - -void Reducer::makeSubList( GenInlineList *outList, const InputLoc &loc, - InlineList *inlineList, GenInlineItem::Type type ) -{ - /* Fill the sub list. */ - GenInlineList *subList = new GenInlineList; - makeGenInlineList( subList, inlineList ); - - /* Make the item. */ - GenInlineItem *inlineItem = new GenInlineItem( loc, type ); - inlineItem->children = subList; - outList->append( inlineItem ); -} - -/* Make a sublist item with a given type. */ -void Reducer::makeSubList( GenInlineList *outList, - InlineList *inlineList, GenInlineItem::Type type ) -{ - makeSubList( outList, InputLoc(), inlineList, type ); -} - -void Reducer::makeLmOnLast( GenInlineList *outList, InlineItem *item ) -{ - makeSetTokend( outList, 1 ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - -void Reducer::makeLmOnNext( GenInlineList *outList, InlineItem *item ) -{ - makeSetTokend( outList, 0 ); - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmHold ) ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - -void Reducer::makeExecGetTokend( GenInlineList *outList ) -{ - /* Make the Exec item. */ - GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::LmExec ); - execItem->children = new GenInlineList; - - /* Make the GetTokEnd */ - GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd ); - execItem->children->append( getTokend ); - - outList->append( execItem ); -} - -void Reducer::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item ) -{ - /* Jump to the tokend. */ - makeExecGetTokend( outList ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - -void Reducer::makeLmSwitch( GenInlineList *outList, InlineItem *item ) -{ - GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch ); - GenInlineList *lmList = lmSwitch->children = new GenInlineList; - LongestMatch *longestMatch = item->longestMatch; - - /* We can't put the <exec> here because we may need to handle the error - * case and in that case p should not be changed. Instead use a default - * label in the switch to adjust p when user actions are not set. An id of - * -1 indicates the default. */ - - if ( longestMatch->lmSwitchHandlesError ) { - /* If the switch handles error then we should have also forced the - * error state. */ - assert( fsm->errState != 0 ); - - GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::HostStmt ); - errCase->lmId = 0; - errCase->children = new GenInlineList; - - GenInlineItem *host = new GenInlineItem( item->loc, GenInlineItem::HostStmt ); - host->children = new GenInlineList; - errCase->children->append( host ); - - /* Make the item. This should probably be an LM goto, would eliminate - * need for wrapping in host statement. .*/ - GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto ); - gotoItem->targId = fsm->errState->alg.stateNum; - host->children->append( gotoItem ); - - lmList->append( errCase ); - } - - bool needDefault = false; - for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) { - if ( lmi->inLmSelect ) { - if ( lmi->action == 0 ) - needDefault = true; - else { - /* Open the action. Write it with the context that sets up _p - * when doing control flow changes from inside the machine. */ - GenInlineItem *lmCase = new GenInlineItem( InputLoc(), GenInlineItem::LmCase ); - lmCase->lmId = lmi->longestMatchId; - lmCase->children = new GenInlineList; - - makeExecGetTokend( lmCase->children ); - - GenInlineItem *subHost = new GenInlineItem( lmi->action->loc, - GenInlineItem::HostStmt ); - subHost->children = new GenInlineList; - makeGenInlineList( subHost->children, lmi->action->inlineList ); - lmCase->children->append( subHost ); - - lmList->append( lmCase ); - } - } - } - - if ( needDefault ) { - GenInlineItem *defCase = new GenInlineItem( item->loc, GenInlineItem::HostStmt ); - defCase->lmId = -1; - defCase->children = new GenInlineList; - - makeExecGetTokend( defCase->children ); - - lmList->append( defCase ); - } - - outList->append( lmSwitch ); -} - -void Reducer::makeLmNfaOnNext( GenInlineList *outList, InlineItem *item ) -{ - makeSetTokend( outList, 0 ); - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmHold ) ); - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::NfaClear ) ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - -void Reducer::makeLmNfaOnEof( GenInlineList *outList, InlineItem *item ) -{ - makeSetTokend( outList, 0 ); - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::NfaClear ) ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - -void Reducer::makeLmNfaOnLast( GenInlineList *outList, InlineItem *item ) -{ - makeSetTokend( outList, 1 ); - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::NfaClear ) ); - - if ( item->longestMatchPart->action != 0 ) { - Action *action = item->longestMatchPart->action; - makeSubList( outList, action->loc, action->inlineList, - GenInlineItem::HostStmt ); - } -} - - -void Reducer::makeSetTokend( GenInlineList *outList, long offset ) -{ - GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd ); - inlineItem->offset = offset; - outList->append( inlineItem ); -} - -void Reducer::makeSetAct( GenInlineList *outList, long lmId ) -{ - GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId ); - inlineItem->lmId = lmId; - outList->append( inlineItem ); -} - -void Reducer::makeGenInlineList( GenInlineList *outList, InlineList *inList ) -{ - for ( InlineList::Iter item = *inList; item.lte(); item++ ) { - switch ( item->type ) { - case InlineItem::Text: - makeText( outList, item ); - break; - case InlineItem::Goto: - makeTargetItem( outList, item->nameTarg, GenInlineItem::Goto ); - break; - case InlineItem::GotoExpr: - makeSubList( outList, item->children, GenInlineItem::GotoExpr ); - break; - case InlineItem::Call: - makeTargetItem( outList, item->nameTarg, GenInlineItem::Call ); - break; - case InlineItem::CallExpr: - makeSubList( outList, item->children, GenInlineItem::CallExpr ); - break; - case InlineItem::Ncall: - makeTargetItem( outList, item->nameTarg, GenInlineItem::Ncall ); - break; - case InlineItem::NcallExpr: - makeSubList( outList, item->children, GenInlineItem::NcallExpr ); - break; - case InlineItem::Next: - makeTargetItem( outList, item->nameTarg, GenInlineItem::Next ); - break; - case InlineItem::NextExpr: - makeSubList( outList, item->children, GenInlineItem::NextExpr ); - break; - case InlineItem::Break: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) ); - break; - case InlineItem::Nbreak: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Nbreak ) ); - break; - case InlineItem::Ret: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) ); - break; - case InlineItem::Nret: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Nret ) ); - break; - case InlineItem::PChar: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) ); - break; - case InlineItem::Char: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) ); - break; - case InlineItem::Curs: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) ); - break; - case InlineItem::Targs: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) ); - break; - case InlineItem::Entry: - makeTargetItem( outList, item->nameTarg, GenInlineItem::Entry ); - break; - - case InlineItem::Hold: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) ); - break; - case InlineItem::Exec: - makeSubList( outList, item->children, GenInlineItem::Exec ); - break; - - case InlineItem::LmSetActId: - makeSetAct( outList, item->longestMatchPart->longestMatchId ); - break; - case InlineItem::LmSetTokEnd: - makeSetTokend( outList, 1 ); - break; - - case InlineItem::LmOnLast: - makeLmOnLast( outList, item ); - break; - case InlineItem::LmOnNext: - makeLmOnNext( outList, item ); - break; - case InlineItem::LmOnLagBehind: - makeLmOnLagBehind( outList, item ); - break; - case InlineItem::LmSwitch: - makeLmSwitch( outList, item ); - break; - - case InlineItem::LmNfaOnLast: - makeLmNfaOnLast( outList, item ); - break; - case InlineItem::LmNfaOnNext: - makeLmNfaOnNext( outList, item ); - break; - case InlineItem::LmNfaOnEof: - makeLmNfaOnEof( outList, item ); - break; - - case InlineItem::LmInitAct: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) ); - break; - case InlineItem::LmInitTokStart: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) ); - break; - case InlineItem::LmSetTokStart: - outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) ); - hasLongestMatch = true; - break; - case InlineItem::Stmt: - makeSubList( outList, item->children, GenInlineItem::GenStmt ); - break; - case InlineItem::Subst: { - /* Find the subst action. */ - Action *subst = curInlineAction->argList->data[item->substPos]; - makeGenInlineList( outList, subst->inlineList ); - break; - } - case InlineItem::NfaWrapAction: { - GenAction *wrap = allActions + item->wrappedAction->actionId; - GenInlineItem *gii = new GenInlineItem( InputLoc(), - GenInlineItem::NfaWrapAction ); - gii->wrappedAction = wrap; - outList->append( gii ); - break; - } - case InlineItem::NfaWrapConds: { - GenCondSpace *condSpace = allCondSpaces + item->condSpace->condSpaceId; - - GenInlineItem *gii = new GenInlineItem( InputLoc(), - GenInlineItem::NfaWrapConds ); - gii->condSpace = condSpace; - gii->condKeySet = item->condKeySet; - outList->append( gii ); - break; - }} - } -} - -void Reducer::makeExports() -{ - for ( ExportList::Iter exp = fsmCtx->exportList; exp.lte(); exp++ ) - exportList.append( new Export( exp->name, exp->key ) ); -} - -void Reducer::makeAction( Action *action ) -{ - GenInlineList *genList = new GenInlineList; - - curInlineAction = action; - makeGenInlineList( genList, action->inlineList ); - curInlineAction = 0; - - newAction( curAction++, action->name, action->loc, genList ); -} - - -void Reducer::makeActionList() -{ - /* Determine which actions to write. */ - int nextActionId = 0; - for ( ActionList::Iter act = fsmCtx->actionList; act.lte(); act++ ) { - if ( act->numRefs() > 0 || act->numCondRefs > 0 ) - act->actionId = nextActionId++; - } - - /* Write the list. */ - initActionList( nextActionId ); - curAction = 0; - - for ( ActionList::Iter act = fsmCtx->actionList; act.lte(); act++ ) { - if ( act->actionId >= 0 ) - makeAction( act ); - } -} - -void Reducer::makeActionTableList() -{ - /* Must first order the action tables based on their id. */ - int numTables = nextActionTableId; - RedActionTable **tables = new RedActionTable*[numTables]; - for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ ) - tables[at->id] = at; - - initActionTableList( numTables ); - curActionTable = 0; - - for ( int t = 0; t < numTables; t++ ) { - long length = tables[t]->key.length(); - - /* Collect the action table. */ - RedAction *redAct = allActionTables + curActionTable; - redAct->actListId = curActionTable; - redAct->key.setAsNew( length ); - - for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) { - redAct->key[atel.pos()].key = 0; - redAct->key[atel.pos()].value = allActions + - atel->value->actionId; - } - - /* Insert into the action table map. */ - redFsm->actionMap.insert( redAct ); - - curActionTable += 1; - } - - delete[] tables; -} - -void Reducer::makeConditions() -{ - if ( fsm->ctx->condData->condSpaceMap.length() > 0 ) { - /* Allocate condition space ids. */ - long nextCondSpaceId = 0; - for ( CondSpaceMap::Iter cs = fsm->ctx->condData->condSpaceMap; cs.lte(); cs++ ) - cs->condSpaceId = nextCondSpaceId++; - - /* Allocate the array of conditions and put them on the list. */ - long length = fsm->ctx->condData->condSpaceMap.length(); - allCondSpaces = new GenCondSpace[length]; - for ( long c = 0; c < length; c++ ) - condSpaceList.append( &allCondSpaces[c] ); - - long curCondSpace = 0; - for ( CondSpaceMap::Iter cs = fsm->ctx->condData->condSpaceMap; cs.lte(); cs++ ) { - /* Transfer the id. */ - allCondSpaces[curCondSpace].condSpaceId = cs->condSpaceId; - - curCondSpace += 1; - } - } - - makeActionList(); - makeActionTableList(); - - if ( fsm->ctx->condData->condSpaceMap.length() > 0 ) { - long curCondSpace = 0; - for ( CondSpaceMap::Iter cs = fsm->ctx->condData->condSpaceMap; cs.lte(); cs++ ) { - for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ ) - condSpaceItem( curCondSpace, (*csi)->actionId ); - curCondSpace += 1; - } - } -} - -bool Reducer::makeNameInst( std::string &res, NameInst *nameInst ) -{ - bool written = false; - if ( nameInst->parent != 0 ) - written = makeNameInst( res, nameInst->parent ); - - if ( !nameInst->name.empty() ) { - if ( written ) - res += '_'; - res += nameInst->name; - written = true; - } - - return written; -} - -void Reducer::makeEntryPoints() -{ - /* List of entry points other than start state. */ - if ( fsm->entryPoints.length() > 0 || fsmCtx->lmRequiresErrorState ) { - if ( fsmCtx->lmRequiresErrorState ) - setForcedErrorState(); - - for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) { - /* Get the name instantiation from nameIndex. */ - NameInst *nameInst = fsmCtx->nameIndex[en->key]; - std::string name; - makeNameInst( name, nameInst ); - StateAp *state = en->value; - addEntryPoint( strdup(name.c_str()), state->alg.stateNum ); - } - } -} - -void Reducer::makeStateActions( StateAp *state ) -{ - RedActionTable *toStateActions = 0; - if ( state->toStateActionTable.length() > 0 ) - toStateActions = actionTableMap.find( state->toStateActionTable ); - - RedActionTable *fromStateActions = 0; - if ( state->fromStateActionTable.length() > 0 ) - fromStateActions = actionTableMap.find( state->fromStateActionTable ); - - if ( toStateActions != 0 || fromStateActions != 0 ) { - long to = -1; - if ( toStateActions != 0 ) - to = toStateActions->id; - - long from = -1; - if ( fromStateActions != 0 ) - from = fromStateActions->id; - - setStateActions( curState, to, from, -1 ); - } -} - -void Reducer::makeTrans( Key lowKey, Key highKey, TransAp *trans ) -{ - RedCondEl *outConds; - int numConds; - - assert( ( allStates + curState ) != redFsm->errState ); - - if ( trans->plain() ) { - long targ = -1; - long action = -1; - - /* First reduce the action. */ - RedActionTable *actionTable = 0; - if ( trans->tdap()->actionTable.length() > 0 ) - actionTable = actionTableMap.find( trans->tdap()->actionTable ); - - if ( trans->tdap()->toState != 0 ) - targ = trans->tdap()->toState->alg.stateNum; - - if ( actionTable != 0 ) - action = actionTable->id; - - /* Make the new transitions. */ - RedStateAp *targState = targ >= 0 ? (allStates + targ) : redFsm->getErrorState(); - RedAction *at = action >= 0 ? (allActionTables + action) : 0; - - RedTransAp *trans = redFsm->allocateTrans( targState, at ); - newTrans( allStates + curState, lowKey, highKey, trans ); - } - else { - numConds = trans->tcap()->condList.length(); - outConds = new RedCondEl[numConds]; - int pos = 0; - for ( CondList::Iter cti = trans->tcap()->condList; cti.lte(); cti++, pos++ ) { - long targ = -1; - long action = -1; - - /* First reduce the action. */ - RedActionTable *actionTable = 0; - if ( cti->actionTable.length() > 0 ) - actionTable = actionTableMap.find( cti->actionTable ); - - if ( cti->toState != 0 ) - targ = cti->toState->alg.stateNum; - - if ( actionTable != 0 ) - action = actionTable->id; - - /* Make the new transitions. */ - RedStateAp *targState = targ >= 0 ? (allStates + targ) : redFsm->getErrorState(); - RedAction *at = action >= 0 ? (allActionTables + action) : 0; - RedCondAp *cond = redFsm->allocateCond( targState, at ); - - outConds[pos].key = cti->key; - outConds[pos].value = cond; - } - - GenCondSpace *condSpace = allCondSpaces + trans->condSpace->condSpaceId; - - /* If the cond list is not full then we need an error cond. */ - RedCondAp *errCond = 0; - if ( numConds < ( 1 << condSpace->condSet.length() ) ) - errCond = redFsm->getErrorCond(); - - RedTransAp *trans = redFsm->allocateTrans( - condSpace, outConds, numConds, errCond ); - - newTrans( allStates + curState, lowKey, highKey, trans ); - } -} - -void Reducer::makeEofTrans( StateAp *state ) -{ - /* EOF actions go out here only if the state has no eof target. If it has - * an eof target then an eof transition will be used instead. */ - RedActionTable *eofActions = 0; - if ( state->eofActionTable.length() > 0 ) - eofActions = actionTableMap.find( state->eofActionTable ); - - /* Add an EOF transition if we have conditions, a target, or actions, */ - if ( state->outCondSpace != 0 || state->eofTarget != 0 || eofActions != 0 ) - redFsm->bAnyEofActivity = true; - - long targ = state->alg.stateNum; - long action = -1; - - if ( state->eofTarget != 0 ) - targ = state->eofTarget->alg.stateNum; - - if ( eofActions != 0 ) - action = eofActions->id; - - - if ( state->outCondSpace == 0 ) { - // std::cerr << "setEofTrans( " << - // state->alg.stateNum << ", " << targ << ", " << action << " );" << endl; - - setEofTrans( state->alg.stateNum, targ, action ); - } - else { - int numConds = state->outCondKeys.length(); - RedCondEl *outConds = new RedCondEl[numConds]; - for ( int pos = 0; pos < numConds; pos++ ) { - /* Make the new transitions. */ - RedStateAp *targState = targ >= 0 ? (allStates + targ) : redFsm->getErrorState(); - RedAction *at = action >= 0 ? (allActionTables + action) : 0; - RedCondAp *cond = redFsm->allocateCond( targState, at ); - - outConds[pos].key = state->outCondKeys[pos]; - outConds[pos].value = cond; - } - - GenCondSpace *condSpace = allCondSpaces + state->outCondSpace->condSpaceId; - - /* If the cond list is not full then we need an error cond. */ - RedCondAp *errCond = 0; - if ( numConds < ( 1 << condSpace->condSet.length() ) ) - errCond = redFsm->getErrorCond(); - - setEofTrans( state->alg.stateNum, condSpace, outConds, numConds, errCond ); - } -} - - -void Reducer::makeTransList( StateAp *state ) -{ - TransListVect outList; - - /* If there is only are no ranges the task is simple. */ - if ( state->outList.length() > 0 ) { - /* Loop each source range. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - /* Reduce the transition. If it reduced to anything then add it. */ - appendTrans( outList, trans->lowKey, trans->highKey, trans ); - } - } - - initTransList( curState, outList.length() ); - - for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ ) - makeTrans( tvi->lowKey, tvi->highKey, tvi->value ); - - finishTransList( curState ); -} - -void Reducer::makeStateList() -{ - /* Write the list of states. */ - long length = fsm->stateList.length(); - initStateList( length ); - curState = 0; - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) { - makeStateActions( st ); - makeEofTrans( st ); - makeTransList( st ); - - long id = st->alg.stateNum; - setId( curState, id ); - - if ( st->isFinState() ) - setFinal( curState ); - - if ( st->nfaOut != 0 ) { - RedStateAp *from = allStates + curState; - from->nfaTargs = new RedNfaTargs; - for ( NfaTransList::Iter targ = *st->nfaOut; targ.lte(); targ++ ) { - RedStateAp *rtarg = allStates + targ->toState->alg.stateNum; - - RedAction *pushRa = 0; - RedAction *popTestRa = 0; - - if ( targ->pushTable.length() > 0 ) { - RedActionTable *pushActions = - actionTableMap.find( targ->pushTable ); - pushRa = allActionTables + pushActions->id; - } - - if ( targ->popTest.length() > 0 ) { - RedActionTable *popActions = - actionTableMap.find( targ->popTest ); - popTestRa = allActionTables + popActions->id; - } - - - from->nfaTargs->append( RedNfaTarg( rtarg, pushRa, - popTestRa, targ->order ) ); - - MergeSort<RedNfaTarg, RedNfaTargCmp> sort; - sort.sort( from->nfaTargs->data, from->nfaTargs->length() ); - } - } - - curState += 1; - } -} - -void Reducer::makeMachine() -{ - createMachine(); - - /* Action tables. */ - reduceActionTables(); - - makeConditions(); - - /* Start State. */ - setStartState( fsm->startState->alg.stateNum ); - - /* Error state. */ - if ( fsm->errState != 0 ) - setErrorState( fsm->errState->alg.stateNum ); - - makeEntryPoints(); - makeStateList(); - - resolveTargetStates(); -} - -void Reducer::make( const HostLang *hostLang, const HostType *alphType ) -{ - /* Alphabet type. */ - setAlphType( hostLang, alphType->internalName ); - - /* Getkey expression. */ - if ( fsmCtx->getKeyExpr != 0 ) { - getKeyExpr = new GenInlineList; - makeGenInlineList( getKeyExpr, fsmCtx->getKeyExpr ); - } - - /* Access expression. */ - if ( fsmCtx->accessExpr != 0 ) { - accessExpr = new GenInlineList; - makeGenInlineList( accessExpr, fsmCtx->accessExpr ); - } - - /* PrePush expression. */ - if ( fsmCtx->prePushExpr != 0 ) { - GenInlineList *il = new GenInlineList; - makeGenInlineList( il, fsmCtx->prePushExpr->inlineList ); - prePushExpr = new GenInlineExpr( fsmCtx->prePushExpr->loc, il ); - } - - /* PostPop expression. */ - if ( fsmCtx->postPopExpr != 0 ) { - GenInlineList *il = new GenInlineList; - makeGenInlineList( il, fsmCtx->postPopExpr->inlineList ); - postPopExpr = new GenInlineExpr( fsmCtx->postPopExpr->loc, il ); - } - - /* PrePush expression. */ - if ( fsmCtx->nfaPrePushExpr != 0 ) { - GenInlineList *il = new GenInlineList; - makeGenInlineList( il, fsmCtx->nfaPrePushExpr->inlineList ); - nfaPrePushExpr = new GenInlineExpr( fsmCtx->nfaPrePushExpr->loc, il ); - } - - /* PostPop expression. */ - if ( fsmCtx->nfaPostPopExpr != 0 ) { - GenInlineList *il = new GenInlineList; - makeGenInlineList( il, fsmCtx->nfaPostPopExpr->inlineList ); - nfaPostPopExpr = new GenInlineExpr( fsmCtx->nfaPostPopExpr->loc, il ); - } - - - /* - * Variable expressions. - */ - - if ( fsmCtx->pExpr != 0 ) { - pExpr = new GenInlineList; - makeGenInlineList( pExpr, fsmCtx->pExpr ); - } - - if ( fsmCtx->peExpr != 0 ) { - peExpr = new GenInlineList; - makeGenInlineList( peExpr, fsmCtx->peExpr ); - } - - if ( fsmCtx->eofExpr != 0 ) { - eofExpr = new GenInlineList; - makeGenInlineList( eofExpr, fsmCtx->eofExpr ); - } - - if ( fsmCtx->csExpr != 0 ) { - csExpr = new GenInlineList; - makeGenInlineList( csExpr, fsmCtx->csExpr ); - } - - if ( fsmCtx->topExpr != 0 ) { - topExpr = new GenInlineList; - makeGenInlineList( topExpr, fsmCtx->topExpr ); - } - - if ( fsmCtx->stackExpr != 0 ) { - stackExpr = new GenInlineList; - makeGenInlineList( stackExpr, fsmCtx->stackExpr ); - } - - if ( fsmCtx->actExpr != 0 ) { - actExpr = new GenInlineList; - makeGenInlineList( actExpr, fsmCtx->actExpr ); - } - - if ( fsmCtx->tokstartExpr != 0 ) { - tokstartExpr = new GenInlineList; - makeGenInlineList( tokstartExpr, fsmCtx->tokstartExpr ); - } - - if ( fsmCtx->tokendExpr != 0 ) { - tokendExpr = new GenInlineList; - makeGenInlineList( tokendExpr, fsmCtx->tokendExpr ); - } - - if ( fsmCtx->dataExpr != 0 ) { - dataExpr = new GenInlineList; - makeGenInlineList( dataExpr, fsmCtx->dataExpr ); - } - - makeExports(); - makeMachine(); - - /* Do this before distributing transitions out to singles and defaults - * makes life easier. */ - redFsm->maxKey = findMaxKey(); - - redFsm->assignActionLocs(); - - /* Find the first final state (The final state with the lowest id). */ - redFsm->findFirstFinState(); -} - -void Reducer::createMachine() -{ - redFsm = new RedFsmAp( fsm->ctx, machineId ); -} - -void Reducer::initActionList( unsigned long length ) -{ - allActions = new GenAction[length]; - for ( unsigned long a = 0; a < length; a++ ) - actionList.append( allActions+a ); -} - -void Reducer::newAction( int anum, std::string name, - const InputLoc &loc, GenInlineList *inlineList ) -{ - allActions[anum].actionId = anum; - allActions[anum].name = name; - allActions[anum].loc = loc; - allActions[anum].inlineList = inlineList; -} - -void Reducer::initActionTableList( unsigned long length ) -{ - allActionTables = new RedAction[length]; -} - -void Reducer::initStateList( unsigned long length ) -{ - redFsm->allStates = allStates = new RedStateAp[length]; - for ( unsigned long s = 0; s < length; s++ ) - redFsm->stateList.append( allStates+s ); - - /* We get the start state as an offset, set the pointer now. */ - if ( startState >= 0 ) - redFsm->startState = allStates + startState; - if ( errState >= 0 ) - redFsm->errState = allStates + errState; - for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ ) - redFsm->entryPoints.insert( allStates + *en ); - - /* The nextStateId is no longer used to assign state ids (they come in set - * from the frontend now), however generation code still depends on it. - * Should eventually remove this variable. */ - redFsm->nextStateId = redFsm->stateList.length(); -} - -void Reducer::setStartState( unsigned long _startState ) -{ - startState = _startState; -} - -void Reducer::setErrorState( unsigned long _errState ) -{ - errState = _errState; -} - -void Reducer::addEntryPoint( char *name, unsigned long entryState ) -{ - entryPointIds.append( entryState ); - entryPointNames.append( name ); -} - -void Reducer::initTransList( int snum, unsigned long length ) -{ - /* Could preallocate the out range to save time growing it. For now do - * nothing. */ -} - -void Reducer::newTrans( RedStateAp *state, Key lowKey, Key highKey, RedTransAp *trans ) -{ - /* Get the current state and range. */ - RedTransList &destRange = state->outRange; - - /* Reduced machines are complete. We need to fill any gaps with the error - * transitions. */ - if ( destRange.length() == 0 ) { - /* Range is currently empty. */ - if ( keyOps->lt( keyOps->minKey, lowKey ) ) { - /* The first range doesn't start at the low end. */ - Key fillHighKey = lowKey; - keyOps->decrement( fillHighKey ); - - /* Create the filler with the state's error transition. */ - RedTransEl newTel( fsm->ctx->keyOps->minKey, fillHighKey, - redFsm->getErrorTrans() ); - destRange.append( newTel ); - } - } - else { - /* The range list is not empty, get the the last range. */ - RedTransEl *last = &destRange[destRange.length()-1]; - Key nextKey = last->highKey; - keyOps->increment( nextKey ); - if ( keyOps->lt( nextKey, lowKey ) ) { - /* There is a gap to fill. Make the high key. */ - Key fillHighKey = lowKey; - keyOps->decrement( fillHighKey ); - - /* Create the filler with the state's error transtion. */ - RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() ); - destRange.append( newTel ); - } - } - - /* Filler taken care of. Append the range. */ - destRange.append( RedTransEl( lowKey, highKey, trans ) ); -} - -void Reducer::finishTransList( int snum ) -{ - /* Get the current state and range. */ - RedStateAp *curState = allStates + snum; - RedTransList &destRange = curState->outRange; - - if ( curState == redFsm->errState ) - return; - - /* We may need filler on the end. */ - /* Check if there are any ranges already. */ - if ( destRange.length() == 0 ) { - /* Fill with the whole alphabet. */ - /* Add the range on the lower and upper bound. */ - RedTransEl newTel( fsm->ctx->keyOps->minKey, - fsm->ctx->keyOps->maxKey, redFsm->getErrorTrans() ); - destRange.append( newTel ); - } - else { - /* Get the last and check for a gap on the end. */ - RedTransEl *last = &destRange[destRange.length()-1]; - if ( keyOps->lt( last->highKey, fsm->ctx->keyOps->maxKey ) ) { - /* Make the high key. */ - Key fillLowKey = last->highKey; - keyOps->increment( fillLowKey ); - - /* Create the new range with the error trans and append it. */ - RedTransEl newTel( fillLowKey, fsm->ctx->keyOps->maxKey, - redFsm->getErrorTrans() ); - destRange.append( newTel ); - } - } -} - -void Reducer::setId( int snum, int id ) -{ - RedStateAp *curState = allStates + snum; - curState->id = id; -} - -void Reducer::setFinal( int snum ) -{ - RedStateAp *curState = allStates + snum; - curState->isFinal = true; -} - - -void Reducer::setStateActions( int snum, long toStateAction, - long fromStateAction, long eofAction ) -{ - RedStateAp *curState = allStates + snum; - if ( toStateAction >= 0 ) - curState->toStateAction = allActionTables + toStateAction; - if ( fromStateAction >= 0 ) - curState->fromStateAction = allActionTables + fromStateAction; - if ( eofAction >= 0 ) - curState->eofAction = allActionTables + eofAction; -} - -void Reducer::setEofTrans( int snum, long eofTarget, long actId ) -{ - RedStateAp *curState = allStates + snum; - RedStateAp *targState = allStates + eofTarget; - RedAction *eofAct = actId >= 0 ? allActionTables + actId : 0; - - RedTransAp *trans = redFsm->allocateTrans( targState, eofAct ); - curState->eofTrans = trans; -} - -void Reducer::setEofTrans( int snum, GenCondSpace *condSpace, - RedCondEl *outConds, int numConds, RedCondAp *errCond ) -{ - RedStateAp *curState = allStates + snum; - - RedTransAp *trans = redFsm->allocateTrans( condSpace, outConds, numConds, errCond ); - - curState->eofTrans = trans; -} - -void Reducer::resolveTargetStates( GenInlineList *inlineList ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - switch ( item->type ) { - case GenInlineItem::Goto: case GenInlineItem::Call: - case GenInlineItem::Ncall: case GenInlineItem::Next: - case GenInlineItem::Entry: - item->targState = allStates + item->targId; - break; - default: - break; - } - - if ( item->children != 0 ) - resolveTargetStates( item->children ); - } -} - -void Reducer::resolveTargetStates() -{ - for ( GenActionList::Iter a = actionList; a.lte(); a++ ) - resolveTargetStates( a->inlineList ); - -#if 0 - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofAction != 0 ) { - for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ ) - setLabelsNeeded( item->value->inlineList ); - } - - if ( st->eofTrans != 0 ) { - long condsFullSize = st->eofTrans->condFullSize(); - for ( int c = 0; c < condsFullSize; c++ ) { - RedCondPair *pair = st->eofTrans->outCond( c ); - setLabelsNeeded( pair ); - } - } -#endif -} - -bool Reducer::setAlphType( const HostLang *hostLang, const char *data ) -{ - HostType *alphType = findAlphTypeInternal( hostLang, data ); - if ( alphType == 0 ) - return false; - - return true; -} - -void Reducer::condSpaceItem( int cnum, long condActionId ) -{ - GenCondSpace *cond = allCondSpaces + cnum; - cond->condSet.append( allActions + condActionId ); -} - -void Reducer::initStateCondList( int snum, ulong length ) -{ - /* Could preallocate these, as we could with transitions. */ -} - -void Reducer::addStateCond( int snum, Key lowKey, Key highKey, long condNum ) -{ -} - -Key Reducer::findMaxKey() -{ - Key maxKey = fsm->ctx->keyOps->maxKey; - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - assert( st->outSingle.length() == 0 ); - assert( st->defTrans == 0 ); - - long rangeLen = st->outRange.length(); - if ( rangeLen > 0 ) { - Key highKey = st->outRange[rangeLen-1].highKey; - if ( keyOps->gt( highKey, maxKey ) ) - maxKey = highKey; - } - } - return maxKey; -} - -void Reducer::actionActionRefs( RedAction *action ) -{ - action->numTransRefs += 1; - for ( GenActionTable::Iter item = action->key; item.lte(); item++ ) - item->value->numTransRefs += 1; -} - -void Reducer::transActionRefs( RedTransAp *trans ) -{ - for ( int c = 0; c < trans->numConds(); c++ ) { - RedCondPair *cond = trans->outCond(c); - if ( cond->action != 0 ) - actionActionRefs( cond->action ); - } - - if ( trans->condSpace != 0 ) - trans->condSpace->numTransRefs += 1; -} - -void Reducer::transListActionRefs( RedTransList &list ) -{ - for ( RedTransList::Iter rtel = list; rtel.lte(); rtel++ ) - transActionRefs( rtel->value ); -} - -void Reducer::findFinalActionRefs() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - /* Rerence count out of single transitions. */ - transListActionRefs( st->outSingle ); - - /* Reference count out of range transitions. */ - transListActionRefs( st->outRange ); - - /* Reference count default transition. */ - if ( st->defTrans != 0 ) - transActionRefs( st->defTrans ); - - /* Reference count EOF transitions. */ - if ( st->eofTrans != 0 ) - transActionRefs( st->eofTrans ); - - /* Reference count to state actions. */ - if ( st->toStateAction != 0 ) { - st->toStateAction->numToStateRefs += 1; - for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ ) - item->value->numToStateRefs += 1; - } - - /* Reference count from state actions. */ - if ( st->fromStateAction != 0 ) { - st->fromStateAction->numFromStateRefs += 1; - for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ ) - item->value->numFromStateRefs += 1; - } - - /* Reference count EOF actions. */ - if ( st->eofAction != 0 ) { - st->eofAction->numEofRefs += 1; - for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ ) - item->value->numEofRefs += 1; - } - - if ( st->nfaTargs != 0 ) { - for ( RedNfaTargs::Iter nt = *st->nfaTargs; nt.lte(); nt++ ) { - - if ( nt->push != 0 ) { - nt->push->numNfaPushRefs += 1; - for ( GenActionTable::Iter item = nt->push->key; item.lte(); item++ ) - item->value->numNfaPushRefs += 1; - } - - if ( nt->popTest != 0 ) { - nt->popTest->numNfaPopTestRefs += 1; - for ( GenActionTable::Iter item = nt->popTest->key; item.lte(); item++ ) - item->value->numNfaPopTestRefs += 1; - } - } - } - } -} - -void Reducer::analyzeAction( GenAction *act, GenInlineList *inlineList ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - /* Only consider actions that are referenced. */ - if ( act->numRefs() > 0 ) { - if ( item->type == GenInlineItem::Goto || item->type == GenInlineItem::GotoExpr ) - { - redFsm->bAnyActionGotos = true; - } - else if ( item->type == GenInlineItem::Call || item->type == GenInlineItem::CallExpr ) { - redFsm->bAnyActionCalls = true; - } - else if ( item->type == GenInlineItem::Ncall || item->type == GenInlineItem::NcallExpr ) { - redFsm->bAnyActionCalls = true; - } - else if ( item->type == GenInlineItem::Ret ) - redFsm->bAnyActionRets = true; - else if ( item->type == GenInlineItem::Nret ) - redFsm->bAnyActionNrets = true; - else if ( item->type == GenInlineItem::LmInitAct || - item->type == GenInlineItem::LmSetActId || - item->type == GenInlineItem::LmSwitch ) - { - redFsm->bUsingAct = true; - } - - /* Any by value control in all actions? */ - if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr ) - redFsm->bAnyActionByValControl = true; - } - - /* Check for various things in regular actions. */ - if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) { - /* Any returns in regular actions? */ - if ( item->type == GenInlineItem::Ret || item->type == GenInlineItem::Nret ) - redFsm->bAnyRegActionRets = true; - - /* Any next statements in the regular actions? */ - if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr || - item->type == GenInlineItem::Ncall || item->type == GenInlineItem::NcallExpr || - item->type == GenInlineItem::Nret ) - redFsm->bAnyRegNextStmt = true; - - /* Any by value control in regular actions? */ - if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr ) - redFsm->bAnyRegActionByValControl = true; - - /* Any references to the current state in regular actions? */ - if ( item->type == GenInlineItem::Curs ) - redFsm->bAnyRegCurStateRef = true; - - if ( item->type == GenInlineItem::Break ) - redFsm->bAnyRegBreak = true; - - if ( item->type == GenInlineItem::Nbreak ) - redFsm->bAnyRegNbreak = true; - } - - if ( item->children != 0 ) - analyzeAction( act, item->children ); - } -} - -void Reducer::analyzeActionList( RedAction *redAct, GenInlineList *inlineList ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - /* Any next statements in the action table? */ - if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr || - item->type == GenInlineItem::Ncall || item->type == GenInlineItem::NcallExpr || - item->type == GenInlineItem::Nret ) - redAct->bAnyNextStmt = true; - - /* Any references to the current state. */ - if ( item->type == GenInlineItem::Curs ) - redAct->bAnyCurStateRef = true; - - if ( item->type == GenInlineItem::Break ) - redAct->bAnyBreakStmt = true; - - if ( item->type == GenInlineItem::NfaWrapConds ) - item->condSpace->numNfaRefs += 1; - - if ( item->children != 0 ) - analyzeActionList( redAct, item->children ); - } -} - -/* Assign ids to referenced actions. */ -void Reducer::assignActionIds() -{ - int nextActionId = 0; - for ( GenActionList::Iter act = actionList; act.lte(); act++ ) { - /* Only ever interested in referenced actions. */ - if ( act->numRefs() > 0 ) - act->actionId = nextActionId++; - } -} - -void Reducer::setValueLimits() -{ - redFsm->maxSingleLen = 0; - redFsm->maxRangeLen = 0; - redFsm->maxKeyOffset = 0; - redFsm->maxIndexOffset = 0; - redFsm->maxActListId = 0; - redFsm->maxActionLoc = 0; - redFsm->maxActArrItem = 0; - redFsm->maxSpan = 0; - redFsm->maxFlatIndexOffset = 0; - redFsm->maxCondSpaceId = 0; - - /* In both of these cases the 0 index is reserved for no value, so the max - * is one more than it would be if they started at 0. */ - redFsm->maxIndex = redFsm->transSet.length(); - redFsm->maxCond = condSpaceList.length(); - - /* The nextStateId - 1 is the last state id assigned. */ - redFsm->maxState = redFsm->nextStateId - 1; - - for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) { - if ( csi->condSpaceId > redFsm->maxCondSpaceId ) - redFsm->maxCondSpaceId = csi->condSpaceId; - } - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - /* Maximum single length. */ - if ( st->outSingle.length() > redFsm->maxSingleLen ) - redFsm->maxSingleLen = st->outSingle.length(); - - /* Maximum range length. */ - if ( st->outRange.length() > redFsm->maxRangeLen ) - redFsm->maxRangeLen = st->outRange.length(); - - /* The key offset index offset for the state after last is not used, skip it.. */ - if ( ! st.last() ) { - redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2; - redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 2; - } - - /* Max key span. */ - if ( st->transList != 0 ) { - unsigned long long span = fsm->ctx->keyOps->span( st->lowKey, st->highKey ); - if ( span > redFsm->maxSpan ) - redFsm->maxSpan = span; - } - - /* Max flat index offset. */ - if ( ! st.last() ) { - if ( st->transList != 0 ) - redFsm->maxFlatIndexOffset += fsm->ctx->keyOps->span( st->lowKey, st->highKey ); - redFsm->maxFlatIndexOffset += 1; - } - } - - for ( GenActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) { - /* Maximum id of action lists. */ - if ( at->actListId+1 > redFsm->maxActListId ) - redFsm->maxActListId = at->actListId+1; - - /* Maximum location of items in action array. */ - if ( at->location+1 > redFsm->maxActionLoc ) - redFsm->maxActionLoc = at->location+1; - - /* Maximum values going into the action array. */ - if ( at->key.length() > redFsm->maxActArrItem ) - redFsm->maxActArrItem = at->key.length(); - for ( GenActionTable::Iter item = at->key; item.lte(); item++ ) { - if ( item->value->actionId > redFsm->maxActArrItem ) - redFsm->maxActArrItem = item->value->actionId; - } - } -} - -/* Gather various info on the machine. */ -void Reducer::analyzeMachine() -{ - /* Find the true count of action references. */ - findFinalActionRefs(); - - /* Check if there are any calls in action code. */ - for ( GenActionList::Iter act = actionList; act.lte(); act++ ) { - /* Record the occurrence of various kinds of actions. */ - if ( act->numToStateRefs > 0 ) - redFsm->bAnyToStateActions = true; - if ( act->numFromStateRefs > 0 ) - redFsm->bAnyFromStateActions = true; - if ( act->numEofRefs > 0 ) - redFsm->bAnyEofActions = true; - if ( act->numTransRefs > 0 ) - redFsm->bAnyRegActions = true; - - if ( act->numNfaPushRefs > 0 ) { - redFsm->bAnyNfaPushPops = true; - redFsm->bAnyNfaPushes = true; - } - - if ( act->numNfaPopActionRefs > 0 ) { - redFsm->bAnyNfaPushPops = true; - redFsm->bAnyNfaPops = true; - } - - if ( act->numNfaPopTestRefs > 0 ) { - redFsm->bAnyNfaPushPops = true; - redFsm->bAnyNfaPops = true; - } - - /* Recurse through the action's parse tree looking for various things. */ - analyzeAction( act, act->inlineList ); - } - - /* Analyze reduced action lists. */ - for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { - for ( GenActionTable::Iter act = redAct->key; act.lte(); act++ ) - if ( act->value->inlineList != 0 ) - analyzeActionList( redAct, act->value->inlineList ); - } - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->nfaTargs != 0 ) - redFsm->bAnyNfaStates = true; - } - - /* Find states that have transitions with actions that have next - * statements. */ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - /* Check any actions out of outSinge. */ - for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) { - RedTransAp *trans = rtel->value; - for ( int c = 0; c < trans->numConds(); c++ ) { - RedCondPair *cond = trans->outCond(c); - if ( cond->action != 0 && cond->action->anyCurStateRef() ) - st->bAnyRegCurStateRef = true; - } - } - - /* Check any actions out of outRange. */ - for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { - RedTransAp *trans = rtel->value; - for ( int c = 0; c < trans->numConds(); c++ ) { - RedCondPair *cond = trans->outCond(c); - if ( cond->action != 0 && cond->action->anyCurStateRef() ) - st->bAnyRegCurStateRef = true; - } - } - - /* Check any action out of default. */ - if ( st->defTrans != 0 ) { - RedTransAp *trans = st->defTrans; - for ( int c = 0; c < trans->numConds(); c++ ) { - RedCondPair *cond = trans->outCond(c); - if ( cond->action != 0 && cond->action->anyCurStateRef() ) - st->bAnyRegCurStateRef = true; - } - } - - if ( st->eofTrans != 0 ) - redFsm->bAnyEofTrans = true; - } - - for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) { - GenCondSpace *condSpace = csi; - - if ( condSpace->numTransRefs > 0 ) - redFsm->bAnyTransCondRefs = true; - - if ( condSpace->numNfaRefs > 0 ) - redFsm->bAnyNfaCondRefs = true; - } - - /* Assign ids to actions that are referenced. */ - assignActionIds(); - - /* Set the maximums of various values used for deciding types. */ - setValueLimits(); -} - -void CodeGenData::genOutputLineDirective( std::ostream &out ) const -{ - std::streambuf *sbuf = out.rdbuf(); - output_filter *filter = dynamic_cast<output_filter*>(sbuf); - if ( filter != 0 ) - (*genLineDirective)( out, lineDirectives, filter->line + 1, filter->fileName ); -} - -void CodeGenData::write_option_error( InputLoc &loc, std::string arg ) -{ - red->id->warning(loc) << "unrecognized write option \"" << arg << "\"" << std::endl; -} - -void CodeGenData::writeClear() -{ - clear(); - - /* Delete all the nodes in the action list. Will cause all the - * string data that represents the actions to be deallocated. */ - red->fsm->ctx->actionList.empty(); - - delete red->fsm; - red->fsm = 0; - - // red->pd->graphDict.empty(); - - cleared = true; -} - -void CodeGenData::collectReferences() -{ - /* Do this once only. */ - if ( !referencesCollected ) { - referencesCollected = true; - - /* Nullify the output and execute the write. We use this pass to collect references. */ - nullbuf nb; - std::streambuf *filt = out.rdbuf( &nb ); - writeExec(); - - /* Restore the output for whatever writing comes next. */ - out.rdbuf( filt ); - } -} diff --git a/src/idbase.cc b/src/idbase.cc deleted file mode 100644 index c4daa344..00000000 --- a/src/idbase.cc +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright 2008-2018 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 "ragel.h" -#include "fsmgraph.h" -#include "parsedata.h" - -/* Error reporting format. */ -ErrorFormat errorFormat = ErrorFormatGNU; - -void FsmCtx::finalizeInstance( FsmAp *graph ) -{ - /* Resolve any labels that point to multiple states. Any labels that are - * still around are referenced only by gotos and calls and they need to be - * made into deterministic entry points. */ - graph->deterministicEntry(); - - /* - * All state construction is now complete. - */ - - /* Transfer actions from the out action tables to eof action tables. */ - for ( StateSet::Iter state = graph->finStateSet; state.lte(); state++ ) - graph->transferOutActions( *state ); - - /* Transfer global error actions. */ - for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) - graph->transferErrorActions( state, 0 ); - - if ( fsmGbl->wantDupsRemoved ) - graph->removeActionDups(); - - /* Remove unreachable states. There should be no dead end states. The - * subtract and intersection operators are the only places where they may - * be created and those operators clean them up. */ - graph->removeUnreachableStates(); - - /* No more fsm operations are to be done. Action ordering numbers are - * no longer of use and will just hinder minimization. Clear them. */ - graph->nullActionKeys(); - - /* Transition priorities are no longer of use. We can clear them - * because they will just hinder minimization as well. Clear them. */ - graph->clearAllPriorities(); - - if ( graph->ctx->minimizeOpt != MinimizeNone ) { - /* Minimize here even if we minimized at every op. Now that function - * keys have been cleared we may get a more minimal fsm. */ - switch ( graph->ctx->minimizeLevel ) { - #ifdef TO_UPGRADE_CONDS - case MinimizeApprox: - graph->minimizeApproximate(); - break; - #endif - #ifdef TO_UPGRADE_CONDS - case MinimizeStable: - graph->minimizeStable(); - break; - #endif - case MinimizePartition1: - graph->minimizePartition1(); - break; - case MinimizePartition2: - graph->minimizePartition2(); - break; - } - } - - graph->compressTransitions(); - - createNfaActions( graph ); -} - -void FsmCtx::analyzeAction( Action *action, InlineList *inlineList ) -{ - /* FIXME: Actions used as conditions should be very constrained. */ - for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) { - if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr || - item->type == InlineItem::Ncall || item->type == InlineItem::NcallExpr ) - { - action->anyCall = true; - } - - /* Need to recurse into longest match items. */ - if ( item->type == InlineItem::LmSwitch ) { - LongestMatch *lm = item->longestMatch; - for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) { - if ( lmi->action != 0 ) - analyzeAction( action, lmi->action->inlineList ); - } - } - - if ( item->type == InlineItem::LmOnLast || - item->type == InlineItem::LmOnNext || - item->type == InlineItem::LmOnLagBehind ) - { - LongestMatchPart *lmi = item->longestMatchPart; - if ( lmi->action != 0 ) - analyzeAction( action, lmi->action->inlineList ); - } - - if ( item->children != 0 ) - analyzeAction( action, item->children ); - } -} - - -/* Check actions for bad uses of fsm directives. We don't go inside longest - * match items in actions created by ragel, since we just want the user - * actions. */ -void FsmCtx::checkInlineList( Action *act, InlineList *inlineList ) -{ - for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) { - /* EOF checks. */ - if ( act->numEofRefs > 0 ) { - switch ( item->type ) { - /* Currently no checks. */ - default: - break; - } - } - - /* Recurse. */ - if ( item->children != 0 ) - checkInlineList( act, item->children ); - } -} - -void FsmCtx::checkAction( Action *action ) -{ - /* Check for actions with calls that are embedded within a longest match - * machine. */ - if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) { - for ( NameInstVect::Iter ar = action->embedRoots; ar.lte(); ar++ ) { - NameInst *check = *ar; - while ( check != 0 ) { - if ( check->isLongestMatch ) { - fsmGbl->error(action->loc) << "within a scanner, fcall and fncall are permitted" - " only in pattern actions" << endl; - break; - } - check = check->parent; - } - } - } - - checkInlineList( action, action->inlineList ); -} - -void FsmCtx::analyzeGraph( FsmAp *graph ) -{ - for ( ActionList::Iter act = actionList; act.lte(); act++ ) - analyzeAction( act, act->inlineList ); - - for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) { - /* The transition list. */ - for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) { - //if ( trans->condSpace != 0 ) { - // for ( CondSet::Iter sci = trans->condSpace->condSet; sci.lte(); sci++ ) - // (*sci)->numCondRefs += 1; - //} - - if ( trans->plain() ) { - for ( ActionTable::Iter at = trans->tdap()->actionTable; at.lte(); at++ ) - at->value->numTransRefs += 1; - } - else { - for ( CondList::Iter cond = trans->tcap()->condList; cond.lte(); cond++ ) { - for ( ActionTable::Iter at = cond->actionTable; at.lte(); at++ ) - at->value->numTransRefs += 1; - } - } - } - - for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ ) - at->value->numToStateRefs += 1; - - for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ ) - at->value->numFromStateRefs += 1; - - for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ ) - at->value->numEofRefs += 1; - - //for ( OutCondSet::Iter oci = st->outCondSet; oci.lte(); oci++ ) - // oci->action->numCondRefs += 1; - - if ( st->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *st->nfaOut; n.lte(); n++ ) { - for ( ActionTable::Iter ati = n->pushTable; ati.lte(); ati++ ) - ati->value->numNfaRefs += 1; - - for ( ActionTable::Iter ati = n->restoreTable; ati.lte(); ati++ ) - ati->value->numNfaRefs += 1; - - for ( ActionTable::Iter ati = n->popAction; ati.lte(); ati++ ) - ati->value->numNfaRefs += 1; - - for ( ActionTable::Iter ati = n->popTest; ati.lte(); ati++ ) - ati->value->numNfaRefs += 1; - } - } - } - - /* Can't count on cond references in transitions, since we don't refcount - * the spaces. FIXME: That would be the proper solution. */ - for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) { - for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ ) - (*csi)->numCondRefs += 1; - } - - /* Checks for bad usage of directives in action code. */ - for ( ActionList::Iter act = actionList; act.lte(); act++ ) - checkAction( act ); -} - -/* This create an action that refs the original embed roots, if the optWrap arg - * is supplied. */ -Action *FsmCtx::newNfaWrapAction( const char *name, InlineList *inlineList, Action *optWrap ) -{ - InputLoc loc; - loc.line = 1; - loc.col = 1; - loc.fileName = "NONE"; - - Action *action = new Action( loc, name, inlineList, nextCondId++ ); - - if ( optWrap != 0 ) - action->embedRoots.append( optWrap->embedRoots ); - - actionList.append( action ); - return action; -} - -void FsmCtx::createNfaActions( FsmAp *fsm ) -{ - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) { - if ( st->nfaOut != 0 ) { - for ( NfaTransList::Iter n = *st->nfaOut; n.lte(); n++ ) { - /* Move pop restore actions into poptest. Wrap to override the - * condition-like testing. */ - for ( ActionTable::Iter ati = n->restoreTable; ati.lte(); ati++ ) { - n->popTest.setAction( ati->key, ati->value ); - } - - /* Move pop actions into pop test. Wrap to override the - * condition-like testing. */ - for ( ActionTable::Iter ati = n->popFrom; ati.lte(); ati++ ) { - - InlineList *il1 = new InlineList; - il1->append( new InlineItem( InputLoc(), - ati->value, InlineItem::NfaWrapAction ) ); - Action *wrap = newNfaWrapAction( "action_wrap", il1, ati->value ); - n->popTest.setAction( ORD_COND2, wrap ); - } - - /* Move condition evaluation into pop test. Wrap with condition - * execution. */ - if ( n->popCondSpace != 0 ) { - InlineList *il1 = new InlineList; - il1->append( new InlineItem( InputLoc(), - n->popCondSpace, n->popCondKeys, - InlineItem::NfaWrapConds ) ); - Action *wrap = newNfaWrapAction( "cond_wrap", il1, 0 ); - n->popTest.setAction( ORD_COND, wrap ); - } - - /* Move pop actions into pop test. Wrap to override the - * condition-like testing. */ - for ( ActionTable::Iter ati = n->popAction; ati.lte(); ati++ ) { - - InlineList *il1 = new InlineList; - il1->append( new InlineItem( InputLoc(), - ati->value, InlineItem::NfaWrapAction ) ); - Action *wrap = newNfaWrapAction( "action_wrap", il1, ati->value ); - n->popTest.setAction( ati->key, wrap ); - } - } - } - } -} - -void FsmCtx::prepareReduction( FsmAp *sectionGraph ) -{ - /* Decide if an error state is necessary. - * 1. There is an error transition - * 2. There is a gap in the transitions - * 3. The longest match operator requires it. */ - if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() ) - sectionGraph->errState = sectionGraph->addState(); - - /* State numbers need to be assigned such that all final states have a - * larger state id number than all non-final states. This enables the - * first_final mechanism to function correctly. We also want states to be - * ordered in a predictable fashion. So we first apply a depth-first - * search, then do a stable sort by final state status, then assign - * numbers. */ - - sectionGraph->depthFirstOrdering(); - sectionGraph->sortStatesByFinal(); - sectionGraph->setStateNumbers( 0 ); -} - - -void translatedHostData( ostream &out, const std::string &data ) -{ - const char *p = data.c_str(); - for ( const char *c = p; *c != 0; ) { - if ( c[0] == '}' && ( c[1] == '@' || c[1] == '$' || c[1] == '=' ) ) { - out << "@}@" << c[1]; - c += 2; - } - else if ( c[0] == '@' ) { - out << "@@"; - c += 1; - } - // Have some escaping issues that these fix, but they lead to other problems. - // Can be reproduced by passing "={}" through ragel and adding --colm-backend - // else if ( c[0] == '=' ) { - // out << "@="; - // c += 1; - //} - // else if ( c[0] == '$' ) { - // out << "@$"; - // c += 1; - //} - else { - out << c[0]; - c += 1; - } - } -} - - -void FsmGbl::abortCompile( int code ) -{ - throw AbortCompile( code ); -} - -/* Print the opening to a warning in the input, then return the error ostream. */ -ostream &FsmGbl::warning( const InputLoc &loc ) -{ - ostream &err = std::cerr; - err << loc << ": warning: "; - return err; -} - -/* Print the opening to a program error, then return the error stream. */ -ostream &FsmGbl::error() -{ - errorCount += 1; - ostream &err = std::cerr; - err << PROGNAME ": "; - return err; -} - -ostream &FsmGbl::error( const InputLoc &loc ) -{ - errorCount += 1; - ostream &err = std::cerr; - err << loc << ": "; - return err; -} - -ostream &FsmGbl::error_plain() -{ - errorCount += 1; - ostream &err = std::cerr; - return err; -} - - -std::ostream &FsmGbl::stats() -{ - return std::cout; -} - -/* Requested info. */ -std::ostream &FsmGbl::info() -{ - return std::cout; -} - -ostream &operator<<( ostream &out, const InputLoc &loc ) -{ - assert( loc.fileName != 0 ); - switch ( errorFormat ) { - case ErrorFormatMSVC: - out << loc.fileName << "(" << loc.line; - if ( loc.col ) - out << "," << loc.col; - out << ")"; - break; - - default: - out << loc.fileName << ":" << loc.line; - if ( loc.col ) - out << ":" << loc.col; - break; - } - return out; -} - diff --git a/src/ipgoto.cc b/src/ipgoto.cc deleted file mode 100644 index 4b8af3d6..00000000 --- a/src/ipgoto.cc +++ /dev/null @@ -1,765 +0,0 @@ -/* - * Copyright 2001-2018 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 "ragel.h" -#include "ipgoto.h" -#include "redfsm.h" -#include "gendata.h" -#include "bstmap.h" -#include "parsedata.h" -#include "inputdata.h" - -#include <sstream> - -using std::ostringstream; - -void IpGoto::tableDataPass() -{ - taNfaTargs(); - taNfaOffsets(); - taNfaPushActions(); - taNfaPopTrans(); -} - -void IpGoto::genAnalysis() -{ - /* For directly executable machines there is no required state - * ordering. Choose a depth-first ordering to increase the - * potential for fall-throughs. */ - redFsm->depthFirstOrdering(); - - /* Choose default transitions and the single transition. */ - redFsm->chooseDefaultSpan(); - - /* Choose single. */ - redFsm->moveSelectTransToSingle(); - - /* If any errors have occured in the input file then don't write anything. */ - if ( red->id->errorCount > 0 ) - return; - - redFsm->setInTrans(); - - /* Anlayze Machine will find the final action reference counts, among other - * things. We will use these in reporting the usage of fsm directives in - * action code. */ - red->analyzeMachine(); - - /* Run the analysis pass over the table data. */ - setTableState( TableArray::AnalyzePass ); - tableDataPass(); - - /* Switch the tables over to the code gen mode. */ - setTableState( TableArray::GeneratePass ); -} - -bool IpGoto::useAgainLabel() -{ - return redFsm->anyActionRets() || - redFsm->anyActionByValControl() || - redFsm->anyRegNextStmt(); -} - -void IpGoto::GOTO( ostream &ret, int gotoDest, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - ret << "goto " << stLabel[gotoDest].reference() << ";"; - - ret << CLOSE_GEN_BLOCK(); -} - -void IpGoto::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - ret << " goto " << _again << ";"; - - ret << CLOSE_GEN_BLOCK(); -} - -void IpGoto::CALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << targState << - "; " << TOP() << "+= 1; "; - - ret << "goto " << stLabel[callDest].reference() << ";"; - - ret << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NCALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << targState << - "; " << TOP() << "+= 1; " << vCS() << " = " << callDest << "; " << - CLOSE_GEN_BLOCK(); -} - -void IpGoto::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << targState << "; " << TOP() << "+= 1;" << - vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - ret << " goto " << _again << ";"; - - ret << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NCALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << targState << "; " << TOP() << "+= 1;" << - vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << "; " << CLOSE_GEN_BLOCK(); -} - -void IpGoto::RET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " - << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << "goto " << _again << ";" << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NRET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " - << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NEXT( ostream &ret, int nextDest, bool inFinish ) -{ - ret << vCS() << " = " << nextDest << ";"; -} - -void IpGoto::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << vCS() << " = ("; - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << ");"; -} - -void IpGoto::CURS( ostream &ret, bool inFinish ) -{ - ret << "(" << ps << ")"; -} - -void IpGoto::TARGS( ostream &ret, bool inFinish, int targState ) -{ - ret << targState; -} - -void IpGoto::BREAK( ostream &ret, int targState, bool csForced ) -{ - ret << OPEN_GEN_BLOCK() << P() << "+= 1; "; - if ( !csForced ) - ret << vCS() << " = " << targState << "; "; - ret << "goto " << _out << ";" << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NBREAK( ostream &ret, int targState, bool csForced ) -{ - ret << OPEN_GEN_BLOCK() << P() << "+= 1; "; - if ( !csForced ) - ret << vCS() << " = " << targState << "; "; - ret << nbreak << " = 1;" << CLOSE_GEN_BLOCK(); -} - -void IpGoto::NFA_PUSH_ACTION( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->push != 0 ) - act = targ->push->actListId+1; - nfaPushActions.value( act ); -} - -void IpGoto::NFA_POP_TEST( RedNfaTarg *targ ) -{ - int act = 0; - if ( targ->popTest != 0 ) - act = targ->popTest->actListId+1; - nfaPopTrans.value( act ); -} - - -bool IpGoto::IN_TRANS_ACTIONS( RedStateAp *state ) -{ - bool anyWritten = false; - - /* Emit any transitions that have actions and that go to this state. */ - for ( int it = 0; it < state->numInConds; it++ ) { - RedCondPair *trans = state->inConds[it]; - if ( trans->action != 0 ) { - /* Remember that we wrote an action so we know to write the - * line directive for going back to the output. */ - anyWritten = true; - - /* Write the label for the transition so it can be jumped to. */ - if ( ctrLabel[trans->id].isReferenced ) - out << "_ctr" << trans->id << ":\n"; - - /* If the action contains a next, then we must preload the current - * state since the action may or may not set it. */ - if ( trans->action->anyNextStmt() ) - out << " " << vCS() << " = " << trans->targ->id << ";\n"; - - if ( redFsm->anyRegNbreak() ) - out << nbreak << " = 0;\n"; - - /* Write each action in the list. */ - for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( trans->targ->id, false, - trans->action->anyNextStmt() ) ); - out << "\n"; - } - - if ( redFsm->anyRegNbreak() ) { - out << - "if ( " << nbreak << " == 1 )\n" - " goto " << _out << ";\n"; - } - - - /* If the action contains a next then we need to reload, otherwise - * jump directly to the target state. */ - if ( trans->action->anyNextStmt() ) - out << "goto " << _again << ";\n"; - else - out << "goto " << stLabel[trans->targ->id].reference() << ";\n"; - } - } - - - return anyWritten; -} - -void IpGoto::GOTO_HEADER( RedStateAp *state ) -{ -} - -void IpGoto::STATE_GOTO_ERROR() -{ -} - - -/* Emit the goto to take for a given transition. */ -std::ostream &IpGoto::TRANS_GOTO( RedTransAp *trans ) -{ - if ( trans->condSpace == 0 || trans->condSpace->condSet.length() == 0 ) { - /* Existing. */ - assert( trans->numConds() == 1 ); - RedCondPair *cond = trans->outCond( 0 ); - if ( cond->action != 0 ) { - /* Go to the transition which will go to the state. */ - out << "goto " << ctrLabel[trans->p.id].reference() << ";"; - } - else { - /* Go directly to the target state. */ - out << "goto " << stLabel[cond->targ->id].reference() << ";"; - } - } - else { - out << ck << " = 0;\n"; - for ( GenCondSet::Iter csi = trans->condSpace->condSet; csi.lte(); csi++ ) { - out << "if ( "; - CONDITION( out, *csi ); - Size condValOffset = (1 << csi.pos()); - out << " )\n" << ck << " += " << condValOffset << ";\n"; - } - CondKey lower = 0; - CondKey upper = trans->condFullSize() - 1; - COND_B_SEARCH( trans, lower, upper, 0, trans->numConds() - 1 ); - - if ( trans->errCond() != 0 ) { - COND_GOTO( trans->errCond() ) << "\n"; - } - } - - return out; -} - -/* Emit the goto to take for a given transition. */ -std::ostream &IpGoto::COND_GOTO( RedCondPair *cond ) -{ - /* Existing. */ - if ( cond->action != 0 ) { - /* Go to the transition which will go to the state. */ - out << "goto " << ctrLabel[cond->id].reference() << ";"; - } - else { - /* Go directly to the target state. */ - out << "goto " << stLabel[cond->targ->id].reference() << ";"; - } - - return out; -} - -std::ostream &IpGoto::EXIT_STATES() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( outLabel[st->id].isReferenced ) { - out << outLabel[st->id].define() << ": " << vCS() << " = " << - st->id << "; goto " << _out << "; \n"; - } - if ( popLabel[st->id].isReferenced ) { - out << popLabel[st->id].define() << ": " << vCS() << " = " << - st->id << "; goto " << _pop << "; \n"; - } - } - return out; -} - -std::ostream &IpGoto::AGAIN_CASES() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - out << - "case " << st->id << ": goto " << stLabel[st->id].reference() << ";\n"; - } - return out; -} - -std::ostream &IpGoto::STATE_GOTO_CASES() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - out << "case " << st->id << ":\n"; - out << "goto st_case_" << st->id << ";\n"; - } - return out; -} - -void IpGoto::NFA_PUSH_ST( RedStateAp *state ) -{ - std::stringstream ss; - ss << state->id; - std::string _state = ss.str(); - - if ( redFsm->anyNfaStates() ) { - - if ( state->nfaTargs != 0 ) { - out << - "if ( " << ARR_REF( nfaOffsets ) << "[" << _state << "] != 0 ) {\n"; - - if ( red->nfaPrePushExpr != 0 ) { - out << - new_recs << " = " << state->nfaTargs->length() << ";\n"; - } - - if ( red->nfaPrePushExpr != 0 ) { - out << OPEN_HOST_BLOCK( red->nfaPrePushExpr ); - INLINE_LIST( out, red->nfaPrePushExpr->inlineList, 0, false, false ); - out << CLOSE_HOST_BLOCK(); - } - - int alt = 0; - for ( RedNfaTargs::Iter nt = *state->nfaTargs; nt.lte(); nt++ ) { - out << - " nfa_bp[nfa_len].state = " << nt->state->id << ";\n" - " nfa_bp[nfa_len].p = " << P() << ";\n"; - - if ( nt->popTest != 0 ) { - out << - " nfa_bp[nfa_len].popTrans = " << (nt->popTest->actListId+1) << ";\n"; - } - else if ( redFsm->bAnyNfaPops ) { - out << - " nfa_bp[nfa_len].popTrans = 0;\n"; - } - - if ( nt->push != 0 ) { - for ( GenActionTable::Iter item = nt->push->key; item.lte(); item++ ) - ACTION( out, item->value, IlOpts( 0, false, false ) ); - } - - out << - " nfa_len += 1;\n"; - - alt += 1; - } - - out << - "}\n"; - } - } -} - -std::ostream &IpGoto::STATE_GOTOS() -{ - bool eof = redFsm->anyEofActivity() || redFsm->anyNfaStates(); - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - IN_TRANS_ACTIONS( st ); - - if ( stLabel[st->id].isReferenced ) - out << "_st" << st->id << ":\n"; - - /* Need to do this if the transition is an eof transition, or if - * the action contains fexec. Otherwise, no need. */ - if ( eof ) { - out << - "if ( " << P() << " == " << vEOF() << " )\n"; - - if ( st->isFinal || !redFsm->anyNfaStates() ) - out << "goto " << outLabel[st->id].reference() << ";\n"; - else - out << "goto " << popLabel[st->id].reference() << ";\n"; - } - - if ( st->toStateAction != 0 ) { - /* Write every action in the list. */ - for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( st->id, false, - st->toStateAction->anyNextStmt() ) ); - out << "\n"; - } - } - - if ( st == redFsm->errState ) { - out << "st_case_" << st->id << ":\n"; - - /* Break out here. */ - if ( !redFsm->anyNfaStates() ) - out << "goto " << outLabel[st->id].reference() << ";\n"; - else - out << "goto " << popLabel[st->id].reference() << ";\n"; - } - else { - - /* Advance and test buffer pos. */ - if ( st->labelNeeded ) { - out << - P() << "+= 1;\n"; - } - - /* Give the st a switch case. */ - out << "st_case_" << st->id << ":\n"; - - if ( !noEnd ) { - if ( eof ) { - out << - "if ( " << P() << " == " << PE() << " && " << P() << " != " << vEOF() << " )\n" - " goto " << outLabel[st->id].reference() << ";\n"; - } - else { - out << - "if ( " << P() << " == " << PE() << " )\n" - " goto " << outLabel[st->id].reference() << ";\n"; - } - } - - - NFA_PUSH_ST( st ); - - if ( st->fromStateAction != 0 ) { - /* Write every action in the list. */ - for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ ) { - ACTION( out, item->value, IlOpts( st->id, false, - st->fromStateAction->anyNextStmt() ) ); - out << "\n"; - } - } - - if ( !noEnd && eof ) { - out << - "if ( " << P() << " == " << vEOF() << " ) {\n"; - - if ( st->eofTrans != 0 ) - TRANS_GOTO( st->eofTrans ); - else { - if ( st->isFinal || !redFsm->anyNfaStates() ) - out << "goto " << outLabel[st->id].reference() << ";\n"; - else - out << "goto " << popLabel[st->id].reference() << ";\n"; - } - - out << - "}\n" - "else {\n"; - } - - /* Record the prev st if necessary. */ - if ( st->anyRegCurStateRef() ) - out << ps << " = " << st->id << ";\n"; - - /* Try singles. */ - if ( st->outSingle.length() > 0 ) - SINGLE_SWITCH( st ); - - /* Default case is to binary search for the ranges, if that fails then */ - if ( st->outRange.length() > 0 ) { - RANGE_B_SEARCH( st, keyOps->minKey, keyOps->maxKey, - 0, st->outRange.length() - 1 ); - } - - /* Write the default transition. */ - TRANS_GOTO( st->defTrans ) << "\n"; - - if ( !noEnd && eof ) { - out << - "}\n"; - } - } - } - return out; -} - -std::ostream &IpGoto::FINISH_CASES() -{ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofTrans != 0 ) { - out << - "case " << st->id << ":\n"; - - TRANS_GOTO( st->eofTrans ); - } - } - - return out; -} - -void IpGoto::setLabelsNeeded( GenInlineList *inlineList ) -{ - for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { - switch ( item->type ) { - case GenInlineItem::Goto: - case GenInlineItem::Call: - case GenInlineItem::Ncall: { - /* Mark the target as needing a label. */ - item->targState->labelNeeded = true; - break; - } - default: break; - } - - if ( item->children != 0 ) - setLabelsNeeded( item->children ); - } -} - -void IpGoto::setLabelsNeeded( RedCondPair *pair ) -{ - /* If there is no action with a next statement, then the label will be - * needed. */ - if ( pair->action == 0 || !pair->action->anyNextStmt() ) - pair->targ->labelNeeded = true; - - /* Need labels for states that have goto or calls in action code - * invoked on characters (ie, not from out action code). */ - if ( pair->action != 0 ) { - /* Loop the actions. */ - for ( GenActionTable::Iter act = pair->action->key; act.lte(); act++ ) { - /* Get the action and walk it's tree. */ - setLabelsNeeded( act->value->inlineList ); - } - } -} - -/* Set up labelNeeded flag for each state. */ -void IpGoto::setLabelsNeeded() -{ - /* If we use the _again label, then we generate the _again switch, which - * uses all labels. */ - if ( useAgainLabel() ) { - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) - st->labelNeeded = true; - } - else { - /* Do not use all labels by default, init all labelNeeded vars to false. */ - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) - st->labelNeeded = false; - - for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) - setLabelsNeeded( &trans->p ); - } - - for ( CondApSet::Iter cond = redFsm->condSet; cond.lte(); cond++ ) - setLabelsNeeded( &cond->p ); - - for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofAction != 0 ) { - for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ ) - setLabelsNeeded( item->value->inlineList ); - } - } - } -} - -void IpGoto::writeData() -{ - STATE_IDS(); - - taNfaTargs(); - taNfaOffsets(); - taNfaPushActions(); - taNfaPopTrans(); -} - -void IpGoto::NFA_FROM_STATE_ACTION_EXEC() -{ -// if ( redFsm->anyFromStateActions() ) { -// /* Unimplemented feature. Don't have the from state actions array in -// * this mode. Need to add it, or to alter the NFA pop codegen to be -// * consistent with the mode. */ -// assert( false ); -// } -} - -void IpGoto::writeExec() -{ - int maxCtrId = redFsm->nextCondId > redFsm->nextTransId ? redFsm->nextCondId : redFsm->nextTransId; - - stLabel = allocateLabels( stLabel, IpLabel::St, redFsm->nextStateId ); - ctrLabel = allocateLabels( ctrLabel, IpLabel::Ctr, maxCtrId ); - outLabel = allocateLabels( outLabel, IpLabel::Out, redFsm->nextStateId ); - popLabel = allocateLabels( popLabel, IpLabel::Pop, redFsm->nextStateId ); - - /* Must set labels immediately before writing because we may depend on the - * noend write option. */ - setLabelsNeeded(); - - out << "{\n"; - - DECLARE( INT(), cpc ); - DECLARE( INT(), ck ); - DECLARE( INT(), pop_test ); - DECLARE( INT(), nbreak ); - DECLARE( INT(), ps ); - DECLARE( INT(), new_recs ); - DECLARE( INT(), alt ); - - if ( _again.isReferenced ) { - out << - " goto " << _resume << ";\n" - "\n"; - - out << EMIT_LABEL( _again ); - - out << - " switch ( " << vCS() << " ) {\n"; - AGAIN_CASES() << - " }\n" - "\n"; - - } - - out << EMIT_LABEL( _resume ); - - out << "switch ( " << vCS() << " ) {\n"; - - STATE_GOTO_CASES(); - - out << "}\n"; - - STATE_GOTOS(); - - EXIT_STATES(); - - out << EMIT_LABEL( _pop ); - - if ( redFsm->anyNfaStates() ) { - out << - "if ( nfa_len == 0 )\n" - " goto " << _out << ";\n" - "\n"; - - out << - "nfa_count += 1;\n" - "nfa_len -= 1;\n" << - P() << " = nfa_bp[nfa_len].p;\n"; - - if ( redFsm->bAnyNfaPops ) { - NFA_FROM_STATE_ACTION_EXEC(); - - NFA_POP_TEST_EXEC(); - - out << - "if ( " << pop_test << " )\n" - " " << vCS() << " = nfa_bp[nfa_len].state;\n" - "else\n" - " " << vCS() << " = " << ERROR_STATE() << ";\n"; - } - else { - out << - vCS() << " = nfa_bp[nfa_len].state;\n"; - - } - - NFA_POST_POP(); - - out << "goto " << _resume << ";\n"; - } - - out << EMIT_LABEL( _out ); - - out << - "}\n"; -} diff --git a/src/libragel.h b/src/libragel.h deleted file mode 100644 index ad328e86..00000000 --- a/src/libragel.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016-2018 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. - */ - -#ifndef _LIBRAGEL_H -#define _LIBRAGEL_H - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C -#endif - -#endif diff --git a/src/redfsm.cc b/src/redfsm.cc deleted file mode 100644 index 1b83e5b5..00000000 --- a/src/redfsm.cc +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * Copyright 2001-2018 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 "redfsm.h" -#include "avlmap.h" -#include "mergesort.h" -#include "fsmgraph.h" -#include <iostream> -#include <sstream> -#include <ctime> - -using std::ostringstream; - -GenInlineItem::~GenInlineItem() -{ - if ( children != 0 ) { - children->empty(); - delete children; - } -} - -string GenAction::nameOrLoc() -{ - if ( name.empty() ) { - ostringstream ret; - ret << loc.line << ":" << loc.col; - return ret.str(); - } - else { - return name; - } -} - -RedFsmAp::RedFsmAp( FsmCtx *fsmCtx, int machineId ) -: - keyOps(fsmCtx->keyOps), - fsmCtx(fsmCtx), - machineId(machineId), - forcedErrorState(false), - nextActionId(0), - nextTransId(0), - nextCondId(0), - startState(0), - errState(0), - errTrans(0), - errCond(0), - firstFinState(0), - numFinStates(0), - bAnyToStateActions(false), - bAnyFromStateActions(false), - bAnyRegActions(false), - bAnyEofActions(false), - bAnyEofTrans(false), - bAnyEofActivity(false), - bAnyActionGotos(false), - bAnyActionCalls(false), - bAnyActionNcalls(false), - bAnyActionRets(false), - bAnyActionNrets(false), - bAnyActionByValControl(false), - bAnyRegActionRets(false), - bAnyRegActionByValControl(false), - bAnyRegNextStmt(false), - bAnyRegCurStateRef(false), - bAnyRegBreak(false), - bAnyRegNbreak(false), - bUsingAct(false), - bAnyNfaStates(false), - bAnyNfaPushPops(false), - bAnyNfaPushes(false), - bAnyNfaPops(false), - bAnyTransCondRefs(false), - bAnyNfaCondRefs(false), - nextClass(0), - classMap(0) -{ -} - -RedFsmAp::~RedFsmAp() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - delete[] st->transList; - if ( st->nfaTargs != 0 ) - delete st->nfaTargs; - if ( st->inConds != 0 ) - delete[] st->inConds; - if ( st->inCondTests != 0 ) - delete[] st->inCondTests; - } - - delete[] allStates; - if ( classMap != 0 ) - delete[] classMap; - - for ( TransApSet::Iter ti = transSet; ti.lte(); ti++ ) { - if ( ti->condSpace != 0 ) - delete[] ti->v.outConds; - } - - condSet.empty(); - transSet.empty(); -} - -/* Does the machine have any actions. */ -bool RedFsmAp::anyActions() -{ - return actionMap.length() > 0; -} - -void RedFsmAp::depthFirstOrdering( RedStateAp *state ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->onStateList ) - return; - - /* Doing depth first, put state on the list. */ - state->onStateList = true; - stateList.append( state ); - - /* At this point transitions should only be in ranges. */ - assert( state->outSingle.length() == 0 ); - assert( state->defTrans == 0 ); - - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - depthFirstOrdering( cond->targ ); - } - } - - if ( state->nfaTargs ) { - for ( RedNfaTargs::Iter s = *state->nfaTargs; s.lte(); s++ ) - depthFirstOrdering( s->state ); - } -} - -/* Ordering states by transition connections. */ -void RedFsmAp::depthFirstOrdering() -{ - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) - st->onStateList = false; - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - /* Add back to the state list from the start state and all other entry - * points. */ - if ( startState != 0 ) - depthFirstOrdering( startState ); - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - depthFirstOrdering( *en ); - if ( forcedErrorState ) - depthFirstOrdering( errState ); - - /* Make sure we put everything back on. */ - assert( stateListLen == stateList.length() ); -} - -void RedFsmAp::breadthFirstAdd( RedStateAp *state ) -{ - if ( state->onStateList ) - return; - - state->onStateList = true; - stateList.append( state ); -} - -void RedFsmAp::breadthFirstOrdering() -{ - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) - st->onStateList = false; - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - if ( startState != 0 ) - breadthFirstAdd( startState ); - - int depth = 0; - int nextLevel = stateList.length(); - int pos = 0; - - /* To implement breadth-first we traverse the current list (assuming a - * start state) and add children. */ - RedStateAp *cur = stateList.head; - while ( cur != 0 ) { - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = cur->outRange; rtel.lte(); rtel++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - breadthFirstAdd( cond->targ ); - } - } - - if ( cur->nfaTargs ) { - for ( RedNfaTargs::Iter s = *cur->nfaTargs; s.lte(); s++ ) - breadthFirstAdd( s->state ); - } - - cur = cur->next; - pos += 1; - - if ( pos == nextLevel ) { - depth += 1; - nextLevel = stateList.length(); - } - } - - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - depthFirstOrdering( *en ); - if ( forcedErrorState ) - depthFirstOrdering( errState ); - - assert( stateListLen == stateList.length() ); -} - -#ifdef SCORE_ORDERING -void RedFsmAp::readScores() -{ - /* - * Reads processed transitions logged by ASM codegen when LOG_TRANS is - * enabled. Process with: - * - * cat trans-log | sort -n -k 1 -k 2 -k 3 | uniq -c | sort -r -n -k1 -r > scores - */ - FILE *sfn = fopen( "scores", "r" ); - - scores = new long*[nextStateId]; - for ( int i = 0; i < nextStateId; i++ ) { - scores[i] = new long[256]; - memset( scores[i], 0, sizeof(long) * 256 ); - } - - long score, m, state, ch; - while ( true ) { - int n = fscanf( sfn, "%ld %ld %ld %ld\n", &score, &m, &state, &ch ); - if ( n != 4 ) - break; - if ( m == machineId ) - scores[state][ch] = score; - } - fclose( sfn ); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - RedTransList::Iter rtel = st->outRange; - int chi = 0; - while ( rtel.lte() ) { - /* 1. Bring chi up to lower end of out range. */ - while ( chi < rtel->lowKey.getVal() ) { - chi++; - } - - /* 2. While inside lower, add in score. */ - while ( chi <= rtel->highKey.getVal() ) { - rtel->score += scores[st->id][chi]; - chi++; - } - - /* 3. Next range. */ - rtel++; - } - } -} - -/* This second pass will collect any states that didn't make it in the first - * pass. Used for depth-first and breadth-first passes. */ -void RedFsmAp::scoreSecondPass( RedStateAp *state ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->onListRest ) - return; - - /* Doing depth first, put state on the list. */ - state->onListRest = true; - - if ( !state->onStateList ) { - state->onStateList = true; - stateList.append( state ); - } - - /* At this point transitions should only be in ranges. */ - assert( state->outSingle.length() == 0 ); - assert( state->defTrans == 0 ); - - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - scoreSecondPass( cond->targ ); - } - } - - if ( state->nfaTargs ) { - for ( RedNfaTargs::Iter s = *state->nfaTargs; s.lte(); s++ ) - scoreSecondPass( s->state ); - } -} - -void RedFsmAp::scoreOrderingDepth( RedStateAp *state ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->onStateList ) - return; - - /* Doing depth first, put state on the list. */ - state->onStateList = true; - stateList.append( state ); - - /* At this point transitions should only be in ranges. */ - assert( state->outSingle.length() == 0 ); - assert( state->defTrans == 0 ); - - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - if ( rtel->score > 10 ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - scoreOrderingDepth( cond->targ ); - } - } - } -} - -void RedFsmAp::scoreOrderingDepth() -{ - readScores(); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->onStateList = false; - st->onListRest = false; - } - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - scoreOrderingDepth( startState ); - - scoreSecondPass( startState ); - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - scoreSecondPass( *en ); - if ( forcedErrorState ) - scoreSecondPass( errState ); - - assert( stateListLen == stateList.length() ); -} - -void RedFsmAp::scoreOrderingBreadth() -{ - readScores(); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->onStateList = false; - st->onListRest = false; - } - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - if ( startState != 0 ) - breadthFirstAdd( startState ); - - int depth = 0; - int nextLevel = stateList.length(); - int pos = 0; - - /* To implement breadth-first we traverse the current list (assuming a - * start state) and add children. */ - RedStateAp *cur = stateList.head; - while ( cur != 0 ) { - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = cur->outRange; rtel.lte(); rtel++ ) { - if ( rtel->score > 100 ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - breadthFirstAdd( cond->targ ); - } - } - } - - cur = cur->next; - pos += 1; - - if ( pos == nextLevel ) { - depth += 1; - nextLevel = stateList.length(); - } - } - - scoreSecondPass( startState ); - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - scoreSecondPass( *en ); - if ( forcedErrorState ) - scoreSecondPass( errState ); - - assert( stateListLen == stateList.length() ); -} -#endif - -void RedFsmAp::randomizedOrdering() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) - st->onStateList = false; - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - srand( time( 0 ) ); - - for ( int i = nextStateId; i > 0; i-- ) { - /* Pick one from 0 ... i (how many are left). */ - int nth = rand() % i; - - /* Go forward through the list adding the nth. Need to scan because - * there are items already added in the list. */ - for ( int j = 0; j < nextStateId; j++ ) { - if ( !allStates[j].onStateList ) { - if ( nth == 0 ) { - /* Add. */ - allStates[j].onStateList = true; - stateList.append( &allStates[j] ); - break; - } - else { - nth -= 1; - } - } - } - } - assert( stateListLen == stateList.length() ); -} - -/* Assign state ids by appearance in the state list. */ -void RedFsmAp::sequentialStateIds() -{ - /* Table based machines depend on the state numbers starting at zero. */ - nextStateId = 0; - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) - st->id = nextStateId++; -} - -/* Stable sort the states by final state status. */ -void RedFsmAp::sortStatesByFinal() -{ - /* Move forward through the list and move final states onto the end. */ - RedStateAp *state = 0; - RedStateAp *next = stateList.head; - RedStateAp *last = stateList.tail; - while ( state != last ) { - /* Move forward and load up the next. */ - state = next; - next = state->next; - - /* Throw to the end? */ - if ( state->isFinal ) { - stateList.detach( state ); - stateList.append( state ); - } - } -} - -/* Assign state ids by final state state status. */ -void RedFsmAp::sortStateIdsByFinal() -{ - /* Table based machines depend on this starting at zero. */ - nextStateId = 0; - - /* First pass to assign non final ids. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( ! st->isFinal ) - st->id = nextStateId++; - } - - /* Second pass to assign final ids. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->isFinal ) - st->id = nextStateId++; - } -} - -struct CmpStateById -{ - static int compare( RedStateAp *st1, RedStateAp *st2 ) - { - if ( st1->id < st2->id ) - return -1; - else if ( st1->id > st2->id ) - return 1; - else - return 0; - } -}; - -void RedFsmAp::sortByStateId() -{ - /* Make the array. */ - int pos = 0; - RedStateAp **ptrList = new RedStateAp*[stateList.length()]; - for ( RedStateList::Iter st = stateList; st.lte(); st++, pos++ ) - ptrList[pos] = st; - - MergeSort<RedStateAp*, CmpStateById> mergeSort; - mergeSort.sort( ptrList, stateList.length() ); - - stateList.abandon(); - for ( int st = 0; st < pos; st++ ) - stateList.append( ptrList[st] ); - - delete[] ptrList; -} - -/* Find the final state with the lowest id. */ -void RedFsmAp::findFirstFinState() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) ) - firstFinState = st; - } -} - -void RedFsmAp::assignActionLocs() -{ - int nextLocation = 0; - for ( GenActionTableMap::Iter act = actionMap; act.lte(); act++ ) { - /* Store the loc, skip over the array and a null terminator. */ - act->location = nextLocation; - nextLocation += act->key.length() + 1; - } -} - -/* Check if we can extend the current range by displacing any ranges - * ahead to the singles. */ -bool RedFsmAp::canExtend( const RedTransList &list, int pos ) -{ - /* Get the transition that we want to extend. */ - RedTransAp *extendTrans = list[pos].value; - - /* Look ahead in the transition list. */ - for ( int next = pos + 1; next < list.length(); pos++, next++ ) { - /* If they are not continuous then cannot extend. */ - Key nextKey = list[next].lowKey; - keyOps->decrement( nextKey ); - if ( keyOps->ne( list[pos].highKey, nextKey ) ) - break; - - /* Check for the extenstion property. */ - if ( extendTrans == list[next].value ) - return true; - - /* If the span of the next element is more than one, then don't keep - * checking, it won't be moved to single. */ - unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey ); - if ( nextSpan > 1 ) - break; - } - return false; -} - -/* Move ranges to the singles list if it means we can extend some ranges, or if - * the spans are of length one. */ -void RedFsmAp::moveSelectTransToSingle( RedStateAp *state ) -{ - RedTransList &range = state->outRange; - RedTransList &single = state->outSingle; - for ( int rpos = 0; rpos < range.length(); ) { - /* Check if this is a range we can extend. */ - if ( canExtend( range, rpos ) ) { - /* Transfer singles over. */ - while ( range[rpos].value != range[rpos+1].value ) { - /* Transfer the range to single. */ - single.append( range[rpos+1] ); - range.remove( rpos+1 ); - } - - /* Extend. */ - range[rpos].highKey = range[rpos+1].highKey; - range.remove( rpos+1 ); - } - /* Maybe move it to the singles. */ - else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) { - single.append( range[rpos] ); - range.remove( rpos ); - } - else { - /* Keeping it in the ranges. */ - rpos += 1; - } - } -} - -void RedFsmAp::moveAllTransToSingle( RedStateAp *state ) -{ - RedTransList &range = state->outRange; - RedTransList &single = state->outSingle; - for ( int rpos = 0; rpos < range.length(); rpos++ ) { - - RedTransEl el = range[rpos]; - unsigned long long span = keyOps->span( el.lowKey, el.highKey ); - - Key key = el.lowKey; - for ( unsigned long long pos = 0; pos < span; pos++ ) { - el.lowKey = el.highKey = key; - single.append( el ); - keyOps->increment( key ); - } - } - range.empty(); -} - -/* Look through ranges and choose suitable single character transitions. */ -void RedFsmAp::moveSelectTransToSingle() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Rewrite the transition list taking out the suitable single - * transtions. */ - moveSelectTransToSingle( st ); - } -} - -void RedFsmAp::moveAllTransToSingle() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Rewrite the transition list taking out the suitable single - * transtions. */ - moveAllTransToSingle( st ); - } -} - -void RedFsmAp::makeFlat() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) { - st->lowKey = st->highKey = 0; - st->transList = 0; - } - else { - st->lowKey = st->outRange[0].lowKey; - st->highKey = st->outRange[st->outRange.length()-1].highKey; - unsigned long long span = keyOps->span( st->lowKey, st->highKey ); - st->transList = new RedTransAp*[ span ]; - memset( st->transList, 0, sizeof(RedTransAp*)*span ); - - for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) { - unsigned long long base, trSpan; - base = keyOps->span( st->lowKey, trans->lowKey )-1; - trSpan = keyOps->span( trans->lowKey, trans->highKey ); - for ( unsigned long long pos = 0; pos < trSpan; pos++ ) - st->transList[base+pos] = trans->value; - } - - /* Fill in the gaps with the default transition. */ - for ( unsigned long long pos = 0; pos < span; pos++ ) { - if ( st->transList[pos] == 0 ) - st->transList[pos] = st->defTrans; - } - } - } -} - -void RedFsmAp::characterClass( EquivList &equiv ) -{ - /* Find the global low and high keys. */ - bool anyTrans = false; - Key lowKey = keyOps->maxKey; - Key highKey = keyOps->minKey; - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) - continue; - - st->lowKey = st->outRange[0].lowKey; - st->highKey = st->outRange[st->outRange.length()-1].highKey; - - if ( keyOps->lt( st->lowKey, lowKey ) ) - lowKey = st->lowKey; - - if ( keyOps->gt( st->highKey, highKey ) ) - highKey = st->highKey; - - anyTrans = true; - } - - if ( ! anyTrans ) { - this->lowKey = lowKey; - this->highKey = highKey; - this->classMap = 0; - this->nextClass = 1; - return; - } - - long long next = 1; - equiv.append( new EquivClass( lowKey, highKey, next++ ) ); - - /* Start with a single equivalence class and break it up using range - * boundaries of each state. This will tell us what the equivalence class - * ranges are. These are the ranges that always go to the same state, - * across all states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) - continue; - - EquivList newList; - PairKeyMap uniqPairs; - - /* What is the set of unique transitions (*for this state) */ - EquivAlloc uniqTrans; - for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { - if ( ! uniqTrans.find( rtel->value ) ) - uniqTrans.insert( rtel->value, next++ ); - } - - /* Merge with whole-machine equiv classes. */ - typedef RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > RangePairIterPiListEquivClassPiVectorRedTransEl; - for ( RangePairIterPiListEquivClassPiVectorRedTransEl - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - switch ( pair.userState ) { - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeOverlap: { - /* Look up the char for s2. */ - EquivAllocEl *s2El = uniqTrans.find( pair.s2Tel.trans->value ); - - /* Can't use either equiv classes, find uniques. */ - PairKey pairKey( pair.s1Tel.trans->value, s2El->value ); - PairKeyMapEl *pairEl = uniqPairs.find( pairKey ); - if ( ! pairEl ) - pairEl = uniqPairs.insert( pairKey, next++ ); - - EquivClass *equivClass = new EquivClass( - pair.s1Tel.lowKey, pair.s1Tel.highKey, - pairEl->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeInS1: { - EquivClass *equivClass = new EquivClass( - pair.s1Tel.lowKey, pair.s1Tel.highKey, - pair.s1Tel.trans->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeInS2: { - /* Look up the char for s2. */ - EquivAllocEl *s2El = uniqTrans.find( pair.s2Tel.trans->value ); - - EquivClass *equivClass = new EquivClass( - pair.s2Tel.lowKey, pair.s2Tel.highKey, - s2El->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::BreakS1: - case RangePairIterPiListEquivClassPiVectorRedTransEl::BreakS2: - break; - } - } - - equiv.empty(); - equiv.transfer( newList ); - } - - /* Reduce to sequential. */ - next = 0; - BstMap<long long, long long> map; - for ( EquivClass *c = equiv.head; c != 0; c = c->next ) { - BstMapEl<long long, long long> *el = map.find( c->value ); - if ( ! el ) - el = map.insert( c->value, next++ ); - c->value = el->value; - } - - /* Build the map and emit arrays from the range-based equiv classes. Will - * likely crash if there are no transitions in the FSM. */ - long long maxSpan = keyOps->span( lowKey, highKey ); - long long *dest = new long long[maxSpan]; - memset( dest, 0, sizeof(long long) * maxSpan ); - - for ( EquivClass *c = equiv.head; c != 0; c = c->next ) { - long long base = keyOps->span( lowKey, c->lowKey ) - 1; - long long span = keyOps->span( c->lowKey, c->highKey ); - for ( long long s = 0; s < span; s++ ) - dest[base + s] = c->value; - } - - this->lowKey = lowKey; - this->highKey = highKey; - this->classMap = dest; - this->nextClass = next; - -} - -void RedFsmAp::makeFlatClass() -{ - EquivList equiv; - characterClass( equiv ); - - /* Expand the transitions. This uses the equivalence classes. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) { - st->lowKey = st->highKey = 0; - st->low = st->high = 0; - st->transList = 0; - } - else { - st->lowKey = st->outRange[0].lowKey; - st->highKey = st->outRange[st->outRange.length()-1].highKey; - - /* Compute low and high in class space. Use a pair iter to find all - * the clases. Alleviates the need to iterate the whole input - * alphabet. */ - st->low = nextClass; - st->high = -1; - for ( RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - if ( pair.userState == RangePairIter<PiList<EquivClass>, PiVector<RedTransEl> >::RangeOverlap || - pair.userState == RangePairIter<PiList<EquivClass>, PiVector<RedTransEl> >::RangeInS2 ) - { - long long off = keyOps->span( lowKey, pair.s2Tel.lowKey ) - 1; - if ( classMap[off] < st->low ) - st->low = classMap[off]; - if ( classMap[off] > st->high ) - st->high = classMap[off]; - } - } - - long long span = st->high - st->low + 1; - st->transList = new RedTransAp*[ span ]; - memset( st->transList, 0, sizeof(RedTransAp*)*span ); - - for ( RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - if ( pair.userState == RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> >::RangeOverlap || - pair.userState == RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> >::RangeInS2 ) - { - long long off = keyOps->span( lowKey, pair.s2Tel.lowKey ) - 1; - st->transList[ classMap[off] - st->low ] = pair.s2Tel.trans->value; - } - } - - /* Fill in the gaps with the default transition. */ - for ( long long pos = 0; pos < span; pos++ ) { - if ( st->transList[pos] == 0 ) - st->transList[pos] = st->defTrans; - } - } - } - - equiv.empty(); -} - - -/* A default transition has been picked, move it from the outRange to the - * default pointer. */ -void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state ) -{ - /* Rewrite the outRange, omitting any ranges that use - * the picked default. */ - RedTransList outRange; - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - /* If it does not take the default, copy it over. */ - if ( rtel->value != defTrans ) - outRange.append( *rtel ); - } - - /* Save off the range we just created into the state's range. */ - state->outRange.transfer( outRange ); - - /* Store the default. */ - state->defTrans = defTrans; -} - -bool RedFsmAp::alphabetCovered( RedTransList &outRange ) -{ - /* Cannot cover without any out ranges. */ - if ( outRange.length() == 0 ) - return false; - - /* If the first range doesn't start at the the lower bound then the - * alphabet is not covered. */ - RedTransList::Iter rtel = outRange; - if ( keyOps->lt( keyOps->minKey, rtel->lowKey ) ) - return false; - - /* Check that every range is next to the previous one. */ - rtel.increment(); - for ( ; rtel.lte(); rtel++ ) { - Key highKey = rtel[-1].highKey; - keyOps->increment( highKey ); - if ( keyOps->ne( highKey, rtel->lowKey ) ) - return false; - } - - /* The last must extend to the upper bound. */ - RedTransEl *last = &outRange[outRange.length()-1]; - if ( keyOps->lt( last->highKey, keyOps->maxKey ) ) - return false; - - return true; -} - -RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state ) -{ - /* Make a set of transitions from the outRange. */ - RedTransSet stateTransSet; - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) - stateTransSet.insert( rtel->value ); - - /* For each transition in the find how many alphabet characters the - * transition spans. */ - unsigned long long *span = new unsigned long long[stateTransSet.length()]; - memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() ); - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - /* Lookup the transition in the set. */ - RedTransAp **inSet = stateTransSet.find( rtel->value ); - int pos = inSet - stateTransSet.data; - span[pos] += keyOps->span( rtel->lowKey, rtel->highKey ); - } - - /* Find the max span, choose it for making the default. */ - RedTransAp *maxTrans = 0; - unsigned long long maxSpan = 0; - for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) { - if ( span[rtel.pos()] > maxSpan ) { - maxSpan = span[rtel.pos()]; - maxTrans = *rtel; - } - } - - delete[] span; - return maxTrans; -} - -/* Pick default transitions from ranges for the states. */ -void RedFsmAp::chooseDefaultSpan() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Only pick a default transition if the alphabet is covered. This - * avoids any transitions in the out range that go to error and avoids - * the need for an ERR state. */ - if ( alphabetCovered( st->outRange ) ) { - /* Pick a default transition by largest span. */ - RedTransAp *defTrans = chooseDefaultSpan( st ); - - /* Rewrite the transition list taking out the transition we picked - * as the default and store the default. */ - moveToDefault( defTrans, st ); - } - } -} - -RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state ) -{ - /* Make a set of transitions from the outRange. */ - RedTransSet stateTransSet; - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond(c); - if ( cond->targ == state->next ) - return rtel->value; - } - } - return 0; -} - -void RedFsmAp::chooseDefaultGoto() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Pick a default transition. */ - RedTransAp *defTrans = chooseDefaultGoto( st ); - if ( defTrans == 0 ) - defTrans = chooseDefaultSpan( st ); - - /* Rewrite the transition list taking out the transition we picked - * as the default and store the default. */ - moveToDefault( defTrans, st ); - } -} - -RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state ) -{ - /* Make a set of transitions from the outRange. */ - RedTransSet stateTransSet; - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) - stateTransSet.insert( rtel->value ); - - /* For each transition in the find how many ranges use the transition. */ - int *numRanges = new int[stateTransSet.length()]; - memset( numRanges, 0, sizeof(int) * stateTransSet.length() ); - for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) { - /* Lookup the transition in the set. */ - RedTransAp **inSet = stateTransSet.find( rtel->value ); - numRanges[inSet - stateTransSet.data] += 1; - } - - /* Find the max number of ranges. */ - RedTransAp *maxTrans = 0; - int maxNumRanges = 0; - for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) { - if ( numRanges[rtel.pos()] > maxNumRanges ) { - maxNumRanges = numRanges[rtel.pos()]; - maxTrans = *rtel; - } - } - - delete[] numRanges; - return maxTrans; -} - -void RedFsmAp::chooseDefaultNumRanges() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Pick a default transition. */ - RedTransAp *defTrans = chooseDefaultNumRanges( st ); - - /* Rewrite the transition list taking out the transition we picked - * as the default and store the default. */ - moveToDefault( defTrans, st ); - } -} - -RedCondAp *RedFsmAp::getErrorCond() -{ - return allocateCond( getErrorState(), 0 ); -} - -RedTransAp *RedFsmAp::getErrorTrans() -{ - return allocateTrans( getErrorState(), 0 ); -} - -RedStateAp *RedFsmAp::getErrorState() -{ - /* Something went wrong. An error state is needed but one was not supplied - * by the frontend. */ - assert( errState != 0 ); - return errState; -} - -/* Makes a plain transition. */ -RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedTransAp redTrans( 0, 0, targ, action ); - RedTransAp *inDict = transSet.find( &redTrans ); - if ( inDict == 0 ) { - inDict = new RedTransAp( nextTransId++, nextCondId++, targ, action ); - transSet.insert( inDict ); - } - return inDict; -} - -/* Makes a cond list transition. */ -RedTransAp *RedFsmAp::allocateTrans( GenCondSpace *condSpace, - RedCondEl *outConds, int numConds, RedCondAp *errCond ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedTransAp redTrans( 0, condSpace, outConds, numConds, errCond ); - RedTransAp *inDict = transSet.find( &redTrans ); - if ( inDict == 0 ) { - inDict = new RedTransAp( nextTransId++, condSpace, outConds, numConds, errCond ); - transSet.insert( inDict ); - } - else { - /* Need to free the out cond vector. */ - delete[] outConds; - } - return inDict; -} - -RedCondAp *RedFsmAp::allocateCond( RedStateAp *targ, RedAction *action ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedCondAp redCond( targ, action, 0 ); - RedCondAp *inDict = condSet.find( &redCond ); - if ( inDict == 0 ) { - inDict = new RedCondAp( targ, action, nextCondId++ ); - condSet.insert( inDict ); - } - return inDict; -} - -void RedFsmAp::partitionFsm( int nparts ) -{ - /* At this point the states are ordered by a depth-first traversal. We - * will allocate to partitions based on this ordering. */ - this->nParts = nparts; - int partSize = stateList.length() / nparts; - int remainder = stateList.length() % nparts; - int numInPart = partSize; - int partition = 0; - if ( remainder-- > 0 ) - numInPart += 1; - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->partition = partition; - - numInPart -= 1; - if ( numInPart == 0 ) { - partition += 1; - numInPart = partSize; - if ( remainder-- > 0 ) - numInPart += 1; - } - } -} - -void RedFsmAp::setInTrans() -{ - /* First pass counts the number of transitions. */ - for ( CondApSet::Iter trans = condSet; trans.lte(); trans++ ) - trans->p.targ->numInConds += 1; - - for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) - trans->p.targ->numInConds += 1; - else { - /* We have a placement choice here, but associate it with the - * first. */ - RedCondPair *pair = trans->outCond( 0 ); - pair->targ->numInCondTests += 1; - } - } - - /* Allocate. Reset the counts so we can use them as the current size. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->inConds = new RedCondPair*[st->numInConds]; - st->numInConds = 0; - - st->inCondTests = new RedTransAp*[st->numInCondTests]; - st->numInCondTests = 0; - } - - /* Fill the arrays. */ - for ( CondApSet::Iter trans = condSet; trans.lte(); trans++ ) { - RedStateAp *targ = trans->p.targ; - targ->inConds[targ->numInConds++] = &trans->p; - } - - for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) { - RedStateAp *targ = trans->p.targ; - targ->inConds[targ->numInConds++] = &trans->p; - } - else { - RedCondPair *pair = trans->outCond( 0 ); - RedStateAp *targ = pair->targ; - targ->inCondTests[targ->numInCondTests++] = trans; - } - } -} diff --git a/src/tabbreak.cc b/src/tabbreak.cc deleted file mode 100644 index 5ded768a..00000000 --- a/src/tabbreak.cc +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright 2018 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 "tables.h" -#include "binary.h" -#include "flat.h" - -std::string TabBreak::BREAK( GotoLabel &label ) -{ - string ret = "break"; - if ( loopLabels ) { - ret += " "; - ret += label.ref(); - } - return ret; -} - -std::string TabBreak::CONTINUE( GotoLabel &label ) -{ - string ret = "continue"; - if ( loopLabels ) { - ret += " "; - ret += label.ref(); - } - return ret; -} - -std::string TabBreak::BREAK_LABEL( GotoLabel &label ) -{ - if ( loopLabels ) { - if ( label.isReferenced ) - return std::string(label.name) + "::\n"; - } - return ""; -} - -void TabBreak::CONTROL_JUMP( ostream &ret, bool inFinish ) -{ - ret << "if ( " << TRUE() << " ) break " << _again << ";"; -} - -void TabBreak::GOTO( ostream &ret, int gotoDest, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << gotoDest << ";"; - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::CALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << " = " << - callDest << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::NCALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << - TOP() << " += 1;" << vCS() << " = " << - callDest << "; " << CLOSE_GEN_BLOCK(); -} - -void TabBreak::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << - " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::NCALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << " += 1;" << vCS() << - " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); - ret << CLOSE_HOST_EXPR() << "; " << CLOSE_GEN_BLOCK(); -} - -void TabBreak::RET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::NRET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << CLOSE_GEN_BLOCK(); -} - -void TabBreak::BREAK( ostream &ret, int targState, bool csForced ) -{ - ret << - OPEN_GEN_BLOCK() << - P() << " += 1; " << - "break " << _resume << "; " << - CLOSE_GEN_BLOCK(); -} - -void TabBreak::NBREAK( ostream &ret, int targState, bool csForced ) -{ - ret << - OPEN_GEN_BLOCK() << - P() << " += 1; " << - nbreak << " = 1;" << - CLOSE_GEN_BLOCK(); -} - -void TabBreak::writeExec() -{ - out << - " {\n"; - - DECLARE( INT(), ps ); - DECLARE( INT(), cpc ); - DECLARE( INT(), nbreak ); - DECLARE( INT(), klen ); - DECLARE( INDEX( ARR_TYPE( condKeys ) ), ckeys ); - DECLARE( INDEX( ARR_TYPE( eofCondKeys ) ), cekeys ); - DECLARE( UINT(), trans, " = 0" ); - DECLARE( UINT(), cond, " = 0" ); - DECLARE( INDEX( ALPH_TYPE() ), keys ); - DECLARE( INDEX( ARR_TYPE( actions ) ), acts ); - DECLARE( INDEX( ARR_TYPE( indices ) ), inds ); - DECLARE( UINT(), nacts ); - DECLARE( INT(), have ); - DECLARE( INT(), pop_test ); - DECLARE( INT(), new_recs ); - DECLARE( INT(), alt ); - DECLARE( INT(), ic ); - - out << BREAK_LABEL( _resume ); - - /* Do we break out on no more input. */ - bool eof = redFsm->anyEofActivity() || redFsm->anyNfaStates(); - if ( !noEnd ) { - if ( eof ) { - out << - " while ( " << P() << " != " << PE() << " || " << P() << " == " << vEOF() << " ) {\n"; - } - else { - out << - " while ( " << P() << " != " << PE() << " ) {\n"; - } - } - else { - out << - " while ( " << TRUE() << " ) {\n"; - - } - - NFA_PUSH( vCS() ); - - if ( loopLabels ) { - out << BREAK_LABEL( _again ); - out << "while ( " << TRUE() << " ) {\n"; - } - - FROM_STATE_ACTIONS(); - - if ( !noEnd && eof ) { - out << - "if ( " << P() << " == " << vEOF() << " ) {\n"; - - if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { - if ( redFsm->anyEofTrans() ) { - out << - " if ( " << ARR_REF( eofTrans ) << "[" << vCS() << "] > 0 ) {\n" - " " << trans << " = " << - CAST(UINT()) << ARR_REF( eofTrans ) << "[" << vCS() << "] - 1;\n" - " }\n"; - } - } - - out << - "}\n" - "else {\n"; - } - - LOCATE_TRANS(); - - if ( !noEnd && eof ) { - out << - "}\n"; - } - - LOCATE_COND(); - - if ( redFsm->anyRegCurStateRef() ) - out << " " << ps << " = " << vCS() << ";\n"; - - string condVar = - red->condSpaceList.length() != 0 ? cond.ref() : trans.ref(); - - out << - " " << vCS() << " = " << CAST(INT()) << ARR_REF( condTargs ) << "[" << condVar << "];\n\n"; - - if ( redFsm->anyRegActions() ) { - out << - " if ( " << ARR_REF( condActions ) << "[" << condVar << "] != 0 ) {\n" - "\n"; - - if ( redFsm->anyRegNbreak() ) - out << " " << nbreak << " = 0;\n"; - - REG_ACTIONS( condVar ); - - if ( redFsm->anyRegNbreak() ) { - out << - " if ( " << nbreak << " == 1 )\n" - " " << BREAK( _resume ) << ";\n"; - } - - out << "}\n"; - } - - - if ( loopLabels ) { - out << BREAK( _again ) << ";\n}\n"; - } - - out << "\n" << EMIT_LABEL( _again ); - - if ( !noEnd && eof ) { - out << - " if ( " << P() << " == " << vEOF() << " ) {\n" - " if ( " << vCS() << " >= " << FIRST_FINAL_STATE() << " )\n" - " " << BREAK( _resume ) << ";\n" - " }\n" - " else {\n"; - } - - TO_STATE_ACTIONS(); - - if ( redFsm->errState != 0 ) { - out << - " if ( " << vCS() << " != " << redFsm->errState->id << " ) {\n"; - } - - out << - " " << P() << " += 1;\n" - " " << CONTINUE( _resume ) << ";\n"; - - if ( redFsm->errState != 0 ) { - out << - " }\n"; - } - - if ( !noEnd && eof ) { - out << - " }\n"; - } - - if ( redFsm->anyNfaStates() ) { - out << - " if ( nfa_len == 0 )\n" - " " << BREAK ( _resume ) << ";\n" - "\n" - " nfa_count += 1;\n" - " nfa_len -= 1;\n" - " " << P() << " = nfa_bp[nfa_len].p;\n" - ; - - if ( redFsm->bAnyNfaPops ) { - NFA_FROM_STATE_ACTION_EXEC(); - - NFA_POP_TEST_EXEC(); - - out << - " if ( " << pop_test << " )\n" - " " << vCS() << " = nfa_bp[nfa_len].state;\n" - " else\n" - " " << vCS() << " = " << ERROR_STATE() << ";\n"; - } - else { - out << - " " << vCS() << " = nfa_bp[nfa_len].state;\n"; - - } - - NFA_POST_POP(); - } - else { - out << - " " << BREAK( _resume ) << ";\n"; - } - - out << - "}\n"; - - out << EMIT_LABEL( _out ); - - out << " }\n"; -} - diff --git a/src/tabgoto.cc b/src/tabgoto.cc deleted file mode 100644 index ca90cb9d..00000000 --- a/src/tabgoto.cc +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2018 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 "tables.h" -#include "binary.h" -#include "flat.h" - -void TabGoto::CONTROL_JUMP( ostream &ret, bool inFinish ) -{ - ret << "goto " << _again << ";"; -} - -void TabGoto::GOTO( ostream &ret, int gotoDest, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << gotoDest << ";"; - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::CALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << " = " << - callDest << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::NCALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << - TOP() << " += 1;" << vCS() << " = " << - callDest << "; " << CLOSE_GEN_BLOCK(); -} - -void TabGoto::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << - " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";"; - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::NCALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << " += 1;" << vCS() << - " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); - ret << CLOSE_HOST_EXPR() << "; " << CLOSE_GEN_BLOCK(); -} - -void TabGoto::RET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - CONTROL_JUMP( ret, inFinish ); - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::NRET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << " -= 1;" << vCS() << " = " << STACK() << "[" << TOP() << "];"; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << CLOSE_GEN_BLOCK(); -} - -void TabGoto::BREAK( ostream &ret, int targState, bool csForced ) -{ - ret << - OPEN_GEN_BLOCK() << - P() << " += 1; " << - "goto " << _out << "; " << - CLOSE_GEN_BLOCK(); -} - -void TabGoto::NBREAK( ostream &ret, int targState, bool csForced ) -{ - ret << - OPEN_GEN_BLOCK() << - P() << " += 1; " << - nbreak << " = 1;" << - CLOSE_GEN_BLOCK(); -} - -void TabGoto::writeExec() -{ - out << - " {\n"; - - DECLARE( INT(), ps ); - DECLARE( INT(), cpc ); - DECLARE( INT(), nbreak ); - DECLARE( INT(), klen ); - DECLARE( INDEX( ARR_TYPE( condKeys ) ), ckeys ); - DECLARE( INDEX( ARR_TYPE( eofCondKeys ) ), cekeys ); - DECLARE( UINT(), trans, " = 0" ); - DECLARE( UINT(), cond, " = 0" ); - DECLARE( INDEX( ALPH_TYPE() ), keys ); - DECLARE( INDEX( ARR_TYPE( actions ) ), acts ); - DECLARE( INDEX( ARR_TYPE( indices ) ), inds ); - DECLARE( UINT(), nacts ); - DECLARE( INT(), pop_test ); - DECLARE( INT(), new_recs ); - DECLARE( INT(), alt ); - DECLARE( INT(), ic ); - - out << EMIT_LABEL( _resume ); - - /* Do we break out on no more input. */ - bool eof = redFsm->anyEofActivity() || redFsm->anyNfaStates(); - if ( !noEnd ) { - if ( eof ) { - out << - " if ( " << P() << " == " << PE() << " && " << P() << " != " << vEOF() << " )\n" - " goto " << _out << ";\n"; - } - else { - out << - " if ( " << P() << " == " << PE() << " )\n" - " goto " << _out << ";\n"; - } - } - - NFA_PUSH( vCS() ); - - FROM_STATE_ACTIONS(); - - if ( !noEnd && eof ) { - out << - "if ( " << P() << " == " << vEOF() << " ) {\n"; - - if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { - if ( redFsm->anyEofTrans() ) { - out << - " if ( " << ARR_REF( eofTrans ) << "[" << vCS() << "] > 0 ) {\n" - " " << trans << " = " << - CAST(UINT()) << ARR_REF( eofTrans ) << "[" << vCS() << "] - 1;\n" - " }\n"; - } - } - - out << - "}\n" - "else {\n"; - } - - LOCATE_TRANS(); - - if ( !noEnd && eof ) { - out << - "}\n"; - } - - LOCATE_COND(); - - if ( redFsm->anyRegCurStateRef() ) - out << " " << ps << " = " << vCS() << ";\n"; - - string condVar = - red->condSpaceList.length() != 0 ? cond.ref() : trans.ref(); - - out << - " " << vCS() << " = " << CAST(INT()) << ARR_REF( condTargs ) << "[" << condVar << "];\n\n"; - - if ( redFsm->anyRegActions() ) { - out << - " if ( " << ARR_REF( condActions ) << "[" << condVar << "] != 0 ) {\n" - "\n"; - - if ( redFsm->anyRegNbreak() ) - out << " " << nbreak << " = 0;\n"; - - REG_ACTIONS( condVar ); - - if ( redFsm->anyRegNbreak() ) { - out << - " if ( " << nbreak << " == 1 )\n" - " goto " << _out << ";\n"; - } - - out << "}\n"; - } - - out << "\n" << EMIT_LABEL( _again ); - - if ( !noEnd && eof ) { - out << - " if ( " << P() << " == " << vEOF() << " ) {\n" - " if ( " << vCS() << " >= " << FIRST_FINAL_STATE() << " )\n" - " goto " << _out << ";\n" - " }\n" - " else {\n"; - } - - TO_STATE_ACTIONS(); - - if ( redFsm->errState != 0 ) { - out << - " if ( " << vCS() << " != " << redFsm->errState->id << " ) {\n"; - } - - out << - " " << P() << " += 1;\n" - " goto " << _resume << ";\n"; - - if ( redFsm->errState != 0 ) { - out << - " }\n"; - } - - if ( !noEnd && eof ) { - out << - " }\n"; - } - - if ( redFsm->anyNfaStates() ) { - out << - " if ( nfa_len == 0 )\n" - " goto " << _out << ";\n" - "\n" - " nfa_count += 1;\n" - " nfa_len -= 1;\n" - " " << P() << " = nfa_bp[nfa_len].p;\n" - ; - - if ( redFsm->bAnyNfaPops ) { - NFA_FROM_STATE_ACTION_EXEC(); - - NFA_POP_TEST_EXEC(); - - out << - " if ( " << pop_test << " )\n" - " " << vCS() << " = nfa_bp[nfa_len].state;\n" - " else\n" - " " << vCS() << " = " << ERROR_STATE() << ";\n"; - } - else { - out << - " " << vCS() << " = nfa_bp[nfa_len].state;\n"; - - } - - NFA_POST_POP(); - - out << "goto " << _resume << ";\n"; - } - - out << EMIT_LABEL( _out ); - - out << " }\n"; -} - diff --git a/src/tables.cc b/src/tables.cc deleted file mode 100644 index 40edd93e..00000000 --- a/src/tables.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2018 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 "tables.h" - -void Tables::CURS( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_EXPR() << ps << CLOSE_GEN_EXPR(); -} - -void Tables::TARGS( ostream &ret, bool inFinish, int targState ) -{ - ret << OPEN_GEN_EXPR() << vCS() << CLOSE_GEN_EXPR(); -} - -void Tables::NEXT( ostream &ret, int nextDest, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << nextDest << ";" << CLOSE_GEN_BLOCK(); -} - -void Tables::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << "" << vCS() << " = " << OPEN_HOST_EXPR(); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";" << CLOSE_GEN_BLOCK(); -} - -void Tables::EOF_TRANS() -{ - out << - "" << trans << " = " << CAST(UINT()) << ARR_REF( eofTrans ) << "[" << vCS() << "] - 1;\n"; - - if ( red->condSpaceList.length() > 0 ) { - out << - "" << cond << " = " << CAST(UINT()) << ARR_REF( transOffsets ) << "[" << trans << "];\n"; - } -} - -void Tables::COND_EXEC( std::string expr ) -{ - out << - " switch ( " << expr << " ) {\n" - "\n"; - - for ( CondSpaceList::Iter csi = red->condSpaceList; csi.lte(); csi++ ) { - GenCondSpace *condSpace = csi; - out << " " << CASE( STR( condSpace->condSpaceId ) ) << " {\n"; - for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { - out << "if ( "; - CONDITION( out, *csi ); - Size condValOffset = (1 << csi.pos()); - out << " ) " << cpc << " += " << condValOffset << ";\n"; - } - - out << - " " << CEND() << "\n}\n"; - } - - out << - " }\n"; -} - diff --git a/src/tabvar.cc b/src/tabvar.cc deleted file mode 100644 index 02bd7b55..00000000 --- a/src/tabvar.cc +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2018 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 "tables.h" -#include "flatvar.h" -#include "binvar.h" - -std::string TabVar::BREAK( GotoLabel &label ) -{ - return "{ _cont = 0; _again = 0; }"; -} - -std::string TabVar::CONTINUE( GotoLabel &label ) -{ - return "{ _cont = 0; _again = 1; }"; -} - -std::string TabVar::BREAK_LABEL( GotoLabel &label ) -{ - return ""; -} - -void TabVar::GOTO( ostream &ret, int gotoDest, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << gotoDest << ";" << CLOSE_GEN_BLOCK(); -} - -void TabVar::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << vCS() << " = " << OPEN_HOST_EXPR( "-", 1 ); - INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";" << CLOSE_GEN_BLOCK(); -} - -void TabVar::CALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - red->id->error() << "cannot use fcall in -B mode" << std::endl; - red->id->abortCompile( 1 ); -} - -void TabVar::NCALL( ostream &ret, int callDest, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << " = " << - callDest << ";" << CLOSE_GEN_BLOCK(); -} - -void TabVar::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - red->id->error() << "cannot use fcall in -B mode" << std::endl; - red->id->abortCompile( 1 ); -} - -void TabVar::NCALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK(); - - if ( red->prePushExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->prePushExpr ); - INLINE_LIST( ret, red->prePushExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << STACK() << "[" << TOP() << "] = " << - vCS() << "; " << TOP() << " += 1;" << vCS() << - " = " << OPEN_HOST_EXPR( "-", 1 ); - INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); - ret << CLOSE_HOST_EXPR() << ";" << CLOSE_GEN_BLOCK(); -} - -void TabVar::RET( ostream &ret, bool inFinish ) -{ - red->id->error() << "cannot use fret in -B mode" << std::endl; - red->id->abortCompile( 1 ); -} - -void TabVar::NRET( ostream &ret, bool inFinish ) -{ - ret << OPEN_GEN_BLOCK() << TOP() << "-= 1;" << vCS() << " = " << - STACK() << "[" << TOP() << "]; "; - - if ( red->postPopExpr != 0 ) { - ret << OPEN_HOST_BLOCK( red->postPopExpr ); - INLINE_LIST( ret, red->postPopExpr->inlineList, 0, false, false ); - ret << CLOSE_HOST_BLOCK(); - } - - ret << CLOSE_GEN_BLOCK(); -} - -void TabVar::BREAK( ostream &ret, int targState, bool csForced ) -{ - red->id->error() << "cannot use fbreak in -B mode" << std::endl; - red->id->abortCompile( 1 ); -} - -void TabVar::NBREAK( ostream &ret, int targState, bool csForced ) -{ - ret << - OPEN_GEN_BLOCK() << - P() << "+= 1;\n" << - nbreak << " = 1;" << - CLOSE_GEN_BLOCK(); -} - -void TabVar::writeExec() -{ - out << - "{\n"; - - DECLARE( INT(), ps ); - DECLARE( INT(), cpc ); - DECLARE( INT(), nbreak ); - DECLARE( INT(), klen ); - DECLARE( INDEX( ARR_TYPE( condKeys ) ), ckeys ); - DECLARE( INDEX( ARR_TYPE( eofCondKeys ) ), cekeys ); - DECLARE( UINT(), trans, " = 0" ); - DECLARE( UINT(), cond, " = 0" ); - DECLARE( INDEX( ALPH_TYPE() ), keys ); - DECLARE( INDEX( ARR_TYPE( actions ) ), acts ); - DECLARE( INDEX( ARR_TYPE( indices ) ), inds ); - DECLARE( UINT(), nacts ); - DECLARE( INT(), have ); - DECLARE( INT(), pop_test ); - DECLARE( INT(), new_recs ); - DECLARE( INT(), alt ); - DECLARE( INT(), ic ); - - out << UINT() << " _have = 0;\n"; - out << UINT() << " _cont = 1;\n"; - out << UINT() << " _again = 1;\n"; - out << UINT() << " _bsc = 1;\n"; - - out << BREAK_LABEL( _resume ); - - /* Do we break out on no more input. */ - bool eof = redFsm->anyEofActivity() || redFsm->anyNfaStates(); - if ( !noEnd ) { - if ( eof ) { - out << - " while ( _again == 1 && ( " << P() << " != " << PE() << " || " << P() << " == " << vEOF() << " ) ) {\n"; - } - else { - out << - " while ( _again == 1 && " << P() << " != " << PE() << " ) {\n"; - } - } - else { - out << - " while ( _again == 1 ) {\n"; - - } - - out << "_cont = 1;\n"; - out << "_again = 1;\n"; - - NFA_PUSH( vCS() ); - - FROM_STATE_ACTIONS(); - - if ( !noEnd && eof ) { - out << - "if ( " << P() << " == " << vEOF() << " ) {\n"; - - if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { - if ( redFsm->anyEofTrans() ) { - out << - " if ( " << ARR_REF( eofTrans ) << "[" << vCS() << "] > 0 ) {\n" - " " << trans << " = " << - CAST(UINT()) << ARR_REF( eofTrans ) << "[" << vCS() << "] - 1;\n" - " }\n"; - } - } - - out << - "}\n" - "else {\n"; - } - - LOCATE_TRANS(); - - if ( !noEnd && eof ) { - out << - "}\n"; - } - - LOCATE_COND(); - - if ( redFsm->anyRegCurStateRef() ) - out << " " << ps << " = " << vCS() << ";\n"; - - string condVar = - red->condSpaceList.length() != 0 ? cond.ref() : trans.ref(); - - out << - " " << vCS() << " = " << CAST(INT()) << ARR_REF( condTargs ) << "[" << condVar << "];\n\n"; - - if ( redFsm->anyRegActions() ) { - out << - " if ( " << ARR_REF( condActions ) << "[" << condVar << "] != 0 ) {\n" - "\n"; - - if ( redFsm->anyRegNbreak() ) - out << " " << nbreak << " = 0;\n"; - - REG_ACTIONS( condVar ); - - if ( redFsm->anyRegNbreak() ) { - out << - " if ( " << nbreak << " == 1 )\n" - " " << BREAK( _resume ) << "\n"; - } - - out << "}\n"; - } - - out << "if ( _cont == 1 ) {\n"; - - out << "\n" << EMIT_LABEL( _again ); - - if ( !noEnd && eof ) { - out << - " if ( " << P() << " == " << vEOF() << " ) {\n" - " if ( " << vCS() << " >= " << FIRST_FINAL_STATE() << " )\n" - " " << BREAK( _resume ) << "\n" - " }\n" - " else {\n"; - } - - TO_STATE_ACTIONS(); - - if ( redFsm->errState != 0 ) { - out << - " if ( " << vCS() << " != " << redFsm->errState->id << " ) {\n"; - } - - out << - " " << P() << " += 1;\n" - " " << CONTINUE( _resume ) << "\n"; - - if ( redFsm->errState != 0 ) { - out << - " }\n"; - } - - if ( !noEnd && eof ) { - out << - " }\n"; - } - - out << "if ( _cont == 1 ) {\n"; - - if ( redFsm->anyNfaStates() ) { - out << - " if ( nfa_len == 0 )\n" - " " << BREAK ( _resume ) << "\n" - "\n"; - - out << "if ( _cont == 1 ) {\n"; - - out << - " nfa_count += 1;\n" - " nfa_len -= 1;\n" - " " << P() << " = nfa_bp[nfa_len].p;\n" - ; - - if ( redFsm->bAnyNfaPops ) { - NFA_FROM_STATE_ACTION_EXEC(); - - NFA_POP_TEST_EXEC(); - - out << - " if ( " << pop_test << " )\n" - " " << vCS() << " = nfa_bp[nfa_len].state;\n" - " else\n" - " " << vCS() << " = " << ERROR_STATE() << ";\n"; - } - else { - out << - " " << vCS() << " = nfa_bp[nfa_len].state;\n"; - - } - - NFA_POST_POP(); - - /* cont */ - out << "}\n"; - } - else { - out << - " " << BREAK( _resume ) << "\n"; - } - - /* cont */ - out << "}}\n"; - - /* P loop. */ - out << "}\n"; - - out << EMIT_LABEL( _out ); - - /* Variable decl. */ - out << "}\n"; -} - diff --git a/src/xml.cc b/src/xml.cc deleted file mode 100644 index 861bb89f..00000000 --- a/src/xml.cc +++ /dev/null @@ -1,786 +0,0 @@ -/* - * Copyright 2005-2018 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. - */ - -/* - * XML Output not included in 7.0 (yet -- possibly) - */ - -#include "ragel.h" -#include "xml.h" -#include "parsedata.h" -#include "fsmgraph.h" -#include "gendata.h" -#include "inputdata.h" -#include <string.h> -#include "version.h" - -using std::endl; - -void InputData::processXML() -{ - /* Compiles machines. */ - prepareAllMachines(); - - if ( errorCount > 0 ) - abortCompile( 1 ); - - createOutputStream(); - - if ( errorCount > 0 ) - abortCompile( 1 ); - - /* - * From this point on we should not be reporting any errors. - */ - - openOutput(); - writeXML( *outStream ); - closeOutput(); -} - -XMLCodeGen::XMLCodeGen( std::string fsmName, int machineId, FsmGbl *id, PdBase *pd, FsmAp *fsm, std::ostream &out ) -: - RedBase( id, pd, fsm, fsmName, machineId ), - out(out) -{ -} - -void XMLCodeGen::writeActionList() -{ - /* Determine which actions to write. */ - int nextActionId = 0; - for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) { - if ( act->numRefs() > 0 || act->numCondRefs > 0 ) - act->actionId = nextActionId++; - } - - /* Write the list. */ - out << " <action_list length=\"" << nextActionId << "\">\n"; - for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) { - if ( act->actionId >= 0 ) - writeAction( act ); - } - out << " </action_list>\n"; -} - -void XMLCodeGen::writeActionTableList() -{ - /* Must first order the action tables based on their id. */ - int numTables = nextActionTableId; - RedActionTable **tables = new RedActionTable*[numTables]; - for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ ) - tables[at->id] = at; - - out << " <action_table_list length=\"" << numTables << "\">\n"; - for ( int t = 0; t < numTables; t++ ) { - out << " <action_table id=\"" << t << "\" length=\"" << - tables[t]->key.length() << "\">"; - for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) { - out << atel->value->actionId; - if ( ! atel.last() ) - out << " "; - } - out << "</action_table>\n"; - } - out << " </action_table_list>\n"; - - delete[] tables; -} - -void XMLCodeGen::writeKey( Key key ) -{ - if ( keyOps->isSigned ) - out << key.getVal(); - else - out << (unsigned long) key.getVal(); -} - -void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans ) -{ - /* Write the transition. */ - out << " <t>"; - writeKey( lowKey ); - out << " "; - writeKey( highKey ); - - if ( trans->plain() ) { - /* First reduce the action. */ - RedActionTable *actionTable = 0; - if ( trans->tdap()->actionTable.length() > 0 ) - actionTable = actionTableMap.find( trans->tdap()->actionTable ); - - if ( trans->tdap()->toState != 0 ) - out << " " << trans->tdap()->toState->alg.stateNum; - else - out << " x"; - - if ( actionTable != 0 ) - out << " " << actionTable->id; - else - out << " x"; - } - else { - for ( CondList::Iter ctel = trans->tcap()->condList; ctel.lte(); ctel++ ) { - out << "<c>"; - out << trans->tcap()->condSpace->condSpaceId; - - /* First reduce the action. */ - RedActionTable *actionTable = 0; - if ( ctel->actionTable.length() > 0 ) - actionTable = actionTableMap.find( ctel->actionTable ); - - if ( ctel->toState != 0 ) - out << " " << ctel->toState->alg.stateNum; - else - out << " x"; - - if ( actionTable != 0 ) - out << " " << actionTable->id; - else - out << " x"; - - out << "</c>"; - } - } - - out << "</t>\n"; -} - -void XMLCodeGen::writeTransList( StateAp *state ) -{ - TransListVect outList; - - out << " <trans_list length=\"" << state->outList.length() << "\">\n"; - - /* If there is only are no ranges the task is simple. */ - if ( state->outList.length() > 0 ) { - /* Loop each source range. */ - for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) { - /* Reduce the transition. If it reduced to anything then add it. */ - appendTrans( outList, trans->lowKey, trans->highKey, trans ); - } - } - - for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ ) - writeTrans( tvi->lowKey, tvi->highKey, tvi->value ); - out << " </trans_list>\n"; -} - -void XMLCodeGen::writeEofTrans( StateAp *state ) -{ - RedActionTable *eofActions = 0; - if ( state->eofActionTable.length() > 0 ) - eofActions = actionTableMap.find( state->eofActionTable ); - - /* The <eof_t> is used when there is an eof target, otherwise the eof - * action goes into state actions. */ - if ( state->eofTarget != 0 ) { - out << " <eof_t>" << state->eofTarget->alg.stateNum; - - if ( eofActions != 0 ) - out << " " << eofActions->id; - else - out << " x"; - - out << "</eof_t>" << endl; - } -} - -void XMLCodeGen::writeText( InlineItem *item ) -{ - if ( item->prev == 0 || item->prev->type != InlineItem::Text ) - out << "<text>"; - xmlEscapeHost( out, item->data.c_str(), item->data.size() ); - if ( item->next == 0 || item->next->type != InlineItem::Text ) - out << "</text>"; -} - -void XMLCodeGen::writeGoto( InlineItem *item ) -{ - if ( pd->generatingSectionSubset ) - out << "<goto>-1</goto>"; - else { - EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id ); - out << "<goto>" << targ->value->alg.stateNum << "</goto>"; - } -} - -void XMLCodeGen::writeCall( InlineItem *item ) -{ - if ( pd->generatingSectionSubset ) - out << "<call>-1</call>"; - else { - EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id ); - out << "<call>" << targ->value->alg.stateNum << "</call>"; - } -} - -void XMLCodeGen::writeNext( InlineItem *item ) -{ - if ( pd->generatingSectionSubset ) - out << "<next>-1</next>"; - else { - EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id ); - out << "<next>" << targ->value->alg.stateNum << "</next>"; - } -} - -void XMLCodeGen::writeGotoExpr( InlineItem *item ) -{ - out << "<goto_expr>"; - writeInlineList( item->children ); - out << "</goto_expr>"; -} - -void XMLCodeGen::writeCallExpr( InlineItem *item ) -{ - out << "<call_expr>"; - writeInlineList( item->children ); - out << "</call_expr>"; -} - -void XMLCodeGen::writeNextExpr( InlineItem *item ) -{ - out << "<next_expr>"; - writeInlineList( item->children ); - out << "</next_expr>"; -} - -void XMLCodeGen::writeEntry( InlineItem *item ) -{ - if ( pd->generatingSectionSubset ) - out << "<entry>-1</entry>"; - else { - EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id ); - out << "<entry>" << targ->value->alg.stateNum << "</entry>"; - } -} - -void XMLCodeGen::writeActionExec( InlineItem *item ) -{ - out << "<exec>"; - writeInlineList( item->children ); - out << "</exec>"; -} - -void XMLCodeGen::writeLmOnLast( InlineItem *item ) -{ - out << "<set_tokend>1</set_tokend>"; - - if ( item->longestMatchPart->action != 0 ) { - out << "<sub_action>"; - writeInlineList( item->longestMatchPart->action->inlineList ); - out << "</sub_action>"; - } -} - -void XMLCodeGen::writeLmOnNext( InlineItem *item ) -{ - out << "<set_tokend>0</set_tokend>"; - out << "<hold></hold>"; - - if ( item->longestMatchPart->action != 0 ) { - out << "<sub_action>"; - writeInlineList( item->longestMatchPart->action->inlineList ); - out << "</sub_action>"; - } -} - -void XMLCodeGen::writeLmOnLagBehind( InlineItem *item ) -{ - out << "<exec><get_tokend></get_tokend></exec>"; - - if ( item->longestMatchPart->action != 0 ) { - out << "<sub_action>"; - writeInlineList( item->longestMatchPart->action->inlineList ); - out << "</sub_action>"; - } -} - -void XMLCodeGen::writeLmSwitch( InlineItem *item ) -{ - LongestMatch *longestMatch = item->longestMatch; - out << "<lm_switch>\n"; - - /* We can't put the <exec> here because we may need to handle the error - * case and in that case p should not be changed. Instead use a default - * label in the switch to adjust p when user actions are not set. An id of - * -1 indicates the default. */ - - if ( longestMatch->lmSwitchHandlesError ) { - /* If the switch handles error then we should have also forced the - * error state. */ - assert( fsm->errState != 0 ); - - out << " <sub_action id=\"0\">"; - out << "<goto>" << fsm->errState->alg.stateNum << "</goto>"; - out << "</sub_action>\n"; - } - - bool needDefault = false; - for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) { - if ( lmi->inLmSelect ) { - if ( lmi->action == 0 ) - needDefault = true; - else { - /* Open the action. Write it with the context that sets up _p - * when doing control flow changes from inside the machine. */ - out << " <sub_action id=\"" << lmi->longestMatchId << "\">"; - out << "<exec><get_tokend></get_tokend></exec>"; - writeInlineList( lmi->action->inlineList ); - out << "</sub_action>\n"; - } - } - } - - if ( needDefault ) { - out << " <sub_action id=\"-1\"><exec><get_tokend>" - "</get_tokend></exec></sub_action>\n"; - } - - out << " </lm_switch>"; -} - -void XMLCodeGen::writeInlineList( InlineList *inlineList ) -{ - for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) { - switch ( item->type ) { - case InlineItem::Text: - writeText( item ); - break; - case InlineItem::Goto: - writeGoto( item ); - break; - case InlineItem::GotoExpr: - writeGotoExpr( item ); - break; - case InlineItem::Call: - writeCall( item ); - break; - case InlineItem::CallExpr: - writeCallExpr( item ); - break; - case InlineItem::Next: - writeNext( item ); - break; - case InlineItem::NextExpr: - writeNextExpr( item ); - break; - case InlineItem::Break: - out << "<break></break>"; - break; - case InlineItem::Ret: - out << "<ret></ret>"; - break; - case InlineItem::PChar: - out << "<pchar></pchar>"; - break; - case InlineItem::Char: - out << "<char></char>"; - break; - case InlineItem::Curs: - out << "<curs></curs>"; - break; - case InlineItem::Targs: - out << "<targs></targs>"; - break; - case InlineItem::Entry: - writeEntry( item ); - break; - - case InlineItem::Hold: - out << "<hold></hold>"; - break; - case InlineItem::Exec: - writeActionExec( item ); - break; - - case InlineItem::LmSetActId: - out << "<set_act>" << - item->longestMatchPart->longestMatchId << - "</set_act>"; - break; - case InlineItem::LmSetTokEnd: - out << "<set_tokend>1</set_tokend>"; - break; - - case InlineItem::LmOnLast: - writeLmOnLast( item ); - break; - case InlineItem::LmOnNext: - writeLmOnNext( item ); - break; - case InlineItem::LmOnLagBehind: - writeLmOnLagBehind( item ); - break; - case InlineItem::LmSwitch: - writeLmSwitch( item ); - break; - - case InlineItem::LmInitAct: - out << "<init_act></init_act>"; - break; - case InlineItem::LmInitTokStart: - out << "<init_tokstart></init_tokstart>"; - break; - case InlineItem::LmSetTokStart: - out << "<set_tokstart></set_tokstart>"; - break; - - /* Stubbed. */ - case InlineItem::Ncall: - case InlineItem::NcallExpr: - case InlineItem::Nret: - case InlineItem::Nbreak: - case InlineItem::Stmt: - case InlineItem::Subst: - case InlineItem::NfaWrapAction: - case InlineItem::NfaWrapConds: - break; - } - } -} - - -void XMLCodeGen::writeAction( Action *action ) -{ - out << " <action id=\"" << action->actionId << "\""; - if ( !action->name.empty() ) - out << " name=\"" << action->name << "\""; - out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">"; - writeInlineList( action->inlineList ); - out << "</action>\n"; -} - -void xmlEscapeHost( std::ostream &out, const char *data, long len ) -{ - const char *end = data + len; - while ( data != end ) { - switch ( *data ) { - case '<': out << "<"; break; - case '>': out << ">"; break; - case '&': out << "&"; break; - default: out << *data; break; - } - data += 1; - } -} - -void XMLCodeGen::writeStateActions( StateAp *state ) -{ - RedActionTable *toStateActions = 0; - if ( state->toStateActionTable.length() > 0 ) - toStateActions = actionTableMap.find( state->toStateActionTable ); - - RedActionTable *fromStateActions = 0; - if ( state->fromStateActionTable.length() > 0 ) - fromStateActions = actionTableMap.find( state->fromStateActionTable ); - - /* EOF actions go out here only if the state has no eof target. If it has - * an eof target then an eof transition will be used instead. */ - RedActionTable *eofActions = 0; - if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 ) - eofActions = actionTableMap.find( state->eofActionTable ); - - if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) { - out << " <state_actions>"; - if ( toStateActions != 0 ) - out << toStateActions->id; - else - out << "x"; - - if ( fromStateActions != 0 ) - out << " " << fromStateActions->id; - else - out << " x"; - - if ( eofActions != 0 ) - out << " " << eofActions->id; - else - out << " x"; - - out << "</state_actions>\n"; - } -} - -void XMLCodeGen::writeStateList() -{ - /* Write the list of states. */ - out << " <state_list length=\"" << fsm->stateList.length() << "\">\n"; - for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) { - out << " <state id=\"" << st->alg.stateNum << "\""; - if ( st->isFinState() ) - out << " final=\"t\""; - out << ">\n"; - - writeStateActions( st ); - writeEofTrans( st ); - writeTransList( st ); - - out << " </state>\n"; - - if ( !st.last() ) - out << "\n"; - } - out << " </state_list>\n"; -} - -bool XMLCodeGen::writeNameInst( NameInst *nameInst ) -{ - bool written = false; - if ( nameInst->parent != 0 ) - written = writeNameInst( nameInst->parent ); - - if ( !nameInst->name.empty() ) { - if ( written ) - out << '_'; - out << nameInst->name; - written = true; - } - - return written; -} - -void XMLCodeGen::writeEntryPoints() -{ - /* List of entry points other than start state. */ - if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) { - out << " <entry_points"; - if ( pd->lmRequiresErrorState ) - out << " error=\"t\""; - out << ">\n"; - for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) { - /* Get the name instantiation from nameIndex. */ - NameInst *nameInst = pd->nameIndex[en->key]; - StateAp *state = en->value; - out << " <entry name=\""; - writeNameInst( nameInst ); - out << "\">" << state->alg.stateNum << "</entry>\n"; - } - out << " </entry_points>\n"; - } -} - -void XMLCodeGen::writeMachine() -{ - /* Open the machine. */ - out << " <machine>\n"; - - /* Action tables. */ - reduceActionTables(); - - writeActionList(); - writeActionTableList(); - writeConditions(); - - /* Start state. */ - out << " <start_state>" << fsm->startState->alg.stateNum << - "</start_state>\n"; - - /* Error state. */ - if ( fsm->errState != 0 ) { - out << " <error_state>" << fsm->errState->alg.stateNum << - "</error_state>\n"; - } - - writeEntryPoints(); - writeStateList(); - - out << " </machine>\n"; -} - - -void XMLCodeGen::writeConditions() -{ - CondData *condData = fsm->ctx->condData; - if ( condData->condSpaceMap.length() > 0 ) { - long nextCondSpaceId = 0; - for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) - cs->condSpaceId = nextCondSpaceId++; - - out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n"; - for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) { - out << " <cond_space id=\"" << cs->condSpaceId << - "\" length=\"" << cs->condSet.length() << "\">"; - for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ ) - out << " " << (*csi)->actionId; - out << "</cond_space>\n"; - } - out << " </cond_space_list>\n"; - } -} - -void XMLCodeGen::writeExports() -{ - if ( pd->exportList.length() > 0 ) { - out << " <exports>\n"; - for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) { - out << " <ex name=\"" << exp->name << "\">"; - writeKey( exp->key ); - out << "</ex>\n"; - } - out << " </exports>\n"; - } -} - -void XMLCodeGen::writeXML() -{ - /* Open the definition. */ - out << "<ragel_def name=\"" << fsmName << "\">\n"; - - /* Alphabet type. */ - out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n"; - - /* Getkey expression. */ - if ( pd->getKeyExpr != 0 ) { - out << " <getkey>"; - writeInlineList( pd->getKeyExpr ); - out << "</getkey>\n"; - } - - /* Access expression. */ - if ( pd->accessExpr != 0 ) { - out << " <access>"; - writeInlineList( pd->accessExpr ); - out << "</access>\n"; - } - - /* PrePush expression. */ - if ( pd->prePushExpr != 0 ) { - out << " <prepush>"; - writeInlineList( pd->prePushExpr->inlineList ); - out << "</prepush>\n"; - } - - /* PostPop expression. */ - if ( pd->postPopExpr != 0 ) { - out << " <postpop>"; - writeInlineList( pd->postPopExpr->inlineList ); - out << "</postpop>\n"; - } - - /* - * Variable expressions. - */ - - if ( pd->pExpr != 0 ) { - out << " <p_expr>"; - writeInlineList( pd->pExpr ); - out << "</p_expr>\n"; - } - - if ( pd->peExpr != 0 ) { - out << " <pe_expr>"; - writeInlineList( pd->peExpr ); - out << "</pe_expr>\n"; - } - - if ( pd->eofExpr != 0 ) { - out << " <eof_expr>"; - writeInlineList( pd->eofExpr ); - out << "</eof_expr>\n"; - } - - if ( pd->csExpr != 0 ) { - out << " <cs_expr>"; - writeInlineList( pd->csExpr ); - out << "</cs_expr>\n"; - } - - if ( pd->topExpr != 0 ) { - out << " <top_expr>"; - writeInlineList( pd->topExpr ); - out << "</top_expr>\n"; - } - - if ( pd->stackExpr != 0 ) { - out << " <stack_expr>"; - writeInlineList( pd->stackExpr ); - out << "</stack_expr>\n"; - } - - if ( pd->actExpr != 0 ) { - out << " <act_expr>"; - writeInlineList( pd->actExpr ); - out << "</act_expr>\n"; - } - - if ( pd->tokstartExpr != 0 ) { - out << " <tokstart_expr>"; - writeInlineList( pd->tokstartExpr ); - out << "</tokstart_expr>\n"; - } - - if ( pd->tokendExpr != 0 ) { - out << " <tokend_expr>"; - writeInlineList( pd->tokendExpr ); - out << "</tokend_expr>\n"; - } - - if ( pd->dataExpr != 0 ) { - out << " <data_expr>"; - writeInlineList( pd->dataExpr ); - out << "</data_expr>\n"; - } - - writeExports(); - - writeMachine(); - - out << - "</ragel_def>\n"; -} - -void InputData::writeLanguage( std::ostream &out ) -{ - out << " lang=\""; - switch ( hostLang->lang ) { - case HostLang::C: out << "C"; break; - case HostLang::D: out << "D"; break; - case HostLang::Go: out << "Go"; break; - case HostLang::Java: out << "Java"; break; - case HostLang::Ruby: out << "Ruby"; break; - case HostLang::CSharp: out << "C#"; break; - case HostLang::OCaml: out << "OCaml"; break; - case HostLang::Crack: out << "Crack"; break; - case HostLang::Asm: out << "ASM"; break; - case HostLang::Rust: out << "Rust"; break; - case HostLang::Julia: out << "Julia"; break; - case HostLang::JS: out << "JavaScript"; break; - } - out << "\""; -} - -void InputData::writeXML( std::ostream &out ) -{ - out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\""; - writeLanguage( out ); - out << ">\n"; - - for ( ParseDataDict::Iter pdel = parseDataDict; pdel.lte(); pdel++ ) { - ParseData *pd = pdel->value; - if ( pd->instanceList.length() > 0 ) - pd->generateXML( *outStream ); - } - - out << "</ragel>\n"; -} diff --git a/src/xml.h b/src/xml.h deleted file mode 100644 index 60135055..00000000 --- a/src/xml.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2005-2018 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. - */ - -#ifndef _XMLCODEGEN_H -#define _XMLCODEGEN_H - -#if 0 - -#include <iostream> -#include "avltree.h" -#include "fsmgraph.h" -#include "parsedata.h" -#include "redfsm.h" -#include "gendata.h" - -class XMLCodeGen : protected RedBase -{ -public: - XMLCodeGen( std::string fsmName, int machineId, FsmGbl *id, PdBase *pd, FsmAp *fsm, std::ostream &out ); - - void writeXML( ); - -private: - void writeStateActions( StateAp *state ); - void writeStateList(); - - void writeKey( Key key ); - void writeText( InlineItem *item ); - void writeGoto( InlineItem *item ); - void writeGotoExpr( InlineItem *item ); - void writeCall( InlineItem *item ); - void writeCallExpr( InlineItem *item ); - void writeNext( InlineItem *item ); - void writeNextExpr( InlineItem *item ); - void writeEntry( InlineItem *item ); - void writeLmOnLast( InlineItem *item ); - void writeLmOnNext( InlineItem *item ); - void writeLmOnLagBehind( InlineItem *item ); - - void writeExports(); - bool writeNameInst( NameInst *nameInst ); - void writeEntryPoints(); - void writeConditions(); - void writeInlineList( InlineList *inlineList ); - void writeActionList(); - void writeActionTableList(); - void reduceTrans( TransAp *trans ); - void writeTransList( StateAp *state ); - void writeEofTrans( StateAp *state ); - void writeTrans( Key lowKey, Key highKey, TransAp *defTrans ); - void writeAction( Action *action ); - void writeLmSwitch( InlineItem *item ); - void writeMachine(); - void writeActionExec( InlineItem *item ); - - std::ostream &out; -}; - -#endif - -#endif - diff --git a/src/xmlparse.kh b/src/xmlparse.kh deleted file mode 100644 index 1b0b30ad..00000000 --- a/src/xmlparse.kh +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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. - */ - -#ifndef _XMLPARSE_H -#define _XMLPARSE_H - -#include "vector.h" -#include "gendata.h" -#include "buffer.h" -#include <iostream> - -using std::istream; -using std::ostream; - -#define XML_BUFSIZE 4096 - -struct AttrMarker -{ - char *id; - int idLen; - char *value; - int valueLen; -}; - -struct Attribute -{ - char *id; - char *value; -}; - -typedef Vector<AttrMarker> AttrMkList; -typedef Vector<Attribute> AttrList; -struct XMLTagHashPair; - -struct XMLTag -{ - enum TagType { Open, Close }; - - XMLTag( XMLTagHashPair *tagId, TagType type ) : - tagId(tagId), type(type), - content(0), attrList(0) {} - - Attribute *findAttr( const char *id ) - { - if ( attrList != 0 ) { - for ( AttrList::Iter attr = *attrList; attr.lte(); attr++ ) { - if ( strcmp( id, attr->id ) == 0 ) - return attr; - } - } - return 0; - } - - XMLTagHashPair *tagId; - TagType type; - - /* Content is associtated with closing tags. */ - char *content; - - /* Attribute lists are associated with opening tags. */ - AttrList *attrList; -}; - - -struct XMLTagHashPair -{ - const char *name; - int id; -}; - -struct Token; - -struct GenInlineItem; -struct GenInlineList; - -struct LmSwitchVect; -struct LmSwitchAction; - -struct XmlScanner -{ - XmlScanner( const char *fileName, istream &input ); - - int scan(); - void adjustAttrPointers( int distance ); - std::ostream &error(); - - const char *fileName; - istream &input; - - /* Scanner State. */ - int cs, act, have, curline, curcol; - char *ts, *te; - char *p, *pe; - int done; - - /* Token data */ - char *data; - int data_len; - int value; - AttrMkList attrMkList; - Buffer buffer; - char *tag_id_start; - int tag_id_len; - int token_col, token_line; - - char buf[XML_BUFSIZE]; -}; - - -struct XmlParser -{ - %%{ - parser XmlParser; - - token TAG_unknown, TAG_ragel, TAG_ragel_def, TAG_host, TAG_state_list, - TAG_state, TAG_trans_list, TAG_t, TAG_machine, TAG_start_state, - TAG_error_state, TAG_action_list, TAG_action_table_list, - TAG_action, TAG_action_table, TAG_alphtype, TAG_element, - TAG_getkey, TAG_state_actions, TAG_entry_points, TAG_sub_action, - TAG_cond_space_list, TAG_cond_space, TAG_cond_list, TAG_c, - TAG_exports, TAG_ex; - - # Inline block tokens. - token TAG_text, TAG_goto, TAG_call, TAG_next, TAG_goto_expr, - TAG_call_expr, TAG_next_expr, TAG_ret, TAG_pchar, TAG_char, - TAG_hold, TAG_exec, TAG_curs, TAG_targs, TAG_entry, TAG_data, - TAG_lm_switch, TAG_init_act, TAG_set_act, TAG_set_tokend, - TAG_get_tokend, TAG_init_tokstart, TAG_set_tokstart; - - token TAG_write, TAG_access, TAG_break, TAG_arg, TAG_cs_expr; - - token TAG_p_expr, TAG_pe_expr, TAG_eof_expr, TAG_cs_expr, TAG_top_expr, - TAG_stack_expr, TAG_act_expr, TAG_tokstart_expr, TAG_tokend_expr, - TAG_data_expr, TAG_prepush, TAG_postpop, TAG_eof_t; - }%% - - %% write instance_data; - - void init(); - int parseLangEl( int type, const Token *token ); - - XmlParser( const char *sourceFileName, const char *xmlFileName, bool outputActive, bool wantComplete ) : - sourceFileName(sourceFileName), - fileName(xmlFileName), - outStream(0), - outputActive(outputActive), - wantComplete(wantComplete), - cgd(0) { } - - int token( int tokenId, Token &token ); - int token( int tokenId, int col, int line ); - int token( XMLTag *tag, int col, int line ); - - void openOutput(); - - /* Report an error encountered by the parser. */ - ostream &warning( const InputLoc &loc ); - ostream &error(); - ostream &error( const InputLoc &loc ); - ostream &parser_error( int tokId, Token &token ); - ostream &source_error( const InputLoc &loc ); - - /* The name of the root section, this does not change during an include. */ - const char *sourceFileName; - const char *fileName; - ostream *outStream; - bool outputActive; - bool wantComplete; - - /* Collected during parsing. */ - char *attrKey; - char *attrValue; - int curAction; - int curActionTable; - int curTrans; - int curState; - int curCondSpace; - int curStateCond; - - CodeGenData *cgd; - CodeGenMap codeGenMap; - - Vector <char*> writeOptions; -}; - -%% write token_defs; - -int xml_parse( std::istream &input, const char *fileName, - bool outputActive, bool wantComplete, - XmlScanner &scanner, XmlParser &parser ); - -#endif diff --git a/src/xmlparse.kl b/src/xmlparse.kl deleted file mode 100644 index 04d95b83..00000000 --- a/src/xmlparse.kl +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * 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 ); -} diff --git a/src/xmlscan.rl b/src/xmlscan.rl deleted file mode 100644 index 4e9ee4e2..00000000 --- a/src/xmlscan.rl +++ /dev/null @@ -1,315 +0,0 @@ -/* - * 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 <iostream> -#include <string.h> -#include "vector.h" -#include "xmlparse.h" - -using std::istream; -using std::cout; -using std::cerr; -using std::endl; - -%%{ - machine XmlScanner; - write data; -}%% - -class Perfect_Hash -{ -private: - static inline unsigned int hash (const char *str, unsigned int len); - -public: - static struct XMLTagHashPair *in_word_set (const char *str, unsigned int len); -}; - -XmlScanner::XmlScanner( const char *fileName, istream &input ) : - fileName(fileName), - input(input), - curline(1), - curcol(1), - p(0), pe(0), - done(false), - data(0), data_len(0), - value(0) -{ - %%{ - machine XmlScanner; - write init; - }%% -} - -#define TK_NO_TOKEN (-1) -#define TK_ERR 1 -#define TK_SPACE 2 -#define TK_EOF 3 -#define TK_OpenTag 4 -#define TK_CloseTag 5 - -#define ret_tok( _tok ) token = (_tok); data = ts - -void XmlScanner::adjustAttrPointers( int distance ) -{ - for ( AttrMkList::Iter attr = attrMkList; attr.lte(); attr++ ) { - attr->id -= distance; - attr->value -= distance; - } -} - -/* There is no claim that this is a proper XML parser, but it is good - * enough for our purposes. */ -%%{ - machine XmlScanner; - - action colup { curcol++; } - action start_tok { token_col = curcol; token_line = curline; } - NL = '\n' @{ curcol = 0; curline++; }; - - WS = [\r\t ] | NL; - id = [_a-zA-Z][_a-zA-Z0-9]*; - literal = '"' ( [^"] | NL )* '"'; - - # Attribute identifiers. - action start_attr_id { attr_id_start = p; } - action leave_attr_id { attr_id_len = p - attr_id_start; } - - attr_id = id >start_attr_id %leave_attr_id; - - # Attribute values - action start_attr_value { attr_value_start = p; } - action leave_attr_value - { - attr_value_len = p - attr_value_start; - - AttrMarker newAttr; - newAttr.id = attr_id_start; - newAttr.idLen = attr_id_len; - newAttr.value = attr_value_start; - newAttr.valueLen = attr_value_len; - attrMkList.append( newAttr ); - } - - attr_value = literal >start_attr_value %leave_attr_value; - - # Attribute list. - attribute = attr_id WS* '=' WS* attr_value WS*; - - # Tag identifiers. - action tag_id_start { tag_id_start = p; } - action leave_tag_id { tag_id_len = p - tag_id_start; } - - tag_id = id >tag_id_start %leave_tag_id; - - main := |* - # Tags - ( '<' WS* tag_id ( WS+ attribute* )? '>' ) >start_tok $colup - => { ret_tok( TK_OpenTag ); fbreak; }; - - ( '<' WS* '/' WS* tag_id WS* '>' ) >start_tok $colup - => { ret_tok( TK_CloseTag ); fbreak; }; - - # Data in between tags. - ( [^<&\0] | NL ) $colup - => { buffer.append( *p ); }; - - # Specials. - "&" $colup - => { buffer.append( '&' ); }; - "<" $colup - => { buffer.append( '<' ); }; - ">" $colup - => { buffer.append( '>' ); }; - - # EOF - 0 >start_tok => { ret_tok( TK_EOF ); fbreak; }; - - *|; -}%% - -int XmlScanner::scan( ) -{ - int token = TK_NO_TOKEN; - int space = 0, readlen = 0; - char *attr_id_start = 0; - char *attr_value_start = 0; - int attr_id_len = 0; - int attr_value_len = 0; - - attrMkList.empty(); - buffer.clear(); - - while ( 1 ) { - if ( p == pe ) { - //printf("scanner: need more data\n"); - - if ( ts == 0 ) - have = 0; - else { - /* There is data that needs to be shifted over. */ - //printf("scanner: buffer broken mid token\n"); - have = pe - ts; - memmove( buf, ts, have ); - - int distance = ts - buf; - te -= distance; - tag_id_start -= distance; - attr_id_start -= distance; - attr_value_start -= distance; - adjustAttrPointers( distance ); - ts = buf; - } - - p = buf + have; - space = XML_BUFSIZE - have; - - if ( space == 0 ) { - /* We filled up the buffer trying to scan a token. */ - return TK_SPACE; - } - - if ( done ) { - //printf("scanner: end of file\n"); - p[0] = 0; - readlen = 1; - } - else { - input.read( p, space ); - readlen = input.gcount(); - if ( input.eof() ) { - //printf("scanner: setting done flag\n"); - done = 1; - } - } - - pe = p + readlen; - } - - %% write exec; - - if ( cs == XmlScanner_error ) - return TK_ERR; - - if ( token != TK_NO_TOKEN ) { - data_len = p - data; - return token; - } - } -} - -int xml_parse( std::istream &input, const char *fileName, - bool outputActive, bool wantComplete, - XmlScanner &scanner, XmlParser &parser ) -{ - while ( 1 ) { - int token = scanner.scan(); - if ( token == TK_NO_TOKEN ) { - cerr << "xmlscan: interal error: scanner returned NO_TOKEN" << endl; - exit(1); - } - else if ( token == TK_EOF ) { - parser.token( XmlParser_tk_eof, scanner.token_col, scanner.token_line ); - break; - } - else if ( token == TK_ERR ) { - scanner.error() << "scanner error" << endl; - break; - } - else if ( token == TK_SPACE ) { - scanner.error() << "scanner is out of buffer space" << endl; - break; - } - else { - /* All other tokens are either open or close tags. */ - XMLTagHashPair *tagId = Perfect_Hash::in_word_set( - scanner.tag_id_start, scanner.tag_id_len ); - - XMLTag *tag = new XMLTag( tagId, token == TK_OpenTag ? - XMLTag::Open : XMLTag::Close ); - - if ( tagId != 0 ) { - /* Get attributes for open tags. */ - if ( token == TK_OpenTag && scanner.attrMkList.length() > 0 ) { - tag->attrList = new AttrList; - for ( AttrMkList::Iter attr = scanner.attrMkList; - attr.lte(); attr++ ) - { - Attribute newAttr; - newAttr.id = new char[attr->idLen+1]; - memcpy( newAttr.id, attr->id, attr->idLen ); - newAttr.id[attr->idLen] = 0; - - /* Exclude the surrounding quotes. */ - newAttr.value = new char[attr->valueLen-1]; - memcpy( newAttr.value, attr->value+1, attr->valueLen-2 ); - newAttr.value[attr->valueLen-2] = 0; - - tag->attrList->append( newAttr ); - } - } - - /* Get content for closing tags. */ - if ( token == TK_CloseTag ) { - switch ( tagId->id ) { - case TAG_host: case TAG_arg: - case TAG_t: case TAG_alphtype: - case TAG_text: case TAG_goto: - case TAG_call: case TAG_next: - case TAG_entry: case TAG_set_tokend: - case TAG_set_act: case TAG_start_state: - case TAG_error_state: case TAG_state_actions: - case TAG_action_table: case TAG_cond_space: - case TAG_c: case TAG_ex: case TAG_eof_t: - tag->content = new char[scanner.buffer.length+1]; - memcpy( tag->content, scanner.buffer.data, - scanner.buffer.length ); - tag->content[scanner.buffer.length] = 0; - break; - } - } - } - - #if 0 - cerr << "parser_driver: " << (tag->type == XMLTag::Open ? "open" : "close") << - ": " << (tag->tagId != 0 ? tag->tagId->name : "<unknown>") << endl; - if ( tag->attrList != 0 ) { - for ( AttrList::Iter attr = *tag->attrList; attr.lte(); attr++ ) - cerr << " " << attr->id << ": " << attr->value << endl; - } - if ( tag->content != 0 ) - cerr << " content: " << tag->content << endl; - #endif - - parser.token( tag, scanner.token_col, scanner.token_line ); - } - } - - return 0; -} - -std::ostream &XmlScanner::error() -{ - gblErrorCount += 1; - cerr << fileName << ":" << curline << ":" << curcol << ": "; - return cerr; -} diff --git a/src/xmltags.gperf b/src/xmltags.gperf deleted file mode 100644 index 1ca544f7..00000000 --- a/src/xmltags.gperf +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2005 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 <string.h> -#include "xmlparse.h" -%} -%compare-strncmp -struct XMLTagHashPair; -%% -ragel, TAG_ragel -ragel_def, TAG_ragel_def -host, TAG_host -state_list, TAG_state_list -state, TAG_state -trans_list, TAG_trans_list -t, TAG_t -machine, TAG_machine -start_state, TAG_start_state -error_state, TAG_error_state -action_list, TAG_action_list -action, TAG_action -action_table_list, TAG_action_table_list -action_table, TAG_action_table -alphtype, TAG_alphtype -getkey, TAG_getkey -state_actions, TAG_state_actions -entry_points, TAG_entry_points -text, TAG_text -goto, TAG_goto -call, TAG_call -next, TAG_next -goto_expr, TAG_goto_expr -call_expr, TAG_call_expr -next_expr, TAG_next_expr -ret, TAG_ret -pchar, TAG_pchar -char, TAG_char -hold, TAG_hold -exec, TAG_exec -curs, TAG_curs -targs, TAG_targs -entry, TAG_entry -data, TAG_data -lm_switch, TAG_lm_switch -sub_action, TAG_sub_action -init_act, TAG_init_act -set_act, TAG_set_act -get_tokend, TAG_get_tokend -set_tokend, TAG_set_tokend -init_tokstart, TAG_init_tokstart -set_tokstart, TAG_set_tokstart -write, TAG_write -access, TAG_access -break, TAG_break -arg, TAG_arg -cond_space_list, TAG_cond_space_list -cond_space, TAG_cond_space -cond_list, TAG_cond_list -c, TAG_c -exports, TAG_exports -ex, TAG_ex -p_expr, TAG_p_expr -pe_expr, TAG_pe_expr -eof_expr, TAG_eof_expr -cs_expr, TAG_cs_expr -top_expr, TAG_top_expr -stack_expr, TAG_stack_expr -act_expr, TAG_act_expr -tokstart_expr, TAG_tokstart_expr -tokend_expr, TAG_tokend_expr -data_expr, TAG_data_expr -prepush, TAG_prepush -postpop, TAG_postpop -eof_t, TAG_eof_t |