aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/ragel5/rlgen-cd
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2023-12-02 01:45:21 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2023-12-02 02:42:50 +0300
commit9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c (patch)
tree9f88a486917d371d099cd712efd91b4c122d209d /contrib/tools/ragel5/rlgen-cd
parent32fb6dda1feb24f9ab69ece5df0cb9ec238ca5e6 (diff)
downloadydb-9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c.tar.gz
Intermediate changes
Diffstat (limited to 'contrib/tools/ragel5/rlgen-cd')
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fflatcodegen.cpp351
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fflatcodegen.h76
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fgotocodegen.cpp262
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fgotocodegen.h76
-rw-r--r--contrib/tools/ragel5/rlgen-cd/flatcodegen.cpp766
-rw-r--r--contrib/tools/ragel5/rlgen-cd/flatcodegen.h108
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fsmcodegen.cpp749
-rw-r--r--contrib/tools/ragel5/rlgen-cd/fsmcodegen.h218
-rw-r--r--contrib/tools/ragel5/rlgen-cd/ftabcodegen.cpp405
-rw-r--r--contrib/tools/ragel5/rlgen-cd/ftabcodegen.h78
-rw-r--r--contrib/tools/ragel5/rlgen-cd/gotocodegen.cpp742
-rw-r--r--contrib/tools/ragel5/rlgen-cd/gotocodegen.h111
-rw-r--r--contrib/tools/ragel5/rlgen-cd/ipgotocodegen.cpp414
-rw-r--r--contrib/tools/ragel5/rlgen-cd/ipgotocodegen.h97
-rw-r--r--contrib/tools/ragel5/rlgen-cd/main.cpp394
-rw-r--r--contrib/tools/ragel5/rlgen-cd/rlgen-cd.h60
-rw-r--r--contrib/tools/ragel5/rlgen-cd/splitcodegen.cpp521
-rw-r--r--contrib/tools/ragel5/rlgen-cd/splitcodegen.h71
-rw-r--r--contrib/tools/ragel5/rlgen-cd/tabcodegen.cpp988
-rw-r--r--contrib/tools/ragel5/rlgen-cd/tabcodegen.h115
-rw-r--r--contrib/tools/ragel5/rlgen-cd/ya.make25
21 files changed, 6627 insertions, 0 deletions
diff --git a/contrib/tools/ragel5/rlgen-cd/fflatcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/fflatcodegen.cpp
new file mode 100644
index 0000000000..813347fd2b
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fflatcodegen.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "fflatcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &FFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+/* Write out the function for a transition. */
+std::ostream &FFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FFlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FFlatCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void FFlatCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FFlatCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out << ";\n";
+ out << " int _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+
+ out << ";\n";
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxCond) << POINTER() << "_conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << CS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << CS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << CS() << ";\n";
+
+ out <<
+ " " << CS() << " = " << TT() << "[_trans];\n\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << CS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void FFlatCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " switch ( " << EA() << "[" << CS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/fflatcodegen.h b/contrib/tools/ragel5/rlgen-cd/fflatcodegen.h
new file mode 100644
index 0000000000..cf92fd9baf
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fflatcodegen.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FFLATCODEGEN_H
+#define _FFLATCODEGEN_H
+
+#include <iostream>
+#include "flatcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * FFlatCodeGen
+ */
+class FFlatCodeGen : public FlatCodeGen
+{
+protected:
+ FFlatCodeGen( ostream &out ) : FsmCodeGen(out), FlatCodeGen(out) {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+};
+
+/*
+ * CFFlatCodeGen
+ */
+struct CFFlatCodeGen
+ : public FFlatCodeGen, public CCodeGen
+{
+ CFFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FFlatCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DFFlatCodeGen
+ */
+struct DFFlatCodeGen
+ : public FFlatCodeGen, public DCodeGen
+{
+ DFFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FFlatCodeGen(out), DCodeGen(out) {}
+};
+
+#endif /* _FFLATCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/fgotocodegen.cpp b/contrib/tools/ragel5/rlgen-cd/fgotocodegen.cpp
new file mode 100644
index 0000000000..9c4f039f39
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fgotocodegen.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "fgotocodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+std::ostream &FGotoCodeGen::EXEC_ACTIONS()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* We are at the start of a glob, write the case. */
+ out << "f" << redAct->actListId << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tgoto _again;\n";
+ }
+ }
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FGotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FGotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FGotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FGotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Jump to the func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+unsigned int FGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ return act;
+}
+
+unsigned int FGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ return act;
+}
+
+unsigned int FGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ return act;
+}
+
+void FGotoCodeGen::writeData()
+{
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FGotoCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << CS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << CS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_ACTIONS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << CS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void FGotoCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " switch ( " << EA() << "[" << CS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/fgotocodegen.h b/contrib/tools/ragel5/rlgen-cd/fgotocodegen.h
new file mode 100644
index 0000000000..076f5c4f7f
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fgotocodegen.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FGOTOCODEGEN_H
+#define _FGOTOCODEGEN_H
+
+#include <iostream>
+#include "gotocodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * class FGotoCodeGen
+ */
+class FGotoCodeGen : public GotoCodeGen
+{
+public:
+ FGotoCodeGen( ostream &out ) : FsmCodeGen(out), GotoCodeGen(out) {}
+
+ std::ostream &EXEC_ACTIONS();
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &FINISH_CASES();
+ std::ostream &EOF_ACTION_SWITCH();
+ unsigned int TO_STATE_ACTION( RedStateAp *state );
+ unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ unsigned int EOF_ACTION( RedStateAp *state );
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+};
+
+/*
+ * class CFGotoCodeGen
+ */
+struct CFGotoCodeGen
+ : public FGotoCodeGen, public CCodeGen
+{
+ CFGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), FGotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DFGotoCodeGen
+ */
+struct DFGotoCodeGen
+ : public FGotoCodeGen, public DCodeGen
+{
+ DFGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), FGotoCodeGen(out), DCodeGen(out) {}
+};
+
+#endif /* _FGOTOCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/flatcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/flatcodegen.cpp
new file mode 100644
index 0000000000..117f3798c9
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/flatcodegen.cpp
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "flatcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+std::ostream &FlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::FLAT_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->transList != 0 )
+ curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->transList != 0 )
+ span = keyOps->span( st->lowKey, st->highKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just cond low key and cond high key. */
+ out << KEY( st->condLowKey ) << ", ";
+ out << KEY( st->condHighKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::COND_KEY_SPANS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ unsigned long long span = 0;
+ if ( st->condList != 0 )
+ span = keyOps->span( st->condLowKey, st->condHighKey );
+ out << span;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::CONDS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->condList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ if ( st->condList[pos] != 0 )
+ out << st->condList[pos]->condSpaceId + 1 << ", ";
+ else
+ out << "0, ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::COND_INDEX_OFFSET()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ if ( st->condList != 0 )
+ curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit just low key and high key. */
+ out << KEY( st->lowKey ) << ", ";
+ out << KEY( st->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->transList != 0 ) {
+ /* Walk the singles. */
+ unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+ for ( unsigned long long pos = 0; pos < span; pos++ ) {
+ out << st->transList[pos]->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 )
+ out << st->defTrans->id << ", ";
+
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &FlatCodeGen::TRANS_TARGS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write out the target state. */
+ RedTransAp *trans = transPtrs[t];
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &FlatCodeGen::TRANS_ACTIONS()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void FlatCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << ARR_OFF( K(), "(" + CS() + "<<1)" ) << ";\n"
+ " _inds = " << ARR_OFF( I(), IO() + "[" + CS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << SP() << "[" << CS() << "];\n"
+ " _trans = _inds[ _slen > 0 && _keys[0] <=" << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= _keys[1] ?\n"
+ " " << GET_WIDE_KEY() << " - _keys[0] : _slen ];\n"
+ "\n";
+}
+
+void FlatCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void FlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << CS() << ")";
+}
+
+void FlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << CS() << " = " << nextDest << ";";
+}
+
+void FlatCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void FlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+}
+
+
+void FlatCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+
+void FlatCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void FlatCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << CTRL_FLOW() << "goto _out;";
+}
+
+void FlatCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+ COND_KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+ CONDS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+ COND_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+ KEY_SPANS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+ FLAT_INDEX_OFFSET();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FlatCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n";
+
+ out <<
+ " _keys = " << ARR_OFF( CK(), "(" + CS() + "<<1)" ) << ";\n"
+ " _conds = " << ARR_OFF( C(), CO() + "[" + CS() + "]" ) << ";\n"
+ "\n"
+ " _slen = " << CSP() << "[" << CS() << "];\n"
+ " _cond = _slen > 0 && _keys[0] <=" << GET_WIDE_KEY() << " &&\n"
+ " " << GET_WIDE_KEY() << " <= _keys[1] ?\n"
+ " _conds[" << GET_WIDE_KEY() << " - _keys[0]] : 0;\n"
+ "\n";
+
+ out <<
+ " switch ( _cond ) {\n";
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ CondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId + 1 << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out << " }\n";
+ out << " break;\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n";
+}
+
+void FlatCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _slen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " int _trans";
+
+ if ( redFsm->anyConditions() )
+ out << ", _cond";
+ out << ";\n";
+
+ if ( redFsm->anyToStateActions() ||
+ redFsm->anyRegActions() || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxIndex) << POINTER() << "_inds;\n";
+
+ if ( redFsm->anyConditions() ) {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxCond) << POINTER() << "_conds;\n"
+ " " << WIDE_ALPH_TYPE() << " _widec;\n";
+ }
+
+ out << "\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << CS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << CS() << ";\n";
+
+ out <<
+ " " << CS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << ARR_OFF( A(), TA() + "[_trans]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *(_acts++) )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void FlatCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts = " <<
+ ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
+ " " << UINT() << " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/flatcodegen.h b/contrib/tools/ragel5/rlgen-cd/flatcodegen.h
new file mode 100644
index 0000000000..27dee2ef92
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/flatcodegen.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2004-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLATCODEGEN_H
+#define _FLATCODEGEN_H
+
+#include <iostream>
+#include "fsmcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * FlatCodeGen
+ */
+class FlatCodeGen : virtual public FsmCodeGen
+{
+public:
+ FlatCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ virtual ~FlatCodeGen() { }
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &FLAT_INDEX_OFFSET();
+ std::ostream &KEY_SPANS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ void LOCATE_TRANS();
+
+ std::ostream &COND_INDEX_OFFSET();
+ void COND_TRANSLATE();
+ std::ostream &CONDS();
+ std::ostream &COND_KEYS();
+ std::ostream &COND_KEY_SPANS();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+};
+
+/*
+ * CFlatCodeGen
+ */
+struct CFlatCodeGen
+ : public FlatCodeGen, public CCodeGen
+{
+ CFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FlatCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DFlatCodeGen
+ */
+struct DFlatCodeGen
+ : public FlatCodeGen, public DCodeGen
+{
+ DFlatCodeGen( ostream &out ) :
+ FsmCodeGen(out), FlatCodeGen(out), DCodeGen(out) {}
+};
+
+#endif /* _FLATCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/fsmcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/fsmcodegen.cpp
new file mode 100644
index 0000000000..c0fc4b00f5
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fsmcodegen.cpp
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "fsmcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include <sstream>
+#include <string>
+#include <assert.h>
+
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+void lineDirective( ostream &out, char *fileName, int line )
+{
+ if ( noLineDirectives )
+ out << "/* ";
+
+ /* Write the preprocessor line info for to the input file. */
+ out << "#line " << line << " \"";
+ for ( char *pc = fileName; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ out << "\\\\";
+ else
+ out << *pc;
+ }
+ out << '"';
+
+ if ( noLineDirectives )
+ out << " */";
+
+ out << '\n';
+}
+
+void genLineDirective( ostream &out )
+{
+ std::streambuf *sbuf = out.rdbuf();
+ output_filter *filter = static_cast<output_filter*>(sbuf);
+ lineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+
+/* Init code gen with in parameters. */
+FsmCodeGen::FsmCodeGen( ostream &out )
+:
+ CodeGenData(out)
+{
+}
+
+unsigned int FsmCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+ return arrayType->size;
+}
+
+string FsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
+{
+ long long maxValLL = (long long) maxVal;
+ HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+ assert( arrayType != 0 );
+
+ string ret = arrayType->data1;
+ if ( arrayType->data2 != 0 ) {
+ ret += " ";
+ ret += arrayType->data2;
+ }
+ return ret;
+}
+
+
+/* Write out the fsm name. */
+string FsmCodeGen::FSM_NAME()
+{
+ return fsmName;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string FsmCodeGen::START_STATE_ID()
+{
+ ostringstream ret;
+ ret << redFsm->startState->id;
+ return ret.str();
+};
+
+/* Write out the array of actions. */
+std::ostream &FsmCodeGen::ACTIONS_ARRAY()
+{
+ out << "\t0, ";
+ int totalActions = 1;
+ for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ /* Write out the length, which will never be the last character. */
+ out << act->key.length() << ", ";
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+
+ for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
+ out << item->value->actionId;
+ if ( ! (act.last() && item.last()) )
+ out << ", ";
+
+ /* Put in a line break every 8 */
+ if ( totalActions++ % 8 == 7 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+string FsmCodeGen::CS()
+{
+ ostringstream ret;
+ if ( curStateExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, curStateExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << ACCESS() << "cs";
+ }
+ return ret.str();
+}
+
+string FsmCodeGen::ACCESS()
+{
+ ostringstream ret;
+ if ( accessExpr != 0 )
+ INLINE_LIST( ret, accessExpr, 0, false );
+ return ret.str();
+}
+
+string FsmCodeGen::GET_WIDE_KEY()
+{
+ if ( redFsm->anyConditions() )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string FsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+ if ( state->stateCondList.length() > 0 )
+ return "_widec";
+ else
+ return GET_KEY();
+}
+
+string FsmCodeGen::GET_KEY()
+{
+ ostringstream ret;
+ if ( getKeyExpr != 0 ) {
+ /* Emit the user supplied method of retrieving the key. */
+ ret << "(";
+ INLINE_LIST( ret, getKeyExpr, 0, false );
+ ret << ")";
+ }
+ else {
+ /* Expression for retrieving the key, use simple dereference. */
+ ret << "(*" << P() << ")";
+ }
+ return ret.str();
+}
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string FsmCodeGen::TABS( int level )
+{
+ string result;
+ while ( level-- > 0 )
+ result += "\t";
+ return result;
+}
+
+/* Write out a key from the fsm code gen. Depends on wether or not the key is
+ * signed. */
+string FsmCodeGen::KEY( Key key )
+{
+ ostringstream ret;
+ if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+ ret << key.getVal();
+ else
+ ret << (unsigned long) key.getVal() << 'u';
+ return ret.str();
+}
+
+void FsmCodeGen::EXEC( ostream &ret, InlineItem *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 << "{" << P() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "))-1;}";
+}
+
+void FsmCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
+{
+ /* Tokend version of exec. */
+
+ /* 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 << "{" << TOKEND() << " = ((";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "));}";
+}
+
+
+void FsmCodeGen::LM_SWITCH( ostream &ret, InlineItem *item,
+ int targState, int inFinish )
+{
+ ret <<
+ " switch( " << ACT() << " ) {\n";
+
+ /* If the switch handles error then we also forced the error state. It
+ * will exist. */
+ if ( item->handlesError ) {
+ ret << " case 0: " << TOKEND() << " = " << TOKSTART() << "; ";
+ GOTO( ret, redFsm->errState->id, inFinish );
+ ret << "\n";
+ }
+
+ for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+ /* Write the case label, the action and the case break. */
+ ret << " case " << lma->lmId << ":\n";
+
+ /* Write the block and close it off. */
+ ret << " {";
+ INLINE_LIST( ret, lma->children, targState, inFinish );
+ ret << "}\n";
+
+ ret << " break;\n";
+ }
+ /* Default required for D code. */
+ ret <<
+ " default: break;\n"
+ " }\n"
+ "\t";
+}
+
+void FsmCodeGen::SET_ACT( ostream &ret, InlineItem *item )
+{
+ ret << ACT() << " = " << item->lmId << ";";
+}
+
+void FsmCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
+{
+ /* The tokend action sets tokend. */
+ ret << TOKEND() << " = " << P();
+ if ( item->offset != 0 )
+ out << "+" << item->offset;
+ out << ";";
+}
+
+void FsmCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
+{
+ ret << TOKEND();
+}
+
+void FsmCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
+{
+ ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void FsmCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
+{
+ ret << ACT() << " = 0;";
+}
+
+void FsmCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
+{
+ ret << TOKSTART() << " = " << P() << ";";
+}
+
+void FsmCodeGen::SUB_ACTION( ostream &ret, InlineItem *item,
+ int targState, bool inFinish )
+{
+ if ( item->children->length() > 0 ) {
+ /* Write the block and close it off. */
+ ret << "{";
+ INLINE_LIST( ret, item->children, targState, inFinish );
+ ret << "}";
+ }
+}
+
+
+/* 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 FsmCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList,
+ int targState, bool inFinish )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Text:
+ ret << item->data;
+ break;
+ case InlineItem::Goto:
+ GOTO( ret, item->targState->id, inFinish );
+ break;
+ case InlineItem::Call:
+ CALL( ret, item->targState->id, targState, inFinish );
+ break;
+ case InlineItem::Next:
+ NEXT( ret, item->targState->id, inFinish );
+ break;
+ case InlineItem::Ret:
+ RET( ret, inFinish );
+ break;
+ case InlineItem::PChar:
+ ret << P();
+ break;
+ case InlineItem::Char:
+ ret << GET_KEY();
+ break;
+ case InlineItem::Hold:
+ ret << P() << "--;";
+ break;
+ case InlineItem::Exec:
+ EXEC( ret, item, targState, inFinish );
+ break;
+ case InlineItem::HoldTE:
+ ret << TOKEND() << "--;";
+ break;
+ case InlineItem::ExecTE:
+ EXECTE( ret, item, targState, inFinish );
+ break;
+ case InlineItem::Curs:
+ CURS( ret, inFinish );
+ break;
+ case InlineItem::Targs:
+ TARGS( ret, inFinish, targState );
+ break;
+ case InlineItem::Entry:
+ ret << item->targState->id;
+ break;
+ case InlineItem::GotoExpr:
+ GOTO_EXPR( ret, item, inFinish );
+ break;
+ case InlineItem::CallExpr:
+ CALL_EXPR( ret, item, targState, inFinish );
+ break;
+ case InlineItem::NextExpr:
+ NEXT_EXPR( ret, item, inFinish );
+ break;
+ case InlineItem::LmSwitch:
+ LM_SWITCH( ret, item, targState, inFinish );
+ break;
+ case InlineItem::LmSetActId:
+ SET_ACT( ret, item );
+ break;
+ case InlineItem::LmSetTokEnd:
+ SET_TOKEND( ret, item );
+ break;
+ case InlineItem::LmGetTokEnd:
+ GET_TOKEND( ret, item );
+ break;
+ case InlineItem::LmInitTokStart:
+ INIT_TOKSTART( ret, item );
+ break;
+ case InlineItem::LmInitAct:
+ INIT_ACT( ret, item );
+ break;
+ case InlineItem::LmSetTokStart:
+ SET_TOKSTART( ret, item );
+ break;
+ case InlineItem::SubAction:
+ SUB_ACTION( ret, item, targState, inFinish );
+ break;
+ case InlineItem::Break:
+ BREAK( ret, targState );
+ break;
+ }
+ }
+}
+/* Write out paths in line directives. Escapes any special characters. */
+string FsmCodeGen::LDIR_PATH( char *path )
+{
+ ostringstream ret;
+ for ( char *pc = path; *pc != 0; pc++ ) {
+ if ( *pc == '\\' )
+ ret << "\\\\";
+ else
+ ret << *pc;
+ }
+ return ret.str();
+}
+
+void FsmCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
+{
+ /* Write the preprocessor line info for going into the source file. */
+ lineDirective( ret, sourceFileName, action->loc.line );
+
+ /* Write the block and close it off. */
+ ret << "\t{";
+ INLINE_LIST( ret, action->inlineList, targState, inFinish );
+ ret << "}\n";
+}
+
+void FsmCodeGen::CONDITION( ostream &ret, Action *condition )
+{
+ ret << "\n";
+ lineDirective( ret, sourceFileName, condition->loc.line );
+ INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+string FsmCodeGen::ERROR_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->errState != 0 )
+ ret << redFsm->errState->id;
+ else
+ ret << "-1";
+ return ret.str();
+}
+
+string FsmCodeGen::FIRST_FINAL_STATE()
+{
+ ostringstream ret;
+ if ( redFsm->firstFinState != 0 )
+ ret << redFsm->firstFinState->id;
+ else
+ ret << redFsm->nextStateId;
+ return ret.str();
+}
+
+void FsmCodeGen::writeInit()
+{
+ out << " {\n";
+
+ if ( redFsm->startState != 0 )
+ out << "\t" << CS() << " = " << START() << ";\n";
+
+ /* If there are any calls, then the stack top needs initialization. */
+ if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "\t" << TOP() << " = 0;\n";
+
+ if ( hasLongestMatch ) {
+ out <<
+ " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
+ " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
+ " " << ACT() << " = 0;\n";
+ }
+ out << " }\n";
+}
+
+string FsmCodeGen::DATA_PREFIX()
+{
+ if ( dataPrefix )
+ return FSM_NAME() + "_";
+ return "";
+}
+
+/* Emit the alphabet data type. */
+string FsmCodeGen::ALPH_TYPE()
+{
+ string ret = keyOps->alphType->data1;
+ if ( keyOps->alphType->data2 != 0 ) {
+ ret += " ";
+ ret += + keyOps->alphType->data2;
+ }
+ return ret;
+}
+
+/* Emit the alphabet data type. */
+string FsmCodeGen::WIDE_ALPH_TYPE()
+{
+ string ret;
+ if ( redFsm->maxKey <= keyOps->maxKey )
+ ret = ALPH_TYPE();
+ else {
+ long long maxKeyVal = redFsm->maxKey.getLongLong();
+ HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
+ assert( wideType != 0 );
+
+ ret = wideType->data1;
+ if ( wideType->data2 != 0 ) {
+ ret += " ";
+ ret += wideType->data2;
+ }
+ }
+ return ret;
+}
+
+void FsmCodeGen::STATE_IDS()
+{
+ if ( redFsm->startState != 0 )
+ STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << "};\n";
+
+ if ( writeFirstFinal )
+ STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << "};\n";
+
+ if ( writeErr )
+ STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << "};\n";
+
+ out << "\n";
+
+ if ( entryPointNames.length() > 0 ) {
+ for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+ STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
+ " = " << entryPointIds[en.pos()] << "};\n";
+ }
+ out << "\n";
+ }
+}
+
+
+/*
+ * Language specific, but style independent code generators functions.
+ */
+
+string CCodeGen::PTR_CONST()
+{
+ return "const ";
+}
+
+std::ostream &CCodeGen::OPEN_ARRAY( const string& type, const string& name )
+{
+ out << "#if defined(__GNUC__)\n";
+ out << "static __attribute__((used)) const " << type << " " << name << "[] = {\n";
+ out << "#else\n";
+ out << "static const " << type << " " << name << "[] = {\n";
+ out << "#endif\n";
+ return out;
+}
+
+std::ostream &CCodeGen::CLOSE_ARRAY()
+{
+ return out << "};\n";
+}
+
+std::ostream &CCodeGen::STATIC_VAR( const string& type, const string& name )
+{
+ out << "enum {" << name;
+ return out;
+}
+
+string CCodeGen::UINT( )
+{
+ return "unsigned int";
+}
+
+string CCodeGen::ARR_OFF( const string& ptr, const string& offset )
+{
+ return ptr + " + " + offset;
+}
+
+string CCodeGen::CAST( const string& type )
+{
+ return "(" + type + ")";
+}
+
+string CCodeGen::NULL_ITEM()
+{
+ return "0";
+}
+
+string CCodeGen::POINTER()
+{
+ return " *";
+}
+
+std::ostream &CCodeGen::SWITCH_DEFAULT()
+{
+ return out;
+}
+
+string CCodeGen::CTRL_FLOW()
+{
+ return "";
+}
+
+void CCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "#define " << DATA_PREFIX() << "ex_" << ex->name << " " <<
+ KEY(ex->key) << "\n";
+ }
+ out << "\n";
+ }
+}
+
+/*
+ * D Specific
+ */
+
+string DCodeGen::NULL_ITEM()
+{
+ return "null";
+}
+
+string DCodeGen::POINTER()
+{
+ // multiple items seperated by commas can also be pointer types.
+ return "* ";
+}
+
+string DCodeGen::PTR_CONST()
+{
+ return "";
+}
+
+std::ostream &DCodeGen::OPEN_ARRAY( const string& type, const string& name )
+{
+ out << "static const " << type << "[] " << name << " = [\n";
+ return out;
+}
+
+std::ostream &DCodeGen::CLOSE_ARRAY()
+{
+ return out << "];\n";
+}
+
+std::ostream &DCodeGen::STATIC_VAR( const string& type, const string& name )
+{
+ out << "static const " << type << " " << name;
+ return out;
+}
+
+string DCodeGen::ARR_OFF( const string& ptr, const string& offset )
+{
+ return "&" + ptr + "[" + offset + "]";
+}
+
+string DCodeGen::CAST( const string& type )
+{
+ return "cast(" + type + ")";
+}
+
+string DCodeGen::UINT( )
+{
+ return "uint";
+}
+
+std::ostream &DCodeGen::SWITCH_DEFAULT()
+{
+ out << " default: break;\n";
+ return out;
+}
+
+string DCodeGen::CTRL_FLOW()
+{
+ return "if (true) ";
+}
+
+void DCodeGen::writeExports()
+{
+ if ( exportList.length() > 0 ) {
+ for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+ out << "static const " << ALPH_TYPE() << " " << DATA_PREFIX() <<
+ "ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
+ }
+ out << "\n";
+ }
+}
+
+/*
+ * End D-specific code.
+ */
+
+void FsmCodeGen::finishRagelDef()
+{
+ if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
+ codeStyle == GenIpGoto || codeStyle == GenSplit )
+ {
+ /* For directly executable machines there is no required state
+ * ordering. Choose a depth-first ordering to increase the
+ * potential for fall-throughs. */
+ redFsm->depthFirstOrdering();
+ }
+ else {
+ /* The frontend will do this for us, but it may be a good idea to
+ * force it if the intermediate file is edited. */
+ redFsm->sortByStateId();
+ }
+
+ /* Choose default transitions and the single transition. */
+ redFsm->chooseDefaultSpan();
+
+ /* Maybe do flat expand, otherwise choose single. */
+ if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+ redFsm->makeFlat();
+ else
+ redFsm->chooseSingle();
+
+ /* If any errors have occured in the input file then don't write anything. */
+ if ( gblErrorCount > 0 )
+ return;
+
+ if ( codeStyle == GenSplit )
+ redFsm->partitionFsm( numSplitPartitions );
+
+ if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+ 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. */
+ analyzeMachine();
+
+ /* Determine if we should use indicies. */
+ calcIndexSize();
+}
+
+ostream &FsmCodeGen::source_warning( const InputLoc &loc )
+{
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+ return cerr;
+}
+
+ostream &FsmCodeGen::source_error( const InputLoc &loc )
+{
+ gblErrorCount += 1;
+ assert( sourceFileName != 0 );
+ cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+ return cerr;
+}
+
diff --git a/contrib/tools/ragel5/rlgen-cd/fsmcodegen.h b/contrib/tools/ragel5/rlgen-cd/fsmcodegen.h
new file mode 100644
index 0000000000..77c76f1b1a
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/fsmcodegen.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FSMCODEGEN_H
+#define _FSMCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+
+using std::string;
+using std::ostream;
+
+/* Integer array line length. */
+#define IALL 8
+
+/* Forwards. */
+struct RedFsmAp;
+struct RedStateAp;
+struct CodeGenData;
+struct Action;
+struct NameInst;
+struct InlineItem;
+struct InlineList;
+struct RedAction;
+struct LongestMatch;
+struct LongestMatchPart;
+
+inline string itoa( int i )
+{
+ char buf[16];
+ sprintf( buf, "%i", i );
+ return buf;
+}
+
+/*
+ * class FsmCodeGen
+ */
+class FsmCodeGen : public CodeGenData
+{
+public:
+ FsmCodeGen( ostream &out );
+ virtual ~FsmCodeGen() {}
+
+ virtual void finishRagelDef();
+ virtual void writeInit();
+
+protected:
+ string FSM_NAME();
+ string START_STATE_ID();
+ ostream &ACTIONS_ARRAY();
+ string GET_WIDE_KEY();
+ string GET_WIDE_KEY( RedStateAp *state );
+ string TABS( int level );
+ string KEY( Key key );
+ string LDIR_PATH( char *path );
+ void ACTION( ostream &ret, Action *action, int targState, bool inFinish );
+ void CONDITION( ostream &ret, Action *condition );
+ string ALPH_TYPE();
+ string WIDE_ALPH_TYPE();
+ string ARRAY_TYPE( unsigned long maxVal );
+
+ virtual string ARR_OFF( const string& ptr, const string& offset ) = 0;
+ virtual string CAST( const string& type ) = 0;
+ virtual string UINT() = 0;
+ virtual string NULL_ITEM() = 0;
+ virtual string POINTER() = 0;
+ virtual string GET_KEY();
+ virtual ostream &SWITCH_DEFAULT() = 0;
+
+ string P() { return "p"; }
+ string PE() { return "pe"; }
+
+ string ACCESS();
+ string CS();
+ string STACK() { return ACCESS() + "stack"; }
+ string TOP() { return ACCESS() + "top"; }
+ string TOKSTART() { return ACCESS() + "tokstart"; }
+ string TOKEND() { return ACCESS() + "tokend"; }
+ string ACT() { return ACCESS() + "act"; }
+
+ string DATA_PREFIX();
+ string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
+ string C() { return "_" + DATA_PREFIX() + "cond_spaces"; }
+ string CK() { return "_" + DATA_PREFIX() + "cond_keys"; }
+ string K() { return "_" + DATA_PREFIX() + "trans_keys"; }
+ string I() { return "_" + DATA_PREFIX() + "indicies"; }
+ string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; }
+ string KO() { return "_" + DATA_PREFIX() + "key_offsets"; }
+ string IO() { return "_" + DATA_PREFIX() + "index_offsets"; }
+ string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; }
+ string SL() { return "_" + DATA_PREFIX() + "single_lengths"; }
+ string RL() { return "_" + DATA_PREFIX() + "range_lengths"; }
+ string A() { return "_" + DATA_PREFIX() + "actions"; }
+ string TA() { return "_" + DATA_PREFIX() + "trans_actions_wi"; }
+ string TT() { return "_" + DATA_PREFIX() + "trans_targs_wi"; }
+ string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; }
+ string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; }
+ string EA() { return "_" + DATA_PREFIX() + "eof_actions"; }
+ string SP() { return "_" + DATA_PREFIX() + "key_spans"; }
+ string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; }
+ string START() { return DATA_PREFIX() + "start"; }
+ string ERROR() { return DATA_PREFIX() + "error"; }
+ string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
+ string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+
+ void INLINE_LIST( ostream &ret, InlineList *inlineList, int targState, bool inFinish );
+ virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+ virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0;
+ virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+ virtual void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish ) = 0;
+ virtual void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish ) = 0;
+ virtual void CALL_EXPR( ostream &ret, InlineItem *ilItem,
+ int targState, bool inFinish ) = 0;
+ virtual void RET( ostream &ret, bool inFinish ) = 0;
+ virtual void BREAK( ostream &ret, int targState ) = 0;
+ virtual void CURS( ostream &ret, bool inFinish ) = 0;
+ virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0;
+ void EXEC( ostream &ret, InlineItem *item, int targState, int inFinish );
+ void EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish );
+ void LM_SWITCH( ostream &ret, InlineItem *item, int targState, int inFinish );
+ void SET_ACT( ostream &ret, InlineItem *item );
+ void INIT_TOKSTART( ostream &ret, InlineItem *item );
+ void INIT_ACT( ostream &ret, InlineItem *item );
+ void SET_TOKSTART( ostream &ret, InlineItem *item );
+ void SET_TOKEND( ostream &ret, InlineItem *item );
+ void GET_TOKEND( ostream &ret, InlineItem *item );
+ void SUB_ACTION( ostream &ret, InlineItem *item,
+ int targState, bool inFinish );
+ void STATE_IDS();
+
+ string ERROR_STATE();
+ string FIRST_FINAL_STATE();
+
+ virtual string PTR_CONST() = 0;
+ virtual ostream &OPEN_ARRAY( const string& type, const string& name ) = 0;
+ virtual ostream &CLOSE_ARRAY() = 0;
+ virtual ostream &STATIC_VAR( const string& type, const string& name ) = 0;
+
+ virtual string CTRL_FLOW() = 0;
+
+ ostream &source_warning(const InputLoc &loc);
+ ostream &source_error(const InputLoc &loc);
+
+ unsigned int arrayTypeSize( unsigned long maxVal );
+
+ bool outLabelUsed;
+ bool againLabelUsed;
+ bool useIndicies;
+
+public:
+ /* Determine if we should use indicies. */
+ virtual void calcIndexSize() {}
+};
+
+class CCodeGen : virtual public FsmCodeGen
+{
+public:
+ CCodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( const string& type, const string& name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( const string& type, const string& name );
+ virtual string ARR_OFF( const string& ptr, const string& offset );
+ virtual string CAST( const string& type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+};
+
+class DCodeGen : virtual public FsmCodeGen
+{
+public:
+ DCodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+ virtual string NULL_ITEM();
+ virtual string POINTER();
+ virtual ostream &SWITCH_DEFAULT();
+ virtual ostream &OPEN_ARRAY( const string& type, const string& name );
+ virtual ostream &CLOSE_ARRAY();
+ virtual ostream &STATIC_VAR( const string& type, const string& name );
+ virtual string ARR_OFF( const string& ptr, const string& offset );
+ virtual string CAST( const string& type );
+ virtual string UINT();
+ virtual string PTR_CONST();
+ virtual string CTRL_FLOW();
+
+ virtual void writeExports();
+};
+
+#endif /* _FSMCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/ftabcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/ftabcodegen.cpp
new file mode 100644
index 0000000000..1d65e7102c
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/ftabcodegen.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "ftabcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void FTabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &FTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->actListId+1;
+ out << act;
+ return out;
+}
+
+std::ostream &FTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->actListId+1;
+ out << act;
+ return out;
+}
+
+
+/* Write out the function for a transition. */
+std::ostream &FTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ int action = 0;
+ if ( trans->action != 0 )
+ action = trans->action->actListId+1;
+ out << action;
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numToStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numFromStateRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &FTabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numEofRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, true );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &FTabCodeGen::ACTION_SWITCH()
+{
+ /* Loop the actions. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ /* Write the entry label. */
+ out << "\tcase " << redAct->actListId+1 << ":\n";
+
+ /* Write each action in the list of action items. */
+ for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+ ACTION( out, item->value, 0, false );
+
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void FTabCodeGen::writeData()
+{
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void FTabCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ " int _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << CS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " switch ( " << FSA() << "[" << CS() << "] ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << CS() << ";\n";
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ out <<
+ " " << CS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " switch ( " << TA() << "[_trans] ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " switch ( " << TSA() << "[" << CS() << "] ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+
+void FTabCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " switch ( " << EA() << "[" << CS() << "] ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/ftabcodegen.h b/contrib/tools/ragel5/rlgen-cd/ftabcodegen.h
new file mode 100644
index 0000000000..9d26d1cadd
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/ftabcodegen.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FTABCODEGEN_H
+#define _FTABCODEGEN_H
+
+#include <iostream>
+#include "tabcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+
+/*
+ * FTabCodeG\verb|e
+ */
+class FTabCodeGen : public TabCodeGen
+{
+protected:
+ FTabCodeGen( ostream &out ) : FsmCodeGen(out), TabCodeGen(out) {}
+
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+ virtual void calcIndexSize();
+};
+
+
+/*
+ * CFTabCodeGen
+ */
+struct CFTabCodeGen
+ : public FTabCodeGen, public CCodeGen
+{
+ CFTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), FTabCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DFTabCodeGen
+ */
+struct DFTabCodeGen
+ : public FTabCodeGen, public DCodeGen
+{
+ DFTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), FTabCodeGen(out), DCodeGen(out) {}
+};
+
+#endif /* _FTABCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/gotocodegen.cpp b/contrib/tools/ragel5/rlgen-cd/gotocodegen.cpp
new file mode 100644
index 0000000000..13be67d097
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/gotocodegen.cpp
@@ -0,0 +1,742 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "gotocodegen.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+/* Emit the goto to take for a given transition. */
+std::ostream &GotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ return out;
+}
+
+std::ostream &GotoCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &GotoCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+void GotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ /* Label the state. */
+ out << "case " << state->id << ":\n";
+}
+
+
+void GotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+ /* Load up the singles. */
+ int numSingles = state->outSingle.length();
+ RedTransEl *data = state->outSingle.data;
+
+ if ( numSingles == 1 ) {
+ /* If there is a single single key then write it out as an if. */
+ out << "\tif ( " << GET_WIDE_KEY(state) << " == " <<
+ KEY(data[0].lowKey) << " )\n\t\t";
+
+ /* Virtual function for writing the target of the transition. */
+ TRANS_GOTO(data[0].value, 0) << "\n";
+ }
+ else if ( numSingles > 1 ) {
+ /* Write out single keys in a switch if there is more than one. */
+ out << "\tswitch( " << GET_WIDE_KEY(state) << " ) {\n";
+
+ /* Write out the single indicies. */
+ for ( int j = 0; j < numSingles; j++ ) {
+ out << "\t\tcase " << KEY(data[j].lowKey) << ": ";
+ TRANS_GOTO(data[j].value, 0) << "\n";
+ }
+
+ /* Emits a default case for D code. */
+ SWITCH_DEFAULT();
+
+ /* Close off the transition switch. */
+ out << "\t}\n";
+ }
+}
+
+void GotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* 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 = data[mid].lowKey == keyOps->minKey;
+ bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " <<
+ KEY(data[mid].lowKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " > " <<
+ KEY(data[mid].highKey) << " ) {\n";
+ emitRangeBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " >= " <<
+ KEY(data[mid].lowKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+ 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 ) {
+ out << TABS(level) << "if ( " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " <= " <<
+ KEY(data[mid].highKey) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid].lowKey) << " <= " <<
+ GET_WIDE_KEY(state) << " )\n";
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ TRANS_GOTO(data[mid].value, level+1) << "\n";
+ }
+ }
+}
+
+void GotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* Label the state and bail immediately. */
+ outLabelUsed = true;
+ RedStateAp *state = redFsm->errState;
+ out << "case " << state->id << ":\n";
+ out << " goto _out;\n";
+}
+
+void GotoCodeGen::COND_TRANSLATE( StateCond *stateCond, int level )
+{
+ CondSpace *condSpace = stateCond->condSpace;
+ out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(level) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+}
+
+void GotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+ /* Get the mid position, staying on the lower end of the range. */
+ int mid = (low + high) >> 1;
+ StateCond **data = state->stateCondVect.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 = data[mid]->lowKey == keyOps->minKey;
+ bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+ if ( anyLower && anyHigher ) {
+ /* Can go lower and higher than mid. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+ out << TABS(level) << "} else if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( anyLower && !anyHigher ) {
+ /* Can go lower than mid but not higher. */
+ out << TABS(level) << "if ( " << GET_KEY() << " < " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ emitCondBSearch( state, level+1, low, mid-1 );
+
+ /* if the higher is the highest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitHigh ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ else if ( !anyLower && anyHigher ) {
+ /* Can go higher than mid but not lower. */
+ out << TABS(level) << "if ( " << GET_KEY() << " > " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ emitCondBSearch( state, level+1, mid+1, high );
+
+ /* If the lower end is the lowest in the alphabet then there is no
+ * sense testing it. */
+ if ( limitLow ) {
+ out << TABS(level) << "} else {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ out << TABS(level) << "} else if ( " << GET_KEY() << " >= " <<
+ KEY(data[mid]->lowKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ }
+ 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 ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " && " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( limitLow && !limitHigh ) {
+ out << TABS(level) << "if ( " << GET_KEY() << " <= " <<
+ KEY(data[mid]->highKey) << " ) {\n";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else if ( !limitLow && limitHigh ) {
+ out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
+ GET_KEY() << " )\n {";
+ COND_TRANSLATE(data[mid], level+1);
+ out << TABS(level) << "}\n";
+ }
+ else {
+ /* Both high and low are at the limit. No tests to do. */
+ COND_TRANSLATE(data[mid], level);
+ }
+ }
+}
+
+std::ostream &GotoCodeGen::STATE_GOTOS()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &GotoCodeGen::TRANSITIONS()
+{
+ /* Emit any transitions that have functions and that go to
+ * this state. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Write the label for the transition so it can be jumped to. */
+ out << " tr" << trans->id << ": ";
+
+ /* Destination state. */
+ if ( trans->action != 0 && trans->action->anyCurStateRef() )
+ out << "_ps = " << CS() << ";";
+ out << CS() << " = " << trans->targ->id << "; ";
+
+ if ( trans->action != 0 ) {
+ /* Write out the transition func. */
+ out << "goto f" << trans->action->actListId << ";\n";
+ }
+ else {
+ /* No code to execute, just loop around. */
+ out << "goto _again;\n";
+ }
+ }
+ return out;
+}
+
+std::ostream &GotoCodeGen::EXEC_FUNCS()
+{
+ /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+ for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+ if ( redAct->numTransRefs > 0 ) {
+ out << " f" << redAct->actListId << ": " <<
+ "_acts = " << ARR_OFF(A(), itoa( redAct->location+1 ) ) << ";"
+ " goto execFuncs;\n";
+ }
+ }
+
+ out <<
+ "\n"
+ "execFuncs:\n"
+ " _nacts = *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " goto _again;\n";
+ return out;
+}
+
+unsigned int GotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ return act;
+}
+
+unsigned int GotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ return act;
+}
+
+unsigned int GotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ return act;
+}
+
+std::ostream &GotoCodeGen::TO_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = TO_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::FROM_STATE_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = FROM_STATE_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::EOF_ACTIONS()
+{
+ /* Take one off for the psuedo start state. */
+ int numStates = redFsm->stateList.length();
+ unsigned int *vals = new unsigned int[numStates];
+ memset( vals, 0, sizeof(unsigned int)*numStates );
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ vals[st->id] = EOF_ACTION(st);
+
+ out << "\t";
+ for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+ /* Write any eof action. */
+ out << vals[st];
+ if ( st < numStates-1 ) {
+ out << ", ";
+ if ( (st+1) % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] vals;
+ return out;
+}
+
+std::ostream &GotoCodeGen::FINISH_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* States that are final and have an out action need a case. */
+ if ( st->eofAction != 0 ) {
+ /* Write the case label. */
+ out << "\t\tcase " << st->id << ": ";
+
+ /* Write the goto func. */
+ out << "goto f" << st->eofAction->actListId << ";\n";
+ }
+ }
+
+ return out;
+}
+
+void GotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void GotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << CS() << ")";
+}
+
+void GotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << CS() << " = " << nextDest << ";";
+}
+
+void GotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void GotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << CTRL_FLOW() << "goto _out;";
+}
+
+void GotoCodeGen::writeData()
+{
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void GotoCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ out << "\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ out <<
+ " switch ( " << CS() << " ) {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ "\n";
+ TRANSITIONS() <<
+ "\n";
+
+ if ( redFsm->anyRegActions() )
+ EXEC_FUNCS() << "\n";
+
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+void GotoCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts = " <<
+ ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
+ " " << UINT() << " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/gotocodegen.h b/contrib/tools/ragel5/rlgen-cd/gotocodegen.h
new file mode 100644
index 0000000000..625c2c23bd
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/gotocodegen.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _GOTOCODEGEN_H
+#define _GOTOCODEGEN_H
+
+#include <iostream>
+#include "fsmcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+struct StateCond;
+
+/*
+ * Goto driven fsm.
+ */
+class GotoCodeGen : virtual public FsmCodeGen
+{
+public:
+ GotoCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+ std::ostream &STATE_GOTOS();
+ std::ostream &TRANSITIONS();
+ std::ostream &EXEC_FUNCS();
+ std::ostream &FINISH_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual unsigned int TO_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int FROM_STATE_ACTION( RedStateAp *state );
+ virtual unsigned int EOF_ACTION( RedStateAp *state );
+
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+
+ void COND_TRANSLATE( StateCond *stateCond, int level );
+ void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+ void STATE_CONDS( RedStateAp *state, bool genDefault );
+
+ virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+ void emitSingleSwitch( RedStateAp *state );
+ void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+ /* Called from STATE_GOTOS just before writing the gotos */
+ virtual void GOTO_HEADER( RedStateAp *state );
+ virtual void STATE_GOTO_ERROR();
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+};
+
+/*
+ * class CGotoCodeGen
+ */
+struct CGotoCodeGen
+ : public GotoCodeGen, public CCodeGen
+{
+ CGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), GotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DGotoCodeGen
+ */
+struct DGotoCodeGen
+ : public GotoCodeGen, public DCodeGen
+{
+ DGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), GotoCodeGen(out), DCodeGen(out) {}
+};
+
+
+#endif /* _GOTOCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.cpp b/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.cpp
new file mode 100644
index 0000000000..ed65be5fe0
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.cpp
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "ipgotocodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "bstmap.h"
+
+bool IpGotoCodeGen::useAgainLabel()
+{
+ return redFsm->anyRegActionRets() ||
+ redFsm->anyRegActionByValControl() ||
+ redFsm->anyRegNextStmt();
+}
+
+void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CTRL_FLOW() << "goto st" << gotoDest << ";}";
+}
+
+void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState <<
+ "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
+}
+
+void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << CS() << " = " << nextDest << ";";
+}
+
+void IpGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << targState;
+}
+
+void IpGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+ ret << CTRL_FLOW() << "goto _out" << targState << ";";
+}
+
+bool IpGotoCodeGen::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->numInTrans; it++ ) {
+ RedTransAp *trans = state->inTrans[it];
+ if ( trans->action != 0 && trans->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 << "tr" << 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 << " " << CS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( ActionTable::Iter item = trans->action->key; item.lte(); item++ )
+ ACTION( out, item->value, trans->targ->id, false );
+
+ /* If the action contains a next then we need to reload, otherwise
+ * jump directly to the target state. */
+ if ( trans->action->anyNextStmt() )
+ out << "\tgoto _again;\n";
+ else
+ out << "\tgoto st" << trans->targ->id << ";\n";
+ }
+ }
+
+ return anyWritten;
+}
+
+/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
+ * state. */
+void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( ActionTable::Iter item = state->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( ActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+void IpGotoCodeGen::STATE_GOTO_ERROR()
+{
+ /* In the error state we need to emit some stuff that usually goes into
+ * the header. */
+ RedStateAp *state = redFsm->errState;
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ /* No case label needed since we don't switch on the error state. */
+ if ( anyWritten )
+ genLineDirective( out );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ /* Break out here. */
+ out << " goto _out" << state->id << ";\n";
+}
+
+
+/* Emit the goto to take for a given transition. */
+std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::EXIT_STATES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->outNeeded ) {
+ outLabelUsed = true;
+ out << " _out" << st->id << ": " << CS() << " = " <<
+ st->id << "; goto _out; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::AGAIN_CASES()
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ out <<
+ " case " << st->id << ": goto st" << st->id << ";\n";
+ }
+ return out;
+}
+
+std::ostream &IpGotoCodeGen::FINISH_CASES()
+{
+ bool anyWritten = false;
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofAction != 0 ) {
+ if ( st->eofAction->eofRefs == 0 )
+ st->eofAction->eofRefs = new IntSet;
+ st->eofAction->eofRefs->insert( st->id );
+ }
+ }
+
+ for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+ if ( act->eofRefs != 0 ) {
+ for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
+ out << " case " << *pst << ": \n";
+
+ /* Remember that we wrote a trans so we know to write the
+ * line directive for going back to the output. */
+ anyWritten = true;
+
+ /* Write each action in the eof action list. */
+ for ( ActionTable::Iter item = act->key; item.lte(); item++ )
+ ACTION( out, item->value, STATE_ERR_STATE, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+ return out;
+}
+
+void IpGotoCodeGen::setLabelsNeeded( InlineList *inlineList )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Goto: case InlineItem::Call: {
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( item->children );
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void IpGotoCodeGen::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;
+
+ if ( redFsm->errState != 0 && redFsm->anyLmSwitchError() )
+ redFsm->errState->labelNeeded = true;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->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 ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( ActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( act->value->inlineList );
+ }
+ }
+ }
+ }
+
+ if ( hasEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->outNeeded = st->labelNeeded;
+ }
+ else {
+ if ( redFsm->errState != 0 )
+ redFsm->errState->outNeeded = true;
+
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Any state with a transition in that has a break will need an
+ * out label. */
+ if ( trans->action != 0 && trans->action->anyBreakStmt() )
+ trans->targ->outNeeded = true;
+ }
+ }
+}
+
+void IpGotoCodeGen::writeData()
+{
+ STATE_IDS();
+}
+
+void IpGotoCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ outLabelUsed = false;
+
+ out << " {\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << CS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << CS() << " )\n {\n";
+ STATE_GOTOS();
+ SWITCH_DEFAULT() <<
+ " }\n";
+ EXIT_STATES() <<
+ "\n";
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+}
+
+void IpGotoCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " switch ( " << CS() << " ) {\n";
+ FINISH_CASES();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.h b/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.h
new file mode 100644
index 0000000000..f32678baba
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/ipgotocodegen.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _IPGCODEGEN_H
+#define _IPGCODEGEN_H
+
+#include <iostream>
+#include "gotocodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+
+/*
+ * class FGotoCodeGen
+ */
+class IpGotoCodeGen : public GotoCodeGen
+{
+public:
+ IpGotoCodeGen( ostream &out ) : FsmCodeGen(out), GotoCodeGen(out) {}
+
+ std::ostream &EXIT_STATES();
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ std::ostream &FINISH_CASES();
+ std::ostream &AGAIN_CASES();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+ void RET( ostream &ret, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void BREAK( ostream &ret, int targState );
+
+ virtual void writeData();
+ virtual void writeEOF();
+ virtual void writeExec();
+
+protected:
+ bool useAgainLabel();
+
+ /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for
+ * each state. */
+ bool IN_TRANS_ACTIONS( RedStateAp *state );
+ void GOTO_HEADER( RedStateAp *state );
+ void STATE_GOTO_ERROR();
+
+ /* Set up labelNeeded flag for each state. */
+ void setLabelsNeeded( InlineList *inlineList );
+ void setLabelsNeeded();
+};
+
+
+/*
+ * class CIpGotoCodeGen
+ */
+struct CIpGotoCodeGen
+ : public IpGotoCodeGen, public CCodeGen
+{
+ CIpGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), IpGotoCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DIpGotoCodeGen
+ */
+struct DIpGotoCodeGen
+ : public IpGotoCodeGen, public DCodeGen
+{
+ DIpGotoCodeGen( ostream &out ) :
+ FsmCodeGen(out), IpGotoCodeGen(out), DCodeGen(out) {}
+};
+
+
+#endif /* _IPGCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/main.cpp b/contrib/tools/ragel5/rlgen-cd/main.cpp
new file mode 100644
index 0000000000..cabe4bd97d
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/main.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+#include "common.h"
+#include "rlgen-cd.h"
+#include "xmlparse.h"
+#include "pcheck.h"
+#include "vector.h"
+#include "version.h"
+
+/* Code generators. */
+#include "tabcodegen.h"
+#include "ftabcodegen.h"
+#include "flatcodegen.h"
+#include "fflatcodegen.h"
+#include "gotocodegen.h"
+#include "fgotocodegen.h"
+#include "ipgotocodegen.h"
+#include "splitcodegen.h"
+
+using std::istream;
+using std::ifstream;
+using std::ostream;
+using std::ios;
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+/* Target language and output style. */
+CodeStyleEnum codeStyle = GenTables;
+
+/* Io globals. */
+istream *inStream = 0;
+ostream *outStream = 0;
+output_filter *outFilter = 0;
+char *outputFileName = 0;
+
+/* Graphviz dot file generation. */
+bool graphvizDone = false;
+
+int numSplitPartitions = 0;
+bool noLineDirectives = false;
+bool printPrintables = false;
+
+/* Print a summary of the options. */
+void usage()
+{
+ cout <<
+"usage: " PROGNAME " [options] file\n"
+"general:\n"
+" -h, -H, -?, --help Print this usage and exit\n"
+" -v, --version Print version information and exit\n"
+" -o <file> Write output to <file>\n"
+"code generation options:\n"
+" -l Inhibit writing of #line directives\n"
+"generated code style:\n"
+" -T0 Table driven FSM (default)\n"
+" -T1 Faster table driven FSM\n"
+" -F0 Flat table driven FSM\n"
+" -F1 Faster flat table-driven FSM\n"
+" -G0 Goto-driven FSM\n"
+" -G1 Faster goto-driven FSM\n"
+" -G2 Really fast goto-driven FSM\n"
+" -P<N> N-Way Split really fast goto-driven FSM\n"
+ ;
+}
+
+/* Print version information. */
+void version()
+{
+ cout << "Ragel Code Generator for C, C++, Objective-C and D" << endl <<
+ "Version " VERSION << ", " PUBDATE << endl <<
+ "Copyright (c) 2001-2007 by Adrian Thurston" << endl;
+}
+
+/* Total error count. */
+int gblErrorCount = 0;
+
+ostream &error()
+{
+ gblErrorCount += 1;
+ cerr << PROGNAME ": ";
+ return cerr;
+}
+
+/*
+ * Callbacks invoked by the XML data parser.
+ */
+
+/* Invoked by the parser when the root element is opened. */
+ostream *openOutput( char *inputFile )
+{
+ if ( hostLangType != CCode && hostLangType != DCode ) {
+ error() << "this code generator is for C and D only" << endl;
+ exit(1);
+ }
+
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 ) {
+ char *ext = findFileExtension( inputFile );
+ if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".h" );
+ else {
+ const char *defExtension = 0;
+ switch ( hostLangType ) {
+ case CCode: defExtension = ".c"; break;
+ case DCode: defExtension = ".d"; break;
+ default: break;
+ }
+ outputFileName = fileNameFromStem( inputFile, defExtension );
+ }
+ }
+
+ /* Make sure we are not writing to the same file as the input file. */
+ if ( outputFileName != 0 && strcmp( inputFile, outputFileName ) == 0 ) {
+ error() << "output file \"" << outputFileName <<
+ "\" is the same as the input file" << endl;
+ }
+
+ if ( outputFileName != 0 ) {
+ /* Create the filter on the output and open it. */
+ outFilter = new output_filter( outputFileName );
+ outFilter->open( outputFileName, ios::out|ios::trunc );
+ if ( !outFilter->is_open() ) {
+ error() << "error opening " << outputFileName << " for writing" << endl;
+ exit(1);
+ }
+
+ /* Open the output stream, attaching it to the filter. */
+ outStream = new ostream( outFilter );
+ }
+ else {
+ /* Writing out ot std out. */
+ outStream = &cout;
+ }
+ return outStream;
+}
+
+/* Invoked by the parser when a ragel definition is opened. */
+CodeGenData *makeCodeGen( char *sourceFileName, char *fsmName,
+ ostream &out, bool wantComplete )
+{
+ CodeGenData *codeGen = 0;
+ switch ( hostLangType ) {
+ case CCode:
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new CTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new CFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new CFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new CFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new CGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new CFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new CIpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new CSplitCodeGen(out);
+ break;
+ }
+ break;
+
+ case DCode:
+ switch ( codeStyle ) {
+ case GenTables:
+ codeGen = new DTabCodeGen(out);
+ break;
+ case GenFTables:
+ codeGen = new DFTabCodeGen(out);
+ break;
+ case GenFlat:
+ codeGen = new DFlatCodeGen(out);
+ break;
+ case GenFFlat:
+ codeGen = new DFFlatCodeGen(out);
+ break;
+ case GenGoto:
+ codeGen = new DGotoCodeGen(out);
+ break;
+ case GenFGoto:
+ codeGen = new DFGotoCodeGen(out);
+ break;
+ case GenIpGoto:
+ codeGen = new DIpGotoCodeGen(out);
+ break;
+ case GenSplit:
+ codeGen = new DSplitCodeGen(out);
+ break;
+ }
+ break;
+
+ default: break;
+ }
+
+ codeGen->sourceFileName = sourceFileName;
+ codeGen->fsmName = fsmName;
+ codeGen->wantComplete = wantComplete;
+
+ return codeGen;
+}
+
+
+
+/* Main, process args and call yyparse to start scanning input. */
+int main(int argc, char **argv)
+{
+ ParamCheck pc("-:Hh?vlo:T:F:G:P:", argc, argv);
+ const char *xmlInputFileName = 0;
+
+ while ( pc.check() ) {
+ switch ( pc.state ) {
+ case ParamCheck::match:
+ switch ( pc.parameter ) {
+ /* Output. */
+ case 'o':
+ if ( *pc.parameterArg == 0 )
+ error() << "a zero length output file name was given" << endl;
+ else if ( outputFileName != 0 )
+ error() << "more than one output file name was given" << endl;
+ else {
+ /* Ok, remember the output file name. */
+ outputFileName = pc.parameterArg;
+ }
+ break;
+
+ case 'l':
+ noLineDirectives = true;
+ break;
+
+ /* Code style. */
+ case 'T':
+ if ( pc.parameterArg[0] == '0' )
+ codeStyle = GenTables;
+ else if ( pc.parameterArg[0] == '1' )
+ codeStyle = GenFTables;
+ else {
+ error() << "-T" << pc.parameterArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'F':
+ if ( pc.parameterArg[0] == '0' )
+ codeStyle = GenFlat;
+ else if ( pc.parameterArg[0] == '1' )
+ codeStyle = GenFFlat;
+ else {
+ error() << "-F" << pc.parameterArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'G':
+ if ( pc.parameterArg[0] == '0' )
+ codeStyle = GenGoto;
+ else if ( pc.parameterArg[0] == '1' )
+ codeStyle = GenFGoto;
+ else if ( pc.parameterArg[0] == '2' )
+ codeStyle = GenIpGoto;
+ else {
+ error() << "-G" << pc.parameterArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
+ break;
+ case 'P':
+ codeStyle = GenSplit;
+ numSplitPartitions = atoi( pc.parameterArg );
+ break;
+
+ /* Version and help. */
+ case 'v':
+ version();
+ exit(0);
+ case 'H': case 'h': case '?':
+ usage();
+ exit(0);
+ case '-':
+ if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
+ usage();
+ exit(0);
+ }
+ else if ( strcasecmp(pc.parameterArg, "version") == 0 ) {
+ version();
+ exit(0);
+ }
+ else {
+ error() << "--" << pc.parameterArg <<
+ " is an invalid argument" << endl;
+ break;
+ }
+ }
+ break;
+
+ case ParamCheck::invalid:
+ error() << "-" << pc.parameter << " is an invalid argument" << endl;
+ break;
+
+ case ParamCheck::noparam:
+ if ( *pc.curArg == 0 )
+ error() << "a zero length input file name was given" << endl;
+ else if ( xmlInputFileName != 0 )
+ error() << "more than one input file name was given" << endl;
+ else {
+ /* OK, Remember the filename. */
+ xmlInputFileName = pc.curArg;
+ }
+ break;
+ }
+ }
+
+ /* Bail on above errors. */
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ /* Open the input file for reading. */
+ if ( xmlInputFileName != 0 ) {
+ /* Open the input file for reading. */
+ ifstream *inFile = new ifstream( xmlInputFileName );
+ inStream = inFile;
+ if ( ! inFile->is_open() )
+ error() << "could not open " << xmlInputFileName << " for reading" << endl;
+ }
+ else {
+ xmlInputFileName = "<stdin>";
+ inStream = &cin;
+ }
+
+ /* Bail on above errors. */
+ if ( gblErrorCount > 0 )
+ exit(1);
+
+ bool wantComplete = true;
+ bool outputActive = true;
+
+ /* Parse the input! */
+ xml_parse( *inStream, xmlInputFileName, outputActive, wantComplete );
+
+ /* If writing to a file, delete the ostream, causing it to flush.
+ * Standard out is flushed automatically. */
+ if ( outputFileName != 0 ) {
+ delete outStream;
+ delete outFilter;
+ }
+
+ /* Finished, final check for errors.. */
+ if ( gblErrorCount > 0 ) {
+ /* If we opened an output file, remove it. */
+ if ( outputFileName != 0 )
+ unlink( outputFileName );
+ exit(1);
+ }
+ return 0;
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/rlgen-cd.h b/contrib/tools/ragel5/rlgen-cd/rlgen-cd.h
new file mode 100644
index 0000000000..93acd99bae
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/rlgen-cd.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _RLCODEGEN_H
+#define _RLCODEGEN_H
+
+#include <stdio.h>
+#include <iostream>
+#include "avltree.h"
+#include "vector.h"
+#include "config.h"
+
+#define PROGNAME "rlgen-cd"
+
+/* Target output style. */
+enum CodeStyleEnum
+{
+ GenTables,
+ GenFTables,
+ GenFlat,
+ GenFFlat,
+ GenGoto,
+ GenFGoto,
+ GenIpGoto,
+ GenSplit
+};
+
+extern CodeStyleEnum codeStyle;
+
+
+/* IO filenames and stream. */
+extern bool graphvizDone;
+
+extern int gblErrorCount;
+
+/* Options. */
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
+std::ostream &error();
+
+#endif /* _RLCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/splitcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/splitcodegen.cpp
new file mode 100644
index 0000000000..d703b37eea
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/splitcodegen.cpp
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2006 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "rlgen-cd.h"
+#include "splitcodegen.h"
+#include "gendata.h"
+#include <assert.h>
+
+using std::ostream;
+using std::ios;
+using std::endl;
+
+/* Emit the goto to take for a given transition. */
+std::ostream &SplitCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+ if ( trans->targ->partition == currentPartition ) {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto tr" << trans->id << ";";
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto st" << trans->targ->id << ";";
+ }
+ }
+ else {
+ if ( trans->action != 0 ) {
+ /* Go to the transition which will go to the state. */
+ out << TABS(level) << "goto ptr" << trans->id << ";";
+ trans->partitionBoundary = true;
+ }
+ else {
+ /* Go directly to the target state. */
+ out << TABS(level) << "goto pst" << trans->targ->id << ";";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+ return out;
+}
+
+/* Called from before writing the gotos for each state. */
+void SplitCodeGen::GOTO_HEADER( RedStateAp *state, bool stateInPartition )
+{
+ bool anyWritten = IN_TRANS_ACTIONS( state );
+
+ if ( state->labelNeeded )
+ out << "st" << state->id << ":\n";
+
+ if ( state->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( ActionTable::Iter item = state->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ /* Advance and test buffer pos. */
+ if ( state->labelNeeded ) {
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out" << state->id << ";\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+ }
+
+ /* Give the state a switch case. */
+ out << "case " << state->id << ":\n";
+
+ if ( state->fromStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ anyWritten = true;
+ for ( ActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, state->id, false );
+ }
+
+ if ( anyWritten )
+ genLineDirective( out );
+
+ /* Record the prev state if necessary. */
+ if ( state->anyRegCurStateRef() )
+ out << " _ps = " << state->id << ";\n";
+}
+
+std::ostream &SplitCodeGen::STATE_GOTOS( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition ) {
+ if ( st == redFsm->errState )
+ STATE_GOTO_ERROR();
+ else {
+ /* We call into the base of the goto which calls back into us
+ * using virtual functions. Set the current partition rather
+ * than coding parameter passing throughout. */
+ currentPartition = partition;
+
+ /* Writing code above state gotos. */
+ GOTO_HEADER( st, st->partition == partition );
+
+ if ( st->stateCondVect.length() > 0 ) {
+ out << " _widec = " << GET_KEY() << ";\n";
+ emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+ }
+
+ /* Try singles. */
+ if ( st->outSingle.length() > 0 )
+ emitSingleSwitch( st );
+
+ /* Default case is to binary search for the ranges, if that fails then */
+ if ( st->outRange.length() > 0 )
+ emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+ /* Write the default transition. */
+ TRANS_GOTO( st->defTrans, 1 ) << "\n";
+ }
+ }
+ }
+ return out;
+}
+
+
+std::ostream &SplitCodeGen::PART_TRANS( int partition )
+{
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ if ( trans->partitionBoundary ) {
+ out <<
+ "ptr" << trans->id << ":\n";
+
+ if ( trans->action != 0 ) {
+ /* 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 << " " << CS() << " = " << trans->targ->id << ";\n";
+
+ /* Write each action in the list. */
+ for ( ActionTable::Iter item = trans->action->key; item.lte(); item++ )
+ ACTION( out, item->value, trans->targ->id, false );
+ }
+
+ out <<
+ " goto pst" << trans->targ->id << ";\n";
+ trans->targ->partitionBoundary = true;
+ }
+ }
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partitionBoundary ) {
+ out <<
+ " pst" << st->id << ":\n"
+ " " << CS() << " = " << st->id << ";\n";
+
+ if ( st->toStateAction != 0 ) {
+ /* Remember that we wrote an action. Write every action in the list. */
+ for ( ActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
+ ACTION( out, item->value, st->id, false );
+ genLineDirective( out );
+ }
+
+ ptOutLabelUsed = true;
+ out << " goto _pt_out; \n";
+ }
+ }
+ return out;
+}
+
+std::ostream &SplitCodeGen::EXIT_STATES( int partition )
+{
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->partition == partition && st->outNeeded ) {
+ outLabelUsed = true;
+ out << " _out" << st->id << ": " << CS() << " = " <<
+ st->id << "; goto _out; \n";
+ }
+ }
+ return out;
+}
+
+
+std::ostream &SplitCodeGen::PARTITION( int partition )
+{
+ outLabelUsed = false;
+ ptOutLabelUsed = false;
+
+ /* Initialize the partition boundaries, which get set during the writing
+ * of states. After the state writing we will */
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ trans->partitionBoundary = false;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->partitionBoundary = false;
+
+ out << " " << ALPH_TYPE() << " *p = *_pp, *pe = *_ppe;\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " int _ps = 0;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( useAgainLabel() ) {
+ out <<
+ " goto _resume;\n"
+ "\n"
+ "_again:\n"
+ " switch ( " << CS() << " ) {\n";
+ AGAIN_CASES() <<
+ " default: break;\n"
+ " }\n"
+ "\n";
+
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out <<
+ "_resume:\n";
+ }
+
+ out <<
+ " switch ( " << CS() << " )\n {\n";
+ STATE_GOTOS( partition );
+ SWITCH_DEFAULT() <<
+ " }\n";
+ PART_TRANS( partition );
+ EXIT_STATES( partition );
+
+ if ( outLabelUsed ) {
+ out <<
+ "\n"
+ " _out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 0;\n";
+ }
+
+ if ( ptOutLabelUsed ) {
+ out <<
+ "\n"
+ " _pt_out:\n"
+ " *_pp = p;\n"
+ " *_ppe = pe;\n"
+ " return 1;\n";
+ }
+
+ return out;
+}
+
+std::ostream &SplitCodeGen::PART_MAP()
+{
+ int *partMap = new int[redFsm->stateList.length()];
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ partMap[st->id] = st->partition;
+
+ out << "\t";
+ int totalItem = 0;
+ for ( int i = 0; i < redFsm->stateList.length(); i++ ) {
+ out << partMap[i];
+ if ( i != redFsm->stateList.length() - 1 ) {
+ out << ", ";
+ if ( ++totalItem % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ delete[] partMap;
+ return out;
+}
+
+void SplitCodeGen::writeData()
+{
+ out <<
+ "static const int " << START() << " = " << START_STATE_ID() << ";\n"
+ "\n";
+
+ if ( writeFirstFinal ) {
+ out <<
+ "static const int " << FIRST_FINAL() << " = " << FIRST_FINAL_STATE() << ";\n"
+ "\n";
+ }
+
+ if ( writeErr ) {
+ out <<
+ "static const int " << ERROR() << " = " << ERROR_STATE() << ";\n"
+ "\n";
+ }
+
+
+ OPEN_ARRAY( ARRAY_TYPE(numSplitPartitions), PM() );
+ PART_MAP();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out << "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm );\n";
+ }
+ out << "\n";
+}
+
+std::ostream &SplitCodeGen::ALL_PARTITIONS()
+{
+ /* compute the format string. */
+ int width = 0, high = redFsm->nParts - 1;
+ while ( high > 0 ) {
+ width++;
+ high /= 10;
+ }
+ assert( width <= 8 );
+ char suffFormat[] = "_%6.6d.c";
+ suffFormat[2] = suffFormat[4] = ( '0' + width );
+
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ char suffix[10];
+ sprintf( suffix, suffFormat, p );
+ char *fn = fileNameFromStem( sourceFileName, suffix );
+ char *include = fileNameFromStem( sourceFileName, ".h" );
+
+ /* Create the filter on the output and open it. */
+ output_filter *partFilter = new output_filter( fn );
+ partFilter->open( fn, ios::out|ios::trunc );
+ if ( !partFilter->is_open() ) {
+ error() << "error opening " << fn << " for writing" << endl;
+ exit(1);
+ }
+
+ /* Attach the new file to the output stream. */
+ std::streambuf *prev_rdbuf = out.rdbuf( partFilter );
+
+ out <<
+ "#include \"" << include << "\"\n"
+ "int partition" << p << "( " << ALPH_TYPE() << " **_pp, " << ALPH_TYPE() <<
+ " **_ppe, struct " << FSM_NAME() << " *fsm )\n"
+ "{\n";
+ PARTITION( p ) <<
+ "}\n\n";
+ out.flush();
+
+ /* Fix the output stream. */
+ out.rdbuf( prev_rdbuf );
+ }
+ return out;
+}
+
+
+void SplitCodeGen::writeExec()
+{
+ /* Must set labels immediately before writing because we may depend on the
+ * noend write option. */
+ setLabelsNeeded();
+ out <<
+ " {\n"
+ " int _stat = 0;\n";
+
+ if ( hasEnd ) {
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << " goto _resume;\n";
+
+ /* In this reentry, to-state actions have already been executed on the
+ * partition-switch exit from the last partition. */
+ out << "_reenter:\n";
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n";
+ }
+
+ out << "_resume:\n";
+
+ out <<
+ " switch ( " << PM() << "[" << CS() << "] ) {\n";
+ for ( int p = 0; p < redFsm->nParts; p++ ) {
+ out <<
+ " case " << p << ":\n"
+ " _stat = partition" << p << "( &p, &pe, fsm );\n"
+ " break;\n";
+ }
+ out <<
+ " }\n"
+ " if ( _stat )\n"
+ " goto _reenter;\n";
+
+ if ( hasEnd )
+ out << " _out: {}\n";
+
+ out <<
+ " }\n";
+
+ ALL_PARTITIONS();
+}
+
+void SplitCodeGen::setLabelsNeeded( RedStateAp *fromState, InlineList *inlineList )
+{
+ for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
+ switch ( item->type ) {
+ case InlineItem::Goto: case InlineItem::Call: {
+ /* In split code gen we only need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == item->targState->partition ){
+ /* Mark the target as needing a label. */
+ item->targState->labelNeeded = true;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ if ( item->children != 0 )
+ setLabelsNeeded( fromState, item->children );
+ }
+}
+
+void SplitCodeGen::setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans )
+{
+ /* In the split code gen we don't need labels for transitions across
+ * partitions. */
+ if ( fromState->partition == trans->targ->partition ) {
+ /* If there is no action with a next statement, then the label will be
+ * needed. */
+ trans->labelNeeded = true;
+ if ( trans->action == 0 || !trans->action->anyNextStmt() )
+ trans->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 ( trans->action != 0 ) {
+ /* Loop the actions. */
+ for ( ActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
+ /* Get the action and walk it's tree. */
+ setLabelsNeeded( fromState, act->value->inlineList );
+ }
+ }
+}
+
+/* Set up labelNeeded flag for each state. */
+void SplitCodeGen::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++ )
+ trans->labelNeeded = false;
+
+ if ( redFsm->errState != 0 && redFsm->anyLmSwitchError() )
+ redFsm->errState->labelNeeded = true;
+
+ /* Walk all transitions and set only those that have targs. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ for ( RedTransList::Iter tel = st->outRange; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ for ( RedTransList::Iter tel = st->outSingle; tel.lte(); tel++ )
+ setLabelsNeeded( st, tel->value );
+
+ if ( st->defTrans != 0 )
+ setLabelsNeeded( st, st->defTrans );
+ }
+ }
+
+ if ( hasEnd ) {
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+ st->outNeeded = st->labelNeeded;
+ }
+ else {
+ if ( redFsm->errState != 0 )
+ redFsm->errState->outNeeded = true;
+
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+ /* Any state with a transition in that has a break will need an
+ * out label. */
+ if ( trans->action != 0 && trans->action->anyBreakStmt() )
+ trans->targ->outNeeded = true;
+ }
+ }
+}
+
diff --git a/contrib/tools/ragel5/rlgen-cd/splitcodegen.h b/contrib/tools/ragel5/rlgen-cd/splitcodegen.h
new file mode 100644
index 0000000000..82fc37150e
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/splitcodegen.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2006 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SPLITCODEGEN_H
+#define _SPLITCODEGEN_H
+
+#include "ipgotocodegen.h"
+
+class SplitCodeGen : public IpGotoCodeGen
+{
+public:
+ SplitCodeGen( ostream &out ) : FsmCodeGen(out), IpGotoCodeGen(out) {}
+
+ bool ptOutLabelUsed;
+
+ std::ostream &PART_MAP();
+ std::ostream &EXIT_STATES( int partition );
+ std::ostream &PART_TRANS( int partition );
+ std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+ void GOTO_HEADER( RedStateAp *state, bool stateInPartition );
+ std::ostream &STATE_GOTOS( int partition );
+ std::ostream &PARTITION( int partition );
+ std::ostream &ALL_PARTITIONS();
+ void writeData();
+ void writeExec();
+ void writeParts();
+
+ void setLabelsNeeded( RedStateAp *fromState, InlineList *inlineList );
+ void setLabelsNeeded( RedStateAp *fromState, RedTransAp *trans );
+ void setLabelsNeeded();
+
+ int currentPartition;
+};
+
+struct CSplitCodeGen
+ : public SplitCodeGen, public CCodeGen
+{
+ CSplitCodeGen( ostream &out ) :
+ FsmCodeGen(out), SplitCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * class DIpGotoCodeGen
+ */
+struct DSplitCodeGen
+ : public SplitCodeGen, public DCodeGen
+{
+ DSplitCodeGen( ostream &out ) :
+ FsmCodeGen(out), SplitCodeGen(out), DCodeGen(out) {}
+};
+
+
+#endif /* _SPLITCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/tabcodegen.cpp b/contrib/tools/ragel5/rlgen-cd/tabcodegen.cpp
new file mode 100644
index 0000000000..22f09534b2
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/tabcodegen.cpp
@@ -0,0 +1,988 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "rlgen-cd.h"
+#include "tabcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+/* Determine if we should use indicies or not. */
+void TabCodeGen::calcIndexSize()
+{
+ int sizeWithInds = 0, sizeWithoutInds = 0;
+
+ /* Calculate cost of using with indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+ }
+ sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+ if ( redFsm->anyActions() )
+ sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
+
+ /* Calculate the cost of not using indicies. */
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ int totalIndex = st->outSingle.length() + st->outRange.length() +
+ (st->defTrans == 0 ? 0 : 1);
+ sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+ if ( redFsm->anyActions() )
+ sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
+ }
+
+ /* If using indicies reduces the size, use them. */
+ useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->toStateAction != 0 )
+ act = state->toStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->fromStateAction != 0 )
+ act = state->fromStateAction->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+ int act = 0;
+ if ( state->eofAction != 0 )
+ act = state->eofAction->location+1;
+ out << act;
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+ /* If there are actions, emit them. Otherwise emit zero. */
+ int act = 0;
+ if ( trans->action != 0 )
+ act = trans->action->location+1;
+ out << act;
+ return out;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numToStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numFromStateRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numEofRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, true );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+
+std::ostream &TabCodeGen::ACTION_SWITCH()
+{
+ /* Walk the list of functions, printing the cases. */
+ for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
+ /* Write out referenced actions. */
+ if ( act->numTransRefs > 0 ) {
+ /* Write the case label, the action and the case break. */
+ out << "\tcase " << act->actionId << ":\n";
+ ACTION( out, act, 0, false );
+ out << "\tbreak;\n";
+ }
+ }
+
+ genLineDirective( out );
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->stateCondList.length();
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::KEY_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curKeyOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the key offset. */
+ out << curKeyOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the key offset ahead. */
+ curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::INDEX_OFFSETS()
+{
+ out << "\t";
+ int totalStateNum = 0, curIndOffset = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write the index offset. */
+ out << curIndOffset;
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Move the index offset ahead. */
+ curIndOffset += st->outSingle.length() + st->outRange.length();
+ if ( st->defTrans != 0 )
+ curIndOffset += 1;
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->stateCondList.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::SINGLE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write singles length. */
+ out << st->outSingle.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::RANGE_LENS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Emit length of range index. */
+ out << st->outRange.length();
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TO_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ TO_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::FROM_STATE_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ FROM_STATE_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::EOF_ACTIONS()
+{
+ out << "\t";
+ int totalStateNum = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Write any eof action. */
+ EOF_ACTION(st);
+ if ( !st.last() ) {
+ out << ", ";
+ if ( ++totalStateNum % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Lower key. */
+ out << KEY( sc->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << KEY( sc->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::COND_SPACES()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the state's transitions. */
+ for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
+ /* Cond Space id. */
+ out << sc->condSpace->condSpaceId << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::KEYS()
+{
+ out << '\t';
+ int totalTrans = 0;
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Loop the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << KEY( stel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Loop the state's transitions. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ /* Lower key. */
+ out << KEY( rtel->lowKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+
+ /* Upper key. */
+ out << KEY( rtel->highKey ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::INDICIES()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ out << stel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ out << rtel->value->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ out << st->defTrans->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TRANS_TARGS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default target state. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ out << trans->targ->id << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTIONS()
+{
+ int totalTrans = 0;
+ out << '\t';
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ /* Walk the singles. */
+ for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
+ RedTransAp *trans = stel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* Walk the ranges. */
+ for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
+ RedTransAp *trans = rtel->value;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+
+ /* The state's default index goes next. */
+ if ( st->defTrans != 0 ) {
+ RedTransAp *trans = st->defTrans;
+ TRANS_ACTION( trans ) << ", ";
+ if ( ++totalTrans % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+
+ /* Output one last number so we don't have to figure out when the last
+ * entry is and avoid writing a comma. */
+ out << 0 << "\n";
+ return out;
+}
+
+std::ostream &TabCodeGen::TRANS_TARGS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalStates = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write out the target state. */
+ RedTransAp *trans = transPtrs[t];
+ out << trans->targ->id;
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalStates % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+
+std::ostream &TabCodeGen::TRANS_ACTIONS_WI()
+{
+ /* Transitions must be written ordered by their id. */
+ RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+ for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+ transPtrs[trans->id] = trans;
+
+ /* Keep a count of the num of items in the array written. */
+ out << '\t';
+ int totalAct = 0;
+ for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+ /* Write the function for the transition. */
+ RedTransAp *trans = transPtrs[t];
+ TRANS_ACTION( trans );
+ if ( t < redFsm->transSet.length()-1 ) {
+ out << ", ";
+ if ( ++totalAct % IALL == 0 )
+ out << "\n\t";
+ }
+ }
+ out << "\n";
+ delete[] transPtrs;
+ return out;
+}
+
+void TabCodeGen::LOCATE_TRANS()
+{
+ out <<
+ " _keys = " << ARR_OFF( K(), KO() + "[" + CS() + "]" ) << ";\n"
+ " _trans = " << IO() << "[" << CS() << "];\n"
+ "\n"
+ " _klen = " << SL() << "[" << CS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_upper = _keys + _klen - 1;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + ((_upper-_lower) >> 1);\n"
+ " if ( " << GET_WIDE_KEY() << " < *_mid )\n"
+ " _upper = _mid - 1;\n"
+ " else if ( " << GET_WIDE_KEY() << " > *_mid )\n"
+ " _lower = _mid + 1;\n"
+ " else {\n"
+ " _trans += (_mid - _keys);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _keys += _klen;\n"
+ " _trans += _klen;\n"
+ " }\n"
+ "\n"
+ " _klen = " << RL() << "[" << CS() << "];\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_upper = _keys + (_klen<<1) - 2;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < _mid[0] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > _mid[1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " _trans += ((_mid - _keys)>>1);\n"
+ " goto _match;\n"
+ " }\n"
+ " }\n"
+ " _trans += _klen;\n"
+ " }\n"
+ "\n";
+}
+
+void TabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+ ret << "{" << CS() << " = " << gotoDest << "; " <<
+ CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << "{" << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::CURS( ostream &ret, bool inFinish )
+{
+ ret << "(_ps)";
+}
+
+void TabCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+ ret << "(" << CS() << ")";
+}
+
+void TabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+ ret << CS() << " = " << nextDest << ";";
+}
+
+void TabCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+ ret << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, 0, inFinish );
+ ret << ");";
+}
+
+void TabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
+ callDest << "; " << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+{
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
+ INLINE_LIST( ret, ilItem->children, targState, inFinish );
+ ret << "); " << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::RET( ostream &ret, bool inFinish )
+{
+ ret << "{" << CS() << " = " << STACK() << "[--" <<
+ TOP() << "]; " << CTRL_FLOW() << "goto _again;}";
+}
+
+void TabCodeGen::BREAK( ostream &ret, int targState )
+{
+ outLabelUsed = true;
+ ret << CTRL_FLOW() << "goto _out;";
+}
+
+void TabCodeGen::writeData()
+{
+ /* If there are any transtion functions then output the array. If there
+ * are none, don't bother emitting an empty array that won't be used. */
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+ ACTIONS_ARRAY();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+ COND_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+ COND_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+ COND_KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+ COND_SPACES();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+ KEY_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+ KEYS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+ SINGLE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+ RANGE_LENS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+ INDEX_OFFSETS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( useIndicies ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+ INDICIES();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS_WI();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+ else {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+ TRANS_TARGS();
+ CLOSE_ARRAY() <<
+ "\n";
+
+ if ( redFsm->anyActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+ TRANS_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+ }
+
+ if ( redFsm->anyToStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+ TO_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+ FROM_STATE_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ if ( redFsm->anyEofActions() ) {
+ OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+ EOF_ACTIONS();
+ CLOSE_ARRAY() <<
+ "\n";
+ }
+
+ STATE_IDS();
+}
+
+void TabCodeGen::COND_TRANSLATE()
+{
+ out <<
+ " _widec = " << GET_KEY() << ";\n"
+ " _klen = " << CL() << "[" << CS() << "];\n"
+ " _keys = " << ARR_OFF( CK(), "(" + CO() + "[" + CS() + "]*2)" ) << ";\n"
+ " if ( _klen > 0 ) {\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_lower = _keys;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_mid;\n"
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_upper = _keys + (_klen<<1) - 2;\n"
+ " while (1) {\n"
+ " if ( _upper < _lower )\n"
+ " break;\n"
+ "\n"
+ " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+ " if ( " << GET_WIDE_KEY() << " < _mid[0] )\n"
+ " _upper = _mid - 2;\n"
+ " else if ( " << GET_WIDE_KEY() << " > _mid[1] )\n"
+ " _lower = _mid + 2;\n"
+ " else {\n"
+ " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
+ " + ((_mid - _keys)>>1)] ) {\n";
+
+ for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+ CondSpace *condSpace = csi;
+ out << " case " << condSpace->condSpaceId << ": {\n";
+ out << TABS(2) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
+ KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
+ " - " << KEY(keyOps->minKey) << "));\n";
+
+ for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+ out << TABS(2) << "if ( ";
+ CONDITION( out, *csi );
+ Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+ out << " ) _widec += " << condValOffset << ";\n";
+ }
+
+ out <<
+ " break;\n"
+ " }\n";
+ }
+
+ SWITCH_DEFAULT();
+
+ out <<
+ " }\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+}
+
+void TabCodeGen::writeExec()
+{
+ outLabelUsed = false;
+
+ out <<
+ " {\n"
+ " int _klen";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << ", _ps";
+
+ out <<
+ ";\n"
+ " " << UINT() << " _trans;\n";
+
+ if ( redFsm->anyConditions() )
+ out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
+
+ if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
+ || redFsm->anyFromStateActions() )
+ {
+ out <<
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts;\n"
+ " " << UINT() << " _nacts;\n";
+ }
+
+ out <<
+ " " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
+ "\n";
+
+ if ( hasEnd ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _out;\n";
+ }
+
+ out << "_resume:\n";
+
+ if ( redFsm->errState != 0 ) {
+ outLabelUsed = true;
+ out <<
+ " if ( " << CS() << " == " << redFsm->errState->id << " )\n"
+ " goto _out;\n";
+ }
+
+ if ( redFsm->anyFromStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ FROM_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyConditions() )
+ COND_TRANSLATE();
+
+ LOCATE_TRANS();
+
+ out << "_match:\n";
+
+ if ( redFsm->anyRegCurStateRef() )
+ out << " _ps = " << CS() << ";\n";
+
+ if ( useIndicies )
+ out << " _trans = " << I() << "[_trans];\n";
+
+ out <<
+ " " << CS() << " = " << TT() << "[_trans];\n"
+ "\n";
+
+ if ( redFsm->anyRegActions() ) {
+ out <<
+ " if ( " << TA() << "[_trans] == 0 )\n"
+ " goto _again;\n"
+ "\n"
+ " _acts = " << ARR_OFF( A(), TA() + "[_trans]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 )\n {\n"
+ " switch ( *_acts++ )\n {\n";
+ ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
+ redFsm->anyActionCalls() || redFsm->anyActionRets() )
+ out << "_again:\n";
+
+ if ( redFsm->anyToStateActions() ) {
+ out <<
+ " _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
+ " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ TO_STATE_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ "\n";
+ }
+
+ if ( hasEnd ) {
+ out <<
+ " if ( ++" << P() << " != " << PE() << " )\n"
+ " goto _resume;\n";
+ }
+ else {
+ out <<
+ " " << P() << " += 1;\n"
+ " goto _resume;\n";
+ }
+
+ if ( outLabelUsed )
+ out << " _out: {}\n";
+
+ out << " }\n";
+}
+
+
+void TabCodeGen::writeEOF()
+{
+ if ( redFsm->anyEofActions() ) {
+ out <<
+ " {\n"
+ " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << POINTER() << "_acts = " <<
+ ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
+ " " << UINT() << " _nacts = " << CAST(UINT()) << " *_acts++;\n"
+ " while ( _nacts-- > 0 ) {\n"
+ " switch ( *_acts++ ) {\n";
+ EOF_ACTION_SWITCH();
+ SWITCH_DEFAULT() <<
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n";
+ }
+}
diff --git a/contrib/tools/ragel5/rlgen-cd/tabcodegen.h b/contrib/tools/ragel5/rlgen-cd/tabcodegen.h
new file mode 100644
index 0000000000..745eb18d81
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/tabcodegen.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
+ * 2004 Erich Ocean <eric.ocean@ampede.com>
+ * 2005 Alan West <alan@alanz.com>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TABCODEGEN_H
+#define _TABCODEGEN_H
+
+#include <iostream>
+#include "fsmcodegen.h"
+
+/* Forwards. */
+struct CodeGenData;
+struct NameInst;
+struct RedTransAp;
+struct RedStateAp;
+
+/*
+ * TabCodeGen
+ */
+class TabCodeGen : virtual public FsmCodeGen
+{
+public:
+ TabCodeGen( ostream &out ) : FsmCodeGen(out) {}
+ virtual ~TabCodeGen() { }
+ virtual void writeData();
+ virtual void writeExec();
+
+protected:
+ std::ostream &TO_STATE_ACTION_SWITCH();
+ std::ostream &FROM_STATE_ACTION_SWITCH();
+ std::ostream &EOF_ACTION_SWITCH();
+ std::ostream &ACTION_SWITCH();
+
+ std::ostream &COND_KEYS();
+ std::ostream &COND_SPACES();
+ std::ostream &KEYS();
+ std::ostream &INDICIES();
+ std::ostream &COND_OFFSETS();
+ std::ostream &KEY_OFFSETS();
+ std::ostream &INDEX_OFFSETS();
+ std::ostream &COND_LENS();
+ std::ostream &SINGLE_LENS();
+ std::ostream &RANGE_LENS();
+ std::ostream &TO_STATE_ACTIONS();
+ std::ostream &FROM_STATE_ACTIONS();
+ std::ostream &EOF_ACTIONS();
+ std::ostream &TRANS_TARGS();
+ std::ostream &TRANS_ACTIONS();
+ std::ostream &TRANS_TARGS_WI();
+ std::ostream &TRANS_ACTIONS_WI();
+ void LOCATE_TRANS();
+
+ void COND_TRANSLATE();
+
+ void GOTO( ostream &ret, int gotoDest, bool inFinish );
+ void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+ void NEXT( ostream &ret, int nextDest, bool inFinish );
+ void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+ void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+ void CURS( ostream &ret, bool inFinish );
+ void TARGS( ostream &ret, bool inFinish, int targState );
+ void RET( ostream &ret, bool inFinish );
+ void BREAK( ostream &ret, int targState );
+
+ virtual std::ostream &TO_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state );
+ virtual std::ostream &EOF_ACTION( RedStateAp *state );
+ virtual std::ostream &TRANS_ACTION( RedTransAp *trans );
+ virtual void calcIndexSize();
+ virtual void writeEOF();
+};
+
+
+/*
+ * CTabCodeGen
+ */
+struct CTabCodeGen
+ : public TabCodeGen, public CCodeGen
+{
+ CTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), TabCodeGen(out), CCodeGen(out) {}
+};
+
+/*
+ * DTabCodeGen
+ */
+struct DTabCodeGen
+ : public TabCodeGen, public DCodeGen
+{
+ DTabCodeGen( ostream &out ) :
+ FsmCodeGen(out), TabCodeGen(out), DCodeGen(out) {}
+};
+
+
+#endif /* _TABCODEGEN_H */
diff --git a/contrib/tools/ragel5/rlgen-cd/ya.make b/contrib/tools/ragel5/rlgen-cd/ya.make
new file mode 100644
index 0000000000..ef2a59f8c2
--- /dev/null
+++ b/contrib/tools/ragel5/rlgen-cd/ya.make
@@ -0,0 +1,25 @@
+PROGRAM()
+
+NO_UTIL()
+NO_COMPILER_WARNINGS()
+
+PEERDIR(
+ contrib/tools/ragel5/aapl
+ contrib/tools/ragel5/common
+ contrib/tools/ragel5/redfsm
+)
+
+SRCS(
+ fflatcodegen.cpp
+ fgotocodegen.cpp
+ flatcodegen.cpp
+ fsmcodegen.cpp
+ ftabcodegen.cpp
+ gotocodegen.cpp
+ ipgotocodegen.cpp
+ main.cpp
+ splitcodegen.cpp
+ tabcodegen.cpp
+)
+
+END()