Java code generation split out into its own executable. Still needs to be
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Fri, 2 Feb 2007 05:59:48 +0000 (05:59 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Fri, 2 Feb 2007 05:59:48 +0000 (05:59 +0000)
removed from rlcodegen.

git-svn-id: http://svn.complang.org/ragel/trunk@53 052ea7fc-9027-0410-9066-f65837a77df0

12 files changed:
configure
configure.in
javagen/Makefile.in [new file with mode: 0644]
javagen/fsmcodegen.cpp [new file with mode: 0644]
javagen/fsmcodegen.h [new file with mode: 0644]
javagen/javacodegen.cpp [new file with mode: 0644]
javagen/javacodegen.h [new file with mode: 0644]
javagen/javagen.h [new file with mode: 0644]
javagen/main.cpp [new file with mode: 0644]
javagen/tabcodegen.cpp [new file with mode: 0644]
javagen/tabcodegen.h [new file with mode: 0644]
test/runtests

index f763687..1173ca2 100755 (executable)
--- a/configure
+++ b/configure
@@ -2856,7 +2856,7 @@ _ACEOF
 
 fi
 
-                                                                      ac_config_files="$ac_config_files Makefile common/Makefile ragel/Makefile redfsm/Makefile rlcodegen/Makefile doc/Makefile test/Makefile"
+                                                                                ac_config_files="$ac_config_files Makefile common/Makefile ragel/Makefile redfsm/Makefile rlcodegen/Makefile javagen/Makefile doc/Makefile test/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -3386,6 +3386,7 @@ do
   "ragel/Makefile" ) CONFIG_FILES="$CONFIG_FILES ragel/Makefile" ;;
   "redfsm/Makefile" ) CONFIG_FILES="$CONFIG_FILES redfsm/Makefile" ;;
   "rlcodegen/Makefile" ) CONFIG_FILES="$CONFIG_FILES rlcodegen/Makefile" ;;
+  "javagen/Makefile" ) CONFIG_FILES="$CONFIG_FILES javagen/Makefile" ;;
   "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
   "test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
   "common/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS common/config.h" ;;
index 3a19d53..3aaa558 100644 (file)
@@ -105,6 +105,6 @@ if test -n "$TXL"; then
 fi
 
 dnl write output files
-AC_OUTPUT(Makefile common/Makefile ragel/Makefile redfsm/Makefile rlcodegen/Makefile doc/Makefile test/Makefile)
+AC_OUTPUT(Makefile common/Makefile ragel/Makefile redfsm/Makefile rlcodegen/Makefile javagen/Makefile doc/Makefile test/Makefile)
 
 echo "configuration of ragel complete"
diff --git a/javagen/Makefile.in b/javagen/Makefile.in
new file mode 100644 (file)
index 0000000..ecb92bc
--- /dev/null
@@ -0,0 +1,71 @@
+#
+#   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 
+
+INCS += -I../common -I../redfsm -I../aapl
+DEFS +=
+
+CFLAGS += -g -Wall
+LDFLAGS +=
+
+CC_SRCS = main.cpp fsmcodegen.cpp tabcodegen.cpp javacodegen.cpp
+
+REDFSM = ../redfsm/redfsm.a
+
+LIBS += @LIBS@
+PREFIX += @prefix@
+
+#*************************************
+
+# Programs
+CXX = @CXX@
+
+# Get objects and dependencies from sources.
+OBJS = $(CC_SRCS:%.cpp=%.o)
+DEPS = $(CC_SRCS:%.cpp=.%.d)
+
+# Get the version info.
+include ../version.mk
+
+# Rules.
+all: redfsm rlcodegen-java
+
+rlcodegen-java: $(REDFSM) $(OBJS)
+       $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(REDFSM) $(LIBS)
+
+.PHONY: redfsm
+
+redfsm:
+       @cd ../redfsm && $(MAKE) 
+
+%.o: %.cpp
+       @$(CXX) -M $(DEFS) $(INCS) $< > .$*.d
+       $(CXX) -c $(CFLAGS) $(DEFS) $(INCS) -o $@ $<
+
+distclean: clean
+       rm -f Makefile
+
+clean:
+       rm -f tags .*.d *.o rlcodegen $(EXTRA_CLEAN)
+
+install: all
+       install -d $(PREFIX)/bin
+       install -s rlcodegen-java $(PREFIX)/bin/rlcodegen-java
+
+-include $(DEPS)
diff --git a/javagen/fsmcodegen.cpp b/javagen/fsmcodegen.cpp
new file mode 100644 (file)
index 0000000..982e2e6
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ *  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 "javagen.h"
+#include "redfsm.h"
+#include "gendata.h"
+#include "fsmcodegen.h"
+#include <sstream>
+#include <string>
+#include <assert.h>
+
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+
+/* 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::writeOutInit()
+{
+       out << "        {\n";
+       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;
+}
+
+
+/*
+ * Language specific, but style independent code generators functions.
+ */
+
+string CCodeGen::PTR_CONST()
+{
+       return "const ";
+}
+
+std::ostream &CCodeGen::OPEN_ARRAY( string type, string name )
+{
+       out << "static const " << type << " " << name << "[] = {\n";
+       return out;
+}
+
+std::ostream &CCodeGen::CLOSE_ARRAY()
+{
+       return out << "};\n";
+}
+
+std::ostream &CCodeGen::STATIC_VAR( string type, string name )
+{
+       out << "static const " << type << " " << name;
+       return out;
+}
+
+string CCodeGen::UINT( )
+{
+       return "unsigned int";
+}
+
+string CCodeGen::ARR_OFF( string ptr, string offset )
+{
+       return ptr + " + " + offset;
+}
+
+string CCodeGen::CAST( 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 "";
+}
+
+/*
+ * 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( string type, string name )
+{
+       out << "static const " << type << "[] " << name << " = [\n";
+       return out;
+}
+
+std::ostream &DCodeGen::CLOSE_ARRAY()
+{
+       return out << "];\n";
+}
+
+std::ostream &DCodeGen::STATIC_VAR( string type, string name )
+{
+       out << "static const " << type << " " << name;
+       return out;
+}
+
+string DCodeGen::ARR_OFF( string ptr, string offset )
+{
+       return "&" + ptr + "[" + offset + "]";
+}
+
+string DCodeGen::CAST( 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) ";
+}
+
+
+/* 
+ * Java Specific
+ */
+
+string JavaCodeGen::PTR_CONST()
+{
+       /* Not used in Java code. */
+       assert( false );
+       return "final";
+}
+
+std::ostream &JavaCodeGen::OPEN_ARRAY( string type, string name )
+{
+       out << "static final " << type << "[] " << name << " = {\n";
+       return out;
+}
+
+std::ostream &JavaCodeGen::CLOSE_ARRAY()
+{
+       return out << "};\n";
+}
+
+std::ostream &JavaCodeGen::STATIC_VAR( string type, string name )
+{
+       out << "static final " << type << " " << name;
+       return out;
+}
+
+string JavaCodeGen::UINT( )
+{
+       /* Not used. */
+       assert( false );
+       return "long";
+}
+
+string JavaCodeGen::ARR_OFF( string ptr, string offset )
+{
+       return ptr + " + " + offset;
+}
+
+string JavaCodeGen::CAST( string type )
+{
+       return "(" + type + ")";
+}
+
+string JavaCodeGen::NULL_ITEM()
+{
+       /* In java we use integers instead of pointers. */
+       return "-1";
+}
+
+string JavaCodeGen::POINTER()
+{
+       /* Not used. */
+       assert( false );
+       return " *";
+}
+
+std::ostream &JavaCodeGen::SWITCH_DEFAULT()
+{
+       return out;
+}
+
+string JavaCodeGen::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 << "data[" << P() << "]";
+       }
+       return ret.str();
+}
+
+string JavaCodeGen::CTRL_FLOW()
+{
+       return "if (true) ";
+}
+
+/* Generate the code for an fsm. Assumes parseData is set up properly. Called
+ * by parser code. */
+void FsmCodeGen::prepareMachine()
+{
+       if ( hasBeenPrepared )
+               return;
+       hasBeenPrepared = true;
+       
+       /* Do this before distributing transitions out to singles and defaults
+        * makes life easier. */
+       redFsm->maxKey = findMaxKey();
+
+       redFsm->assignActionLocs();
+
+       /* Order the states. */
+       redFsm->depthFirstOrdering();
+
+       if ( codeStyle == GenGoto || codeStyle == GenFGoto || 
+                       codeStyle == GenIpGoto || codeStyle == GenSplit )
+       {
+               /* For goto driven machines we can keep the original depth
+                * first ordering because it's ok if the state ids are not
+                * sequential. Split the the ids by final state status. */
+               redFsm->sortStateIdsByFinal();
+       }
+       else {
+               /* For table driven machines the location of the state is used to
+                * identify it so the states must be sorted by their final ids.
+                * Though having a deterministic ordering is important,
+                * specifically preserving the depth first ordering is not because
+                * states are stored in tables. */
+               redFsm->sortStatesByFinal();
+               redFsm->sequentialStateIds();
+       }
+
+       /* Find the first final state. This is the final state with the lowest
+        * id.  */
+       redFsm->findFirstFinState();
+
+       /* 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();
+}
+
+void FsmCodeGen::finishRagelDef()
+{
+       assert( outputFormat == OutCode );
+       prepareMachine();
+}
+
+void FsmCodeGen::writeStatement( InputLoc &loc, int nargs, char **args )
+{
+       if ( outputFormat == OutCode ) {
+               /* Force a newline. */
+               out << "\n";
+               genLineDirective( out );
+
+               if ( strcmp( args[0], "data" ) == 0 ) {
+                       for ( int i = 1; i < nargs; i++ ) {
+                               if ( strcmp( args[i], "noerror" ) == 0 )
+                                       writeErr = false;
+                               else if ( strcmp( args[i], "noprefix" ) == 0 )
+                                       dataPrefix = false;
+                               else if ( strcmp( args[i], "nofinal" ) == 0 )
+                                       writeFirstFinal = false;
+                               else {
+                                       source_warning(loc) << "unrecognized write option \"" << 
+                                                       args[i] << "\"" << endl;
+                               }
+                       }
+                       writeOutData();
+               }
+               else if ( strcmp( args[0], "init" ) == 0 ) {
+                       for ( int i = 1; i < nargs; i++ ) {
+                               source_warning(loc) << "unrecognized write option \"" << 
+                                               args[i] << "\"" << endl;
+                       }
+                       writeOutInit();
+               }
+               else if ( strcmp( args[0], "exec" ) == 0 ) {
+                       for ( int i = 1; i < nargs; i++ ) {
+                               if ( strcmp( args[i], "noend" ) == 0 )
+                                       hasEnd = false;
+                               else {
+                                       source_warning(loc) << "unrecognized write option \"" << 
+                                                       args[i] << "\"" << endl;
+                               }
+                       }
+
+                       /* Must set labels immediately before writing because we may depend
+                        * on the noend write option. */
+                       setLabelsNeeded();
+                       writeOutExec();
+               }
+               else if ( strcmp( args[0], "eof" ) == 0 ) {
+                       for ( int i = 1; i < nargs; i++ ) {
+                               source_warning(loc) << "unrecognized write option \"" << 
+                                               args[i] << "\"" << endl;
+                       }
+                       writeOutEOF();
+               }
+               else {
+                       /* EMIT An error here. */
+               }
+       }
+}
+
+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;
+}
+
+void genLineDirective( ostream &out )
+{
+       assert( outputFormat == OutCode );
+       std::streambuf *sbuf = out.rdbuf();
+       output_filter *filter = static_cast<output_filter*>(sbuf);
+       lineDirective( out, filter->fileName, filter->line + 1 );
+}
+
diff --git a/javagen/fsmcodegen.h b/javagen/fsmcodegen.h
new file mode 100644 (file)
index 0000000..1071190
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ *  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 writeOutData() = 0;
+       virtual void writeOutInit();
+       virtual void writeOutExec() = 0;
+       virtual void writeOutEOF() = 0;
+       
+
+protected:
+       friend struct CodeGenData;
+
+       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( string ptr, string offset ) = 0;
+       virtual string CAST( 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 );
+
+       string ERROR_STATE();
+       string FIRST_FINAL_STATE();
+
+       virtual string PTR_CONST() = 0;
+       virtual ostream &OPEN_ARRAY( string type, string name ) = 0;
+       virtual ostream &CLOSE_ARRAY() = 0;
+       virtual ostream &STATIC_VAR( string type, 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 );
+
+       /* Set up labelNeeded flag for each state. Differs for each goto style so
+        * is virtual. */
+       virtual void setLabelsNeeded() {}
+
+       bool outLabelUsed;
+       bool againLabelUsed;
+
+       bool useIndicies;
+
+public:
+       void prepareMachine();
+
+       virtual void finishRagelDef();
+       virtual void writeStatement( InputLoc &loc, int nargs, char **args );
+
+       /* 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( string type, string name );
+       virtual ostream &CLOSE_ARRAY();
+       virtual ostream &STATIC_VAR( string type, string name );
+       virtual string ARR_OFF( string ptr, string offset );
+       virtual string CAST( string type );
+       virtual string UINT();
+       virtual string PTR_CONST();
+       virtual string CTRL_FLOW();
+};
+
+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( string type, string name );
+       virtual ostream &CLOSE_ARRAY();
+       virtual ostream &STATIC_VAR( string type, string name );
+       virtual string ARR_OFF( string ptr, string offset );
+       virtual string CAST( string type );
+       virtual string UINT();
+       virtual string PTR_CONST();
+       virtual string CTRL_FLOW();
+};
+
+class JavaCodeGen : virtual public FsmCodeGen
+{
+public:
+       JavaCodeGen( ostream &out ) : FsmCodeGen(out) {}
+
+       virtual string NULL_ITEM();
+       virtual string POINTER();
+       virtual ostream &SWITCH_DEFAULT();
+       virtual ostream &OPEN_ARRAY( string type, string name );
+       virtual ostream &CLOSE_ARRAY();
+       virtual ostream &STATIC_VAR( string type, string name );
+       virtual string ARR_OFF( string ptr, string offset );
+       virtual string CAST( string type );
+       virtual string UINT();
+       virtual string PTR_CONST();
+       virtual string GET_KEY();
+       virtual string CTRL_FLOW();
+};
+
+#endif /* _FSMCODEGEN_H */
diff --git a/javagen/javacodegen.cpp b/javagen/javacodegen.cpp
new file mode 100644 (file)
index 0000000..109a846
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *  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 "javacodegen.h"
+#include "javagen.h"
+#include "tabcodegen.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+       ret << "{" << CS() << " = " << gotoDest << "; " << 
+                       CTRL_FLOW() << "break _again;}";
+}
+
+void JavaTabCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+       ret << "{" << CS() << " = (";
+       INLINE_LIST( ret, ilItem->children, 0, inFinish );
+       ret << "); " << CTRL_FLOW() << "break _again;}";
+}
+
+void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+       ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
+                       callDest << "; " << CTRL_FLOW() << "break _again;}";
+}
+
+void JavaTabCodeGen::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() << "break _again;}";
+}
+
+void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
+{
+       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() 
+                       << "]; " << CTRL_FLOW() << "break _again;}";
+}
+
+void JavaTabCodeGen::BREAK( ostream &ret, int targState )
+{
+       ret << CTRL_FLOW() << "break _resume;";
+}
+
+void JavaTabCodeGen::COND_TRANSLATE()
+{
+       out << 
+               "       _widec = " << GET_KEY() << ";\n"
+               "       _keys = " << CO() << "[" << CS() << "]*2\n;"
+               "       _klen = " << CL() << "[" << CS() << "];\n"
+               "       if ( _klen > 0 ) {\n"
+               "               int _lower = _keys\n;"
+               "               int _mid;\n"
+               "               int _upper = _keys + (_klen<<1) - 2;\n"
+               "               while (true) {\n"
+               "                       if ( _upper < _lower )\n"
+               "                               break;\n"
+               "\n"
+               "                       _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+               "                       if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
+               "                               _upper = _mid - 2;\n"
+               "                       else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid] )\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 = " << 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";
+       }
+
+       out << 
+               "                               }\n"
+               "                               break;\n"
+               "                       }\n"
+               "               }\n"
+               "       }\n"
+               "\n";
+}
+
+
+void JavaTabCodeGen::LOCATE_TRANS()
+{
+       out <<
+               "       _match: do {\n"
+               "       _keys = " << KO() << "[" << CS() << "]" << ";\n"
+               "       _trans = " << IO() << "[" << CS() << "];\n"
+               "       _klen = " << SL() << "[" << CS() << "];\n"
+               "       if ( _klen > 0 ) {\n"
+               "               int _lower = _keys;\n"
+               "               int _mid;\n"
+               "               int _upper = _keys + _klen - 1;\n"
+               "               while (true) {\n"
+               "                       if ( _upper < _lower )\n"
+               "                               break;\n"
+               "\n"
+               "                       _mid = _lower + ((_upper-_lower) >> 1);\n"
+               "                       if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+               "                               _upper = _mid - 1;\n"
+               "                       else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
+               "                               _lower = _mid + 1;\n"
+               "                       else {\n"
+               "                               _trans += (_mid - _keys);\n"
+               "                               break _match;\n"
+               "                       }\n"
+               "               }\n"
+               "               _keys += _klen;\n"
+               "               _trans += _klen;\n"
+               "       }\n"
+               "\n"
+               "       _klen = " << RL() << "[" << CS() << "];\n"
+               "       if ( _klen > 0 ) {\n"
+               "               int _lower = _keys;\n"
+               "               int _mid;\n"
+               "               int _upper = _keys + (_klen<<1) - 2;\n"
+               "               while (true) {\n"
+               "                       if ( _upper < _lower )\n"
+               "                               break;\n"
+               "\n"
+               "                       _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
+               "                       if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
+               "                               _upper = _mid - 2;\n"
+               "                       else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
+               "                               _lower = _mid + 2;\n"
+               "                       else {\n"
+               "                               _trans += ((_mid - _keys)>>1);\n"
+               "                               break _match;\n"
+               "                       }\n"
+               "               }\n"
+               "               _trans += _klen;\n"
+               "       }\n"
+               "       } while (false);\n"
+               "\n";
+}
+
+void JavaTabCodeGen::writeOutExec()
+{
+       out <<
+               "       {\n"
+               "       int _klen";
+
+       if ( redFsm->anyRegCurStateRef() )
+               out << ", _ps";
+
+       out << 
+               ";\n"
+               "       int _trans;\n";
+
+       if ( redFsm->anyConditions() )
+               out << "        int _widec;\n";
+
+       if ( redFsm->anyToStateActions() || redFsm->anyRegActions() || 
+                       redFsm->anyFromStateActions() )
+       {
+               out << 
+                       "       int _acts;\n"
+                       "       int _nacts;\n";
+       }
+
+       out <<
+               "       int _keys;\n"
+               "\n";
+
+       if ( hasEnd )
+               out << "        if ( " << P() << " != " << PE() << " ) {\n";
+
+       out << "        _resume: while ( true ) {\n";
+
+       out << "        _again: do {\n";
+
+       if ( redFsm->errState != 0 ) {
+               out << 
+                       "       if ( " << CS() << " == " << redFsm->errState->id << " )\n"
+                       "               break _resume;\n";
+       }
+
+       if ( redFsm->anyFromStateActions() ) {
+               out <<
+                       "       _acts = " << FSA() << "[" << CS() << "]" << ";\n"
+                       "       _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( " << A() << "[_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";
+
+       if ( useIndicies )
+               out << "        _trans = " << I() << "[_trans];\n";
+
+       out <<
+               "       " << CS() << " = " << TT() << "[_trans];\n"
+               "\n";
+
+       if ( redFsm->anyRegActions() ) {
+               out <<
+                       "       if ( " << TA() << "[_trans] == 0 )\n"
+                       "               break _again;\n"
+                       "\n"
+                       "       _acts = " <<  TA() << "[_trans]" << ";\n"
+                       "       _nacts = " << CAST("int") << " " <<  A() << "[_acts++];\n"
+                       "       while ( _nacts-- > 0 )\n        {\n"
+                       "               switch ( " << A() << "[_acts++] )\n"
+                       "               {\n";
+                       ACTION_SWITCH();
+                       SWITCH_DEFAULT() <<
+                       "               }\n"
+                       "       }\n"
+                       "\n";
+       }
+
+       /* Again loop, functions as again label. */
+       out << "        } while (false);\n";
+
+       if ( redFsm->anyToStateActions() ) {
+               out <<
+                       "       _acts = " << TSA() << "[" << CS() << "]" << ";\n"
+                       "       _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( " << A() << "[_acts++] ) {\n";
+                       TO_STATE_ACTION_SWITCH();
+                       SWITCH_DEFAULT() <<
+                       "               }\n"
+                       "       }\n"
+                       "\n";
+       }
+
+       if ( hasEnd ) {
+               out << 
+                       "       if ( ++" << P() << " == " << PE() << " )\n"
+                       "               break _resume;\n";
+       }
+       else {
+               out << 
+                       "       " << P() << " += 1;\n";
+       }
+
+       /* Close the resume loop. */
+       out << "        }\n";
+
+       /* The if guarding on empty string. */
+       if ( hasEnd )
+               out << "        }\n";
+
+       /* The execute block. */
+       out << "        }\n";
+}
+
+void JavaTabCodeGen::writeOutEOF()
+{
+       if ( redFsm->anyEofActions() ) {
+               out <<
+                       "       int _acts = " << EA() << "[" << CS() << "]" << ";\n"
+                       "       int _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( " << A() << "[_acts++] ) {\n";
+                       EOF_ACTION_SWITCH();
+                       SWITCH_DEFAULT() <<
+                       "               }\n"
+                       "       }\n"
+                       "\n";
+       }
+}
+
diff --git a/javagen/javacodegen.h b/javagen/javacodegen.h
new file mode 100644 (file)
index 0000000..3481a6c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  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 _JAVACODEGEN_H
+#define _JAVACODEGEN_H
+
+#include "tabcodegen.h"
+
+/*
+ * JavaTabCodeGen
+ */
+struct JavaTabCodeGen
+       : public TabCodeGen, public JavaCodeGen
+{
+       JavaTabCodeGen( ostream &out ) : 
+               FsmCodeGen(out), TabCodeGen(out), JavaCodeGen(out) {}
+
+       void BREAK( ostream &ret, int targState );
+       void GOTO( ostream &ret, int gotoDest, bool inFinish );
+       void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+       void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+       void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+       void RET( ostream &ret, bool inFinish );
+
+       void COND_TRANSLATE();
+       void LOCATE_TRANS();
+       virtual void writeOutExec();
+       virtual void writeOutEOF();
+};
+
+
+#endif
diff --git a/javagen/javagen.h b/javagen/javagen.h
new file mode 100644 (file)
index 0000000..b787291
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  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 <fstream>
+#include "avltree.h"
+#include "vector.h"
+#include "config.h"
+
+#define PROGNAME "rlcodegen"
+
+/* Target language. */
+enum OutputFormat
+{
+       OutCode,
+       OutGraphvizDot
+};
+
+/* Target output style. */
+enum CodeStyleEnum
+{
+       GenTables,
+       GenFTables,
+       GenFlat,
+       GenFFlat,
+       GenGoto,
+       GenFGoto,
+       GenIpGoto,
+       GenSplit
+};
+
+/* Filter on the output stream that keeps track of the number of lines
+ * output. */
+class output_filter : public std::filebuf
+{
+public:
+       output_filter( char *fileName ) : fileName(fileName), line(1) { }
+
+       virtual int sync();
+       virtual std::streamsize xsputn(const char* s, std::streamsize n);
+
+       char *fileName;
+       int line;
+};
+       
+extern OutputFormat outputFormat;
+extern CodeStyleEnum codeStyle;
+
+/* IO filenames and stream. */
+extern bool printPrintables;
+extern bool graphvizDone;
+
+extern int gblErrorCount;
+extern char machineMain[];
+
+extern int numSplitPartitions;
+
+std::ostream &error();
+char *fileNameFromStem( char *stemFile, char *suffix );
+
+#endif /* _RLCODEGEN_H */
diff --git a/javagen/main.cpp b/javagen/main.cpp
new file mode 100644 (file)
index 0000000..ff98ed2
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ *  Copyright 2001-2005 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>
+#include <unistd.h>
+
+#include "javagen.h"
+#include "xmlparse.h"
+#include "pcheck.h"
+#include "vector.h"
+#include "version.h"
+
+/* Code generators. */
+#include "javacodegen.h"
+
+#include "common.h"
+#include "common.cpp"
+
+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. */
+OutputFormat outputFormat = OutCode;
+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 printPrintables = false;
+
+/* Print a summary of the options. */
+void usage()
+{
+       cout <<
+"usage: rlcodegen [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"
+"output:\n"
+"   -V                    Generate a Graphviz dotfile instead of code\n"
+"   -p                    Print printable characters in Graphviz output\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 version " VERSION << " " PUBDATE << endl <<
+                       "Copyright (c) 2001-2006 by Adrian Thurston" << endl;
+}
+
+/* Scans a string looking for the file extension. If there is a file
+ * extension then pointer returned points to inside the string
+ * passed in. Otherwise returns null. */
+char *findFileExtension( char *stemFile )
+{
+       char *ppos = stemFile + strlen(stemFile) - 1;
+
+       /* Scan backwards from the end looking for the first dot.
+        * If we encounter a '/' before the first dot, then stop the scan. */
+       while ( 1 ) {
+               /* If we found a dot or got to the beginning of the string then
+                * we are done. */
+               if ( ppos == stemFile || *ppos == '.' )
+                       break;
+
+               /* If we hit a / then there is no extension. Done. */
+               if ( *ppos == '/' ) {
+                       ppos = stemFile;
+                       break;
+               }
+               ppos--;
+       } 
+
+       /* If we got to the front of the string then bail we 
+        * did not find an extension  */
+       if ( ppos == stemFile )
+               ppos = 0;
+
+       return ppos;
+}
+
+/* Make a file name from a stem. Removes the old filename suffix and
+ * replaces it with a new one. Returns a newed up string. */
+char *fileNameFromStem( char *stemFile, char *suffix )
+{
+       int len = strlen( stemFile );
+       assert( len > 0 );
+
+       /* Get the extension. */
+       char *ppos = findFileExtension( stemFile );
+
+       /* If an extension was found, then shorten what we think the len is. */
+       if ( ppos != 0 )
+               len = ppos - stemFile;
+
+       /* Make the return string from the stem and the suffix. */
+       char *retVal = new char[ len + strlen( suffix ) + 1 ];
+       strncpy( retVal, stemFile, len );
+       strcpy( retVal + len, suffix );
+
+       return retVal;
+}
+
+/* Total error count. */
+int gblErrorCount = 0;
+
+ostream &error()
+{
+       gblErrorCount += 1;
+       cerr << PROGNAME ": ";
+       return cerr;
+}
+
+/* Counts newlines before sending sync. */
+int output_filter::sync( )
+{
+       line += 1;
+       return std::filebuf::sync();
+}
+
+/* Counts newlines before sending data out to file. */
+std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
+{
+       for ( int i = 0; i < n; i++ ) {
+               if ( s[i] == '\n' )
+                       line += 1;
+       }
+       return std::filebuf::xsputn( s, n );
+}
+
+void escapeLineDirectivePath( std::ostream &out, char *path )
+{
+       for ( char *pc = path; *pc != 0; pc++ ) {
+               if ( *pc == '\\' )
+                       out << "\\\\";
+               else
+                       out << *pc;
+       }
+}
+
+/*
+ * Callbacks invoked by the XML data parser.
+ */
+
+/* Invoked by the parser when the root element is opened. */
+ostream *openOutput( char *inputFile, char *language )
+{
+       if ( strcmp( language, "C" ) == 0 ) {
+               hostLangType = CCode;
+               hostLang = &hostLangC;
+       }
+       else if ( strcmp( language, "D" ) == 0 ) {
+               hostLangType = DCode;
+               hostLang = &hostLangD;
+       }
+       else if ( strcmp( language, "Java" ) == 0 ) {
+               hostLangType = JavaCode;
+               hostLang = &hostLangJava;
+       }
+
+       /* Eventually more types will be supported. */
+       if ( hostLangType == JavaCode && codeStyle != GenTables ) {
+               error() << "java: only the table code style -T0 is "
+                                       "currently supported" << endl;
+       }
+
+       /* If the output format is code and no output file name is given, then
+        * make a default. */
+       if ( outputFormat == OutCode && outputFileName == 0 ) {
+               char *ext = findFileExtension( inputFile );
+               if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+                       outputFileName = fileNameFromStem( inputFile, ".h" );
+               else {
+                       char *defExtension = 0;
+                       switch ( hostLangType ) {
+                               case CCode: defExtension = ".c"; break;
+                               case DCode: defExtension = ".d"; break;
+                               case JavaCode: defExtension = ".java"; 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 = new JavaTabCodeGen(out);
+
+       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("o:VpT:F:G:vHh?-:P:", argc, argv);
+       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;
+
+                       /* Output formats. */
+                       case 'V':
+                               outputFormat = OutGraphvizDot;
+                               break;
+
+                       case 'p':
+                               printPrintables = 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 = outputFormat != OutGraphvizDot;
+       bool outputActive = outputFormat == OutCode;
+
+       /* 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/javagen/tabcodegen.cpp b/javagen/tabcodegen.cpp
new file mode 100644 (file)
index 0000000..be6c8cc
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ *  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 "javagen.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::writeOutData()
+{
+       /* 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";
+       }
+
+       STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n"
+       "\n";
+
+       if ( writeFirstFinal ) {
+               STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n"
+               "\n";
+       }
+
+       if ( writeErr ) {
+               STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n"
+               "\n";
+       }
+}
+
+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::writeOutExec()
+{
+       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::writeOutEOF()
+{
+       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/javagen/tabcodegen.h b/javagen/tabcodegen.h
new file mode 100644 (file)
index 0000000..c946e80
--- /dev/null
@@ -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 writeOutData();
+       virtual void writeOutExec();
+
+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 writeOutEOF();
+};
+
+
+/*
+ * 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 */
index 32b5fb0..50722bd 100755 (executable)
@@ -51,15 +51,8 @@ shift $((OPTIND - 1));
 
 [ -z "$*" ] && set -- *.rl
 
-# find the config file
 config=../common/config.h
 ragel=../ragel/ragel
-rlcodegen=../rlcodegen/rlcodegen
-if ! [ -d ../common ]; then 
-       config=../$config
-       ragel=../$ragel
-       rlcodegen=../$rlcodegen
-fi
 
 cxx_compiler=`sed '/^#define CXX/s/#define CXX *//p;d' $config`
 c_compiler=`sed '/^#define CC/s/#define CC *//p;d' $config`
@@ -104,30 +97,35 @@ for test_case; do
 
        case $lang in
                c++)
+                       codegen=../rlcodegen/rlcodegen;
                        code_suffix=cpp;
                        compiler=$cxx_compiler;
                        lang_opt=-C;
                        cflags="-pedantic -ansi -Wall -O3"
                ;;
                d)
+                       codegen=../rlcodegen/rlcodegen;
                        code_suffix=d;
                        compiler=$d_compiler;
                        lang_opt=-D;
                        cflags="-Wall -O3"
                ;;
                c)
+                       codegen=../rlcodegen/rlcodegen;
                        code_suffix=c;
                        compiler=$c_compiler;
                        lang_opt=-C;
                        cflags="-pedantic -ansi -Wall -O3"
                ;;
                obj-c)
+                       codegen=../rlcodegen/rlcodegen;
                        code_suffix=m;
                        compiler=$objc_compiler
                        lang_opt=-C;
                        cflags="-Wall -O3 -fno-strict-aliasing -lobjc"
                ;;
                java)
+                       codegen=../javagen/rlcodegen-java;
                        code_suffix=java;
                        compiler=$java_compiler
                        lang_opt=-J;
@@ -193,8 +191,8 @@ for test_case; do
                        fi
                        echo "$allow_genflags" | grep -e $grep_gen_opt >/dev/null || continue
 
-                       echo "$ragel $min_opt $lang_opt $test_case | $rlcodegen  $gen_opt -o $code_src"
-                       if ! $ragel $min_opt $lang_opt $test_case | $rlcodegen $gen_opt -o $code_src; then
+                       echo "$ragel $min_opt $lang_opt $test_case | $codegen  $gen_opt -o $code_src"
+                       if ! $ragel $min_opt $lang_opt $test_case | $codegen $gen_opt -o $code_src; then
                                test_error;
                        fi