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