summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2021-12-28 17:49:55 +0000
committerAdrian Thurston <thurston@colm.net>2021-12-28 17:49:55 +0000
commitf5116edb1e8773ea21e51e5d9644dcea173c9016 (patch)
tree93e639406fda342da3c6b34b738257ac43bc1233
parent8dc93d3b2cc730e5344ce9c047d4d595dac3dc29 (diff)
downloadragel-f5116edb1e8773ea21e51e5d9644dcea173c9016.tar.gz
removed code that is unused, or that now lives in the colm package
-rw-r--r--src/actexp.cc218
-rw-r--r--src/actloop.cc229
-rw-r--r--src/asm.cc2047
-rw-r--r--src/buffer.h56
-rw-r--r--src/fsmap.cc1200
-rw-r--r--src/fsmattach.cc857
-rw-r--r--src/fsmbase.cc853
-rw-r--r--src/fsmcond.cc520
-rw-r--r--src/fsmgraph.cc1948
-rw-r--r--src/fsmmin.cc934
-rw-r--r--src/fsmnfa.cc660
-rw-r--r--src/fsmstate.cc603
-rw-r--r--src/gendata.cc1648
-rw-r--r--src/idbase.cc422
-rw-r--r--src/ipgoto.cc765
-rw-r--r--src/libragel.h32
-rw-r--r--src/redfsm.cc1192
-rw-r--r--src/tabbreak.cc378
-rw-r--r--src/tabgoto.cc330
-rw-r--r--src/tables.cc81
-rw-r--r--src/tabvar.cc332
-rw-r--r--src/xml.cc786
-rw-r--r--src/xml.h81
-rw-r--r--src/xmlparse.kh211
-rw-r--r--src/xmlparse.kl1006
-rw-r--r--src/xmlscan.rl315
-rw-r--r--src/xmltags.gperf95
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 << "&lt;"; break;
- case '>': out << "&gt;"; break;
- case '&': out << "&amp;"; 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.
- "&amp;" $colup
- => { buffer.append( '&' ); };
- "&lt;" $colup
- => { buffer.append( '<' ); };
- "&gt;" $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