Patch from Victor Hugo Borja <vic@rubyforge.org>
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Thu, 6 Sep 2007 16:23:17 +0000 (16:23 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Thu, 6 Sep 2007 16:23:17 +0000 (16:23 +0000)
This patch implements -T1 -F0 -F1 and -G0 in the ruby code generator.
Goto-driven code generation requires rubinius asm directives (specify with
--rbx option). These code generators pass all the ruby tests.

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

16 files changed:
rlgen-ruby/Makefile.in
rlgen-ruby/main.cpp
rlgen-ruby/rbx-gotocodegen.cpp [new file with mode: 0644]
rlgen-ruby/rbx-gotocodegen.h [new file with mode: 0644]
rlgen-ruby/rlgen-ruby.h
rlgen-ruby/ruby-codegen.cpp [new file with mode: 0644]
rlgen-ruby/ruby-codegen.h [moved from rlgen-ruby/rubycodegen.h with 60% similarity]
rlgen-ruby/ruby-fflatcodegen.cpp [new file with mode: 0644]
rlgen-ruby/ruby-fflatcodegen.h [new file with mode: 0644]
rlgen-ruby/ruby-flatcodegen.cpp [new file with mode: 0644]
rlgen-ruby/ruby-flatcodegen.h [new file with mode: 0644]
rlgen-ruby/ruby-ftabcodegen.cpp [new file with mode: 0644]
rlgen-ruby/ruby-ftabcodegen.h [new file with mode: 0644]
rlgen-ruby/ruby-tabcodegen.cpp [moved from rlgen-ruby/rubycodegen.cpp with 54% similarity]
rlgen-ruby/ruby-tabcodegen.h [new file with mode: 0644]
test/runtests

index b69b473..069847f 100644 (file)
@@ -24,7 +24,8 @@ DEFS +=
 CFLAGS += -g -Wall
 LDFLAGS +=
 
-CC_SRCS = main.cpp rubycodegen.cpp
+CC_SRCS = main.cpp ruby-codegen.cpp ruby-tabcodegen.cpp ruby-ftabcodegen.cpp \
+       ruby-flatcodegen.cpp ruby-fflatcodegen.cpp rbx-gotocodegen.cpp
 
 LIBS = ../common/common.a ../redfsm/redfsm.a
 
index 8cb1469..ecf19da 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
  */
 
 #include <fstream>
 #include <unistd.h>
 
-#include "rlgen-ruby.h"
 #include "xmlparse.h"
 #include "pcheck.h"
 #include "vector.h"
 #include "version.h"
 #include "common.h"
-#include "rubycodegen.h"
+#include "rlgen-ruby.h"
+#include "ruby-tabcodegen.h"
+#include "ruby-ftabcodegen.h"
+#include "ruby-flatcodegen.h"
+#include "ruby-fflatcodegen.h"
+#include "rbx-gotocodegen.h"
 
 using std::istream;
 using std::ifstream;
@@ -43,6 +48,12 @@ using std::cout;
 using std::cerr;
 using std::endl;
 
+/* Target ruby impl */
+RubyImplEnum rubyImpl = MRI;
+
+/* Target language and output style. */
+CodeStyleEnum codeStyle = GenTables;
+
 /* Io globals. */
 istream *inStream = 0;
 ostream *outStream = 0;
@@ -53,6 +64,7 @@ char *outputFileName = 0;
 bool graphvizDone = false;
 
 int numSplitPartitions = 0;
+bool noLineDirectives = false;
 bool printPrintables = false;
 
 /* Print a summary of the options. */
@@ -64,6 +76,15 @@ void usage()
 "   -h, -H, -?, --help    Print this usage and exit\n"
 "   -v, --version         Print version information and exit\n"
 "   -o <file>             Write output to <file>\n"
+"   -x, --rbx             Allow to use Rubinius asm features\n"
+"code generation options:\n"
+"   -l                    Inhibit writing of #line directives\n"
+"generated code style:\n"
+"   -T0                   Table driven FSM (default)\n"
+"   -T1                   Faster table driven FSM\n"
+"   -F0                   Flat table driven FSM\n"
+"   -F1                   Faster flat table-driven FSM\n"
+"   -G0                   Goto-driven FSM\n"
        ;       
 }
 
@@ -72,7 +93,8 @@ void version()
 {
        cout << "Ragel Code Generator for Ruby" << endl <<
                        "Version " VERSION << ", " PUBDATE << endl <<
-                       "Copyright (c) 2001-2007 by Adrian Thurston" << endl;
+                        "Copyright (c) 2001-2007 by Adrian Thurston" << endl <<
+                       "Copyright (c) 2007 by Victor Hugo Borja" << endl;
 }
 
 ostream &error()
@@ -133,8 +155,36 @@ ostream *openOutput( char *inputFile )
 CodeGenData *makeCodeGen( char *sourceFileName, char *fsmName, 
                ostream &out, bool wantComplete )
 {
-       CodeGenData *codeGen = new RubyCodeGen(out);
-
+       CodeGenData *codeGen = 0;
+       switch ( codeStyle ) {
+               case GenTables: 
+                       codeGen = new RubyTabCodeGen(out);
+                       break;
+               case GenFTables:
+                       codeGen = new RubyFTabCodeGen(out);
+                       break;
+               case GenFlat:
+                       codeGen = new RubyFlatCodeGen(out);
+                       break;
+               case GenFFlat:
+                       codeGen = new RubyFFlatCodeGen(out);
+                       break;
+               case GenGoto:
+                       if ( rubyImpl == Rubinius ) {
+                               codeGen = new RbxGotoCodeGen(out);
+                       } else {
+                               cout << "Goto style is still _very_ experimental " 
+                                       "and only supported using Rubinius.\n"
+                                       "You may want to enable the --rbx flag "
+                                       " to give it a try.\n";
+                               exit(1);
+                       }
+                       break;
+               default:
+                       cout << "Invalid code style\n";
+                       exit(1);
+                       break;
+       }
        codeGen->sourceFileName = sourceFileName;
        codeGen->fsmName = fsmName;
        codeGen->wantComplete = wantComplete;
@@ -145,7 +195,7 @@ CodeGenData *makeCodeGen( char *sourceFileName, char *fsmName,
 /* Main, process args and call yyparse to start scanning input. */
 int main(int argc, char **argv)
 {
-       ParamCheck pc("o:vHh?-:", argc, argv);
+       ParamCheck pc("-:xHlh?vo:T:F:G:P:", argc, argv);
        char *xmlInputFileName = 0;
 
        while ( pc.check() ) {
@@ -164,6 +214,55 @@ int main(int argc, char **argv)
                                }
                                break;
 
+                       case 'l':
+                               noLineDirectives = true;
+                               break;
+
+                       /* Code style. */
+                       case 'T':
+                               if ( pc.parameterArg[0] == '0' )
+                                       codeStyle = GenTables;
+                               else if ( pc.parameterArg[0] == '1' )
+                                       codeStyle = GenFTables;
+                               else {
+                                       error() << "-T" << pc.parameterArg[0] << 
+                                                       " is an invalid argument" << endl;
+                                       exit(1);
+                               }
+                               break;
+                       case 'F':
+                               if ( pc.parameterArg[0] == '0' )
+                                       codeStyle = GenFlat;
+                               else if ( pc.parameterArg[0] == '1' )
+                                       codeStyle = GenFFlat;
+                               else {
+                                       error() << "-F" << pc.parameterArg[0] << 
+                                                       " is an invalid argument" << endl;
+                                       exit(1);
+                               }
+                               break;
+                       case 'G':
+                               if ( pc.parameterArg[0] == '0' )
+                                       codeStyle = GenGoto;
+                               else if ( pc.parameterArg[0] == '1' )
+                                       codeStyle = GenFGoto;
+                               else if ( pc.parameterArg[0] == '2' )
+                                       codeStyle = GenIpGoto;
+                               else {
+                                       error() << "-G" << pc.parameterArg[0] << 
+                                                       " is an invalid argument" << endl;
+                                       exit(1);
+                               }
+                               break;
+                       case 'P':
+                               codeStyle = GenSplit;
+                               numSplitPartitions = atoi( pc.parameterArg );
+                               break;
+
+                        case 'x':
+                                rubyImpl = Rubinius;
+                                break;
+
                        /* Version and help. */
                        case 'v':
                                version();
@@ -171,6 +270,7 @@ int main(int argc, char **argv)
                        case 'H': case 'h': case '?':
                                usage();
                                exit(0);
+
                        case '-':
                                if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
                                        usage();
@@ -180,6 +280,9 @@ int main(int argc, char **argv)
                                        version();
                                        exit(0);
                                }
+                                else if ( strcasecmp(pc.parameterArg, "rbx") == 0 ) {
+                                        rubyImpl = Rubinius;
+                                }
                                else {
                                        error() << "--" << pc.parameterArg << 
                                                        " is an invalid argument" << endl;
@@ -248,3 +351,11 @@ int main(int argc, char **argv)
        }
        return 0;
 }
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/rlgen-ruby/rbx-gotocodegen.cpp b/rlgen-ruby/rbx-gotocodegen.cpp
new file mode 100644 (file)
index 0000000..65f5a55
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ *            2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include <stdio.h>
+#include <string>
+#include "rlgen-ruby.h"
+#include "rbx-gotocodegen.h"
+#include "redfsm.h"
+#include "bstmap.h"
+#include "gendata.h"
+
+using std::ostream;
+using std::string;
+
+inline string label(string a, int i)
+{
+       return a + itoa(i);
+}
+
+ostream &RbxGotoCodeGen::rbxLabel(ostream &out, string label) {
+       return out << "Ruby.asm \"_" << FSM_NAME() << "_" << label << ":\"";
+}
+
+ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label) {
+       return out << "Ruby.asm \"goto _" << FSM_NAME() << "_" << label << "\"";
+}
+
+/* Emit the goto to take for a given transition. */
+std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
+{
+       out << TABS(level);
+       return rbxGoto(out, label("tr",trans->id));
+}
+
+std::ostream &RbxGotoCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, true );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+void RbxGotoCodeGen::GOTO_HEADER( RedStateAp *state )
+{
+       /* Label the state. */
+       out << "when " << state->id << "\n";
+}
+
+
+void RbxGotoCodeGen::emitSingleSwitch( RedStateAp *state )
+{
+       /* Load up the singles. */
+       int numSingles = state->outSingle.length();
+       RedTransEl *data = state->outSingle.data;
+
+       if ( numSingles == 1 ) {
+               /* If there is a single single key then write it out as an if. */
+               out << "\tif " << GET_WIDE_KEY(state) << " == " << 
+                       KEY(data[0].lowKey) << " \n\t\t"; 
+
+               /* Virtual function for writing the target of the transition. */
+               TRANS_GOTO(data[0].value, 0) << "\n";
+
+               out << "end\n";
+       }
+       else if ( numSingles > 1 ) {
+               /* Write out single keys in a switch if there is more than one. */
+               out << "\tcase  " << GET_WIDE_KEY(state) << "\n";
+
+               /* Write out the single indicies. */
+               for ( int j = 0; j < numSingles; j++ ) {
+                       out << "\t\twhen " << KEY(data[j].lowKey) << "\n";
+                       TRANS_GOTO(data[j].value, 0) << "\n";
+               }
+               
+               /* Close off the transition switch. */
+               out << "\tend\n";
+       }
+}
+
+void RbxGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
+{
+       /* Get the mid position, staying on the lower end of the range. */
+       int mid = (low + high) >> 1;
+       RedTransEl *data = state->outRange.data;
+
+       /* Determine if we need to look higher or lower. */
+       bool anyLower = mid > low;
+       bool anyHigher = mid < high;
+
+       /* Determine if the keys at mid are the limits of the alphabet. */
+       bool limitLow = data[mid].lowKey == keyOps->minKey;
+       bool limitHigh = data[mid].highKey == keyOps->maxKey;
+
+       if ( anyLower && anyHigher ) {
+               /* Can go lower and higher than mid. */
+               out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << 
+                       KEY(data[mid].lowKey) << " \n";
+               emitRangeBSearch( state, level+1, low, mid-1 );
+               out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " > " << 
+                       KEY(data[mid].highKey) << " \n";
+               emitRangeBSearch( state, level+1, mid+1, high );
+               out << TABS(level) << "else\n";
+               TRANS_GOTO(data[mid].value, level+1) << "\n";
+               out << TABS(level) << "end\n";
+       }
+       else if ( anyLower && !anyHigher ) {
+               /* Can go lower than mid but not higher. */
+               out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << 
+                       KEY(data[mid].lowKey) << " then\n";
+               emitRangeBSearch( state, level+1, low, mid-1 );
+
+               /* if the higher is the highest in the alphabet then there is no
+                * sense testing it. */
+               if ( limitHigh ) {
+                       out << TABS(level) << "else\n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+               }
+               else {
+                       out << TABS(level) << "elsif" << GET_WIDE_KEY(state) << " <= " << 
+                               KEY(data[mid].highKey) << " )\n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+               }
+               out << TABS(level) << "end\n";
+       }
+       else if ( !anyLower && anyHigher ) {
+               /* Can go higher than mid but not lower. */
+               out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " << 
+                       KEY(data[mid].highKey) << " \n";
+               emitRangeBSearch( state, level+1, mid+1, high );
+
+               /* If the lower end is the lowest in the alphabet then there is no
+                * sense testing it. */
+               if ( limitLow ) {
+                       out << TABS(level) << "else\n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+               }
+               else {
+                       out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " >= " << 
+                               KEY(data[mid].lowKey) << " then\n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+               }
+               out << TABS(level) << "end\n";
+       }
+       else {
+               /* Cannot go higher or lower than mid. It's mid or bust. What
+                * tests to do depends on limits of alphabet. */
+               if ( !limitLow && !limitHigh ) {
+                       out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << 
+                               GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " << 
+                               KEY(data[mid].highKey) << " \n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+                       out << TABS(level) << "end\n";
+               }
+               else if ( limitLow && !limitHigh ) {
+                       out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " << 
+                               KEY(data[mid].highKey) << " \n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+                       out << TABS(level) << "end\n";
+               }
+               else if ( !limitLow && limitHigh ) {
+                       out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << 
+                               GET_WIDE_KEY(state) << " \n";
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+                       out << TABS(level) << "end\n";
+               }
+               else {
+                       /* Both high and low are at the limit. No tests to do. */
+                       TRANS_GOTO(data[mid].value, level+1) << "\n";
+               }
+       }
+}
+
+void RbxGotoCodeGen::STATE_GOTO_ERROR()
+{
+       /* Label the state and bail immediately. */
+       outLabelUsed = true;
+       RedStateAp *state = redFsm->errState;
+       out << "when " << state->id << "\n";
+       rbxGoto(out << "        ", "_out") << "\n";
+}
+
+void RbxGotoCodeGen::COND_TRANSLATE( StateCond *stateCond, int level )
+{
+       CondSpace *condSpace = stateCond->condSpace;
+       out << TABS(level) << "_widec = " <<
+               KEY(condSpace->baseKey) << " + (" << GET_KEY() << 
+               " - " << KEY(keyOps->minKey) << ");\n";
+
+       for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
+               out << TABS(level) << "if ";
+               CONDITION( out, *csi );
+               Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
+               out << "\n _widec += " << condValOffset << ";\n end";
+       }
+}
+
+void RbxGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
+{
+       /* Get the mid position, staying on the lower end of the range. */
+       int mid = (low + high) >> 1;
+       StateCond **data = state->stateCondVect.data;
+
+       /* Determine if we need to look higher or lower. */
+       bool anyLower = mid > low;
+       bool anyHigher = mid < high;
+
+       /* Determine if the keys at mid are the limits of the alphabet. */
+       bool limitLow = data[mid]->lowKey == keyOps->minKey;
+       bool limitHigh = data[mid]->highKey == keyOps->maxKey;
+
+       if ( anyLower && anyHigher ) {
+               /* Can go lower and higher than mid. */
+               out << TABS(level) << "if " << GET_KEY() << " < " << 
+                       KEY(data[mid]->lowKey) << " \n";
+               emitCondBSearch( state, level+1, low, mid-1 );
+               out << TABS(level) << "elsif " << GET_KEY() << " > " << 
+                       KEY(data[mid]->highKey) << " \n";
+               emitCondBSearch( state, level+1, mid+1, high );
+               out << TABS(level) << "else\n";
+               COND_TRANSLATE(data[mid], level+1);
+               out << TABS(level) << "end\n";
+       }
+       else if ( anyLower && !anyHigher ) {
+               /* Can go lower than mid but not higher. */
+               out << TABS(level) << "if " << GET_KEY() << " < " << 
+                       KEY(data[mid]->lowKey) << " \n";
+               emitCondBSearch( state, level+1, low, mid-1 );
+
+               /* if the higher is the highest in the alphabet then there is no
+                * sense testing it. */
+               if ( limitHigh ) {
+                       out << TABS(level) << "else\n";
+                       COND_TRANSLATE(data[mid], level+1);
+               }
+               else {
+                       out << TABS(level) << "elsif " << GET_KEY() << " <= " << 
+                               KEY(data[mid]->highKey) << " then\n";
+                       COND_TRANSLATE(data[mid], level+1);
+               }
+               out << TABS(level) << "end\n";
+
+       }
+       else if ( !anyLower && anyHigher ) {
+               /* Can go higher than mid but not lower. */
+               out << TABS(level) << "if " << GET_KEY() << " > " << 
+                       KEY(data[mid]->highKey) << " \n";
+               emitCondBSearch( state, level+1, mid+1, high );
+
+               /* If the lower end is the lowest in the alphabet then there is no
+                * sense testing it. */
+               if ( limitLow ) {
+                       out << TABS(level) << "else\n";
+                       COND_TRANSLATE(data[mid], level+1);
+               }
+               else {
+                       out << TABS(level) << "elsif " << GET_KEY() << " >= " << 
+                               KEY(data[mid]->lowKey) << " then\n";
+                       COND_TRANSLATE(data[mid], level+1);
+               }
+               out << TABS(level) << "end\n";
+       }
+       else {
+               /* Cannot go higher or lower than mid. It's mid or bust. What
+                * tests to do depends on limits of alphabet. */
+               if ( !limitLow && !limitHigh ) {
+                       out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " << 
+                               GET_KEY() << " && " << GET_KEY() << " <= " << 
+                               KEY(data[mid]->highKey) << " then\n";
+                       COND_TRANSLATE(data[mid], level+1);
+                       out << TABS(level) << "end\n";
+               }
+               else if ( limitLow && !limitHigh ) {
+                       out << TABS(level) << "if " << GET_KEY() << " <= " << 
+                               KEY(data[mid]->highKey) << " then\n";
+                       COND_TRANSLATE(data[mid], level+1);
+                       out << TABS(level) << "end\n";
+               }
+               else if ( !limitLow && limitHigh ) {
+                       out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " << 
+                               GET_KEY() << " then\n";
+                       COND_TRANSLATE(data[mid], level+1);
+                       out << TABS(level) << "end\n";
+               }
+               else {
+                       /* Both high and low are at the limit. No tests to do. */
+                       COND_TRANSLATE(data[mid], level);
+               }
+       }
+}
+
+std::ostream &RbxGotoCodeGen::STATE_GOTOS()
+{
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               if ( st == redFsm->errState )
+                       STATE_GOTO_ERROR();
+               else {
+                       /* Writing code above state gotos. */
+                       GOTO_HEADER( st );
+
+                       if ( st->stateCondVect.length() > 0 ) {
+                               out << "        _widec = " << GET_KEY() << ";\n";
+                               emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
+                       }
+
+                       /* Try singles. */
+                       if ( st->outSingle.length() > 0 )
+                               emitSingleSwitch( st );
+
+                       /* Default case is to binary search for the ranges, if that fails then */
+                       if ( st->outRange.length() > 0 )
+                               emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
+
+                       /* Write the default transition. */
+                       TRANS_GOTO( st->defTrans, 1 ) << "\n";
+               }
+       }
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::TRANSITIONS()
+{
+       /* Emit any transitions that have functions and that go to 
+        * this state. */
+       for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
+               /* Write the label for the transition so it can be jumped to. */
+               rbxLabel(out << "       ", label("tr", trans->id)) << "\n";
+
+               /* Destination state. */
+               if ( trans->action != 0 && trans->action->anyCurStateRef() )
+                       out << "_ps = " << CS() << "'n";
+               out << CS() << " = " << trans->targ->id << "\n";
+
+               if ( trans->action != 0 ) {
+                       /* Write out the transition func. */
+                       rbxGoto(out, label("f", trans->action->actListId)) << "\n";
+               }
+               else {
+                       /* No code to execute, just loop around. */
+                       rbxGoto(out, "_again") << "\n";
+               }
+       }
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::EXEC_FUNCS()
+{
+       /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numTransRefs > 0 ) {
+                       rbxLabel(out, label("f", redAct->actListId)) << "\n" <<
+                               "_acts = " << itoa( redAct->location+1 ) << "\n";
+                       rbxGoto(out, "execFuncs") << "\n";
+               }
+       }
+
+       rbxLabel(out, "execFuncs") <<
+               "\n"
+               "       _nacts = " << A() << "[_acts]\n"
+               "       _acts += 1\n"
+               "       while ( _nacts > 0 ) \n"
+               "               _nacts -= 1\n"
+               "               _acts += 1\n"
+               "               case ( "<< A() << "[_acts-1] ) \n";
+       ACTION_SWITCH();
+       out <<
+               "               end\n"
+               "       end \n";
+       rbxGoto(out, "_again");
+       return out;
+}
+
+int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->toStateAction != 0 )
+               act = state->toStateAction->location+1;
+       return act;
+}
+
+int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->fromStateAction != 0 )
+               act = state->fromStateAction->location+1;
+       return act;
+}
+
+int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->eofAction != 0 )
+               act = state->eofAction->location+1;
+       return act;
+}
+
+std::ostream &RbxGotoCodeGen::TO_STATE_ACTIONS()
+{
+       /* Take one off for the psuedo start state. */
+       int numStates = redFsm->stateList.length();
+       unsigned int *vals = new unsigned int[numStates];
+       memset( vals, 0, sizeof(unsigned int)*numStates );
+
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+               vals[st->id] = TO_STATE_ACTION(st);
+
+       out << "\t";
+       for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+               /* Write any eof action. */
+               out << vals[st];
+               if ( st < numStates-1 ) {
+                       out << ", ";
+                       if ( (st+1) % IALL == 0 )
+                               out << "\n\t";
+               }
+       }
+       out << "\n";
+       delete[] vals;
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::FROM_STATE_ACTIONS()
+{
+       /* Take one off for the psuedo start state. */
+       int numStates = redFsm->stateList.length();
+       unsigned int *vals = new unsigned int[numStates];
+       memset( vals, 0, sizeof(unsigned int)*numStates );
+
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+               vals[st->id] = FROM_STATE_ACTION(st);
+
+       out << "\t";
+       for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+               /* Write any eof action. */
+               out << vals[st];
+               if ( st < numStates-1 ) {
+                       out << ", ";
+                       if ( (st+1) % IALL == 0 )
+                               out << "\n\t";
+               }
+       }
+       out << "\n";
+       delete[] vals;
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::EOF_ACTIONS()
+{
+       /* Take one off for the psuedo start state. */
+       int numStates = redFsm->stateList.length();
+       unsigned int *vals = new unsigned int[numStates];
+       memset( vals, 0, sizeof(unsigned int)*numStates );
+
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
+               vals[st->id] = EOF_ACTION(st);
+
+       out << "\t";
+       for ( int st = 0; st < redFsm->nextStateId; st++ ) {
+               /* Write any eof action. */
+               out << vals[st];
+               if ( st < numStates-1 ) {
+                       out << ", ";
+                       if ( (st+1) % IALL == 0 )
+                               out << "\n\t";
+               }
+       }
+       out << "\n";
+       delete[] vals;
+       return out;
+}
+
+std::ostream &RbxGotoCodeGen::FINISH_CASES()
+{
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* States that are final and have an out action need a case. */
+               if ( st->eofAction != 0 ) {
+                       /* Write the case label. */
+                       out << "\t\twhen " << st->id << "\n";
+
+                       /* Write the goto func. */
+                       rbxGoto(out, label("f", st->eofAction->actListId)) << "\n";
+               }
+       }
+       
+       return out;
+}
+
+void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
+{
+       ret << "begin\n" << CS() << " = " << gotoDest << " ";
+       rbxGoto(ret, "_again") << 
+               "\nend\n";
+}
+
+void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+       ret << "begin\n" << CS() << " = (";
+       INLINE_LIST( ret, ilItem->children, 0, inFinish );
+       ret << ")";
+       rbxGoto(ret, "_again") << 
+               "\nend\n";
+}
+
+void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
+{
+       ret << "(_ps)";
+}
+
+void RbxGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+       ret << "(" << CS() << ")";
+}
+
+void RbxGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+       ret << CS() << " = " << nextDest << ";";
+}
+
+void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+       ret << CS() << " = (";
+       INLINE_LIST( ret, ilItem->children, 0, inFinish );
+       ret << ");";
+}
+
+void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
+{
+       ret << "begin\n" 
+           << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
+               callDest << "; ";
+       rbxGoto(ret, "_again") << 
+               "\nend\n";
+}
+
+void RbxGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+{
+       ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
+       INLINE_LIST( ret, ilItem->children, targState, inFinish );
+       ret << "); ";
+       rbxGoto(ret, "_again") << 
+               "\nend\n";
+}
+
+void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
+{
+       ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
+       rbxGoto(ret, "_again") << 
+               "\nend\n";
+}
+
+void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
+{
+       outLabelUsed = true;
+       rbxGoto(ret, "_out") << "\n";
+}
+
+void RbxGotoCodeGen::writeData()
+{
+       if ( redFsm->anyActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+               ACTIONS_ARRAY();
+               CLOSE_ARRAY() <<
+                       "\n";
+       }
+
+       if ( redFsm->anyToStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+               TO_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+                       "\n";
+       }
+
+       if ( redFsm->anyFromStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+               FROM_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+                       "\n";
+       }
+
+       if ( redFsm->anyEofActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+               EOF_ACTIONS();
+               CLOSE_ARRAY() <<
+                       "\n";
+       }
+
+       STATE_IDS();
+}
+
+void RbxGotoCodeGen::writeExec()
+{
+       outLabelUsed = false;
+
+       out << "        begin\n";
+
+       if ( redFsm->anyRegCurStateRef() )
+               out << "        _ps = 0;\n";
+
+       if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
+            || redFsm->anyFromStateActions() )
+       {
+                out <<  " _acts, _nacts = nil\n";
+       }
+
+       if ( redFsm->anyConditions() )
+               out << "        _widec = nil\n";
+
+       out << "\n";
+
+       if ( hasEnd ) {
+               outLabelUsed = true;
+               out << 
+                       "       if ( " << P() << " == " << PE() << " )\n";
+               rbxGoto(out << "                ", "_out") << "\n" <<
+                       "       end\n";
+       }
+
+       if ( redFsm->errState != 0 ) {
+               outLabelUsed = true;
+               out << 
+                       "       if ( " << CS() << " == " << redFsm->errState->id << " )\n";
+               rbxGoto(out << "                ", "_out") << "\n" <<
+                       "       end\n";
+       }
+
+       rbxLabel(out, "_resume") << "\n";
+
+       if ( redFsm->anyFromStateActions() ) {
+               out <<
+
+                       "       _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
+                       "       _nacts = " << " *_acts++;\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( *_acts++ ) {\n";
+               FROM_STATE_ACTION_SWITCH();
+               out <<
+                       "               }\n"
+                       "       }\n"
+                       "\n";
+       }
+
+       out <<
+               "       case ( " << CS() << " )\n";
+       STATE_GOTOS();
+       out <<
+               "       end # case\n"
+               "\n";
+       TRANSITIONS() <<
+               "\n";
+
+       if ( redFsm->anyRegActions() )
+               EXEC_FUNCS() << "\n";
+
+
+       rbxLabel(out, "_again") << "\n";
+
+       if ( redFsm->anyToStateActions() ) {
+               out <<
+                       "       _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
+                       "       _nacts = " << " *_acts++;\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( *_acts++ ) {\n";
+               TO_STATE_ACTION_SWITCH();
+               out <<
+                       "               }\n"
+                       "       }\n"
+                       "\n";
+       }
+
+       if ( redFsm->errState != 0 ) {
+               outLabelUsed = true;
+               out << 
+                       "       if ( " << CS() << " == " << redFsm->errState->id << " )\n";
+               rbxGoto(out << "                ", "_out") << "\n" <<
+                       "       end" << "\n";
+       }
+
+       if ( hasEnd ) {
+               out <<  "       "  << P() << " += 1\n"
+                       "       if ( " << P() << " != " << PE() << " )\n";
+               rbxGoto(out << "                ", "_resume") << "\n" <<
+                       "       end" << "\n";
+       }
+       else {
+               out << 
+                       "       " << P() << " += 1;\n";
+               rbxGoto(out << "        ", "_resume") << "\n";
+       }
+
+       if ( outLabelUsed )
+               rbxLabel(out, "_out") << "\n";
+
+       out << "        end\n";
+}
+
+void RbxGotoCodeGen::writeEOF()
+{
+       if ( redFsm->anyEofActions() ) {
+               out << 
+                       "       {\n"
+                       "        _acts = " << 
+                       ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
+                       "       " << " _nacts = " << " *_acts++;\n"
+                       "       while ( _nacts-- > 0 ) {\n"
+                       "               switch ( *_acts++ ) {\n";
+               EOF_ACTION_SWITCH();
+               out <<
+                       "               }\n"
+                       "       }\n"
+                       "       }\n"
+                       "\n";
+       }
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/rlgen-ruby/rbx-gotocodegen.h b/rlgen-ruby/rbx-gotocodegen.h
new file mode 100644 (file)
index 0000000..f460919
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ *            2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#ifndef _RBX_GOTOCODEGEN_H
+#define _RBX_GOTOCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include "ruby-codegen.h"
+
+using std::string;
+
+class RbxGotoCodeGen : public RubyCodeGen
+{
+public:
+        RbxGotoCodeGen( ostream &out ) : RubyCodeGen(out) {}
+        virtual ~RbxGotoCodeGen() {}
+
+       std::ostream &TO_STATE_ACTION_SWITCH();
+       std::ostream &FROM_STATE_ACTION_SWITCH();
+       std::ostream &EOF_ACTION_SWITCH();
+       std::ostream &ACTION_SWITCH();
+       std::ostream &STATE_GOTOS();
+       std::ostream &TRANSITIONS();
+       std::ostream &EXEC_FUNCS();
+       std::ostream &FINISH_CASES();
+
+       void GOTO( ostream &ret, int gotoDest, bool inFinish );
+       void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+       void NEXT( ostream &ret, int nextDest, bool inFinish );
+       void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+       void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+       void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+       void CURS( ostream &ret, bool inFinish );
+       void TARGS( ostream &ret, bool inFinish, int targState );
+       void RET( ostream &ret, bool inFinish );
+       void BREAK( ostream &ret, int targState );
+
+       int TO_STATE_ACTION( RedStateAp *state );
+        int FROM_STATE_ACTION( RedStateAp *state );
+        int EOF_ACTION( RedStateAp *state );
+
+       void COND_TRANSLATE( StateCond *stateCond, int level );
+       void emitCondBSearch( RedStateAp *state, int level, int low, int high );
+       void STATE_CONDS( RedStateAp *state, bool genDefault ); 
+
+       virtual std::ostream &TRANS_GOTO( RedTransAp *trans, int level );
+
+       void emitSingleSwitch( RedStateAp *state );
+       void emitRangeBSearch( RedStateAp *state, int level, int low, int high );
+
+       /* Called from STATE_GOTOS just before writing the gotos */
+       virtual void GOTO_HEADER( RedStateAp *state );
+       virtual void STATE_GOTO_ERROR();
+
+       virtual void writeData();
+       virtual void writeEOF();
+       virtual void writeExec();
+
+        
+        std::ostream &TO_STATE_ACTIONS();
+        std::ostream &FROM_STATE_ACTIONS();
+        std::ostream &EOF_ACTIONS();
+
+private:
+       ostream &rbxGoto(ostream &out, string label);
+       ostream &rbxLabel(ostream &out, string label);  
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif 
index d76d1ed..7b5c21c 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
  */
 
 
 #define PROGNAME "rlgen-ruby"
 
+/* Target implementation */
+enum RubyImplEnum
+{
+  MRI,
+  Rubinius
+};
+
+extern RubyImplEnum rubyImpl;
+
+/* Target output style. */
+enum CodeStyleEnum
+{
+       GenTables,
+       GenFTables,
+       GenFlat,
+       GenFFlat,
+       GenGoto,
+       GenFGoto,
+       GenIpGoto,
+       GenSplit
+
+};
+
+extern CodeStyleEnum codeStyle;
+
 extern int gblErrorCount;
 extern char machineMain[];
 
+/* Options. */
+extern int numSplitPartitions;
+extern bool noLineDirectives;
+
 std::ostream &error();
 
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
 #endif /* _RLGEN_RUBY_H */
diff --git a/rlgen-ruby/ruby-codegen.cpp b/rlgen-ruby/ruby-codegen.cpp
new file mode 100644 (file)
index 0000000..e926ca3
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include <iomanip>
+#include <sstream>
+#include "redfsm.h"
+#include "gendata.h"
+#include "rlgen-ruby.h"
+#include "ruby-codegen.h"
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+
+void lineDirective( ostream &out, char *fileName, int line )
+{
+       /* Write a comment containing line info. */
+       out << "# line " << line  << " \"";
+       for ( char *pc = fileName; *pc != 0; pc++ ) {
+               if ( *pc == '\\' )
+                       out << "\\\\";
+               else
+                       out << *pc;
+       }
+       out << "\"\n";
+}
+
+void genLineDirective( ostream &out )
+{
+       std::streambuf *sbuf = out.rdbuf();
+       output_filter *filter = static_cast<output_filter*>(sbuf);
+       lineDirective( out, filter->fileName, filter->line + 1 );
+}
+
+string RubyCodeGen::DATA_PREFIX()
+{
+       if ( dataPrefix )
+               return FSM_NAME() + "_";
+       return "";
+}
+
+std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
+{
+       out << 
+               "class << self\n"
+               "       attr_accessor :" << name << "\n"
+               "end\n"
+               "self." << name;
+       return out;
+}
+
+
+std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
+{
+       out << 
+               "class << self\n"
+               "       attr_accessor :" << name << "\n"
+               "       private :" << name << ", :" << name << "=\n"
+               "end\n"
+               "self." << name << " = [\n";
+       return out;
+}
+
+std::ostream &RubyCodeGen::CLOSE_ARRAY()
+{
+       out << "]\n";
+       return out;
+}
+
+
+string RubyCodeGen::ARR_OFF( string ptr, string offset )
+{
+       return ptr + "[" + offset + "]";
+}
+
+string RubyCodeGen::NULL_ITEM()
+{
+       return "nil";
+}
+
+
+string RubyCodeGen::P()
+{ 
+       ostringstream ret;
+       if ( pExpr == 0 )
+               ret << "p";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, pExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::PE()
+{
+       ostringstream ret;
+       if ( peExpr == 0 )
+               ret << "pe";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, peExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::CS()
+{
+       ostringstream ret;
+       if ( csExpr == 0 )
+               ret << ACCESS() << "cs";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, csExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::TOP()
+{
+       ostringstream ret;
+       if ( topExpr == 0 )
+               ret << ACCESS() + "top";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, topExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::STACK()
+{
+       ostringstream ret;
+       if ( stackExpr == 0 )
+               ret << ACCESS() + "stack";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, stackExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::ACT()
+{
+       ostringstream ret;
+       if ( actExpr == 0 )
+               ret << ACCESS() + "act";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, actExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::TOKSTART()
+{
+       ostringstream ret;
+       if ( tokstartExpr == 0 )
+               ret << ACCESS() + "tokstart";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, tokstartExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::TOKEND()
+{
+       ostringstream ret;
+       if ( tokendExpr == 0 )
+               ret << ACCESS() + "tokend";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, tokendExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+string RubyCodeGen::DATA()
+{
+       ostringstream ret;
+       if ( dataExpr == 0 )
+               ret << ACCESS() + "data";
+       else {
+               //ret << "(";
+               INLINE_LIST( ret, dataExpr, 0, false );
+               //ret << ")";
+       }
+       return ret.str();
+}
+
+/* Write out the fsm name. */
+string RubyCodeGen::FSM_NAME()
+{
+       return fsmName;
+}
+
+
+void RubyCodeGen::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 << "                begin\n";
+       INLINE_LIST( ret, action->inlineList, targState, inFinish );
+       ret << "                end\n";
+       lineDirective( ret, sourceFileName, action->loc.line );
+}
+
+
+
+string RubyCodeGen::GET_WIDE_KEY()
+{
+       if ( redFsm->anyConditions() ) 
+               return "_widec";
+       else
+               return GET_KEY();
+}
+
+string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
+{
+       if ( state->stateCondList.length() > 0 )
+               return "_widec";
+       else
+               return GET_KEY();
+}
+
+string RubyCodeGen::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 RubyCodeGen::KEY( Key key )
+{
+       ostringstream ret;
+       if ( keyOps->isSigned || !hostLang->explicitUnsigned )
+               ret << key.getVal();
+       else
+               ret << (unsigned long) key.getVal();
+       return ret.str();
+}
+
+
+/* Write out level number of tabs. Makes the nested binary search nice
+ * looking. */
+string RubyCodeGen::TABS( int level )
+{
+       string result;
+       while ( level-- > 0 )
+               result += "\t";
+       return result;
+}
+
+string RubyCodeGen::INT( int i )
+{
+       ostringstream ret;
+       ret << i;
+       return ret.str();
+}
+
+void RubyCodeGen::CONDITION( ostream &ret, Action *condition )
+{
+       ret << "\n";
+       lineDirective( ret, sourceFileName, condition->loc.line );
+       INLINE_LIST( ret, condition->inlineList, 0, false );
+}
+
+/* Emit the alphabet data type. */
+string RubyCodeGen::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 RubyCodeGen::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;
+}
+
+
+string RubyCodeGen::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 array of actions. */
+std::ostream &RubyCodeGen::ACTIONS_ARRAY()
+{
+       START_ARRAY_LINE();
+       int totalActions = 0;
+       ARRAY_ITEM( INT(0), ++totalActions, false );
+       for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
+               /* Write out the length, which will never be the last character. */
+               ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
+
+               for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
+                       ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
+               }
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+void RubyCodeGen::STATE_IDS()
+{
+       if ( redFsm->startState != 0 )
+               STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
+
+       if ( writeFirstFinal )
+               STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
+
+       if ( writeErr )
+               STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
+
+       out << "\n";
+
+       if ( entryPointNames.length() > 0 ) {
+               for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
+                       STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) << 
+                                       " = " << entryPointIds[en.pos()] << ";\n";
+               }
+               out << "\n";
+       }
+}
+
+std::ostream &RubyCodeGen::START_ARRAY_LINE()
+{
+       out << "\t";
+       return out;
+}
+
+std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
+{
+       out << item;
+       if ( !last )
+       {
+               out << ", ";
+               if ( count % IALL == 0 )
+               {
+                       END_ARRAY_LINE();
+                       START_ARRAY_LINE();
+               }
+       }
+       return out;
+}
+
+std::ostream &RubyCodeGen::END_ARRAY_LINE()
+{
+       out << "\n";
+       return out;
+}
+
+/* Emit the offset of the start state as a decimal integer. */
+string RubyCodeGen::START_STATE_ID()
+{
+       ostringstream ret;
+       ret << redFsm->startState->id;
+       return ret.str();
+};
+
+string RubyCodeGen::ERROR_STATE()
+{
+       ostringstream ret;
+       if ( redFsm->errState != 0 )
+               ret << redFsm->errState->id;
+       else
+               ret << "-1";
+       return ret.str();
+}
+
+string RubyCodeGen::FIRST_FINAL_STATE()
+{
+       ostringstream ret;
+       if ( redFsm->firstFinState != 0 )
+               ret << redFsm->firstFinState->id;
+       else
+               ret << redFsm->nextStateId;
+       return ret.str();
+}
+
+string RubyCodeGen::ACCESS()
+{
+       ostringstream ret;
+       if ( accessExpr != 0 )
+               INLINE_LIST( ret, accessExpr, 0, false );
+       return ret.str();
+}
+
+/* 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 RubyCodeGen::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() << " = " << P() << " - 1;";
+                       break;
+               case InlineItem::Exec:
+                       EXEC( ret, item, targState, inFinish );
+                       break;
+               case InlineItem::Curs:
+                       ret << "(_ps)";
+                       break;
+               case InlineItem::Targs:
+                       ret << "(" << CS() << ")";
+                       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;
+               }
+       }
+}
+
+
+void RubyCodeGen::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 << " begin " << P() << " = ((";
+       INLINE_LIST( ret, item->children, targState, inFinish );
+       ret << "))-1; end\n";
+}
+
+void RubyCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, 
+               int targState, int inFinish )
+{
+       ret << 
+               "       case " << ACT() << "\n";
+
+       for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
+               /* Write the case label, the action and the case break. */
+               ret << "        when " << lma->lmId << ":\n";
+
+               /* Write the block and close it off. */
+               ret << "        begin";
+               INLINE_LIST( ret, lma->children, targState, inFinish );
+               ret << "end\n";
+       }
+
+       ret << "end \n\t";
+}
+
+void RubyCodeGen::SET_ACT( ostream &ret, InlineItem *item )
+{
+       ret << ACT() << " = " << item->lmId << ";";
+}
+
+void RubyCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
+{
+       ret << TOKSTART() << " = " << NULL_ITEM() << ";";
+}
+
+void RubyCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
+{
+       ret << ACT() << " = 0\n";
+}
+
+void RubyCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
+{
+       ret << TOKSTART() << " = " << P() << "\n";
+}
+
+void RubyCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
+{
+       /* The tokend action sets tokend. */
+       ret << TOKEND() << " = " << P();
+       if ( item->offset != 0 ) 
+               out << "+" << item->offset;
+       out << "\n";
+}
+
+void RubyCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
+{
+       ret << TOKEND();
+}
+
+void RubyCodeGen::SUB_ACTION( ostream &ret, InlineItem *item, 
+               int targState, bool inFinish )
+{
+       if ( item->children->length() > 0 ) {
+               /* Write the block and close it off. */
+               ret << " begin ";
+               INLINE_LIST( ret, item->children, targState, inFinish );
+               ret << " end\n";
+       }
+}
+
+int RubyCodeGen::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;
+       return act;
+}
+
+ostream &RubyCodeGen::source_warning( const InputLoc &loc )
+{
+       cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
+       return cerr;
+}
+
+ostream &RubyCodeGen::source_error( const InputLoc &loc )
+{
+       gblErrorCount += 1;
+       assert( sourceFileName != 0 );
+       cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
+       return cerr;
+}
+
+void RubyCodeGen::finishRagelDef()
+{
+
+       if ( codeStyle == GenGoto || codeStyle == GenFGoto || 
+                       codeStyle == GenIpGoto || codeStyle == GenSplit )
+       {
+               /* For directly executable machines there is no required state
+                * ordering. Choose a depth-first ordering to increase the
+                * potential for fall-throughs. */
+               redFsm->depthFirstOrdering();
+       }
+       else {
+               /* The frontend will do this for us, but it may be a good idea to
+                * force it if the intermediate file is edited. */
+               redFsm->sortByStateId();
+       }
+
+       /* Choose default transitions and the single transition. */
+       redFsm->chooseDefaultSpan();
+               
+       /* Maybe do flat expand, otherwise choose single. */
+       if ( codeStyle == GenFlat || codeStyle == GenFFlat )
+               redFsm->makeFlat();
+       else
+               redFsm->chooseSingle();
+
+       /* If any errors have occured in the input file then don't write anything. */
+       if ( gblErrorCount > 0 )
+               return;
+       
+       if ( codeStyle == GenSplit )
+               redFsm->partitionFsm( numSplitPartitions );
+
+       if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
+               redFsm->setInTrans();
+
+       /* Anlayze Machine will find the final action reference counts, among
+        * other things. We will use these in reporting the usage
+        * of fsm directives in action code. */
+       analyzeMachine();
+
+       /* Determine if we should use indicies. */
+       calcIndexSize();
+}
+
+
+/* Determine if we should use indicies or not. */
+void RubyCodeGen::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;
+}
+
+unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
+{
+       long long maxValLL = (long long) maxVal;
+       HostType *arrayType = keyOps->typeSubsumes( maxValLL );
+       assert( arrayType != 0 );
+       return arrayType->size;
+}
+
+
+void RubyCodeGen::writeInit()
+{
+       out << "begin\n";
+       
+       out << "        " << P() << " ||= 0\n";
+
+       if ( hasEnd ) 
+               out << "        " << PE() << " ||= " << DATA() << ".length\n";
+
+       if ( writeCS )
+               out << "        " << CS() << " = " << START() << "\n";
+
+       /* If there are any calls, then the stack top needs initialization. */
+       if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
+               out << "        " << TOP() << " = 0\n";
+
+       if ( hasLongestMatch ) {
+               out <<
+                       "       " << TOKSTART() << " = " << NULL_ITEM() << "\n"
+                       "       " << TOKEND() << " = " << NULL_ITEM() << "\n"
+                       "       " << ACT() << " = 0\n";
+       }
+
+       out << "end\n";
+}
+
+void RubyCodeGen::writeExports()
+{
+       if ( exportList.length() > 0 ) {
+               for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
+                       STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name ) 
+                                       << " = " << KEY(ex->key) << "\n";
+               }
+               out << "\n";
+       }
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
similarity index 60%
rename from rlgen-ruby/rubycodegen.h
rename to rlgen-ruby/ruby-codegen.h
index 6e99d63..9f4c166 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
- *            2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
  */
 
 /*  This file is part of Ragel.
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
 
-#ifndef _RUBYCODEGEN_H
-#define _RUBYCODEGEN_H
+#ifndef _RUBY_CODEGEN_H
+#define _RUBY_CODEGEN_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
 
-/*
- * RubyCodeGen
- */
-struct RubyCodeGen : public CodeGenData
+inline string itoa( int i )
 {
-       RubyCodeGen( ostream &out ) : 
-               CodeGenData(out),
-               indent_level(1) { }
-
-public:
-       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 writeExec();
-       virtual void writeEOF();
-       virtual void writeInit();
-       virtual void writeData();
-       virtual void writeExports();
-       virtual void finishRagelDef();
-
- 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 NEXT( ostream &ret, int nextDest, bool inFinish );
-       void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
-
-       int TO_STATE_ACTION( RedStateAp *state );
-       int FROM_STATE_ACTION( RedStateAp *state );
-       int EOF_ACTION( RedStateAp *state );
-       int TRANS_ACTION( RedTransAp *trans );
-
-       /* Determine if we should use indicies. */
-       void calcIndexSize();
+       char buf[16];
+       sprintf( buf, "%i", i );
+       return buf;
+}
 
-private:
-       string array_type;
-       string array_name;
 
+class RubyCodeGen : public CodeGenData
+{
 public:
-
+   RubyCodeGen( ostream &out ) : CodeGenData(out) { }
+   virtual ~RubyCodeGen() {}
+protected:
        ostream &START_ARRAY_LINE();
        ostream &ARRAY_ITEM( string item, int count, bool last );
        ostream &END_ARRAY_LINE();
+  
 
        string FSM_NAME();
-       string START_STATE_ID();
-       ostream &ACTIONS_ARRAY();
-       string GET_WIDE_KEY();
+
+        string START_STATE_ID();
+       string ERROR_STATE();
+       string FIRST_FINAL_STATE();
+        void INLINE_LIST(ostream &ret, InlineList *inlineList, int targState, bool inFinish);
+        string ACCESS();
+
+        void ACTION( ostream &ret, Action *action, int targState, bool inFinish );
+       string GET_KEY();
+        string GET_WIDE_KEY();
        string GET_WIDE_KEY( RedStateAp *state );
-       string TABS( int level );
        string KEY( Key key );
+       string TABS( int level );
        string INT( int i );
        void CONDITION( ostream &ret, Action *condition );
        string ALPH_TYPE();
        string WIDE_ALPH_TYPE();
-       string ARRAY_TYPE( unsigned long maxVal );
+       string ARRAY_TYPE( unsigned long maxVal );
+       ostream &ACTIONS_ARRAY();
+       void STATE_IDS();
 
-       string ACCESS();
-       string P();
-       string PE();
-       string CS();
-       string TOP();
-       string STACK();
-       string ACT();
-       string TOKSTART();
-       string TOKEND();
-       string DATA();
 
        string DATA_PREFIX();
        string PM() { return "_" + DATA_PREFIX() + "partition_map"; }
@@ -154,9 +96,52 @@ public:
        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 );
-       void EXEC( ostream &ret, InlineItem *item, int targState, int inFinish );
-       void EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish );
+public:
+       string NULL_ITEM();
+       ostream &OPEN_ARRAY( string type, string name );
+       ostream &CLOSE_ARRAY();
+       ostream &STATIC_VAR( string type, string name );
+       string ARR_OFF( string ptr, string offset );
+
+       string P();
+       string PE();
+       string CS();
+       string TOP();
+       string STACK();
+       string ACT();
+       string TOKSTART();
+       string TOKEND();
+       string DATA();
+
+
+       void finishRagelDef();
+       unsigned int arrayTypeSize( unsigned long maxVal );
+
+protected:
+       virtual void writeExports();
+       virtual void writeInit();
+
+       /* Determine if we should use indicies. */
+       virtual void calcIndexSize();
+
+       virtual void BREAK( ostream &ret, int targState ) = 0;
+       virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
+       virtual void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish ) = 0;
+       virtual void CALL( ostream &ret, int callDest, int targState, 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 NEXT( ostream &ret, int nextDest, bool inFinish ) = 0;
+       virtual void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish ) = 0;
+
+       virtual int TO_STATE_ACTION( RedStateAp *state ) = 0;
+       virtual int FROM_STATE_ACTION( RedStateAp *state ) = 0;
+       virtual int EOF_ACTION( RedStateAp *state ) = 0;
+
+       virtual int TRANS_ACTION( RedTransAp *trans );
+
+        void EXEC( 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 );
@@ -164,35 +149,26 @@ public:
        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();
+       void SUB_ACTION( ostream &ret, InlineItem *item, int targState, bool inFinish );
 
+protected:
        ostream &source_warning(const InputLoc &loc);
        ostream &source_error(const InputLoc &loc);
 
-       unsigned int arrayTypeSize( unsigned long maxVal );
 
+        /* fields */
        bool outLabelUsed;
        bool againLabelUsed;
-
        bool useIndicies;
 
-public:
-       string NULL_ITEM();
-       ostream &OPEN_ARRAY( string type, string name );
-       ostream &CLOSE_ARRAY();
-       ostream &STATIC_VAR( string type, string name );
-       string ARR_OFF( string ptr, string offset );
-       string GET_KEY();
-       void ACTION( ostream &ret, Action *action, int targState, bool inFinish );
-
-private:
-       string INDENT(int level);
-       int indent_level;
 };
 
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
 
 #endif
diff --git a/rlgen-ruby/ruby-fflatcodegen.cpp b/rlgen-ruby/ruby-fflatcodegen.cpp
new file mode 100644 (file)
index 0000000..b8abdde
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include "ruby-fflatcodegen.h"
+
+int RubyFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->toStateAction != 0 )
+               act = state->toStateAction->actListId+1;
+       return act;
+}
+
+int RubyFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->fromStateAction != 0 )
+               act = state->fromStateAction->actListId+1;
+       return act;
+}
+
+int RubyFFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->eofAction != 0 )
+               act = state->eofAction->actListId+1;
+       return act;
+}
+
+/* Write out the function for a transition. */
+int RubyFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+       int action = 0;
+       if ( trans->action != 0 )
+               action = trans->action->actListId+1;
+       return action;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::TO_STATE_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numToStateRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << "\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numFromStateRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << "\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RubyFFlatCodeGen::EOF_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numEofRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << "\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, true );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFFlatCodeGen::ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numTransRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << "\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+void RubyFFlatCodeGen::writeData()
+{
+       if ( redFsm->anyConditions() ) {
+               OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+               COND_KEYS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+               COND_KEY_SPANS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+               CONDS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+               COND_INDEX_OFFSET();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+       KEYS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+       KEY_SPANS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+       FLAT_INDEX_OFFSET();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+       INDICIES();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+       TRANS_TARGS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       if ( redFsm->anyActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+               TRANS_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyToStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc),  TSA() );
+               TO_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyFromStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+               FROM_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyEofActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+               EOF_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       STATE_IDS();
+}
+
+void RubyFFlatCodeGen::writeExec()
+{
+       out << 
+               "begin # ragel fflat\n"
+               "       _slen, _trans, _keys, _inds";
+       if ( redFsm->anyRegCurStateRef() )
+               out << ", _ps";
+       if ( redFsm->anyConditions() )
+               out << ", _cond, _conds, _widec";
+       if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
+                       || redFsm->anyFromStateActions() )
+               out << ", _acts, _nacts";
+       
+       out << " = nil\n";
+       
+       if ( hasEnd ) 
+               out << "        if " << P() << " != " << PE() << " # pe guard\n";
+
+       if ( redFsm->errState != 0 ) 
+               out << "        if " << CS() << " != " << redFsm->errState->id << " # errstate guard\n";
+
+
+       
+       out << /* Open the _resume loop. */
+               "       while true # _resume loop \n"
+               "               _break_resume = false\n";       
+       out << /* Open the _again loop. */
+               "       begin\n"
+               "               _break_again = false\n";
+
+       if ( redFsm->anyFromStateActions() ) {
+               out <<
+                       "       case " << FSA() << "[" << CS() << "] \n";
+               FROM_STATE_ACTION_SWITCH();
+               out << 
+                       "       end # from state action switch \n"
+                       "       break if _break_again\n";
+       }
+
+       if ( redFsm->anyConditions() )
+               COND_TRANSLATE();
+       
+       LOCATE_TRANS();
+
+       if ( redFsm->anyRegCurStateRef() )
+               out << "        _ps = " << CS() << "\n";
+
+       out << "        " << CS() << " = " << TT() << "[_trans]\n";
+
+       if ( redFsm->anyRegActions() ) {
+               /* break _again */
+               out << 
+                       "       break if " << TA() << "[_trans] == 0\n"
+                       "       case " << TA() << "[_trans]" << "\n";
+               ACTION_SWITCH();
+               out << 
+                       "       end # action switch\n";
+               /* Not necessary as long as there is no code between here and the
+                * end while false. */
+               // "break if _break_again\n";
+       }
+       
+       out << /* Close the _again loop. */
+               "       end while false # _again loop\n"
+               "       break if _break_resume\n";
+       
+       if ( redFsm->anyToStateActions() ) {
+               out <<
+                       "       case " << TSA() << "[" << CS() << "] \n";
+               TO_STATE_ACTION_SWITCH();
+               out <<
+                       "       end # to state action switch \n"
+                       "\n";
+       }
+
+       if ( redFsm->errState != 0 ) 
+               out << "        break if " << CS() << " == " << redFsm->errState->id << "\n";
+
+       out << "        " << P() << " += 1\n";
+
+       if ( hasEnd )
+               out << "        break if " << P() << " == " << PE() << "\n";
+
+       
+       out << /* Close the _resume loop. */
+               "       end # _resume loop\n";
+
+       if ( redFsm->errState != 0 ) 
+               out << "        end # errstate guard\n";
+
+       
+       if ( hasEnd )
+               out << "        end # pe guard\n";
+
+       out << "end # ragel fflat";
+
+}
+
+
+void RubyFFlatCodeGen::writeEOF()
+{
+       if ( redFsm->anyEofActions() ) {
+               out <<
+                       "         case " << EA() << "[" << CS() << "]\n";
+               EOF_ACTION_SWITCH();
+               out <<
+                       "         end # eof action switch \n"
+                       "\n";
+       }
+}
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
diff --git a/rlgen-ruby/ruby-fflatcodegen.h b/rlgen-ruby/ruby-fflatcodegen.h
new file mode 100644 (file)
index 0000000..9836b95
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#ifndef _RUBY_FFLATCODEGEN_H
+#define _RUBY_FFLATCODEGEN_H
+
+#include <iostream>
+#include "ruby-flatcodegen.h"
+
+class RubyFFlatCodeGen : public RubyFlatCodeGen 
+{
+public:
+       RubyFFlatCodeGen( ostream &out ) : 
+               RubyFlatCodeGen(out) {}
+protected:
+       
+       std::ostream &TO_STATE_ACTION_SWITCH();
+       std::ostream &FROM_STATE_ACTION_SWITCH();
+       std::ostream &EOF_ACTION_SWITCH();
+       std::ostream &ACTION_SWITCH();
+
+       virtual int TO_STATE_ACTION( RedStateAp *state );
+       virtual int FROM_STATE_ACTION( RedStateAp *state );
+       virtual int EOF_ACTION( RedStateAp *state );
+       virtual int TRANS_ACTION( RedTransAp *trans );
+
+       virtual void writeData();
+       virtual void writeEOF();
+       virtual void writeExec();
+};
+
+#endif /* _RUBY_FFLATCODEGEN_H */
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
diff --git a/rlgen-ruby/ruby-flatcodegen.cpp b/rlgen-ruby/ruby-flatcodegen.cpp
new file mode 100644 (file)
index 0000000..eebca6e
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ */
+
+/*  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 "ruby-flatcodegen.h"
+#include "rlgen-ruby.h"
+#include "redfsm.h"
+#include "gendata.h"
+
+using std::ostream;
+using std::string;
+
+std::ostream &RubyFlatCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, true );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::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 << "\twhen " << act->actionId << "\n";
+                       ACTION( out, act, 0, false );
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+
+std::ostream &RubyFlatCodeGen::KEYS()
+{
+       START_ARRAY_LINE();
+       int totalTrans = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Emit just low key and high key. */
+               ARRAY_ITEM( KEY( st->lowKey ), ++totalTrans, false );
+               ARRAY_ITEM( KEY( st->highKey ), ++totalTrans, false );
+               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. */
+       ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::INDICIES()
+{
+       int totalTrans = 0;
+       START_ARRAY_LINE();
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               if ( st->transList != 0 ) {
+                       /* Walk the singles. */
+                       unsigned long long span = keyOps->span( st->lowKey, st->highKey );
+                       for ( unsigned long long pos = 0; pos < span; pos++ ) {
+                               ARRAY_ITEM( KEY( st->transList[pos]->id ), ++totalTrans, false );
+                       }
+               }
+
+               /* The state's default index goes next. */
+               if ( st->defTrans != 0 )
+                       ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
+       }
+
+       /* Output one last number so we don't have to figure out when the last
+        * entry is and avoid writing a comma. */
+       ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::FLAT_INDEX_OFFSET()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0, curIndOffset = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write the index offset. */
+               ARRAY_ITEM( INT( curIndOffset ), ++totalStateNum, st.last() );
+               /* Move the index offset ahead. */
+               if ( st->transList != 0 )
+                       curIndOffset += keyOps->span( st->lowKey, st->highKey );
+
+               if ( st->defTrans != 0 )
+                       curIndOffset += 1;
+       }
+
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::KEY_SPANS()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write singles length. */
+               unsigned long long span = 0;
+               if ( st->transList != 0 )
+                       span = keyOps->span( st->lowKey, st->highKey );
+               ARRAY_ITEM( INT( span ), ++totalStateNum, st.last() );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::TO_STATE_ACTIONS()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write any eof action. */
+               ARRAY_ITEM( INT( TO_STATE_ACTION(st) ), ++totalStateNum, st.last() );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::FROM_STATE_ACTIONS()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write any eof action. */
+               ARRAY_ITEM( INT( FROM_STATE_ACTION(st) ), ++totalStateNum, st.last() );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::EOF_ACTIONS()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write any eof action. */
+               ARRAY_ITEM( INT( EOF_ACTION(st) ), ++totalStateNum, st.last() );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::TRANS_TARGS()
+{
+       /* Transitions must be written ordered by their id. */
+       RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+       for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+               transPtrs[trans->id] = trans;
+
+       /* Keep a count of the num of items in the array written. */
+       START_ARRAY_LINE();
+
+       int totalStates = 0;
+       for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+               /* Write out the target state. */
+               RedTransAp *trans = transPtrs[t];
+               ARRAY_ITEM( INT( trans->targ->id ), ++totalStates, t >= redFsm->transSet.length()-1  );
+       }
+       END_ARRAY_LINE();
+       delete[] transPtrs;
+       return out;
+}
+
+
+std::ostream &RubyFlatCodeGen::TRANS_ACTIONS()
+{
+       /* Transitions must be written ordered by their id. */
+       RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
+       for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
+               transPtrs[trans->id] = trans;
+
+       /* Keep a count of the num of items in the array written. */
+       START_ARRAY_LINE();
+       int totalAct = 0;
+       for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
+               /* Write the function for the transition. */
+               RedTransAp *trans = transPtrs[t];
+               ARRAY_ITEM( INT( TRANS_ACTION( trans ) ), ++totalAct, t >= redFsm->transSet.length()-1 );
+       }
+       END_ARRAY_LINE();
+       delete[] transPtrs;
+       return out;
+}
+
+
+void RubyFlatCodeGen::LOCATE_TRANS()
+{
+       out <<
+               "       _keys = " << CS() << " << 1\n"
+               "       _inds = " << IO() << "[" << CS() << "]\n"
+               "       _slen = " << SP() << "[" << CS() << "]\n"
+               "       _trans = if (   _slen > 0 && \n"
+               "                       " << K() << "[_keys] <= " << GET_WIDE_KEY() << " && \n"
+               "                       " << GET_WIDE_KEY() << " <= " << K() << "[_keys + 1] \n"
+               "                   ) then\n"
+               "                       " << I() << "[ _inds + " << GET_WIDE_KEY() << " - " << K() << "[_keys] ] \n"
+               "                else \n"
+               "                       " << I() << "[ _inds + _slen ]\n"
+               "                end\n"
+               "";
+       
+}
+
+std::ostream &RubyFlatCodeGen::COND_INDEX_OFFSET()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0, curIndOffset = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write the index offset. */
+               ARRAY_ITEM( INT( curIndOffset ), ++totalStateNum, st.last() );
+               /* Move the index offset ahead. */
+               if ( st->condList != 0 )
+                       curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+void RubyFlatCodeGen::COND_TRANSLATE()
+{
+       out << 
+               "       _widec = " << GET_KEY() << "\n"
+               "       _keys = " << CS() << " << 1\n"
+               "       _conds = " << CO() << "[" << CS() << "]\n"
+               "       _slen = " << CSP() << "[" << CS() << "]\n"
+               "       _cond = if ( _slen > 0 && \n" 
+               "                    " << CK() << "[_keys] <= " << GET_WIDE_KEY() << " &&\n" 
+               "                    " << GET_WIDE_KEY() << " <= " << CK() << "[_keys + 1]\n"
+               "                  ) then \n"
+               "                       " << C() << "[ _conds + " << GET_WIDE_KEY() << " - " << CK() << "[_keys]" << " ]\n"
+               "               else\n"
+               "                      0\n"
+               "               end\n";
+       out <<
+               "       case _cond \n";
+       for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
+               CondSpace *condSpace = csi;
+               out << "        when " << condSpace->condSpaceId + 1 << "\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 << 
+                               " ) then \n" <<
+                               TABS(3) << "  _widec += " << condValOffset << "\n"
+                               "end\n";
+               }
+       }
+
+       out <<
+               "       end # _cond switch \n";
+}
+
+std::ostream &RubyFlatCodeGen::CONDS()
+{
+       int totalTrans = 0;
+       START_ARRAY_LINE();
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               if ( st->condList != 0 ) {
+                       /* Walk the singles. */
+                       unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
+                       for ( unsigned long long pos = 0; pos < span; pos++ ) {
+                               if ( st->condList[pos] != 0 )
+                                       ARRAY_ITEM( INT( st->condList[pos]->condSpaceId + 1 ), ++totalTrans, false );
+                               else
+                                       ARRAY_ITEM( INT( 0 ), ++totalTrans, false );
+                       }
+               }
+       }
+
+       /* Output one last number so we don't have to figure out when the last
+        * entry is and avoid writing a comma. */
+       ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::COND_KEYS()
+{
+       START_ARRAY_LINE();
+       int totalTrans = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Emit just cond low key and cond high key. */
+               ARRAY_ITEM( KEY( st->condLowKey ), ++totalTrans, false );
+               ARRAY_ITEM( KEY( st->condHighKey ), ++totalTrans, false );
+       }
+
+       /* Output one last number so we don't have to figure out when the last
+        * entry is and avoid writing a comma. */
+       ARRAY_ITEM( INT( 0 ), ++totalTrans, true );
+       END_ARRAY_LINE();
+       return out;
+}
+
+std::ostream &RubyFlatCodeGen::COND_KEY_SPANS()
+{
+       START_ARRAY_LINE();
+       int totalStateNum = 0;
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               /* Write singles length. */
+               unsigned long long span = 0;
+               if ( st->condList != 0 )
+                       span = keyOps->span( st->condLowKey, st->condHighKey );
+               ARRAY_ITEM( INT( span ), ++totalStateNum, false );
+       }
+       END_ARRAY_LINE();
+       return out;
+}
+
+
+void RubyFlatCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+{
+       out << 
+               "       begin\n"
+               "               " << CS() << " = " << gotoDest << "\n"
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+}
+
+void RubyFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+{
+       out <<
+               "       begin\n"
+               "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
+               "               " << TOP() << "+= 1\n"
+               "               " << CS() << " = " << callDest << "\n"
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+}
+
+void RubyFlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+{
+       ret << CS() << " = " << nextDest << ";";
+}
+
+void RubyFlatCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
+{
+       out << 
+               "       begin\n"
+               "               " << CS() << " = (";
+       INLINE_LIST( out, ilItem->children, 0, inFinish );
+       out << ")\n";
+       out <<
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+}
+
+void RubyFlatCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+       ret << CS() << " = (";
+       INLINE_LIST( ret, ilItem->children, 0, inFinish );
+       ret << ");";
+}
+
+
+void RubyFlatCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
+{
+       out <<
+               "       begin\n"
+               "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
+               "               " << TOP() << " += 1\n"
+               "               " << CS() << " = (";
+       INLINE_LIST( out, ilItem->children, targState, inFinish );
+       out << ")\n";
+
+       out << 
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+}
+
+void RubyFlatCodeGen::CURS( ostream &ret, bool inFinish )
+{
+       ret << "(_ps)";
+}
+
+void RubyFlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
+{
+       ret << "(" << CS() << ")";
+}
+
+void RubyFlatCodeGen::RET( ostream &out, bool inFinish )
+{
+       out <<
+               "       begin\n"
+               "               " << TOP() << " -= 1\n"
+               "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n"
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+}
+
+void RubyFlatCodeGen::BREAK( ostream &out, int targState )
+{
+       out << 
+               "       begin\n"
+               "               _break_resume = true\n"
+               "               break\n"
+               "       end\n";
+}
+
+int RubyFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->toStateAction != 0 )
+               act = state->toStateAction->location+1;
+       return act;
+}
+
+int RubyFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->fromStateAction != 0 )
+               act = state->fromStateAction->location+1;
+       return act;
+}
+
+int RubyFlatCodeGen::EOF_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->eofAction != 0 )
+               act = state->eofAction->location+1;
+       return act;
+}
+
+int RubyFlatCodeGen::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;
+       return act;
+}
+
+void RubyFlatCodeGen::writeData()
+{
+       /* If there are any transtion functions then output the array. If there
+        * are none, don't bother emitting an empty array that won't be used. */
+       if ( redFsm->anyActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
+               ACTIONS_ARRAY();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyConditions() ) {
+               OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+               COND_KEYS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
+               COND_KEY_SPANS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
+               CONDS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
+               COND_INDEX_OFFSET();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+       KEYS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
+       KEY_SPANS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
+       FLAT_INDEX_OFFSET();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+       INDICIES();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+       TRANS_TARGS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       if ( redFsm->anyActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
+               TRANS_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyToStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+               TO_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyFromStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+               FROM_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyEofActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
+               EOF_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       STATE_IDS();
+}
+
+void RubyFlatCodeGen::writeEOF()
+{
+       if ( redFsm->anyEofActions() ) {
+               out << 
+                       "       begin\n"
+                       "       " << "_acts = " << EA() << "[" << CS() << "]\n"
+                       "       _nacts = " << A() << "[_acts]\n" << 
+                       "       _acts += 1\n"
+                       "       while ( _nacts > 0 ) \n"
+                       "               _nacts -= 1\n"
+                       "               _acts += 1\n"
+                       "               case ( "<< A() << "[_acts-1] ) \n";
+               EOF_ACTION_SWITCH();
+               out <<
+                       "               end # eof action switch \n"
+                       "       end\n"
+                       "       end\n"
+                       "\n";
+       }
+}
+
+void RubyFlatCodeGen::writeExec()
+{
+       out << 
+               "begin # ragel flat\n"
+               "       _slen, _trans, _keys, _inds";
+       if ( redFsm->anyRegCurStateRef() )
+               out << ", _ps";
+       if ( redFsm->anyConditions() )
+               out << ", _cond, _conds, _widec";
+       if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
+                       || redFsm->anyFromStateActions() )
+               out << ", _acts, _nacts";
+       
+       out << " = nil\n";
+       
+       if ( hasEnd ) 
+               out << "        if " << P() << " != " << PE() << " # pe guard\n";
+
+       if ( redFsm->errState != 0 ) 
+               out << "        if " << CS() << " != " << redFsm->errState->id << " # errstate guard\n";
+
+
+       
+       out << /* Open the _resume loop. */
+               "       while true # _resume loop \n"
+               "               _break_resume = false\n";       
+       out << /* Open the _again loop. */
+               "       begin\n"
+               "               _break_again = false\n";
+
+       if ( redFsm->anyFromStateActions() ) {
+               out << 
+                       "       _acts = " << FSA() << "[" << CS() << "]\n"
+                       "       _nacts = " << A() << "[_acts]\n"
+                       "       _acts += 1\n"
+                       "       while _nacts > 0\n"
+                       "               _nacts -= 1\n"
+                       "               _acts += 1\n"
+                       "               case " << A() << "[_acts - 1]\n";
+               FROM_STATE_ACTION_SWITCH();
+               out <<
+                       "               end # from state action switch\n"
+                       "       end\n"
+                       "       break if _break_again\n";
+       }
+
+       if ( redFsm->anyConditions() )
+               COND_TRANSLATE();
+       
+       LOCATE_TRANS();
+
+       if ( redFsm->anyRegCurStateRef() )
+               out << "        _ps = " << CS() << "\n";
+
+       out << "        " << CS() << " = " << TT() << "[_trans]\n";
+
+       if ( redFsm->anyRegActions() ) {
+               /* break _again */
+               out << 
+                       "       break if " << TA() << "[_trans] == 0\n"
+                       "       _acts = " << TA() << "[_trans]\n"
+                       "       _nacts = " << A() << "[_acts]\n"
+                       "       _acts += 1\n"
+                       "       while _nacts > 0\n"
+                       "               _nacts -= 1\n"
+                       "               _acts += 1\n"
+                       "               case " << A() << "[_acts - 1]\n";
+               ACTION_SWITCH();
+               out <<
+                       "               end # action switch\n"
+                       "       end\n";
+
+                       /* Not necessary as long as there is no code between here and the
+                        * end while false. */
+                       // "break if _break_again\n";
+       }
+
+       
+       out << /* Close the _again loop. */
+               "       end while false # _again loop\n"
+               "       break if _break_resume\n";
+       
+       if ( redFsm->anyToStateActions() ) {
+               out <<
+                       "       _acts = " << TSA() << "["  << CS() << "]\n"
+                       "       _nacts = " << A() << "[_acts]\n"
+                       "       _acts += 1\n"
+                       "       while _nacts > 0\n"
+                       "               _nacts -= 1\n"
+                       "               _acts += 1\n"
+                       "               case " << A() << "[_acts - 1]\n";
+               TO_STATE_ACTION_SWITCH();
+               out <<
+                       "               end # to state action switch\n"
+                       "       end\n";
+       }
+
+       if ( redFsm->errState != 0 ) 
+               out << "        break if " << CS() << " == " << redFsm->errState->id << "\n";
+
+       out << "        " << P() << " += 1\n";
+
+       if ( hasEnd )
+               out << "        break if " << P() << " == " << PE() << "\n";
+
+       
+       out << /* Close the _resume loop. */
+               "       end # _resume loop\n";
+
+       if ( redFsm->errState != 0 ) 
+               out << "        end # errstate guard\n";
+
+       
+       if ( hasEnd )
+               out << "        end # pe guard\n";
+
+       out << "end # ragel flat";
+}
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/rlgen-ruby/ruby-flatcodegen.h b/rlgen-ruby/ruby-flatcodegen.h
new file mode 100644 (file)
index 0000000..f7b97a1
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#ifndef _RUBY_FLATCODEGEN_H
+#define _RUBY_FLATCODEGEN_H
+
+#include <iostream>
+#include "ruby-codegen.h"
+
+using std::string;
+using std::ostream;
+
+
+/*
+ * FlatCodeGen
+ */
+class RubyFlatCodeGen : public RubyCodeGen
+{
+public:
+       RubyFlatCodeGen( ostream &out ) :
+               RubyCodeGen(out) {};
+       virtual ~RubyFlatCodeGen() {}
+protected:
+       
+       std::ostream &TO_STATE_ACTION_SWITCH();
+       std::ostream &FROM_STATE_ACTION_SWITCH();
+       std::ostream &EOF_ACTION_SWITCH();
+       std::ostream &ACTION_SWITCH();
+
+       std::ostream &KEYS();
+       std::ostream &INDICIES();
+       std::ostream &FLAT_INDEX_OFFSET();
+       std::ostream &KEY_SPANS();
+       std::ostream &TO_STATE_ACTIONS();
+       std::ostream &FROM_STATE_ACTIONS();
+       std::ostream &EOF_ACTIONS();
+       std::ostream &TRANS_TARGS();
+       std::ostream &TRANS_ACTIONS();
+       void LOCATE_TRANS();
+       
+       std::ostream &COND_INDEX_OFFSET();
+       void COND_TRANSLATE();
+       std::ostream &CONDS();
+       std::ostream &COND_KEYS();
+       std::ostream &COND_KEY_SPANS();
+       
+
+       void GOTO( ostream &ret, int gotoDest, bool inFinish );
+       void CALL( ostream &ret, int callDest, int targState, bool inFinish );
+       void NEXT( ostream &ret, int nextDest, bool inFinish );
+       void GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+       void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+       void CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish );
+       void CURS( ostream &ret, bool inFinish );
+       void TARGS( ostream &ret, bool inFinish, int targState );
+       void RET( ostream &ret, bool inFinish );
+       void BREAK( ostream &ret, int targState );
+
+
+       virtual int TO_STATE_ACTION( RedStateAp *state );
+       virtual int FROM_STATE_ACTION( RedStateAp *state );
+       virtual int EOF_ACTION( RedStateAp *state );
+       virtual int TRANS_ACTION( RedTransAp *trans );
+
+       virtual void writeData();
+       virtual void writeEOF();
+       virtual void writeExec();
+
+};
+
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/rlgen-ruby/ruby-ftabcodegen.cpp b/rlgen-ruby/ruby-ftabcodegen.cpp
new file mode 100644 (file)
index 0000000..fed8dad
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include <iomanip>
+#include <sstream>
+#include "redfsm.h"
+#include "gendata.h"
+#include "rlgen-ruby.h"
+#include "ruby-ftabcodegen.h"
+
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::cerr;
+using std::endl;
+
+std::ostream &RubyFTabCodeGen::TO_STATE_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numToStateRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << "\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFTabCodeGen::FROM_STATE_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numFromStateRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << ":\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+std::ostream &RubyFTabCodeGen::EOF_ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numEofRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << ":\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, true );
+
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+/* Write out the function switch. This switch is keyed on the values
+ * of the func index. */
+std::ostream &RubyFTabCodeGen::ACTION_SWITCH()
+{
+       /* Loop the actions. */
+       for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
+               if ( redAct->numTransRefs > 0 ) {
+                       /* Write the entry label. */
+                       out << "\twhen " << redAct->actListId+1 << ":\n";
+
+                       /* Write each action in the list of action items. */
+                       for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
+                               ACTION( out, item->value, 0, false );
+
+               }
+       }
+
+       genLineDirective( out );
+       return out;
+}
+
+
+int RubyFTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->toStateAction != 0 )
+               act = state->toStateAction->actListId+1;
+       return act;
+}
+
+int RubyFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->fromStateAction != 0 )
+               act = state->fromStateAction->actListId+1;
+       return act;
+}
+
+int RubyFTabCodeGen::EOF_ACTION( RedStateAp *state )
+{
+       int act = 0;
+       if ( state->eofAction != 0 )
+               act = state->eofAction->actListId+1;
+        return act;
+}
+
+
+/* Write out the function for a transition. */
+int RubyFTabCodeGen::TRANS_ACTION( RedTransAp *trans )
+{
+       int action = 0;
+       if ( trans->action != 0 )
+               action = trans->action->actListId+1;
+       return action;
+}
+
+void RubyFTabCodeGen::writeData()
+{
+
+       if ( redFsm->anyConditions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
+               COND_OFFSETS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
+               COND_LENS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
+               COND_KEYS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
+               COND_SPACES();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
+       KEY_OFFSETS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
+       KEYS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
+       SINGLE_LENS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
+       RANGE_LENS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
+       INDEX_OFFSETS();
+       CLOSE_ARRAY() <<
+       "\n";
+
+       if ( useIndicies ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
+               INDICIES();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+               TRANS_TARGS_WI();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               if ( redFsm->anyActions() ) {
+                       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+                       TRANS_ACTIONS_WI();
+                       CLOSE_ARRAY() <<
+                       "\n";
+               }
+       }
+       else {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
+               TRANS_TARGS();
+               CLOSE_ARRAY() <<
+               "\n";
+
+               if ( redFsm->anyActions() ) {
+                       OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
+                       TRANS_ACTIONS();
+                       CLOSE_ARRAY() <<
+                       "\n";
+               }
+       }
+
+       if ( redFsm->anyToStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
+               TO_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyFromStateActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
+               FROM_STATE_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       if ( redFsm->anyEofActions() ) {
+               OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
+               EOF_ACTIONS();
+               CLOSE_ARRAY() <<
+               "\n";
+       }
+
+       STATE_IDS();
+}
+
+void RubyFTabCodeGen::writeEOF()
+{
+       if ( redFsm->anyEofActions() ) {
+               out <<
+                       "       begin\n"
+                       "               case ( " << EA() << "[" << CS() << "] )\n";
+                       EOF_ACTION_SWITCH();
+               out <<
+                       "               end\n"
+                       "       end\n"
+                       "\n";
+       }
+}
+
+void RubyFTabCodeGen::writeExec()
+{
+       out << 
+                "      begin # ragel ftab \n"
+               "         _klen, _trans, _keys";
+
+       if ( redFsm->anyRegCurStateRef() )
+               out << ", _ps";
+
+       if ( redFsm->anyConditions() )
+               out << ", _widec";
+
+       out << " = nil\n";
+
+       if ( hasEnd ) {
+               out <<  "       if " << P() << " != " << PE() << " \n";
+       }
+
+       if ( redFsm->errState != 0 ) {
+               outLabelUsed = true;
+               out << "        if  " << CS() << " != " << redFsm->errState->id << "\n";
+       }
+
+        /* Open the _resume loop. */
+       out << "        loop do # _resume \n"
+               "               _break_resume = false\n";
+
+       /* Open the _again loop. */
+       out << "        begin # _again loop \n"
+           << "                _break_again = false\n";
+
+       if ( redFsm->anyFromStateActions() ) {
+               out <<
+                       "       case " << FSA() << "[" << CS() << "] \n";
+                       FROM_STATE_ACTION_SWITCH();
+               out <<
+                       "       end # from state action switch \n"
+                        "      break if _break_again\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() ) {
+                /* break _again */
+               out << 
+                       "       break if " << TA() << "[_trans] == 0\n"
+                       "\n"
+                       "       case " << TA() << "[_trans] \n";
+                       ACTION_SWITCH();
+                out <<
+                       "       end # action switch \n"
+                       "\n";
+                /* Not necessary as long as there is no code between here and the
+                 * end while false. */
+                // "break if _break_again\n";
+
+       }
+        
+        /* Close the again loop. */
+        out << "       end while false # _again loop\n";
+        out << "       break if _break_resume\n";
+
+       if ( redFsm->anyToStateActions() ) {
+               out <<
+                       "       case " << TSA() << "[" << CS() << "] \n";
+                       TO_STATE_ACTION_SWITCH();
+               out <<
+                       "       end # to state action switch \n"
+                       "\n";
+       }
+
+       if ( redFsm->errState != 0 ) {
+               out << 
+                       "       break if  " << CS() << " == " << redFsm->errState->id << "\n";
+       }
+
+       out << "        " << P() << " += 1\n";
+
+       if ( hasEnd ) {
+               out << 
+                       "       break if "<< P() << " == " << PE() << " \n";
+       }
+
+       /* Close the resume loop. */
+       out << "        end # close the resume loop \n";
+
+
+       /* The if guarding on the error state. */
+       if ( redFsm->errState != 0 ) 
+               out << "        end # close if guarding error state \n";
+
+       /* The if guarding on empty string. */
+       if ( hasEnd ) 
+               out << "        end # close if guarding empty string \n";
+
+       /* Wrapping the execute block. */
+       out << "        end # close execution block \n";
+}
+
+
+void RubyFTabCodeGen::calcIndexSize()
+{
+       int sizeWithInds = 0, sizeWithoutInds = 0;
+
+       /* Calculate cost of using with indicies. */
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               int totalIndex = st->outSingle.length() + st->outRange.length() + 
+                               (st->defTrans == 0 ? 0 : 1);
+               sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
+       }
+       sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
+       if ( redFsm->anyActions() )
+               sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length();
+
+       /* Calculate the cost of not using indicies. */
+       for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+               int totalIndex = st->outSingle.length() + st->outRange.length() + 
+                               (st->defTrans == 0 ? 0 : 1);
+               sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
+               if ( redFsm->anyActions() )
+                       sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex;
+       }
+
+       /* If using indicies reduces the size, use them. */
+       useIndicies = sizeWithInds < sizeWithoutInds;
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
diff --git a/rlgen-ruby/ruby-ftabcodegen.h b/rlgen-ruby/ruby-ftabcodegen.h
new file mode 100644 (file)
index 0000000..0b45e29
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  2007 Victor Hugo Borja <vic@rubyforge.org>
+ *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#ifndef _RUBY_FTABCODEGEN_H
+#define _RUBY_FTABCODEGEN_H
+
+#include "ruby-tabcodegen.h"
+
+class RubyFTabCodeGen : public RubyTabCodeGen
+{
+public:
+        RubyFTabCodeGen( ostream &out ): RubyTabCodeGen(out) {}
+protected:
+        std::ostream &TO_STATE_ACTION_SWITCH();
+       std::ostream &FROM_STATE_ACTION_SWITCH();
+       std::ostream &EOF_ACTION_SWITCH();
+       std::ostream &ACTION_SWITCH();
+
+       int TO_STATE_ACTION( RedStateAp *state );
+       int FROM_STATE_ACTION( RedStateAp *state );
+       int EOF_ACTION( RedStateAp *state );
+       virtual int TRANS_ACTION( RedTransAp *trans );
+
+       void writeData();
+       void writeEOF();
+       void writeExec();
+       void calcIndexSize();
+};
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
+
+#endif
+
similarity index 54%
rename from rlgen-ruby/rubycodegen.cpp
rename to rlgen-ruby/ruby-tabcodegen.cpp
index 581dbba..c037730 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
 
-#include "rlgen-ruby.h"
-#include "rubycodegen.h"
-#include "redfsm.h"
-#include "gendata.h"
 #include <iomanip>
 #include <sstream>
-
-/* Integer array line length. */
-#define IALL 8
+#include "redfsm.h"
+#include "gendata.h"
+#include "rlgen-ruby.h"
+#include "ruby-tabcodegen.h"
 
 using std::ostream;
 using std::ostringstream;
@@ -36,27 +33,9 @@ using std::string;
 using std::cerr;
 using std::endl;
 
-void lineDirective( ostream &out, char *fileName, int line )
-{
-       /* Write a comment containing line info. */
-       out << "# line " << line  << " \"";
-       for ( char *pc = fileName; *pc != 0; pc++ ) {
-               if ( *pc == '\\' )
-                       out << "\\\\";
-               else
-                       out << *pc;
-       }
-       out << "\"\n";
-}
 
-void genLineDirective( ostream &out )
-{
-       std::streambuf *sbuf = out.rdbuf();
-       output_filter *filter = static_cast<output_filter*>(sbuf);
-       lineDirective( out, filter->fileName, filter->line + 1 );
-}
 
-void RubyCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
+void RubyTabCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
 {
        out << 
                "       begin\n"
@@ -66,7 +45,7 @@ void RubyCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
                "       end\n";
 }
 
-void RubyCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
+void RubyTabCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
 {
        out << 
                "       begin\n"
@@ -79,7 +58,7 @@ void RubyCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish )
                "       end\n";
 }
 
-void RubyCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
+void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
 {
        out <<
                "       begin\n"
@@ -91,7 +70,7 @@ void RubyCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish
                "       end\n";
 }
 
-void RubyCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
+void RubyTabCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
 {
        out <<
                "       begin\n"
@@ -107,7 +86,7 @@ void RubyCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, boo
                "       end\n";
 }
 
-void RubyCodeGen::RET( ostream &out, bool inFinish )
+void RubyTabCodeGen::RET( ostream &out, bool inFinish )
 {
        out <<
                "       begin\n"
@@ -118,7 +97,7 @@ void RubyCodeGen::RET( ostream &out, bool inFinish )
                "       end\n";
 }
 
-void RubyCodeGen::BREAK( ostream &out, int targState )
+void RubyTabCodeGen::BREAK( ostream &out, int targState )
 {
        out << 
                "       begin\n"
@@ -127,7 +106,7 @@ void RubyCodeGen::BREAK( ostream &out, int targState )
                "       end\n";
 }
 
-void RubyCodeGen::COND_TRANSLATE()
+void RubyTabCodeGen::COND_TRANSLATE()
 {
        out <<
                "       _widec = " << GET_KEY() << "\n"
@@ -168,7 +147,8 @@ void RubyCodeGen::COND_TRANSLATE()
                "       end\n";
 }
 
-void RubyCodeGen::LOCATE_TRANS()
+
+void RubyTabCodeGen::LOCATE_TRANS()
 {
        out <<
                "       _keys = " << KO() << "[" << CS() << "]\n"
@@ -223,7 +203,7 @@ void RubyCodeGen::LOCATE_TRANS()
                "       end while false\n";
 }
 
-void RubyCodeGen::writeExec()
+void RubyTabCodeGen::writeExec()
 {
        out << "begin\n"
                << "    _klen, _trans, _keys";
@@ -261,8 +241,8 @@ void RubyCodeGen::writeExec()
                        "               _nacts -= 1\n"
                        "               _acts += 1\n"
                        "               case " << A() << "[_acts - 1]\n";
-
-               FROM_STATE_ACTION_SWITCH() << 
+               FROM_STATE_ACTION_SWITCH();
+               out <<
                        "               end # from state action switch\n"
                        "       end\n"
                        "       break if _break_again\n";
@@ -292,7 +272,8 @@ void RubyCodeGen::writeExec()
                        "               _nacts -= 1\n"
                        "               _acts += 1\n"
                        "               case " << A() << "[_acts - 1]\n";
-               ACTION_SWITCH() << 
+               ACTION_SWITCH();
+               out <<
                        "               end # action switch\n"
                        "       end\n";
 
@@ -314,7 +295,8 @@ void RubyCodeGen::writeExec()
                        "               _nacts -= 1\n"
                        "               _acts += 1\n"
                        "               case " << A() << "[_acts - 1]\n";
-               TO_STATE_ACTION_SWITCH() <<
+               TO_STATE_ACTION_SWITCH();
+               out <<
                        "               end # to state action switch\n"
                        "       end\n";
        }
@@ -342,7 +324,7 @@ void RubyCodeGen::writeExec()
        out << "        end\n";
 }
 
-void RubyCodeGen::writeEOF()
+void RubyTabCodeGen::writeEOF()
 {
        if ( redFsm->anyEofActions() ) {
                out << 
@@ -359,7 +341,9 @@ void RubyCodeGen::writeEOF()
        }
 }
 
-std::ostream &RubyCodeGen::FROM_STATE_ACTION_SWITCH() 
+
+
+std::ostream &RubyTabCodeGen::FROM_STATE_ACTION_SWITCH() 
 {
        /* Walk the list of functions, printing the cases. */
        for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
@@ -376,14 +360,14 @@ std::ostream &RubyCodeGen::FROM_STATE_ACTION_SWITCH()
 }
 
 
-std::ostream &RubyCodeGen::TO_STATE_ACTION_SWITCH()
+std::ostream &RubyTabCodeGen::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 << "when " << act->actionId << ":\n";
+                       out << "when " << act->actionId << "\n";
                        ACTION( out, act, 0, false );
                }
        }
@@ -392,7 +376,7 @@ std::ostream &RubyCodeGen::TO_STATE_ACTION_SWITCH()
        return out;
 }
 
-std::ostream &RubyCodeGen::EOF_ACTION_SWITCH()
+std::ostream &RubyTabCodeGen::EOF_ACTION_SWITCH()
 {
        /* Walk the list of functions, printing the cases. */
        for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
@@ -408,7 +392,7 @@ std::ostream &RubyCodeGen::EOF_ACTION_SWITCH()
        return out;
 }
 
-std::ostream &RubyCodeGen::ACTION_SWITCH()
+std::ostream &RubyTabCodeGen::ACTION_SWITCH()
 {
        /* Walk the list of functions, printing the cases. */
        for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
@@ -425,264 +409,20 @@ std::ostream &RubyCodeGen::ACTION_SWITCH()
 }
 
 
-void RubyCodeGen::writeInit()
-{
-       out << "begin\n";
-
-       if ( writeCS )
-               out << "        " << CS() << " = " << START() << "\n";
-
-       /* If there are any calls, then the stack top needs initialization. */
-       if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
-               out << "        " << TOP() << " = 0\n";
-
-       if ( hasLongestMatch ) {
-               out <<
-                       "       " << TOKSTART() << " = " << NULL_ITEM() << "\n"
-                       "       " << TOKEND() << " = " << NULL_ITEM() << "\n"
-                       "       " << ACT() << " = 0\n";
-       }
-
-       out << "end\n";
-}
-
-std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
-{
-       out << 
-               "class << self\n"
-               "       attr_accessor :" << name << "\n"
-               "       private :" << name << ", :" << name << "=\n"
-               "end\n"
-               "self." << name << " = [\n";
-       return out;
-}
-
-std::ostream &RubyCodeGen::CLOSE_ARRAY()
-{
-       out << "]\n";
-       return out;
-}
-
-std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
-{
-       out << 
-               "class << self\n"
-               "       attr_accessor :" << name << "\n"
-               "end\n"
-               "self." << name;
-       return out;
-}
-
-string RubyCodeGen::ARR_OFF( string ptr, string offset )
-{
-       return ptr + " + " + offset;
-}
-
-string RubyCodeGen::NULL_ITEM()
-{
-       return "nil";
-}
-
-string RubyCodeGen::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();
-}
-
-void RubyCodeGen::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 << "                begin\n";
-       INLINE_LIST( ret, action->inlineList, targState, inFinish );
-       ret << "                end\n";
-       lineDirective( ret, sourceFileName, action->loc.line );
-}
-
-void RubyCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
+void RubyTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
 {
        ret << CS() << " = " << nextDest << ";";
 }
 
-void RubyCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+void RubyTabCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
 {
        ret << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, 0, inFinish );
        ret << ");";
 }
 
-void RubyCodeGen::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 << " begin " << P() << " = ((";
-       INLINE_LIST( ret, item->children, targState, inFinish );
-       ret << "))-1; end\n";
-}
-
-/* Write out an inline tree structure. Walks the list and possibly calls out
- * to virtual functions than handle language specific items in the tree. */
-void RubyCodeGen::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() << " = " << P() << " - 1;";
-                       break;
-               case InlineItem::Exec:
-                       EXEC( ret, item, targState, inFinish );
-                       break;
-               case InlineItem::Curs:
-                       ret << "(_ps)";
-                       break;
-               case InlineItem::Targs:
-                       ret << "(" << CS() << ")";
-                       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;
-               }
-       }
-}
 
-string RubyCodeGen::DATA_PREFIX()
-{
-       if ( dataPrefix )
-               return FSM_NAME() + "_";
-       return "";
-}
-
-/* Emit the alphabet data type. */
-string RubyCodeGen::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 RubyCodeGen::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;
-}
-
-/* Determine if we should use indicies or not. */
-void RubyCodeGen::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;
-}
-
-int RubyCodeGen::TO_STATE_ACTION( RedStateAp *state )
+int RubyTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
 {
        int act = 0;
        if ( state->toStateAction != 0 )
@@ -690,7 +430,7 @@ int RubyCodeGen::TO_STATE_ACTION( RedStateAp *state )
        return act;
 }
 
-int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+int RubyTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
 {
        int act = 0;
        if ( state->fromStateAction != 0 )
@@ -698,7 +438,7 @@ int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
        return act;
 }
 
-int RubyCodeGen::EOF_ACTION( RedStateAp *state )
+int RubyTabCodeGen::EOF_ACTION( RedStateAp *state )
 {
        int act = 0;
        if ( state->eofAction != 0 )
@@ -707,16 +447,7 @@ int RubyCodeGen::EOF_ACTION( RedStateAp *state )
 }
 
 
-int RubyCodeGen::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;
-       return act;
-}
-
-std::ostream &RubyCodeGen::COND_OFFSETS()
+std::ostream &RubyTabCodeGen::COND_OFFSETS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0, curKeyOffset = 0;
@@ -731,7 +462,7 @@ std::ostream &RubyCodeGen::COND_OFFSETS()
        return out;
 }
 
-std::ostream &RubyCodeGen::KEY_OFFSETS()
+std::ostream &RubyTabCodeGen::KEY_OFFSETS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0, curKeyOffset = 0;
@@ -747,7 +478,7 @@ std::ostream &RubyCodeGen::KEY_OFFSETS()
 }
 
 
-std::ostream &RubyCodeGen::INDEX_OFFSETS()
+std::ostream &RubyTabCodeGen::INDEX_OFFSETS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0, curIndOffset = 0;
@@ -764,7 +495,7 @@ std::ostream &RubyCodeGen::INDEX_OFFSETS()
        return out;
 }
 
-std::ostream &RubyCodeGen::COND_LENS()
+std::ostream &RubyTabCodeGen::COND_LENS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -777,7 +508,7 @@ std::ostream &RubyCodeGen::COND_LENS()
 }
 
 
-std::ostream &RubyCodeGen::SINGLE_LENS()
+std::ostream &RubyTabCodeGen::SINGLE_LENS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -789,7 +520,7 @@ std::ostream &RubyCodeGen::SINGLE_LENS()
        return out;
 }
 
-std::ostream &RubyCodeGen::RANGE_LENS()
+std::ostream &RubyTabCodeGen::RANGE_LENS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -801,7 +532,7 @@ std::ostream &RubyCodeGen::RANGE_LENS()
        return out;
 }
 
-std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
+std::ostream &RubyTabCodeGen::TO_STATE_ACTIONS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -813,7 +544,7 @@ std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
        return out;
 }
 
-std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
+std::ostream &RubyTabCodeGen::FROM_STATE_ACTIONS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -825,7 +556,7 @@ std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
        return out;
 }
 
-std::ostream &RubyCodeGen::EOF_ACTIONS()
+std::ostream &RubyTabCodeGen::EOF_ACTIONS()
 {
        START_ARRAY_LINE();
        int totalStateNum = 0;
@@ -837,7 +568,7 @@ std::ostream &RubyCodeGen::EOF_ACTIONS()
        return out;
 }
 
-std::ostream &RubyCodeGen::COND_KEYS()
+std::ostream &RubyTabCodeGen::COND_KEYS()
 {
        START_ARRAY_LINE();
        int totalTrans = 0;
@@ -857,7 +588,7 @@ std::ostream &RubyCodeGen::COND_KEYS()
        return out;
 }
 
-std::ostream &RubyCodeGen::COND_SPACES()
+std::ostream &RubyTabCodeGen::COND_SPACES()
 {
        START_ARRAY_LINE();
        int totalTrans = 0;
@@ -876,7 +607,7 @@ std::ostream &RubyCodeGen::COND_SPACES()
        return out;
 }
 
-std::ostream &RubyCodeGen::KEYS()
+std::ostream &RubyTabCodeGen::KEYS()
 {
        START_ARRAY_LINE();
        int totalTrans = 0;
@@ -903,7 +634,7 @@ std::ostream &RubyCodeGen::KEYS()
        return out;
 }
 
-std::ostream &RubyCodeGen::INDICIES()
+std::ostream &RubyTabCodeGen::INDICIES()
 {
        int totalTrans = 0;
        START_ARRAY_LINE();
@@ -931,7 +662,7 @@ std::ostream &RubyCodeGen::INDICIES()
        return out;
 }
 
-std::ostream &RubyCodeGen::TRANS_TARGS()
+std::ostream &RubyTabCodeGen::TRANS_TARGS()
 {
        int totalTrans = 0;
        START_ARRAY_LINE();
@@ -963,7 +694,7 @@ std::ostream &RubyCodeGen::TRANS_TARGS()
 }
 
 
-std::ostream &RubyCodeGen::TRANS_ACTIONS()
+std::ostream &RubyTabCodeGen::TRANS_ACTIONS()
 {
        int totalTrans = 0;
        START_ARRAY_LINE();
@@ -994,7 +725,7 @@ std::ostream &RubyCodeGen::TRANS_ACTIONS()
        return out;
 }
 
-std::ostream &RubyCodeGen::TRANS_TARGS_WI()
+std::ostream &RubyTabCodeGen::TRANS_TARGS_WI()
 {
        /* Transitions must be written ordered by their id. */
        RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
@@ -1015,7 +746,7 @@ std::ostream &RubyCodeGen::TRANS_TARGS_WI()
 }
 
 
-std::ostream &RubyCodeGen::TRANS_ACTIONS_WI()
+std::ostream &RubyTabCodeGen::TRANS_ACTIONS_WI()
 {
        /* Transitions must be written ordered by their id. */
        RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
@@ -1035,19 +766,8 @@ std::ostream &RubyCodeGen::TRANS_ACTIONS_WI()
        return out;
 }
 
-void RubyCodeGen::writeExports()
-{
-       if ( exportList.length() > 0 ) {
-               for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
-                       STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name ) 
-                                       << " = " << KEY(ex->key) << "\n";
-               }
-               out << "\n";
-       }
-}
-
 
-void RubyCodeGen::writeData()
+void RubyTabCodeGen::writeData()
 {
        /* If there are any transtion functions then output the array. If there
         * are none, don't bother emitting an empty array that won't be used. */
@@ -1157,408 +877,14 @@ void RubyCodeGen::writeData()
                CLOSE_ARRAY() <<
                "\n";
        }
-
-       if ( redFsm->startState != 0 )
-               STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
-
-       if ( writeFirstFinal )
-               STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
-
-       if ( writeErr )
-               STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
        
-       out << "\n";
-
-       if ( entryPointNames.length() > 0 ) {
-               for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
-                       STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) << 
-                                       " = " << entryPointIds[en.pos()] << ";\n";
-               }
-               out << "\n";
-       }
-}
-
-std::ostream &RubyCodeGen::START_ARRAY_LINE()
-{
-       out << "\t";
-       return out;
-}
-
-std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
-{
-       out << item;
-       if ( !last )
-       {
-               out << ", ";
-               if ( count % IALL == 0 )
-               {
-                       END_ARRAY_LINE();
-                       START_ARRAY_LINE();
-               }
-       }
-       return out;
-}
-
-std::ostream &RubyCodeGen::END_ARRAY_LINE()
-{
-       out << "\n";
-       return out;
-}
-
-
-unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
-{
-       long long maxValLL = (long long) maxVal;
-       HostType *arrayType = keyOps->typeSubsumes( maxValLL );
-       assert( arrayType != 0 );
-       return arrayType->size;
-}
-
-string RubyCodeGen::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;
+       STATE_IDS();
 }
 
-
-/* Write out the fsm name. */
-string RubyCodeGen::FSM_NAME()
-{
-       return fsmName;
-}
-
-/* Emit the offset of the start state as a decimal integer. */
-string RubyCodeGen::START_STATE_ID()
-{
-       ostringstream ret;
-       ret << redFsm->startState->id;
-       return ret.str();
-};
-
-/* Write out the array of actions. */
-std::ostream &RubyCodeGen::ACTIONS_ARRAY()
-{
-       START_ARRAY_LINE();
-       int totalActions = 0;
-       ARRAY_ITEM( INT(0), ++totalActions, false );
-       for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
-               /* Write out the length, which will never be the last character. */
-               ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
-
-               for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
-                       ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
-               }
-       }
-       END_ARRAY_LINE();
-       return out;
-}
-
-
-string RubyCodeGen::ACCESS()
-{
-       ostringstream ret;
-       if ( accessExpr != 0 )
-               INLINE_LIST( ret, accessExpr, 0, false );
-       return ret.str();
-}
-
-string RubyCodeGen::P()
-{ 
-       ostringstream ret;
-       if ( pExpr == 0 )
-               ret << "p";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, pExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::PE()
-{
-       ostringstream ret;
-       if ( peExpr == 0 )
-               ret << "pe";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, peExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::CS()
-{
-       ostringstream ret;
-       if ( csExpr == 0 )
-               ret << ACCESS() << "cs";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, csExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::TOP()
-{
-       ostringstream ret;
-       if ( topExpr == 0 )
-               ret << ACCESS() + "top";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, topExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::STACK()
-{
-       ostringstream ret;
-       if ( stackExpr == 0 )
-               ret << ACCESS() + "stack";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, stackExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::ACT()
-{
-       ostringstream ret;
-       if ( actExpr == 0 )
-               ret << ACCESS() + "act";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, actExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::TOKSTART()
-{
-       ostringstream ret;
-       if ( tokstartExpr == 0 )
-               ret << ACCESS() + "tokstart";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, tokstartExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::TOKEND()
-{
-       ostringstream ret;
-       if ( tokendExpr == 0 )
-               ret << ACCESS() + "tokend";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, tokendExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-string RubyCodeGen::DATA()
-{
-       ostringstream ret;
-       if ( dataExpr == 0 )
-               ret << ACCESS() + "data";
-       else {
-               //ret << "(";
-               INLINE_LIST( ret, dataExpr, 0, false );
-               //ret << ")";
-       }
-       return ret.str();
-}
-
-
-string RubyCodeGen::GET_WIDE_KEY()
-{
-       if ( redFsm->anyConditions() ) 
-               return "_widec";
-       else
-               return GET_KEY();
-}
-
-string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
-{
-       if ( state->stateCondList.length() > 0 )
-               return "_widec";
-       else
-               return GET_KEY();
-}
-
-/* Write out level number of tabs. Makes the nested binary search nice
- * looking. */
-string RubyCodeGen::TABS( int level )
-{
-       string result;
-       while ( level-- > 0 )
-               result += "\t";
-       return result;
-}
-
-string RubyCodeGen::KEY( Key key )
-{
-       ostringstream ret;
-       if ( keyOps->isSigned || !hostLang->explicitUnsigned )
-               ret << key.getVal();
-       else
-               ret << (unsigned long) key.getVal();
-       return ret.str();
-}
-
-string RubyCodeGen::INT( int i )
-{
-       ostringstream ret;
-       ret << i;
-       return ret.str();
-}
-
-void RubyCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, 
-               int targState, int inFinish )
-{
-       ret << 
-               "       case " << ACT() << "\n";
-
-       for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
-               /* Write the case label, the action and the case break. */
-               ret << "        when " << lma->lmId << ":\n";
-
-               /* Write the block and close it off. */
-               ret << "        begin";
-               INLINE_LIST( ret, lma->children, targState, inFinish );
-               ret << "end\n";
-       }
-
-       ret << "end \n\t";
-}
-
-void RubyCodeGen::SET_ACT( ostream &ret, InlineItem *item )
-{
-       ret << ACT() << " = " << item->lmId << ";";
-}
-
-void RubyCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
-{
-       /* The tokend action sets tokend. */
-       ret << TOKEND() << " = " << P();
-       if ( item->offset != 0 ) 
-               out << "+" << item->offset;
-       out << "\n";
-}
-
-void RubyCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
-{
-       ret << TOKEND();
-}
-
-void RubyCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
-{
-       ret << TOKSTART() << " = " << NULL_ITEM() << ";";
-}
-
-void RubyCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
-{
-       ret << ACT() << " = 0\n";
-}
-
-void RubyCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
-{
-       ret << TOKSTART() << " = " << P() << "\n";
-}
-
-void RubyCodeGen::SUB_ACTION( ostream &ret, InlineItem *item, 
-               int targState, bool inFinish )
-{
-       if ( item->children->length() > 0 ) {
-               /* Write the block and close it off. */
-               ret << " begin ";
-               INLINE_LIST( ret, item->children, targState, inFinish );
-               ret << " end\n";
-       }
-}
-
-void RubyCodeGen::CONDITION( ostream &ret, Action *condition )
-{
-       ret << "\n";
-       lineDirective( ret, sourceFileName, condition->loc.line );
-       INLINE_LIST( ret, condition->inlineList, 0, false );
-}
-
-string RubyCodeGen::ERROR_STATE()
-{
-       ostringstream ret;
-       if ( redFsm->errState != 0 )
-               ret << redFsm->errState->id;
-       else
-               ret << "-1";
-       return ret.str();
-}
-
-string RubyCodeGen::FIRST_FINAL_STATE()
-{
-       ostringstream ret;
-       if ( redFsm->firstFinState != 0 )
-               ret << redFsm->firstFinState->id;
-       else
-               ret << redFsm->nextStateId;
-       return ret.str();
-}
-
-void RubyCodeGen::finishRagelDef()
-{
-       /* The frontend will do this for us, but it may be a good idea to force it
-        * if the intermediate file is edited. */
-       redFsm->sortByStateId();
-
-       /* Choose default transitions and the single transition. */
-       redFsm->chooseDefaultSpan();
-               
-       /* Maybe do flat expand, otherwise choose single. */
-       redFsm->chooseSingle();
-
-       /* If any errors have occured in the input file then don't write anything. */
-       if ( gblErrorCount > 0 )
-               return;
-       
-       /* Anlayze Machine will find the final action reference counts, among
-        * other things. We will use these in reporting the usage
-        * of fsm directives in action code. */
-       analyzeMachine();
-
-       /* Determine if we should use indicies. */
-       calcIndexSize();
-}
-
-ostream &RubyCodeGen::source_warning( const InputLoc &loc )
-{
-       cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
-       return cerr;
-}
-
-ostream &RubyCodeGen::source_error( const InputLoc &loc )
-{
-       gblErrorCount += 1;
-       assert( sourceFileName != 0 );
-       cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
-       return cerr;
-}
-
-
+/*
+ Local Variables:
+ mode: c++
+ indent-tabs-mode: 1
+ c-file-style: "bsd"
+ End:
+ */
diff --git a/rlgen-ruby/ruby-tabcodegen.h b/rlgen-ruby/ruby-tabcodegen.h
new file mode 100644 (file)
index 0000000..bd11a7b
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
+ *            2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ */
+
+/*  This file is part of Ragel.
+ *
+ *  Ragel is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  Ragel is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with Ragel; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#ifndef _RUBY_TABCODEGEN_H
+#define _RUBY_TABCODEGEN_H
+
+#include <iostream>
+#include <string>
+#include <stdio.h>
+#include "common.h"
+#include "gendata.h"
+#include "ruby-codegen.h"
+
+
+using std::string;
+using std::ostream;
+
+/*
+ * RubyCodeGen
+ */
+class RubyTabCodeGen : public RubyCodeGen
+{
+public:
+       RubyTabCodeGen( ostream &out ) : 
+          RubyCodeGen(out) {}
+        virtual ~RubyTabCodeGen() {}
+
+public:
+       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 writeExec();
+       virtual void writeEOF();
+       virtual void writeData();
+
+ protected:
+       virtual std::ostream &TO_STATE_ACTION_SWITCH();
+       virtual std::ostream &FROM_STATE_ACTION_SWITCH();
+       virtual std::ostream &EOF_ACTION_SWITCH();
+       virtual 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 NEXT( ostream &ret, int nextDest, bool inFinish );
+       void NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish );
+
+       virtual int TO_STATE_ACTION( RedStateAp *state );
+       virtual int FROM_STATE_ACTION( RedStateAp *state );
+       virtual int EOF_ACTION( RedStateAp *state );
+
+private:
+       string array_type;
+       string array_name;
+
+public:
+
+       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 );
+
+
+};
+
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
index b647dcd..77d1a92 100755 (executable)
@@ -258,7 +258,6 @@ for test_case; do
 
                for min_opt in $minflags; do
                        echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
-
                        for gen_opt in $genflags; do
                                echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
                                run_test
@@ -266,7 +265,7 @@ for test_case; do
                done
        ;;
 
-       java|ruby
+       java) 
                # Not interested in gen opt.
                gen_opt=""
                for min_opt in $minflags; do
@@ -274,6 +273,23 @@ for test_case; do
                        run_test
                done
        ;;
+
+       ruby) 
+               # Using genflags, get the allowed gen flags from the test case. If the
+               # test case doesn't specify assume that all gen flags are allowed.
+               allow_genflags=`sed '/@ALLOW_GENFLAGS:/s/^.*: *//p;d' $test_case`
+               [ -z "$allow_genflags" ] && allow_genflags="-T0 -T1 -F0 -F1"
+
+               for min_opt in $minflags; do
+                       echo "$allow_minflags" | grep -e $min_opt >/dev/null || continue
+
+                       for gen_opt in $genflags; do
+                               echo "$allow_genflags" | grep -e $gen_opt >/dev/null || continue
+                               run_test
+                       done
+               done
+       ;;
+
        esac
 
 done