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
/*
+ * 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;
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;
bool graphvizDone = false;
int numSplitPartitions = 0;
+bool noLineDirectives = false;
bool printPrintables = false;
/* Print a summary of the options. */
" -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"
;
}
{
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()
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;
/* 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() ) {
}
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();
case 'H': case 'h': case '?':
usage();
exit(0);
+
case '-':
if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
usage();
version();
exit(0);
}
+ else if ( strcasecmp(pc.parameterArg, "rbx") == 0 ) {
+ rubyImpl = Rubinius;
+ }
else {
error() << "--" << pc.parameterArg <<
" is an invalid argument" << endl;
}
return 0;
}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * indent-tabs-mode: 1
+ * c-file-style: "bsd"
+ * End:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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
/*
+ * 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 */
--- /dev/null
+/*
+ * 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:
+ */
/*
- * 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"; }
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 );
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
--- /dev/null
+/*
+ * 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:
+ */
+
--- /dev/null
+/*
+ * 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:
+ */
+
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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
+
* 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;
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"
" 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"
" 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"
" 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"
" end\n";
}
-void RubyCodeGen::RET( ostream &out, bool inFinish )
+void RubyTabCodeGen::RET( ostream &out, bool inFinish )
{
out <<
" begin\n"
" end\n";
}
-void RubyCodeGen::BREAK( ostream &out, int targState )
+void RubyTabCodeGen::BREAK( ostream &out, int targState )
{
out <<
" begin\n"
" end\n";
}
-void RubyCodeGen::COND_TRANSLATE()
+void RubyTabCodeGen::COND_TRANSLATE()
{
out <<
" _widec = " << GET_KEY() << "\n"
" end\n";
}
-void RubyCodeGen::LOCATE_TRANS()
+
+void RubyTabCodeGen::LOCATE_TRANS()
{
out <<
" _keys = " << KO() << "[" << CS() << "]\n"
" end while false\n";
}
-void RubyCodeGen::writeExec()
+void RubyTabCodeGen::writeExec()
{
out << "begin\n"
<< " _klen, _trans, _keys";
" _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";
" _nacts -= 1\n"
" _acts += 1\n"
" case " << A() << "[_acts - 1]\n";
- ACTION_SWITCH() <<
+ ACTION_SWITCH();
+ out <<
" end # action switch\n"
" end\n";
" _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";
}
out << " end\n";
}
-void RubyCodeGen::writeEOF()
+void RubyTabCodeGen::writeEOF()
{
if ( redFsm->anyEofActions() ) {
out <<
}
}
-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++ ) {
}
-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 );
}
}
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++ ) {
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++ ) {
}
-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 )
return act;
}
-int RubyCodeGen::FROM_STATE_ACTION( RedStateAp *state )
+int RubyTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
{
int act = 0;
if ( state->fromStateAction != 0 )
return act;
}
-int RubyCodeGen::EOF_ACTION( RedStateAp *state )
+int RubyTabCodeGen::EOF_ACTION( RedStateAp *state )
{
int act = 0;
if ( state->eofAction != 0 )
}
-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;
return out;
}
-std::ostream &RubyCodeGen::KEY_OFFSETS()
+std::ostream &RubyTabCodeGen::KEY_OFFSETS()
{
START_ARRAY_LINE();
int totalStateNum = 0, curKeyOffset = 0;
}
-std::ostream &RubyCodeGen::INDEX_OFFSETS()
+std::ostream &RubyTabCodeGen::INDEX_OFFSETS()
{
START_ARRAY_LINE();
int totalStateNum = 0, curIndOffset = 0;
return out;
}
-std::ostream &RubyCodeGen::COND_LENS()
+std::ostream &RubyTabCodeGen::COND_LENS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
}
-std::ostream &RubyCodeGen::SINGLE_LENS()
+std::ostream &RubyTabCodeGen::SINGLE_LENS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
return out;
}
-std::ostream &RubyCodeGen::RANGE_LENS()
+std::ostream &RubyTabCodeGen::RANGE_LENS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
return out;
}
-std::ostream &RubyCodeGen::TO_STATE_ACTIONS()
+std::ostream &RubyTabCodeGen::TO_STATE_ACTIONS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
return out;
}
-std::ostream &RubyCodeGen::FROM_STATE_ACTIONS()
+std::ostream &RubyTabCodeGen::FROM_STATE_ACTIONS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
return out;
}
-std::ostream &RubyCodeGen::EOF_ACTIONS()
+std::ostream &RubyTabCodeGen::EOF_ACTIONS()
{
START_ARRAY_LINE();
int totalStateNum = 0;
return out;
}
-std::ostream &RubyCodeGen::COND_KEYS()
+std::ostream &RubyTabCodeGen::COND_KEYS()
{
START_ARRAY_LINE();
int totalTrans = 0;
return out;
}
-std::ostream &RubyCodeGen::COND_SPACES()
+std::ostream &RubyTabCodeGen::COND_SPACES()
{
START_ARRAY_LINE();
int totalTrans = 0;
return out;
}
-std::ostream &RubyCodeGen::KEYS()
+std::ostream &RubyTabCodeGen::KEYS()
{
START_ARRAY_LINE();
int totalTrans = 0;
return out;
}
-std::ostream &RubyCodeGen::INDICIES()
+std::ostream &RubyTabCodeGen::INDICIES()
{
int totalTrans = 0;
START_ARRAY_LINE();
return out;
}
-std::ostream &RubyCodeGen::TRANS_TARGS()
+std::ostream &RubyTabCodeGen::TRANS_TARGS()
{
int totalTrans = 0;
START_ARRAY_LINE();
}
-std::ostream &RubyCodeGen::TRANS_ACTIONS()
+std::ostream &RubyTabCodeGen::TRANS_ACTIONS()
{
int totalTrans = 0;
START_ARRAY_LINE();
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()];
}
-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()];
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. */
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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
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
;;
- java|ruby)
+ java)
# Not interested in gen opt.
gen_opt=""
for min_opt in $minflags; 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