diff options
author | Anton Ageev <antage@gmail.com> | 2012-09-07 18:24:09 +0400 |
---|---|---|
committer | Anton Ageev <antage@gmail.com> | 2012-09-07 18:24:09 +0400 |
commit | 3b8f5c0ea8bc1645937bf6626071afa2137a9d1b (patch) | |
tree | ee3081fcd7aa1ef4afaf465b7fb58a9cf3a117f6 /ragel | |
parent | 5efb17311da2cac1254da4a0bc9ba53a01fbe1b5 (diff) | |
download | ragel-3b8f5c0ea8bc1645937bf6626071afa2137a9d1b.tar.gz |
Added/replaced code generators for Go1 (-T0, -T1, -F0, -F1, -G0, -G1 code styles added, -G2 code style rewritten from scratch)
Diffstat (limited to 'ragel')
-rw-r--r-- | ragel/.gitignore | 1 | ||||
-rw-r--r-- | ragel/Makefile.am | 8 | ||||
-rw-r--r-- | ragel/common.cpp | 36 | ||||
-rw-r--r-- | ragel/gendata.cpp | 32 | ||||
-rw-r--r-- | ragel/gendata.h | 2 | ||||
-rw-r--r-- | ragel/gocodegen.cpp | 776 | ||||
-rw-r--r-- | ragel/gocodegen.h | 181 | ||||
-rw-r--r-- | ragel/gofflat.cpp | 380 | ||||
-rw-r--r-- | ragel/gofflat.h | 58 | ||||
-rw-r--r-- | ragel/gofgoto.cpp | 296 | ||||
-rw-r--r-- | ragel/gofgoto.h | 54 | ||||
-rw-r--r-- | ragel/goflat.cpp | 764 | ||||
-rw-r--r-- | ragel/goflat.h | 80 | ||||
-rw-r--r-- | ragel/goftable.cpp | 441 | ||||
-rw-r--r-- | ragel/goftable.h | 59 | ||||
-rw-r--r-- | ragel/gogoto.cpp | 733 | ||||
-rw-r--r-- | ragel/gogoto.h | 83 | ||||
-rw-r--r-- | ragel/goipgoto.cpp | 738 | ||||
-rw-r--r-- | ragel/goipgoto.h | 77 | ||||
-rw-r--r-- | ragel/gotable.cpp | 977 | ||||
-rw-r--r-- | ragel/gotable.h | 76 | ||||
-rw-r--r-- | ragel/gotablish.cpp | 111 | ||||
-rw-r--r-- | ragel/gotablish.h | 48 |
23 files changed, 5540 insertions, 471 deletions
diff --git a/ragel/.gitignore b/ragel/.gitignore index 9c7e23c0..953f8a01 100644 --- a/ragel/.gitignore +++ b/ragel/.gitignore @@ -11,3 +11,4 @@ /ragel.exe /.deps /stamp-h1 +/*.o diff --git a/ragel/Makefile.am b/ragel/Makefile.am index 6582a526..ac7406c2 100644 --- a/ragel/Makefile.am +++ b/ragel/Makefile.am @@ -12,7 +12,9 @@ ragel_SOURCES = \ parsedata.h rlparse.h rubytable.h cdfgoto.h cdtable.h csflat.h \ dotcodegen.h parsetree.h rlscan.h version.h cdflat.h common.h \ csftable.h fsmgraph.h pcheck.h rubycodegen.h xmlcodegen.h cdftable.h \ - csgoto.h gendata.h ragel.h rubyfflat.h goipgoto.h \ + csgoto.h gendata.h ragel.h rubyfflat.h \ + gocodegen.h gotable.h goftable.h goflat.h gofflat.h gogoto.h gofgoto.h \ + goipgoto.h gotablish.h \ mlcodegen.h mltable.h mlftable.h mlflat.h mlfflat.h mlgoto.h \ main.cpp parsetree.cpp parsedata.cpp fsmstate.cpp fsmbase.cpp \ fsmattach.cpp fsmmin.cpp fsmgraph.cpp fsmap.cpp rlscan.cpp rlparse.cpp \ @@ -21,7 +23,9 @@ ragel_SOURCES = \ cdipgoto.cpp cdsplit.cpp javacodegen.cpp rubycodegen.cpp rubytable.cpp \ rubyftable.cpp rubyflat.cpp rubyfflat.cpp rbxgoto.cpp cscodegen.cpp \ cstable.cpp csftable.cpp csflat.cpp csfflat.cpp csgoto.cpp csfgoto.cpp \ - csipgoto.cpp cssplit.cpp dotcodegen.cpp xmlcodegen.cpp goipgoto.cpp \ + csipgoto.cpp cssplit.cpp dotcodegen.cpp xmlcodegen.cpp \ + gocodegen.cpp gotable.cpp goftable.cpp goflat.cpp gofflat.cpp gogoto.cpp gofgoto.cpp \ + goipgoto.cpp gotablish.cpp \ mlcodegen.cpp mltable.cpp mlftable.cpp mlflat.cpp mlfflat.cpp mlgoto.cpp BUILT_SOURCES = \ diff --git a/ragel/common.cpp b/ragel/common.cpp index c4c90704..3047e708 100644 --- a/ragel/common.cpp +++ b/ragel/common.cpp @@ -49,20 +49,20 @@ HostType hostTypesC[] = #define U16BIT_MIN 0 #define U16BIT_MAX 65535 -#define S31BIT_MIN -1073741824l -#define S31BIT_MAX 1073741823l +#define S31BIT_MIN -1073741824L +#define S31BIT_MAX 1073741823L -#define S32BIT_MIN –2147483648l -#define S32BIT_MAX 2147483647l +#define S32BIT_MIN -2147483648L +#define S32BIT_MAX 2147483647L #define U32BIT_MIN 0 -#define U32BIT_MAX 4294967295l +#define U32BIT_MAX 4294967295UL -#define S64BIT_MIN –9223372036854775808ll -#define S64BIT_MAX 9223372036854775807ll +#define S64BIT_MIN -9223372036854775807LL +#define S64BIT_MAX 9223372036854775807LL #define U64BIT_MIN 0 -#define U64BIT_MAX 18446744073709551615ll +#define U64BIT_MAX 18446744073709551615ULL HostType hostTypesD[] = { @@ -79,14 +79,16 @@ HostType hostTypesD[] = HostType hostTypesGo[] = { - { "byte", 0, "ubyte", false, true, false, 0, UCHAR_MAX, 1 }, - { "int8", 0, "byte", true, true, false, CHAR_MIN, CHAR_MAX, 1 }, - { "uint8", 0, "ubyte", false, true, false, 0, UCHAR_MAX, 1 }, - { "int16", 0, "short", true, true, false, SHRT_MIN, SHRT_MAX, 2 }, - { "uint16", 0, "ushort", false, true, false, 0, USHRT_MAX, 2 }, - { "int32", 0, "int", true, true, false, INT_MIN, INT_MAX, 4 }, - { "uint32", 0, "uint", false, true, false, 0, UINT_MAX, 4 }, - { "int", 0, "long", true, true, false, LONG_MIN, LONG_MAX, sizeof(long) }, + { "byte", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 }, + { "int8", 0, "int8", true, true, false, S8BIT_MIN, S8BIT_MAX, 1 }, + { "uint8", 0, "uint8", false, true, false, U8BIT_MIN, U8BIT_MAX, 1 }, + { "int16", 0, "int16", true, true, false, S16BIT_MIN, S16BIT_MAX, 2 }, + { "uint16", 0, "uint16", false, true, false, U16BIT_MIN, U16BIT_MAX, 2 }, + { "int32", 0, "int32", true, true, false, S32BIT_MIN, S32BIT_MAX, 4 }, + { "uint32", 0, "uint32", false, true, false, U32BIT_MIN, U32BIT_MAX, 4 }, + { "int64", 0, "int64", true, true, false, S64BIT_MIN, S64BIT_MAX, 8 }, + { "uint64", 0, "uint64", false, true, false, U64BIT_MIN, U64BIT_MAX, 8 }, + { "rune", 0, "int32", true, true, true, S32BIT_MIN, S32BIT_MAX, 4 } }; HostType hostTypesJava[] = @@ -126,7 +128,7 @@ HostType hostTypesOCaml[] = HostLang hostLangC = { HostLang::C, hostTypesC, 8, hostTypesC+0, true }; HostLang hostLangD = { HostLang::D, hostTypesD, 9, hostTypesD+2, true }; HostLang hostLangD2 = { HostLang::D2, hostTypesD, 9, hostTypesD+2, true }; -HostLang hostLangGo = { HostLang::Go, hostTypesGo, 7, hostTypesGo+0, false }; +HostLang hostLangGo = { HostLang::Go, hostTypesGo, 10, hostTypesGo+0, false }; HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false }; HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false }; HostLang hostLangCSharp = { HostLang::CSharp, hostTypesCSharp, 9, hostTypesCSharp+4, true }; diff --git a/ragel/gendata.cpp b/ragel/gendata.cpp index f7abe3de..6e6b8931 100644 --- a/ragel/gendata.cpp +++ b/ragel/gendata.cpp @@ -49,6 +49,13 @@ #include "javacodegen.h" +#include "gocodegen.h" +#include "gotable.h" +#include "goftable.h" +#include "goflat.h" +#include "gofflat.h" +#include "gogoto.h" +#include "gofgoto.h" #include "goipgoto.h" #include "mltable.h" @@ -205,15 +212,32 @@ CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName, o /* Invoked by the parser when a ragel definition is opened. */ CodeGenData *goMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out ) { - CodeGenData *codeGen; + CodeGenData *codeGen = 0; switch ( codeStyle ) { + case GenTables: + codeGen = new GoTabCodeGen(out); + break; + case GenFTables: + codeGen = new GoFTabCodeGen(out); + break; + case GenFlat: + codeGen = new GoFlatCodeGen(out); + break; + case GenFFlat: + codeGen = new GoFFlatCodeGen(out); + break; + case GenGoto: + codeGen = new GoGotoCodeGen(out); + break; + case GenFGoto: + codeGen = new GoFGotoCodeGen(out); + break; case GenIpGoto: codeGen = new GoIpGotoCodeGen(out); break; default: - cerr << "I only support the -G2 output style for Go. Please " - "rerun ragel including this flag.\n"; + cerr << "Invalid output style, only -T0, -T1, -F0, -F1, -G0, -G1 and -G2 are supported for Go.\n"; exit(1); } @@ -367,7 +391,7 @@ void lineDirective( ostream &out, const char *fileName, int line ) else if ( hostLang == &hostLangD2 ) cdLineDirective( out, fileName, line ); else if ( hostLang == &hostLangGo ) - gothicLineDirective( out, fileName, line ); + goLineDirective( out, fileName, line ); else if ( hostLang == &hostLangJava ) javaLineDirective( out, fileName, line ); else if ( hostLang == &hostLangRuby ) diff --git a/ragel/gendata.h b/ragel/gendata.h index 07eab32e..ec918916 100644 --- a/ragel/gendata.h +++ b/ragel/gendata.h @@ -45,7 +45,7 @@ typedef AvlMapEl<char *, CodeGenData*> CodeGenMapEl; void cdLineDirective( ostream &out, const char *fileName, int line ); void javaLineDirective( ostream &out, const char *fileName, int line ); -void gothicLineDirective( ostream &out, const char *fileName, int line ); +void goLineDirective( ostream &out, const char *fileName, int line ); void rubyLineDirective( ostream &out, const char *fileName, int line ); void csharpLineDirective( ostream &out, const char *fileName, int line ); void ocamlLineDirective( ostream &out, const char *fileName, int line ); diff --git a/ragel/gocodegen.cpp b/ragel/gocodegen.cpp new file mode 100644 index 00000000..72faf183 --- /dev/null +++ b/ragel/gocodegen.cpp @@ -0,0 +1,776 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "gocodegen.h" +#include "ragel.h" +#include "redfsm.h" +#include "gendata.h" +#include <sstream> +#include <string> +#include <assert.h> + + +using std::ostream; +using std::ostringstream; +using std::string; +using std::cerr; +using std::endl; +using std::istream; +using std::ifstream; +using std::ostream; +using std::ios; +using std::cin; +using std::cout; +using std::cerr; +using std::endl; + +/* + * Go Specific + */ + +void goLineDirective( ostream &out, const char *fileName, int line ) +{ + out << "// line " << line << " \"" << fileName << "\"" << endl; +} + +void GoCodeGen::genLineDirective( ostream &out ) +{ + std::streambuf *sbuf = out.rdbuf(); + output_filter *filter = static_cast<output_filter*>(sbuf); + goLineDirective( out, filter->fileName, filter->line + 1 ); +} + +unsigned int GoCodeGen::arrayTypeSize( unsigned long maxVal ) +{ + long long maxValLL = (long long) maxVal; + HostType *arrayType = keyOps->typeSubsumes( maxValLL ); + assert( arrayType != 0 ); + return arrayType->size; +} + +string GoCodeGen::ARRAY_TYPE( unsigned long maxVal ) +{ + long long maxValLL = (long long) maxVal; + HostType *arrayType = keyOps->typeSubsumes( maxValLL ); + assert( arrayType != 0 ); + + string ret = arrayType->data1; + if ( arrayType->data2 != 0 ) { + ret += " "; + ret += arrayType->data2; + } + return ret; +} + + +/* Write out the fsm name. */ +string GoCodeGen::FSM_NAME() +{ + return fsmName; +} + +/* Emit the offset of the start state as a decimal integer. */ +string GoCodeGen::START_STATE_ID() +{ + ostringstream ret; + ret << redFsm->startState->id; + return ret.str(); +}; + +/* Write out the array of actions. */ +std::ostream &GoCodeGen::ACTIONS_ARRAY() +{ + out << " 0, "; + int totalActions = 1; + for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) { + /* Write out the length, which will never be the last character. */ + out << act->key.length() << ", "; + if ( totalActions++ % IALL == 0 ) + out << endl << " "; + + for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) { + out << item->value->actionId << ", "; + if ( ! (act.last() && item.last()) ) { + if ( totalActions++ % IALL == 0 ) + out << endl << " "; + } + } + } + out << endl; + return out; +} + + +string GoCodeGen::ACCESS() +{ + ostringstream ret; + if ( accessExpr != 0 ) + INLINE_LIST( ret, accessExpr, 0, false, false ); + return ret.str(); +} + + +string GoCodeGen::P() +{ + ostringstream ret; + if ( pExpr == 0 ) + ret << "p"; + else { + ret << "("; + INLINE_LIST( ret, pExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::PE() +{ + ostringstream ret; + if ( peExpr == 0 ) + ret << "pe"; + else { + ret << "("; + INLINE_LIST( ret, peExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::vEOF() +{ + ostringstream ret; + if ( eofExpr == 0 ) + ret << "eof"; + else { + ret << "("; + INLINE_LIST( ret, eofExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::vCS() +{ + ostringstream ret; + if ( csExpr == 0 ) + ret << ACCESS() << "cs"; + else { + /* Emit the user supplied method of retrieving the key. */ + ret << "("; + INLINE_LIST( ret, csExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::TOP() +{ + ostringstream ret; + if ( topExpr == 0 ) + ret << ACCESS() + "top"; + else { + ret << "("; + INLINE_LIST( ret, topExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::STACK() +{ + ostringstream ret; + if ( stackExpr == 0 ) + ret << ACCESS() + "stack"; + else { + ret << "("; + INLINE_LIST( ret, stackExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::ACT() +{ + ostringstream ret; + if ( actExpr == 0 ) + ret << ACCESS() + "act"; + else { + ret << "("; + INLINE_LIST( ret, actExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::TOKSTART() +{ + ostringstream ret; + if ( tokstartExpr == 0 ) + ret << ACCESS() + "ts"; + else { + ret << "("; + INLINE_LIST( ret, tokstartExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::TOKEND() +{ + ostringstream ret; + if ( tokendExpr == 0 ) + ret << ACCESS() + "te"; + else { + ret << "("; + INLINE_LIST( ret, tokendExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::GET_WIDE_KEY() +{ + if ( redFsm->anyConditions() ) + return "_widec"; + else + return GET_KEY(); +} + +string GoCodeGen::GET_WIDE_KEY( RedStateAp *state ) +{ + if ( state->stateCondList.length() > 0 ) + return "_widec"; + else + return GET_KEY(); +} + +string GoCodeGen::GET_KEY() +{ + ostringstream ret; + if ( getKeyExpr != 0 ) { + /* Emit the user supplied method of retrieving the key. */ + ret << "("; + INLINE_LIST( ret, getKeyExpr, 0, false, false ); + ret << ")"; + } + else { + /* Expression for retrieving the key, use simple dereference. */ + ret << DATA() << "[" << P() << "]"; + } + return ret.str(); +} + +/* Write out level number of tabs. Makes the nested binary search nice + * looking. */ +string GoCodeGen::TABS( int level ) +{ + string result; + while ( level-- > 0 ) + result += " "; + return result; +} + +/* Write out a key from the fsm code gen. Depends on wether or not the key is + * signed. */ +string GoCodeGen::KEY( Key key ) +{ + ostringstream ret; + if ( keyOps->isSigned || !hostLang->explicitUnsigned ) + ret << key.getVal(); + else + ret << (unsigned long) key.getVal() << 'u'; + return ret.str(); +} + +bool GoCodeGen::isAlphTypeSigned() +{ + return keyOps->isSigned; +} + +bool GoCodeGen::isWideAlphTypeSigned() +{ + string ret; + if ( redFsm->maxKey <= keyOps->maxKey ) + return isAlphTypeSigned(); + else { + long long maxKeyVal = redFsm->maxKey.getLongLong(); + HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal ); + return wideType->isSigned; + } +} + +string GoCodeGen::WIDE_KEY( RedStateAp *state, Key key ) +{ + if ( state->stateCondList.length() > 0 ) { + ostringstream ret; + if ( isWideAlphTypeSigned() ) + ret << key.getVal(); + else + ret << (unsigned long) key.getVal() << 'u'; + return ret.str(); + } + else { + return KEY( key ); + } +} + + + +void GoCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish ) +{ + /* The parser gives fexec two children. The double brackets are for D + * code. If the inline list is a single word it will get interpreted as a + * C-style cast by the D compiler. */ + ret << P() << " = ("; + INLINE_LIST( ret, item->children, targState, inFinish, false ); + ret << ") - 1" << endl; +} + +void GoCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, + int targState, int inFinish, bool csForced ) +{ + ret << + " switch " << ACT() << " {" << endl; + + for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) { + /* Write the case label, the action and the case break. */ + if ( lma->lmId < 0 ) { + ret << " default:" << endl; + } + else + ret << " case " << lma->lmId << ":" << endl; + + /* Write the block and close it off. */ + ret << " {"; + INLINE_LIST( ret, lma->children, targState, inFinish, csForced ); + ret << "}" << endl; + } + + ret << + " }" << endl << + " "; +} + +void GoCodeGen::SET_ACT( ostream &ret, GenInlineItem *item ) +{ + ret << ACT() << " = " << item->lmId << ";"; +} + +void GoCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item ) +{ + /* The tokend action sets tokend. */ + ret << TOKEND() << " = " << P(); + if ( item->offset != 0 ) + out << "+" << item->offset; + out << endl; +} + +void GoCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item ) +{ + ret << TOKEND(); +} + +void GoCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item ) +{ + ret << TOKSTART() << " = " << NULL_ITEM() << endl; +} + +void GoCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item ) +{ + ret << ACT() << " = 0" << endl; +} + +void GoCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item ) +{ + ret << TOKSTART() << " = " << P() << endl; +} + +void GoCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << "{"; + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << "}"; + } +} + + +/* Write out an inline tree structure. Walks the list and possibly calls out + * to virtual functions than handle language specific items in the tree. */ +void GoCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList, + int targState, bool inFinish, bool csForced ) +{ + for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { + switch ( item->type ) { + case GenInlineItem::Text: + ret << item->data; + break; + case GenInlineItem::Goto: + GOTO( ret, item->targState->id, inFinish ); + break; + case GenInlineItem::Call: + CALL( ret, item->targState->id, targState, inFinish ); + break; + case GenInlineItem::Next: + NEXT( ret, item->targState->id, inFinish ); + break; + case GenInlineItem::Ret: + RET( ret, inFinish ); + break; + case GenInlineItem::PChar: + ret << P(); + break; + case GenInlineItem::Char: + ret << GET_KEY(); + break; + case GenInlineItem::Hold: + ret << P() << "--" << endl; + break; + case GenInlineItem::Exec: + EXEC( ret, item, targState, inFinish ); + break; + case GenInlineItem::Curs: + CURS( ret, inFinish ); + break; + case GenInlineItem::Targs: + TARGS( ret, inFinish, targState ); + break; + case GenInlineItem::Entry: + ret << item->targState->id; + break; + case GenInlineItem::GotoExpr: + GOTO_EXPR( ret, item, inFinish ); + break; + case GenInlineItem::CallExpr: + CALL_EXPR( ret, item, targState, inFinish ); + break; + case GenInlineItem::NextExpr: + NEXT_EXPR( ret, item, inFinish ); + break; + case GenInlineItem::LmSwitch: + LM_SWITCH( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::LmSetActId: + SET_ACT( ret, item ); + break; + case GenInlineItem::LmSetTokEnd: + SET_TOKEND( ret, item ); + break; + case GenInlineItem::LmGetTokEnd: + GET_TOKEND( ret, item ); + break; + case GenInlineItem::LmInitTokStart: + INIT_TOKSTART( ret, item ); + break; + case GenInlineItem::LmInitAct: + INIT_ACT( ret, item ); + break; + case GenInlineItem::LmSetTokStart: + SET_TOKSTART( ret, item ); + break; + case GenInlineItem::SubAction: + SUB_ACTION( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::Break: + BREAK( ret, targState, csForced ); + break; + } + } +} +/* Write out paths in line directives. Escapes any special characters. */ +string GoCodeGen::LDIR_PATH( char *path ) +{ + ostringstream ret; + for ( char *pc = path; *pc != 0; pc++ ) { + if ( *pc == '\\' ) + ret << "\\\\"; + else + ret << *pc; + } + return ret.str(); +} + +void GoCodeGen::ACTION( ostream &ret, GenAction *action, int targState, + bool inFinish, bool csForced ) +{ + /* Write the preprocessor line info for going into the source file. */ + goLineDirective( ret, action->loc.fileName, action->loc.line ); + + /* Write the block and close it off. */ + ret << endl; + INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced ); + ret << endl; +} + +void GoCodeGen::CONDITION( ostream &ret, GenAction *condition ) +{ + INLINE_LIST( ret, condition->inlineList, 0, false, false ); +} + +string GoCodeGen::ERROR_STATE() +{ + ostringstream ret; + if ( redFsm->errState != 0 ) + ret << redFsm->errState->id; + else + ret << "-1"; + return ret.str(); +} + +string GoCodeGen::FIRST_FINAL_STATE() +{ + ostringstream ret; + if ( redFsm->firstFinState != 0 ) + ret << redFsm->firstFinState->id; + else + ret << redFsm->nextStateId; + return ret.str(); +} + +void GoCodeGen::writeInit() +{ + out << " {" << endl; + + if ( !noCS ) + out << " " << vCS() << " = " << START() << endl; + + /* If there are any calls, then the stack top needs initialization. */ + if ( redFsm->anyActionCalls() || redFsm->anyActionRets() ) + out << " " << TOP() << " = 0" << endl; + + if ( hasLongestMatch ) { + out << + " " << TOKSTART() << " = " << NULL_ITEM() << endl << + " " << TOKEND() << " = " << NULL_ITEM() << endl << + " " << ACT() << " = 0" << endl; + } + out << " }" << endl; +} + +string GoCodeGen::DATA() +{ + ostringstream ret; + if ( dataExpr == 0 ) + ret << ACCESS() + "data"; + else { + ret << "("; + INLINE_LIST( ret, dataExpr, 0, false, false ); + ret << ")"; + } + return ret.str(); +} + +string GoCodeGen::DATA_PREFIX() +{ + if ( !noPrefix ) + return FSM_NAME() + "_"; + return ""; +} + +/* Emit the alphabet data type. */ +string GoCodeGen::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 GoCodeGen::WIDE_ALPH_TYPE() +{ + string ret; + if ( redFsm->maxKey <= keyOps->maxKey ) + ret = ALPH_TYPE(); + else { + long long maxKeyVal = redFsm->maxKey.getLongLong(); + HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal ); + assert( wideType != 0 ); + + ret = wideType->data1; + if ( wideType->data2 != 0 ) { + ret += " "; + ret += wideType->data2; + } + } + return ret; +} + +void GoCodeGen::STATE_IDS() +{ + if ( redFsm->startState != 0 ) + CONST( "int", START() ) << " = " << START_STATE_ID() << endl; + + if ( !noFinal ) + CONST( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << endl; + + if ( !noError ) + CONST( "int", ERROR() ) << " = " << ERROR_STATE() << endl; + + out << endl; + + if ( entryPointNames.length() > 0 ) { + for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) { + CONST( "int", DATA_PREFIX() + "en_" + *en ) << + " = " << entryPointIds[en.pos()] << endl; + } + out << endl; + } +} + +void GoCodeGen::writeStart() +{ + out << START_STATE_ID(); +} + +void GoCodeGen::writeFirstFinal() +{ + out << FIRST_FINAL_STATE(); +} + +void GoCodeGen::writeError() +{ + out << ERROR_STATE(); +} + +void GoCodeGen::finishRagelDef() +{ + if ( codeStyle == GenGoto || codeStyle == GenFGoto || + codeStyle == GenIpGoto || codeStyle == GenSplit ) + { + /* For directly executable machines there is no required state + * ordering. Choose a depth-first ordering to increase the + * potential for fall-throughs. */ + redFsm->depthFirstOrdering(); + } + else { + /* The frontend will do this for us, but it may be a good idea to + * force it if the intermediate file is edited. */ + redFsm->sortByStateId(); + } + + /* Choose default transitions and the single transition. */ + redFsm->chooseDefaultSpan(); + + /* Maybe do flat expand, otherwise choose single. */ + if ( codeStyle == GenFlat || codeStyle == GenFFlat ) + redFsm->makeFlat(); + else + redFsm->chooseSingle(); + + /* If any errors have occured in the input file then don't write anything. */ + if ( gblErrorCount > 0 ) + return; + + if ( codeStyle == GenSplit ) + redFsm->partitionFsm( numSplitPartitions ); + + if ( codeStyle == GenIpGoto || codeStyle == GenSplit ) + redFsm->setInTrans(); + + /* Anlayze Machine will find the final action reference counts, among + * other things. We will use these in reporting the usage + * of fsm directives in action code. */ + analyzeMachine(); + + /* Determine if we should use indicies. */ + calcIndexSize(); +} + +ostream &GoCodeGen::source_warning( const InputLoc &loc ) +{ + cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: "; + return cerr; +} + +ostream &GoCodeGen::source_error( const InputLoc &loc ) +{ + gblErrorCount += 1; + assert( sourceFileName != 0 ); + cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": "; + return cerr; +} + + +/* + * Go implementation. + * + */ + +std::ostream &GoCodeGen::OPEN_ARRAY( string type, string name ) +{ + out << "var " << name << " []" << type << " = []" << type << "{" << endl; + return out; +} + +std::ostream &GoCodeGen::CLOSE_ARRAY() +{ + return out << "}" << endl; +} + +std::ostream &GoCodeGen::STATIC_VAR( string type, string name ) +{ + out << "var " << name << " " << type; + return out; +} + +std::ostream &GoCodeGen::CONST( string type, string name ) +{ + out << "const " << name << " " << type; + return out; +} + +string GoCodeGen::UINT( ) +{ + return "uint"; +} + +string GoCodeGen::INT() +{ + return "int"; +} + +string GoCodeGen::CAST( string type, string expr ) +{ + return type + "(" + expr + ")"; +} + +string GoCodeGen::NULL_ITEM() +{ + return "0"; +} + +void GoCodeGen::writeExports() +{ + if ( exportList.length() > 0 ) { + for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) { + out << "const " << DATA_PREFIX() << "ex_" << ex->name << " = " << + KEY(ex->key) << endl; + } + out << endl; + } +} diff --git a/ragel/gocodegen.h b/ragel/gocodegen.h new file mode 100644 index 00000000..50e8804b --- /dev/null +++ b/ragel/gocodegen.h @@ -0,0 +1,181 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOCODEGEN_H +#define _GOCODEGEN_H + +#include <iostream> +#include <string> +#include <stdio.h> +#include "common.h" +#include "gendata.h" + +using std::string; +using std::ostream; + +/* Integer array line length. */ +#define IALL 8 + +/* Forwards. */ +struct RedFsmAp; +struct RedStateAp; +struct CodeGenData; +struct GenAction; +struct NameInst; +struct GenInlineItem; +struct GenInlineList; +struct RedAction; +struct LongestMatch; +struct LongestMatchPart; + +class GoCodeGen : public CodeGenData +{ +public: + GoCodeGen( ostream &out ) + : CodeGenData(out) {} + + virtual ~GoCodeGen() {} + + virtual void finishRagelDef(); + virtual void writeInit(); + virtual void writeStart(); + virtual void writeFirstFinal(); + virtual void writeError(); + virtual void writeExports(); +protected: + string FSM_NAME(); + string START_STATE_ID(); + ostream &ACTIONS_ARRAY(); + string GET_WIDE_KEY(); + string GET_WIDE_KEY( RedStateAp *state ); + string TABS( int level ); + string KEY( Key key ); + string WIDE_KEY( RedStateAp *state, Key key ); + string LDIR_PATH( char *path ); + virtual void ACTION( ostream &ret, GenAction *action, int targState, + bool inFinish, bool csForced ); + void CONDITION( ostream &ret, GenAction *condition ); + string ALPH_TYPE(); + string WIDE_ALPH_TYPE(); + string ARRAY_TYPE( unsigned long maxVal ); + + bool isAlphTypeSigned(); + bool isWideAlphTypeSigned(); + + virtual string CAST( string type, string expr ); + virtual string UINT(); + virtual string INT(); + virtual string NULL_ITEM(); + virtual string GET_KEY(); + + string P(); + string PE(); + string vEOF(); + + string ACCESS(); + string vCS(); + string STACK(); + string TOP(); + string TOKSTART(); + string TOKEND(); + string ACT(); + string DATA(); + + string DATA_PREFIX(); + string PM() { return "_" + DATA_PREFIX() + "partition_map"; } + string C() { return "_" + DATA_PREFIX() + "cond_spaces"; } + string CK() { return "_" + DATA_PREFIX() + "cond_keys"; } + string K() { return "_" + DATA_PREFIX() + "trans_keys"; } + string I() { return "_" + DATA_PREFIX() + "indicies"; } + string CO() { return "_" + DATA_PREFIX() + "cond_offsets"; } + string KO() { return "_" + DATA_PREFIX() + "key_offsets"; } + string IO() { return "_" + DATA_PREFIX() + "index_offsets"; } + string CL() { return "_" + DATA_PREFIX() + "cond_lengths"; } + string SL() { return "_" + DATA_PREFIX() + "single_lengths"; } + string RL() { return "_" + DATA_PREFIX() + "range_lengths"; } + string A() { return "_" + DATA_PREFIX() + "actions"; } + string TA() { return "_" + DATA_PREFIX() + "trans_actions"; } + string TT() { return "_" + DATA_PREFIX() + "trans_targs"; } + string TSA() { return "_" + DATA_PREFIX() + "to_state_actions"; } + string FSA() { return "_" + DATA_PREFIX() + "from_state_actions"; } + string EA() { return "_" + DATA_PREFIX() + "eof_actions"; } + string ET() { return "_" + DATA_PREFIX() + "eof_trans"; } + string SP() { return "_" + DATA_PREFIX() + "key_spans"; } + string CSP() { return "_" + DATA_PREFIX() + "cond_key_spans"; } + string START() { return DATA_PREFIX() + "start"; } + string ERROR() { return DATA_PREFIX() + "error"; } + string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; } + string CTXDATA() { return DATA_PREFIX() + "ctxdata"; } + + void INLINE_LIST( ostream &ret, GenInlineList *inlineList, + int targState, bool inFinish, bool csForced ); + virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0; + virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ) = 0; + virtual void NEXT( ostream &ret, int nextDest, bool inFinish ) = 0; + virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0; + virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) = 0; + virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, + int targState, bool inFinish ) = 0; + virtual void RET( ostream &ret, bool inFinish ) = 0; + virtual void BREAK( ostream &ret, int targState, bool csForced ) = 0; + virtual void CURS( ostream &ret, bool inFinish ) = 0; + virtual void TARGS( ostream &ret, bool inFinish, int targState ) = 0; + void EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish ); + void LM_SWITCH( ostream &ret, GenInlineItem *item, int targState, + int inFinish, bool csForced ); + void SET_ACT( ostream &ret, GenInlineItem *item ); + void INIT_TOKSTART( ostream &ret, GenInlineItem *item ); + void INIT_ACT( ostream &ret, GenInlineItem *item ); + void SET_TOKSTART( ostream &ret, GenInlineItem *item ); + void SET_TOKEND( ostream &ret, GenInlineItem *item ); + void GET_TOKEND( ostream &ret, GenInlineItem *item ); + virtual void SUB_ACTION( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ); + void STATE_IDS(); + + string ERROR_STATE(); + string FIRST_FINAL_STATE(); + + virtual ostream &OPEN_ARRAY( string type, string name ); + virtual ostream &CLOSE_ARRAY(); + virtual ostream &STATIC_VAR( string type, string name ); + virtual ostream &CONST( string type, string name ); + + ostream &source_warning(const InputLoc &loc); + ostream &source_error(const InputLoc &loc); + + unsigned int arrayTypeSize( unsigned long maxVal ); + + bool outLabelUsed; + bool testEofUsed; + bool againLabelUsed; + bool useIndicies; + + void genLineDirective( ostream &out ); + +public: + /* Determine if we should use indicies. */ + virtual void calcIndexSize() {} +}; + +#endif diff --git a/ragel/gofflat.cpp b/ragel/gofflat.cpp new file mode 100644 index 00000000..66e6737e --- /dev/null +++ b/ragel/gofflat.cpp @@ -0,0 +1,380 @@ +/* + * Copyright 2004-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "gofflat.h" +#include "redfsm.h" +#include "gendata.h" + +using std::endl; + +std::ostream &GoFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->actListId+1; + out << act; + return out; +} + +std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->actListId+1; + out << act; + return out; +} + +std::ostream &GoFFlatCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->actListId+1; + out << act; + return out; +} + +/* Write out the function for a transition. */ +std::ostream &GoFFlatCodeGen::TRANS_ACTION( RedTransAp *trans ) +{ + int action = 0; + if ( trans->action != 0 ) + action = trans->action->actListId+1; + out << action; + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFFlatCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numToStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numFromStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoFFlatCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numEofRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, true, false ); + } + } + + genLineDirective( out ); + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFFlatCodeGen::ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numTransRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +void GoFFlatCodeGen::writeData() +{ + if ( redFsm->anyConditions() ) { + OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() ); + COND_KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() ); + COND_KEY_SPANS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() ); + CONDS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() ); + COND_INDEX_OFFSET(); + CLOSE_ARRAY() << + endl; + } + + OPEN_ARRAY( WIDE_ALPH_TYPE(), K() ); + KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() ); + KEY_SPANS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() ); + FLAT_INDEX_OFFSET(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() ); + INDICIES(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS(); + CLOSE_ARRAY() << + endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() ); + TRANS_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofTrans() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() ); + EOF_TRANS(); + CLOSE_ARRAY() << + endl; + } + + STATE_IDS(); +} + +void GoFFlatCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << + " {" << endl << + " var _slen " << INT() << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << endl; + + out << " var _trans " << INT() << endl; + + if ( redFsm->anyConditions() ) + out << " var _cond " << INT() << endl; + + out << + " var _keys " << INT() << endl << + " var _inds " << INT() << endl; + + if ( redFsm->anyConditions() ) { + out << + " var _conds " << INT() << endl << + " var _widec " << WIDE_ALPH_TYPE() << endl; + } + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " switch " << FSA() << "[" << vCS() << "] {" << endl; + FROM_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->anyConditions() ) + COND_TRANSLATE(); + + LOCATE_TRANS(); + + if ( redFsm->anyEofTrans() ) + out << "_eof_trans:" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " _ps = " << vCS() << endl; + + out << + " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl << + endl; + + if ( redFsm->anyRegActions() ) { + out << + " if " << TA() << "[_trans] == 0 {" << endl << + " goto _again" << endl << + " }" << endl << + endl << + " switch " << TA() << "[_trans] {" << endl; + ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || + redFsm->anyActionCalls() || redFsm->anyActionRets() ) + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " switch " << TSA() << "[" << vCS() << "] {" << endl; + TO_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " if " << P() << "++; " << P() << " != " << PE() << " {" + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " if " << ET() << "[" << vCS() << "] > 0 {" << endl << + " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl << + " goto _eof_trans" << endl << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " switch " << EA() << "[" << vCS() << "] {" << endl; + EOF_ACTION_SWITCH(2); + out << + " }" << endl; + } + + out << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/gofflat.h b/ragel/gofflat.h new file mode 100644 index 00000000..bd3bde4c --- /dev/null +++ b/ragel/gofflat.h @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOFFLAT_H +#define _GOFFLAT_H + +#include <iostream> +#include "goflat.h" + +/* Forwards. */ +struct CodeGenData; + +/* + * FFlatCodeGen + */ +class GoFFlatCodeGen + : public GoFlatCodeGen +{ +public: + GoFFlatCodeGen( ostream &out ) + : GoFlatCodeGen(out) {} + +protected: + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &EOF_ACTION_SWITCH( int level ); + std::ostream &ACTION_SWITCH( int level ); + + virtual std::ostream &TO_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &EOF_ACTION( RedStateAp *state ); + virtual std::ostream &TRANS_ACTION( RedTransAp *trans ); + + virtual void writeData(); + virtual void writeExec(); +}; + +#endif diff --git a/ragel/gofgoto.cpp b/ragel/gofgoto.cpp new file mode 100644 index 00000000..7ce9450d --- /dev/null +++ b/ragel/gofgoto.cpp @@ -0,0 +1,296 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "gofgoto.h" +#include "redfsm.h" +#include "gendata.h" +#include "bstmap.h" + +using std::endl; + +std::ostream &GoFGotoCodeGen::EXEC_ACTIONS() +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numTransRefs > 0 ) { + /* We are at the start of a glob, write the case. */ + out << "f" << redAct->actListId << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + + out << TABS(1) << "goto _again" << endl; + } + } + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFGotoCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numToStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numFromStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoFGotoCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numEofRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, true, false ); + } + } + + genLineDirective( out ); + return out; +} + + +std::ostream &GoFGotoCodeGen::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 << TABS(2) << "case " << st->id << ":" << endl; + + /* Jump to the func. */ + out << TABS(3) << "goto f" << st->eofAction->actListId << endl; + } + } + + return out; +} + +unsigned int GoFGotoCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->actListId+1; + return act; +} + +unsigned int GoFGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->actListId+1; + return act; +} + +unsigned int GoFGotoCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->actListId+1; + return act; +} + +void GoFGotoCodeGen::writeData() +{ + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + STATE_IDS(); +} + +void GoFGotoCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << " {" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << " = 0" << endl; + + if ( redFsm->anyConditions() ) + out << " var _widec " << WIDE_ALPH_TYPE() << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " switch " << FSA() << "[" << vCS() << "] {" << endl; + FROM_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + out << + " switch " << vCS() << " {" << endl; + STATE_GOTOS(1); + out << + " }" << endl << + endl; + TRANSITIONS() << + endl; + + if ( redFsm->anyRegActions() ) + EXEC_ACTIONS() << endl; + + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " switch " << TSA() << "[" << vCS() << "] {" << endl; + TO_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " if " << P() << "++; " << P() << " != " << PE() << " {" << endl << + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " switch " << vCS() << " {" << endl; + + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->eofTrans != 0 ) + out << " case " << st->id << ":" << endl << + " goto tr" << st->eofTrans->id << endl; + } + + out << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " switch " << EA() << "[" << vCS() << "] {" << endl; + EOF_ACTION_SWITCH(2); + out << + " }" << endl; + } + + out << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/gofgoto.h b/ragel/gofgoto.h new file mode 100644 index 00000000..c53e4504 --- /dev/null +++ b/ragel/gofgoto.h @@ -0,0 +1,54 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOFGOTO_H +#define _GOFGOTO_H + +#include <iostream> +#include "gogoto.h" + +/* Forwards. */ +struct CodeGenData; + + +class GoFGotoCodeGen + : public GoGotoCodeGen +{ +public: + GoFGotoCodeGen( ostream &out ) + : GoGotoCodeGen(out) {} + + std::ostream &EXEC_ACTIONS(); + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &FINISH_CASES(); + std::ostream &EOF_ACTION_SWITCH( int level ); + unsigned int TO_STATE_ACTION( RedStateAp *state ); + unsigned int FROM_STATE_ACTION( RedStateAp *state ); + unsigned int EOF_ACTION( RedStateAp *state ); + + virtual void writeData(); + virtual void writeExec(); +}; + +#endif diff --git a/ragel/goflat.cpp b/ragel/goflat.cpp new file mode 100644 index 00000000..45442e55 --- /dev/null +++ b/ragel/goflat.cpp @@ -0,0 +1,764 @@ +/* + * Copyright 2004-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "goflat.h" +#include "redfsm.h" +#include "gendata.h" + +using std::endl; + +std::ostream &GoFlatCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->location+1; + out << act; + return out; +} + +std::ostream &GoFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->location+1; + out << act; + return out; +} + +std::ostream &GoFlatCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->location+1; + out << act; + return out; +} + +std::ostream &GoFlatCodeGen::TRANS_ACTION( RedTransAp *trans ) +{ + /* If there are actions, emit them. Otherwise emit zero. */ + int act = 0; + if ( trans->action != 0 ) + act = trans->action->location+1; + out << act; + return out; +} + +std::ostream &GoFlatCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoFlatCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, true, false ); + } + } + + genLineDirective( out ); + return out; +} + + +std::ostream &GoFlatCodeGen::ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + + +std::ostream &GoFlatCodeGen::FLAT_INDEX_OFFSET() +{ + out << " "; + int totalStateNum = 0, curIndOffset = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write the index offset. */ + out << curIndOffset << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + + /* Move the index offset ahead. */ + if ( st->transList != 0 ) + curIndOffset += keyOps->span( st->lowKey, st->highKey ); + + if ( st->defTrans != 0 ) + curIndOffset += 1; + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::KEY_SPANS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write singles length. */ + unsigned long long span = 0; + if ( st->transList != 0 ) + span = keyOps->span( st->lowKey, st->highKey ); + out << span << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::TO_STATE_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + TO_STATE_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::FROM_STATE_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + FROM_STATE_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::EOF_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + EOF_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::EOF_TRANS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + + long trans = 0; + if ( st->eofTrans != 0 ) { + assert( st->eofTrans->pos >= 0 ); + trans = st->eofTrans->pos+1; + } + out << trans << ", "; + + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + + +std::ostream &GoFlatCodeGen::COND_KEYS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Emit just cond low key and cond high key. */ + out << KEY( st->condLowKey ) << ", "; + out << KEY( st->condHighKey ) << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::COND_KEY_SPANS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write singles length. */ + unsigned long long span = 0; + if ( st->condList != 0 ) + span = keyOps->span( st->condLowKey, st->condHighKey ); + out << span << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::CONDS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->condList != 0 ) { + /* Walk the singles. */ + unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey ); + for ( unsigned long long pos = 0; pos < span; pos++ ) { + if ( st->condList[pos] != 0 ) + out << st->condList[pos]->condSpaceId + 1 << ", "; + else + out << "0, "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + } + } + + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::COND_INDEX_OFFSET() +{ + out << " "; + int totalStateNum = 0; + int curIndOffset = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write the index offset. */ + out << curIndOffset << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + + /* Move the index offset ahead. */ + if ( st->condList != 0 ) + curIndOffset += keyOps->span( st->condLowKey, st->condHighKey ); + } + out << endl; + return out; +} + + +std::ostream &GoFlatCodeGen::KEYS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Emit just low key and high key. */ + out << KEY( st->lowKey ) << ", "; + out << KEY( st->highKey ) << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::INDICIES() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->transList != 0 ) { + /* Walk the singles. */ + unsigned long long span = keyOps->span( st->lowKey, st->highKey ); + for ( unsigned long long pos = 0; pos < span; pos++ ) { + out << st->transList[pos]->id << ", "; + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + + /* The state's default index goes next. */ + if ( st->defTrans != 0 ) { + out << st->defTrans->id << ", "; + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoFlatCodeGen::TRANS_TARGS() +{ + /* Transitions must be written ordered by their id. */ + RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()]; + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) + transPtrs[trans->id] = trans; + + /* Keep a count of the num of items in the array written. */ + out << " "; + int totalStates = 0; + for ( int t = 0; t < redFsm->transSet.length(); t++ ) { + /* Save the position. Needed for eofTargs. */ + RedTransAp *trans = transPtrs[t]; + trans->pos = t; + + /* Write out the target state. */ + out << trans->targ->id << ", "; + if ( t < redFsm->transSet.length()-1 ) { + if ( ++totalStates % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] transPtrs; + return out; +} + + +std::ostream &GoFlatCodeGen::TRANS_ACTIONS() +{ + /* Transitions must be written ordered by their id. */ + RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()]; + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) + transPtrs[trans->id] = trans; + + /* Keep a count of the num of items in the array written. */ + out << " "; + int totalAct = 0; + for ( int t = 0; t < redFsm->transSet.length(); t++ ) { + /* Write the function for the transition. */ + RedTransAp *trans = transPtrs[t]; + TRANS_ACTION( trans ); + out << ", "; + if ( t < redFsm->transSet.length()-1 ) { + if ( ++totalAct % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] transPtrs; + return out; +} + +void GoFlatCodeGen::LOCATE_TRANS() +{ + out << + " _keys = " << CAST(INT(), vCS() + " << 1") << endl << + " _inds = " << CAST(INT(), IO() + "[" + vCS() + "]") << endl << + endl << + " _slen = " << CAST(INT(), SP() + "[" + vCS() + "]") << endl << + " if _slen > 0 && " << K() << "[_keys] <= " << GET_WIDE_KEY() << " && " << + GET_WIDE_KEY() << " <= " << K() << "[_keys + 1]" << " {" << endl << + " _trans = " << CAST(INT(), I() + "[_inds + " + CAST(INT(), GET_WIDE_KEY() + " - " + K() + "[_keys]") + "]") << endl << + " } else {" << endl << + " _trans = " << CAST(INT(), I() + "[_inds + _slen]") << endl << + " }" << endl << + endl; +} + +void GoFlatCodeGen::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() << + endl; + } + + if ( redFsm->anyConditions() ) { + OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() ); + COND_KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() ); + COND_KEY_SPANS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() ); + CONDS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() ); + COND_INDEX_OFFSET(); + CLOSE_ARRAY() << + endl; + } + + OPEN_ARRAY( WIDE_ALPH_TYPE(), K() ); + KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() ); + KEY_SPANS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() ); + FLAT_INDEX_OFFSET(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() ); + INDICIES(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS(); + CLOSE_ARRAY() << + endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() ); + TRANS_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofTrans() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() ); + EOF_TRANS(); + CLOSE_ARRAY() << + endl; + } + + STATE_IDS(); +} + +void GoFlatCodeGen::COND_TRANSLATE() +{ + out << + " _widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl; + + out << + " _keys = " << CAST(INT(), vCS() + " << 1") << endl << + " _conds = " << CAST(INT(), CO() + "[" + vCS() + "]") << endl << + endl << + " _slen = " << CAST(INT(), CSP() + "[" + vCS() + "]") << endl << + " if _slen > 0 && " << CK() << "[_keys]" << " <= " << GET_WIDE_KEY() << " && " << + GET_WIDE_KEY() << " <= " << CK() << "[_keys + 1] {" << endl << + " _cond = " << CAST(INT(), C() + "[_conds + " + CAST(INT(), GET_WIDE_KEY() + " - " + CK() + "[_keys]") + "]") << endl << + " } else {" << endl << + " _cond = 0" << endl << + " }" << endl << + endl; + + out << + " switch _cond {" << endl; + for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) { + GenCondSpace *condSpace = csi; + out << " case " << condSpace->condSpaceId + 1 << ":" << endl; + out << TABS(2) << "_widec = " << + KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << + " - " << KEY(keyOps->minKey) << ")" << endl; + + for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { + out << TABS(2) << "if "; + CONDITION( out, *csi ); + Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize()); + out << " {" << endl << + " _widec += " << condValOffset << endl << + " }" << endl; + } + } + + out << + " }" << endl; +} + +void GoFlatCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << + " {" << endl << + " var _slen " << INT() << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << endl; + + out << + " var _trans " << INT() << endl; + + if ( redFsm->anyConditions() ) + out << " var _cond " << INT() << endl; + + if ( redFsm->anyToStateActions() || + redFsm->anyRegActions() || redFsm->anyFromStateActions() ) + { + out << + " var _acts " << INT() << endl << + " var _nacts " << UINT() << endl; + } + + out << + " var _keys " << INT() << endl << + " var _inds " << INT() << endl; + + if ( redFsm->anyConditions() ) { + out << + " var _conds " << INT() << endl << + " var _widec " << WIDE_ALPH_TYPE() << endl; + } + + out << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + FROM_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + if ( redFsm->anyConditions() ) + COND_TRANSLATE(); + + LOCATE_TRANS(); + + if ( redFsm->anyEofTrans() ) + out << "_eof_trans:" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " _ps = " << vCS() << endl; + + out << + " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl << + endl; + + if ( redFsm->anyRegActions() ) { + out << + " if " << TA() << "[_trans] == 0 {" << endl << + " goto _again" << endl << + " }" << endl << + endl << + " _acts = " << CAST(INT(), TA() + "[_trans]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || + redFsm->anyActionCalls() || redFsm->anyActionRets() ) + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + TO_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " if " << P() << "++; " << P() << " != " << PE() << " {" << endl << + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " if " << ET() << "[" << vCS() << "] > 0 {" << endl << + " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl << + " goto _eof_trans" << endl << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " __acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl << + " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl << + " for ; __nacts > 0; __nacts-- {" << endl << + " __acts++" << endl << + " switch " << A() << "[__acts - 1]" << " {" << endl; + EOF_ACTION_SWITCH(3); + out << + " }" << endl << + " }" << endl; + } + + out << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/goflat.h b/ragel/goflat.h new file mode 100644 index 00000000..5216e85c --- /dev/null +++ b/ragel/goflat.h @@ -0,0 +1,80 @@ +/* + * Copyright 2004-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOFLAT_H +#define _GOFLAT_H + +#include <iostream> +#include "gotablish.h" + +/* Forwards. */ +struct CodeGenData; +struct NameInst; +struct RedTransAp; +struct RedStateAp; + +/* + * GoFlatCodeGen + */ +class GoFlatCodeGen + : public GoTablishCodeGen +{ +public: + GoFlatCodeGen( ostream &out ) + : GoTablishCodeGen(out) {} + + virtual ~GoFlatCodeGen() { } + +protected: + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &EOF_ACTION_SWITCH( int level ); + std::ostream &ACTION_SWITCH( int level ); + 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 &EOF_TRANS(); + 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(); + + virtual std::ostream &TO_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &EOF_ACTION( RedStateAp *state ); + virtual std::ostream &TRANS_ACTION( RedTransAp *trans ); + + virtual void writeData(); + virtual void writeExec(); +}; + +#endif diff --git a/ragel/goftable.cpp b/ragel/goftable.cpp new file mode 100644 index 00000000..85bce310 --- /dev/null +++ b/ragel/goftable.cpp @@ -0,0 +1,441 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "goftable.h" +#include "redfsm.h" +#include "gendata.h" + +using std::endl; + +/* Determine if we should use indicies or not. */ +void GoFTabCodeGen::calcIndexSize() +{ + int sizeWithInds = 0, sizeWithoutInds = 0; + + /* Calculate cost of using with indicies. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + int totalIndex = st->outSingle.length() + st->outRange.length() + + (st->defTrans == 0 ? 0 : 1); + sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex; + } + sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length(); + if ( redFsm->anyActions() ) + sizeWithInds += arrayTypeSize(redFsm->maxActListId) * redFsm->transSet.length(); + + /* Calculate the cost of not using indicies. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + int totalIndex = st->outSingle.length() + st->outRange.length() + + (st->defTrans == 0 ? 0 : 1); + sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex; + if ( redFsm->anyActions() ) + sizeWithoutInds += arrayTypeSize(redFsm->maxActListId) * totalIndex; + } + + /* If using indicies reduces the size, use them. */ + useIndicies = sizeWithInds < sizeWithoutInds; +} + +std::ostream &GoFTabCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->actListId+1; + out << act; + return out; +} + +std::ostream &GoFTabCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->actListId+1; + out << act; + return out; +} + +std::ostream &GoFTabCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->actListId+1; + out << act; + return out; +} + + +/* Write out the function for a transition. */ +std::ostream &GoFTabCodeGen::TRANS_ACTION( RedTransAp *trans ) +{ + int action = 0; + if ( trans->action != 0 ) + action = trans->action->actListId+1; + out << action; + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFTabCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numToStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + + out << endl; + } + } + + genLineDirective( out ); + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFTabCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numFromStateRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + + out << endl; + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoFTabCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numEofRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, true, false ); + + out << endl; + } + } + + genLineDirective( out ); + return out; +} + +/* Write out the function switch. This switch is keyed on the values + * of the func index. */ +std::ostream &GoFTabCodeGen::ACTION_SWITCH( int level ) +{ + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numTransRefs > 0 ) { + /* Write the entry label. */ + out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, 0, false, false ); + + out << endl; + } + } + + genLineDirective( out ); + return out; +} + +void GoFTabCodeGen::writeData() +{ + if ( redFsm->anyConditions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() ); + COND_OFFSETS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() ); + COND_LENS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() ); + COND_KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() ); + COND_SPACES(); + CLOSE_ARRAY() << + endl; + } + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() ); + KEY_OFFSETS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( WIDE_ALPH_TYPE(), K() ); + KEYS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() ); + SINGLE_LENS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() ); + RANGE_LENS(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() ); + INDEX_OFFSETS(); + CLOSE_ARRAY() << + endl; + + if ( useIndicies ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() ); + INDICIES(); + CLOSE_ARRAY() << + endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS_WI(); + CLOSE_ARRAY() << + endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() ); + TRANS_ACTIONS_WI(); + CLOSE_ARRAY() << + endl; + } + } + else { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS(); + CLOSE_ARRAY() << + endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() ); + TRANS_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + } + + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofTrans() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() ); + EOF_TRANS(); + CLOSE_ARRAY() << + endl; + } + + STATE_IDS(); +} + +void GoFTabCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << + " {" << endl << + " var _klen " << INT() << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << endl; + + out << + " var _keys " << INT() << endl << + " var _trans " << INT() << endl; + + if ( redFsm->anyConditions() ) + out << " var _widec " << WIDE_ALPH_TYPE() << endl; + + out << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " switch " << FSA() << "[" << vCS() << "] {" << endl; + FROM_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->anyConditions() ) + COND_TRANSLATE(); + + LOCATE_TRANS(); + + out << "_match:" << endl; + + if ( useIndicies ) + out << " _trans = " << CAST(INT(), I() + "[_trans]") << endl; + + if ( redFsm->anyEofTrans() ) + out << "_eof_trans:" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " _ps = " << vCS() << endl; + + out << + " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl << + endl; + + if ( redFsm->anyRegActions() ) { + out << + " if " << TA() << "[_trans] == 0 {" << endl << + " goto _again" << endl << + " }" << endl << + endl << + " switch " << TA() << "[_trans] {" << endl; + ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || + redFsm->anyActionCalls() || redFsm->anyActionRets() ) + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " switch " << TSA() << "[" << vCS() << "] {" << endl; + TO_STATE_ACTION_SWITCH(1); + out << + " }" << endl << + endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " if " << P() << "++; " << P() << " != " << PE() << " {" << endl << + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " if " << ET() << "[" << vCS() << "] > 0 {" << endl << + " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl << + " goto _eof_trans" << endl << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " switch " << EA() << "[" << vCS() << "] {" << endl; + EOF_ACTION_SWITCH(2); + out << + " }" << endl; + } + + out << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/goftable.h b/ragel/goftable.h new file mode 100644 index 00000000..524b6a21 --- /dev/null +++ b/ragel/goftable.h @@ -0,0 +1,59 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOFTABLE_H +#define _GOFTABLE_H + +#include <iostream> +#include "gotable.h" + +/* Forwards. */ +struct CodeGenData; + +/* + * GoFTabCode + */ +class GoFTabCodeGen + : public GoTabCodeGen +{ +public: + GoFTabCodeGen( ostream &out ) + : GoTabCodeGen(out) {} + +protected: + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &EOF_ACTION_SWITCH( int level ); + std::ostream &ACTION_SWITCH( int level ); + + virtual std::ostream &TO_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &EOF_ACTION( RedStateAp *state ); + virtual std::ostream &TRANS_ACTION( RedTransAp *trans ); + + virtual void writeData(); + virtual void writeExec(); + virtual void calcIndexSize(); +}; + +#endif diff --git a/ragel/gogoto.cpp b/ragel/gogoto.cpp new file mode 100644 index 00000000..0bfae545 --- /dev/null +++ b/ragel/gogoto.cpp @@ -0,0 +1,733 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "gogoto.h" +#include "redfsm.h" +#include "bstmap.h" +#include "gendata.h" + +using std::endl; + +/* Emit the goto to take for a given transition. */ +std::ostream &GoGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level ) +{ + out << TABS(level) << "goto tr" << trans->id << ";"; + return out; +} + +int GoGotoCodeGen::TRANS_NR( RedTransAp *trans ) +{ + return trans->id; +} + +std::ostream &GoGotoCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoGotoCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, true, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoGotoCodeGen::ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +void GoGotoCodeGen::GOTO_HEADER( RedStateAp *state, int level ) +{ + /* Label the state. */ + out << TABS(level) << "case " << state->id << ":" << endl; +} + +void GoGotoCodeGen::emitSingleSwitch( RedStateAp *state, int level ) +{ + /* 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 << TABS(level) << "if " << GET_WIDE_KEY(state) << " == " << + WIDE_KEY(state, data[0].lowKey) << " {" << endl; + + /* Virtual function for writing the target of the transition. */ + TRANS_GOTO(data[0].value, level + 1) << endl; + out << TABS(level) << "}" << endl; + } + else if ( numSingles > 1 ) { + /* Write out single keys in a switch if there is more than one. */ + out << TABS(level) << "switch " << GET_WIDE_KEY(state) << " {" << endl; + + /* Write out the single indicies. */ + for ( int j = 0; j < numSingles; j++ ) { + out << TABS(level) << "case " << WIDE_KEY(state, data[j].lowKey) << ":" << endl; + TRANS_GOTO(data[j].value, level + 1) << endl; + } + + /* Close off the transition switch. */ + out << TABS(level) << "}" << endl; + } +} + +void GoGotoCodeGen::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) << "switch {" << endl; + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " < " << + WIDE_KEY(state, data[mid].lowKey) << ":" << endl; + emitRangeBSearch( state, level+1, low, mid-1 ); + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " > " << + WIDE_KEY(state, data[mid].highKey) << ":" << endl; + emitRangeBSearch( state, level+1, mid+1, high ); + out << TABS(level) << "default:" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + out << TABS(level) << "}" << endl; + } + else if ( anyLower && !anyHigher ) { + /* Can go lower than mid but not higher. */ + out << TABS(level) << "switch {" << endl; + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " < " << + WIDE_KEY(state, data[mid].lowKey) << ":" << endl; + 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) << "default:" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + } + else { + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " <= " << + WIDE_KEY(state, data[mid].highKey) << ":" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + } + out << TABS(level) << "}" << endl; + } + else if ( !anyLower && anyHigher ) { + /* Can go higher than mid but not lower. */ + out << TABS(level) << "switch {" << endl; + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " > " << + WIDE_KEY(state, data[mid].highKey) << ":" << endl; + 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) << "default:" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + } + else { + out << TABS(level) << "case " << GET_WIDE_KEY(state) << " >= " << + WIDE_KEY(state, data[mid].lowKey) << ":" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + } + out << TABS(level) << "}" << endl; + } + 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 " << WIDE_KEY(state, data[mid].lowKey) << " <= " << + GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " << + WIDE_KEY(state, data[mid].highKey) << " {" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + out << TABS(level) << "}" << endl; + } + else if ( limitLow && !limitHigh ) { + out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " << + WIDE_KEY(state, data[mid].highKey) << " {" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + out << TABS(level) << "}" << endl; + } + else if ( !limitLow && limitHigh ) { + out << TABS(level) << "if " << WIDE_KEY(state, data[mid].lowKey) << " <= " << + GET_WIDE_KEY(state) << " {" << endl; + TRANS_GOTO(data[mid].value, level+1) << endl; + out << TABS(level) << "}" << endl; + } + else { + /* Both high and low are at the limit. No tests to do. */ + TRANS_GOTO(data[mid].value, level) << endl; + } + } +} + +void GoGotoCodeGen::STATE_GOTO_ERROR( int level ) +{ + /* Label the state and bail immediately. */ + outLabelUsed = true; + RedStateAp *state = redFsm->errState; + out << TABS(level) << "case " << state->id << ":" << endl; + out << TABS(level + 1) << "goto _out" << endl; +} + +void GoGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level ) +{ + GenCondSpace *condSpace = stateCond->condSpace; + out << TABS(level) << "_widec = " << + KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << + " - " << KEY(keyOps->minKey) << ")" << endl; + + for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { + out << TABS(level) << "if "; + CONDITION( out, *csi ); + Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize()); + out << " {" << endl; + out << TABS(level + 1) << "_widec += " << condValOffset << endl; + out << TABS(level) << "}" << endl; + } +} + +void GoGotoCodeGen::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; + GenStateCond **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) << "switch {" << endl; + out << TABS(level) << "case " << GET_KEY() << " < " << + KEY(data[mid]->lowKey) << ":" << endl; + emitCondBSearch( state, level+1, low, mid-1 ); + out << TABS(level) << "case " << GET_KEY() << " > " << + KEY(data[mid]->highKey) << ":" << endl; + emitCondBSearch( state, level+1, mid+1, high ); + out << TABS(level) << "default:" << endl; + COND_TRANSLATE(data[mid], level+1); + out << TABS(level) << "}" << endl; + } + else if ( anyLower && !anyHigher ) { + /* Can go lower than mid but not higher. */ + out << TABS(level) << "switch {" << endl; + out << TABS(level) << "case " << GET_KEY() << " < " << + KEY(data[mid]->lowKey) << ":" << endl; + 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) << "default:" << endl; + COND_TRANSLATE(data[mid], level+1); + } + else { + out << TABS(level) << "case " << GET_KEY() << " <= " << + KEY(data[mid]->highKey) << ":" << endl; + COND_TRANSLATE(data[mid], level+1); + } + out << TABS(level) << "}" << endl; + } + else if ( !anyLower && anyHigher ) { + /* Can go higher than mid but not lower. */ + out << TABS(level) << "switch {" << endl; + out << TABS(level) << "case " << GET_KEY() << " > " << + KEY(data[mid]->highKey) << ":" << endl; + 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) << "default:" << endl; + COND_TRANSLATE(data[mid], level+1); + } + else { + out << TABS(level) << "case " << GET_KEY() << " >= " << + KEY(data[mid]->lowKey) << ":" << endl; + COND_TRANSLATE(data[mid], level+1); + } + out << TABS(level) << "}" << endl; + } + 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) << " {" << endl; + COND_TRANSLATE(data[mid], level+1); + out << TABS(level) << "}" << endl; + } + else if ( limitLow && !limitHigh ) { + out << TABS(level) << "if " << GET_KEY() << " <= " << + KEY(data[mid]->highKey) << " {" << endl; + COND_TRANSLATE(data[mid], level+1); + out << TABS(level) << "}" << endl; + } + else if ( !limitLow && limitHigh ) { + out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " << + GET_KEY() << " {" << endl; + COND_TRANSLATE(data[mid], level+1); + out << TABS(level) << "}" << endl; + } + else { + /* Both high and low are at the limit. No tests to do. */ + COND_TRANSLATE(data[mid], level); + } + } +} + +std::ostream &GoGotoCodeGen::STATE_GOTOS( int level ) +{ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st == redFsm->errState ) + STATE_GOTO_ERROR(level); + else { + /* Writing code above state gotos. */ + GOTO_HEADER( st, level ); + + if ( st->stateCondVect.length() > 0 ) { + out << TABS(level + 1) << "_widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl; + emitCondBSearch( st, level + 1, 0, st->stateCondVect.length() - 1 ); + } + + /* Try singles. */ + if ( st->outSingle.length() > 0 ) + emitSingleSwitch( st, level + 1 ); + + /* Default case is to binary search for the ranges, if that fails then */ + if ( st->outRange.length() > 0 ) + emitRangeBSearch( st, level + 1, 0, st->outRange.length() - 1 ); + + /* Write the default transition. */ + TRANS_GOTO( st->defTrans, level + 1 ) << endl; + } + } + return out; +} + +std::ostream &GoGotoCodeGen::TRANSITIONS() +{ + /* Emit any transitions that have functions and that go to + * this state. */ + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { + /* Write the label for the transition so it can be jumped to. */ + out << " tr" << trans->id << ": "; + + /* Destination state. */ + if ( trans->action != 0 && trans->action->anyCurStateRef() ) + out << "_ps = " << vCS() << ";"; + out << vCS() << " = " << trans->targ->id << "; "; + + if ( trans->action != 0 ) { + /* Write out the transition func. */ + out << "goto f" << trans->action->actListId << endl; + } + else { + /* No code to execute, just loop around. */ + out << "goto _again" << endl; + } + } + return out; +} + +std::ostream &GoGotoCodeGen::EXEC_FUNCS() +{ + /* Make labels that set acts and jump to execFuncs. Loop func indicies. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) { + if ( redAct->numTransRefs > 0 ) { + out << " f" << redAct->actListId << ": " << + "_acts = " << (redAct->location + 1) << ";" + " goto execFuncs" << endl; + } + } + + out << + endl << + "execFuncs:" << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + " goto _again" << endl; + return out; +} + +unsigned int GoGotoCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->location+1; + return act; +} + +unsigned int GoGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->location+1; + return act; +} + +unsigned int GoGotoCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->location+1; + return act; +} + +std::ostream &GoGotoCodeGen::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 << " "; + for ( int st = 0; st < redFsm->nextStateId; st++ ) { + /* Write any eof action. */ + out << vals[st] << ", "; + if ( st < numStates-1 ) { + if ( (st+1) % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] vals; + return out; +} + +std::ostream &GoGotoCodeGen::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 << " "; + for ( int st = 0; st < redFsm->nextStateId; st++ ) { + /* Write any eof action. */ + out << vals[st] << ", "; + if ( st < numStates-1 ) { + if ( (st+1) % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] vals; + return out; +} + +std::ostream &GoGotoCodeGen::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 << " "; + for ( int st = 0; st < redFsm->nextStateId; st++ ) { + /* Write any eof action. */ + out << vals[st] << ", "; + if ( st < numStates-1 ) { + if ( (st+1) % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] vals; + return out; +} + +std::ostream &GoGotoCodeGen::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 << TABS(2) << "case " << st->id << ":" << endl; + + /* Write the goto func. */ + out << TABS(3) << "goto f" << st->eofAction->actListId << endl; + } + } + + return out; +} + +void GoGotoCodeGen::writeData() +{ + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() ); + ACTIONS_ARRAY(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << + endl; + } + + STATE_IDS(); +} + +void GoGotoCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << " {" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << " = 0" << endl; + + if ( redFsm->anyToStateActions() || redFsm->anyRegActions() + || redFsm->anyFromStateActions() ) + { + out << + " var _acts " << INT() << endl << + " var _nacts " << UINT() << endl; + } + + if ( redFsm->anyConditions() ) + out << " var _widec " << WIDE_ALPH_TYPE() << endl; + + out << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + FROM_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + out << + " switch " << vCS() << " {" << endl; + STATE_GOTOS(1); + out << + " }" << endl << + endl; + TRANSITIONS() << + endl; + + if ( redFsm->anyRegActions() ) + EXEC_FUNCS() << endl; + + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + TO_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " if " << P() << "++; " << P() << " != " << PE() << " {" << endl << + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " switch " << vCS() << " {" << endl; + + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->eofTrans != 0 ) + out << " case " << st->id << ":" << endl << + " goto tr" << st->eofTrans->id << endl; + } + + out << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " __acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl << + " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl << + " for ; __nacts > 0; __nacts-- {" << endl << + " __acts++" << endl << + " switch " << A() << "[__acts - 1]" << " {" << endl; + EOF_ACTION_SWITCH(3); + out << + " }" << endl << + " }" << endl; + } + + out << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/gogoto.h b/ragel/gogoto.h new file mode 100644 index 00000000..18d058e5 --- /dev/null +++ b/ragel/gogoto.h @@ -0,0 +1,83 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOGOTO_H +#define _GOGOTO_H + +#include <iostream> +#include "gotablish.h" + +/* Forwards. */ +struct CodeGenData; +struct NameInst; +struct RedTransAp; +struct RedStateAp; +struct GenStateCond; + +/* + * Goto driven fsm. + */ +class GoGotoCodeGen + : public GoTablishCodeGen +{ +public: + GoGotoCodeGen( ostream &out ) + : GoTablishCodeGen(out) {} + +protected: + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &EOF_ACTION_SWITCH( int level ); + std::ostream &ACTION_SWITCH( int level ); + std::ostream &STATE_GOTOS( int level ); + std::ostream &TRANSITIONS(); + std::ostream &EXEC_FUNCS(); + std::ostream &FINISH_CASES(); + + virtual unsigned int TO_STATE_ACTION( RedStateAp *state ); + virtual unsigned int FROM_STATE_ACTION( RedStateAp *state ); + virtual unsigned int EOF_ACTION( RedStateAp *state ); + + std::ostream &TO_STATE_ACTIONS(); + std::ostream &FROM_STATE_ACTIONS(); + std::ostream &EOF_ACTIONS(); + + void COND_TRANSLATE( GenStateCond *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 ); + virtual int TRANS_NR( RedTransAp *trans ); + + void emitSingleSwitch( RedStateAp *state, int level ); + 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, int level ); + virtual void STATE_GOTO_ERROR( int level ); + + virtual void writeData(); + virtual void writeExec(); +}; + +#endif diff --git a/ragel/goipgoto.cpp b/ragel/goipgoto.cpp index 107acfff..c72f0004 100644 --- a/ragel/goipgoto.cpp +++ b/ragel/goipgoto.cpp @@ -1,6 +1,5 @@ /* - * Copyright 2010 Justine Tunney <jtunney@gmail.com> - * 2001-2006 Adrian Thurston <thurston@complang.org> + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> * 2004 Erich Ocean <eric.ocean@ampede.com> * 2005 Alan West <alan@alanz.com> */ @@ -11,115 +10,35 @@ * 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 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ragel.h" -#include "cdipgoto.h" #include "goipgoto.h" #include "redfsm.h" #include "gendata.h" #include "bstmap.h" -#include <iomanip> -#include <sstream> -using std::ostringstream; -using std::streambuf; +using std::endl; -void GoIpGotoCodeGen::writeExec() +bool GoIpGotoCodeGen::useAgainLabel() { - /* Must set labels immediately before writing because we may - * depend on the noend write option. */ - setLabelsNeeded(); - testEofUsed = false; - outLabelUsed = false; - out << " {\n"; - if ( redFsm->anyRegCurStateRef() ) - out << " _ps := 0\n"; - if ( redFsm->anyConditions() ) - out << " " << WIDE_ALPH_TYPE() << " _widec\n"; - if ( !noEnd ) { - testEofUsed = true; - out << - " if " << P() << " == " << PE() << - " { goto _test_eof }\n"; - } - if ( useAgainLabel() ) { - out << - " goto _resume\n" - "\n" - "_again:\n" - " switch " << vCS() << " {\n"; - AGAIN_CASES() << - " default: break\n" - " }\n" - "\n"; - if ( !noEnd ) { - testEofUsed = true; - out << - " " << P() << "++\n" - " if " << P() << " == " << PE() << - " { goto _test_eof }\n"; - } else { - out << - " " << P() << "++\n"; - } - out << "_resume:\n"; - } - out << " switch " << vCS() << " {\n"; - - // kludge for labels before the first real case statement - out << " case -666: // i am a hack D:\n"; - // isFirstCase = true; - - STATE_GOTOS(); - SWITCH_DEFAULT() << - " }\n"; - EXIT_STATES() << - "\n"; - if ( testEofUsed ) - out << " _test_eof: {}\n"; - if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { - out << - " if " << P() << " == " << vEOF() << " {\n" - " switch " << vCS() << " {\n"; - FINISH_CASES(); - SWITCH_DEFAULT() << - " }\n" - " }\n" - "\n"; - } - if ( outLabelUsed ) - out << " _out: {}\n"; - out << - " }\n"; + return redFsm->anyRegActionRets() || + redFsm->anyRegActionByValControl() || + redFsm->anyRegNextStmt(); } -void GoIpGotoCodeGen::STATE_IDS() +void GoIpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish ) { - if ( redFsm->startState != 0 ) - out << "var " << START() << " int = " << START_STATE_ID() << "\n"; - if ( !noFinal ) - out << "var " << FIRST_FINAL() << " int = " << FIRST_FINAL_STATE() << "\n"; - if ( !noError ) - out << "var " << ERROR() << " int = " << ERROR_STATE() << "\n"; - out << "\n"; - if ( entryPointNames.length() > 0 ) { - for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) { - out << - "var " << (DATA_PREFIX() + "en_" + *en) << - " int = " << entryPointIds[en.pos()] << "\n"; - } - out << "\n"; - } + ret << "{" << "goto st" << gotoDest << " }"; } void GoIpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish ) @@ -128,10 +47,10 @@ void GoIpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFi ret << "{"; INLINE_LIST( ret, prePushExpr, 0, false, false ); } - ret << "{" << - STACK() << "[" << TOP() << "] = " << targState << "; " << - TOP() << "++; " << - CTRL_FLOW() << "goto st" << callDest << ";}"; + + ret << "{" << STACK() << "[" << TOP() << "] = " << targState << + "; " << TOP() << "++; " << "goto st" << callDest << " }"; + if ( prePushExpr != 0 ) ret << "}"; } @@ -142,386 +61,241 @@ void GoIpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targSt ret << "{"; INLINE_LIST( ret, prePushExpr, 0, false, false ); } - ret << "{" << - STACK() << "[" << TOP() << "] = " << targState << "; " << - TOP() << "++; " << - vCS() << " = ("; + + ret << "{" << STACK() << "[" << TOP() << "] = " << targState << "; " << TOP() << "++; " << vCS() << " = ("; INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); - ret << "); " << CTRL_FLOW() << "goto _again;}"; + ret << "); " << "goto _again }"; + if ( prePushExpr != 0 ) ret << "}"; } void GoIpGotoCodeGen::RET( ostream &ret, bool inFinish ) { - ret << "{" << - TOP() << "--; " << - vCS() << " = " << STACK() << "[" << TOP() << "];"; + ret << "{" << TOP() << "--; " << vCS() << " = " << STACK() << "[" << TOP() << "];"; + if ( postPopExpr != 0 ) { ret << "{"; INLINE_LIST( ret, postPopExpr, 0, false, false ); ret << "}"; } - ret << CTRL_FLOW() << "goto _again;}"; + + ret << "goto _again }"; +} + +void GoIpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) +{ + ret << "{" << vCS() << " = ("; + INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); + ret << "); " << "goto _again }"; +} + +void GoIpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish ) +{ + ret << vCS() << " = " << nextDest << ";"; +} + +void GoIpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) +{ + ret << vCS() << " = ("; + INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); + ret << ");"; +} + +void GoIpGotoCodeGen::CURS( ostream &ret, bool inFinish ) +{ + ret << "(_ps)"; +} + +void GoIpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState ) +{ + ret << targState; +} + +void GoIpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced ) +{ + outLabelUsed = true; + ret << "{" << P() << "++; "; + if ( !csForced ) + ret << vCS() << " = " << targState << "; "; + ret << "goto _out }"; +} + +bool GoIpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state ) +{ + bool anyWritten = false; + + /* Emit any transitions that have actions and that go to this state. */ + for ( int it = 0; it < state->numInTrans; it++ ) { + RedTransAp *trans = state->inTrans[it]; + if ( trans->action != 0 && trans->labelNeeded ) { + /* Remember that we wrote an action so we know to write the + * line directive for going back to the output. */ + anyWritten = true; + + /* Write the label for the transition so it can be jumped to. */ + out << "tr" << trans->id << ":" << endl; + + /* If the action contains a next, then we must preload the current + * state since the action may or may not set it. */ + if ( trans->action->anyNextStmt() ) + out << " " << vCS() << " = " << trans->targ->id << endl; + + /* Write each action in the list. */ + for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) { + ACTION( out, item->value, trans->targ->id, false, + trans->action->anyNextStmt() ); + } + + /* If the action contains a next then we need to reload, otherwise + * jump directly to the target state. */ + if ( trans->action->anyNextStmt() ) + out << " goto _again" << endl; + else + out << " goto st" << trans->targ->id << endl; + } + } + + return anyWritten; } -/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos - * for each state. */ -void GoIpGotoCodeGen::GOTO_HEADER( RedStateAp *state ) +std::ostream &GoIpGotoCodeGen::STATE_GOTOS_SWITCH( int level ) +{ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + out << TABS(level) << "case " << st->id << ":" << endl; + if ( redFsm->errState == st ) + out << TABS(level + 1) << "goto st" << st->id << endl; + else + out << TABS(level + 1) << "goto st" << st->id << "_body" << endl; + } + return out; +} + +/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each + * state. */ +void GoIpGotoCodeGen::GOTO_HEADER( RedStateAp *state, int level ) { bool anyWritten = IN_TRANS_ACTIONS( state ); - if ( state->labelNeeded ) - out << "st" << state->id << ":\n"; + + if ( state->labelNeeded ) + out << TABS(level) << "st" << state->id << ":" << endl; + if ( state->toStateAction != 0 ) { /* Remember that we wrote an action. Write every action in the list. */ anyWritten = true; for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) { - ACTION( out, item->value, state->id, false, - state->toStateAction->anyNextStmt() ); + ACTION( out, item->value, state->id, false, + state->toStateAction->anyNextStmt() ); } } + /* Advance and test buffer pos. */ if ( state->labelNeeded ) { if ( !noEnd ) { out << - " " << P() << "++\n" - " if " << P() << " == " << PE() << - " { goto _test_eof" << state->id << " }\n"; + TABS(level + 1) << "if " << P() << "++; " << P() << " == " << PE() << " {" << endl << + TABS(level + 2) << "goto _test_eof" << state->id << endl << + TABS(level + 1) << "}" << endl; } else { - out << - " " << P() << "++\n"; + out << + TABS(level + 1) << P() << "++" << endl; } } - // emulate c switch statement behavior - out << " fallthrough\n"; - // if (!isFirstCase) { - // out << " fallthrough\n"; - // } else { - // isFirstCase = false; - // } + /* Give the state a label. */ + out << TABS(level) << "st" << state->id << "_body:" << endl; - /* Give the state a switch case. */ - out << "case " << state->id << ":\n"; if ( state->fromStateAction != 0 ) { /* Remember that we wrote an action. Write every action in the list. */ anyWritten = true; for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) { ACTION( out, item->value, state->id, false, - state->fromStateAction->anyNextStmt() ); + state->fromStateAction->anyNextStmt() ); } } + if ( anyWritten ) genLineDirective( out ); + /* Record the prev state if necessary. */ if ( state->anyRegCurStateRef() ) - out << " _ps = " << state->id << "\n"; -} - -ostream &GoIpGotoCodeGen::STATIC_VAR( string type, string name ) -{ - out << "var " << name << " " << type; - return out; + out << TABS(level + 1) << "_ps = " << state->id << endl; } -void GoIpGotoCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, - int targState, int inFinish, bool csForced ) +void GoIpGotoCodeGen::STATE_GOTO_ERROR( int level ) { - ret << " switch " << ACT() << " {\n"; - bool haveDefault = false; - for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) { - /* Write the case label, the action and the case break. */ - if ( lma->lmId < 0 ) { - ret << " default:\n"; - haveDefault = true; - } - else - ret << " case " << lma->lmId << ":\n"; - /* Write the block and close it off. */ - ret << " {"; - INLINE_LIST( ret, lma->children, targState, inFinish, csForced ); - ret << "}\n"; - ret << " break\n"; - } - ret << " }\n "; -} - -string GoIpGotoCodeGen::GET_KEY() -{ - ostringstream ret; - if ( getKeyExpr != 0 ) { - /* Emit the user supplied method of retrieving the key. */ - ret << "("; - INLINE_LIST( ret, getKeyExpr, 0, false, false ); - ret << ")"; - } - else { - /* Expression for retrieving the key, use simple dereference. */ - ret << "data[" << P() << "]"; - } - return ret.str(); -} + /* In the error state we need to emit some stuff that usually goes into + * the header. */ + RedStateAp *state = redFsm->errState; + bool anyWritten = IN_TRANS_ACTIONS( state ); -void GoIpGotoCodeGen::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) << " { "; - /* Virtual function for writing the target of the transition. */ - TRANS_GOTO(data[0].value, 0) << " }\n"; - } - else if ( numSingles > 1 ) { - /* Write out single keys in a switch if there is more than one. */ - out << "\tswitch " << GET_WIDE_KEY(state) << " {\n"; - /* Write out the single indicies. */ - for ( int j = 0; j < numSingles; j++ ) { - out << "\t\tcase " << KEY(data[j].lowKey) << ": "; - TRANS_GOTO(data[j].value, 0) << "\n"; - } - /* Emits a default case for D code. */ - SWITCH_DEFAULT(); - /* Close off the transition switch. */ - out << "\t}\n"; - } -} + /* No case label needed since we don't switch on the error state. */ + if ( anyWritten ) + genLineDirective( out ); -void GoIpGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high ) -{ - /* Get the mid position, staying on the lower end of the range. */ - int mid = (low + high) >> 1; - RedTransEl *data = state->outRange.data; - /* Determine if we need to look higher or lower. */ - bool anyLower = mid > low; - bool anyHigher = mid < high; - /* Determine if the keys at mid are the limits of the alphabet. */ - bool limitLow = data[mid].lowKey == keyOps->minKey; - bool limitHigh = data[mid].highKey == keyOps->maxKey; - if ( anyLower && anyHigher ) { - /* Can go lower and higher than mid. */ - out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << - KEY(data[mid].lowKey) << " {\n"; - emitRangeBSearch( state, level+1, low, mid-1 ); - out << TABS(level) << "} else if " << GET_WIDE_KEY(state) << " > " << - KEY(data[mid].highKey) << " {\n"; - emitRangeBSearch( state, level+1, mid+1, high ); - out << TABS(level) << "} else {\n"; - TRANS_GOTO(data[mid].value, level+1) << "\n"; - out << TABS(level) << "}\n"; - } - else if ( anyLower && !anyHigher ) { - /* Can go lower than mid but not higher. */ - out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << - KEY(data[mid].lowKey) << " {\n"; - emitRangeBSearch( state, level+1, low, mid-1 ); - /* if the higher is the highest in the alphabet then there is no - * sense testing it. */ - if ( limitHigh ) { - out << TABS(level) << "} else {\n"; - TRANS_GOTO(data[mid].value, level+1) << "\n"; - out << TABS(level) << "}\n"; - } - else { - out << TABS(level) << "} else if " << GET_WIDE_KEY(state) << " <= " << - KEY(data[mid].highKey) << " {\n"; - TRANS_GOTO(data[mid].value, level+1) << "\n"; - out << TABS(level) << "}\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"; - out << TABS(level) << "}\n"; - } - else { - out << TABS(level) << "} else if " << GET_WIDE_KEY(state) << " >= " << - KEY(data[mid].lowKey) << " {\n"; - TRANS_GOTO(data[mid].value, level+1) << "\n"; - out << TABS(level) << "}\n"; - } - } - else { - /* Cannot go higher or lower than mid. It's mid or bust. What - * tests to do depends on limits of alphabet. */ - if ( !limitLow && !limitHigh ) { - out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << - GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " << - KEY(data[mid].highKey) << " { "; - TRANS_GOTO(data[mid].value, 0) << " }\n"; - } - else if ( limitLow && !limitHigh ) { - out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " << - KEY(data[mid].highKey) << " { "; - TRANS_GOTO(data[mid].value, 0) << " }\n"; - } - else if ( !limitLow && limitHigh ) { - out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << - GET_WIDE_KEY(state) << " { "; - TRANS_GOTO(data[mid].value, 0) << " }\n"; - } - else { - /* Both high and low are at the limit. No tests to do. */ - TRANS_GOTO(data[mid].value, level+1) << "\n"; - } - } -} + if ( state->labelNeeded ) + out << TABS(level) << "st" << state->id << ":" << endl; -void GoIpGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level ) -{ - GenCondSpace *condSpace = stateCond->condSpace; - out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" << - KEY(condSpace->baseKey) << " + (" << GET_KEY() << - " - " << KEY(keyOps->minKey) << "))\n"; - for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { - out << TABS(level) << "if "; - CONDITION( out, *csi ); - Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize()); - out << " { _widec += " << condValOffset << " }\n"; - } + /* Break out here. */ + outLabelUsed = true; + out << TABS(level + 1) << vCS() << " = " << state->id << endl; + out << TABS(level + 1) << "goto _out" << endl; } -ostream &GoIpGotoCodeGen::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; -} /* Emit the goto to take for a given transition. */ -ostream &GoIpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level ) +std::ostream &GoIpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level ) { if ( trans->action != 0 ) { /* Go to the transition which will go to the state. */ out << TABS(level) << "goto tr" << trans->id; - } else { + } + else { /* Go directly to the target state. */ out << TABS(level) << "goto st" << trans->targ->id; } return out; } -void GoIpGotoCodeGen::writeInit() +int GoIpGotoCodeGen::TRANS_NR( RedTransAp *trans ) { - if ( !noCS ) - out << "\t" << vCS() << " = " << START() << "\n"; - /* If there are any calls, then the stack top needs initialization. */ - if ( redFsm->anyActionCalls() || redFsm->anyActionRets() ) - out << "\t" << TOP() << " = 0\n"; - if ( hasLongestMatch ) { - out << - " " << TOKSTART() << " = " << NULL_ITEM() << "\n" - " " << TOKEND() << " = " << NULL_ITEM() << "\n" - " " << ACT() << " = 0\n"; + if ( trans->action != 0 ) { + /* Go to the transition which will go to the state. */ + return trans->id + redFsm->stateList.length(); } -} - -void GoIpGotoCodeGen::writeData() -{ - STATE_IDS(); -} - -void gothicLineDirective( ostream &out, const char *fileName, int line ) -{ - /* Write the preprocessor line info for to the input file. */ - out << "// line " << line << " \""; - for ( const char *pc = fileName; *pc != 0; pc++ ) { - if ( *pc == '\\' ) - out << "\\\\"; - else - out << *pc; + else { + /* Go directly to the target state. */ + return trans->targ->id; } - out << "\"\n"; } -void GoIpGotoCodeGen::genLineDirective( ostream &out ) +std::ostream &GoIpGotoCodeGen::EXIT_STATES() { - streambuf *sbuf = out.rdbuf(); - output_filter *filter = static_cast<output_filter*>(sbuf); - gothicLineDirective( out, filter->fileName, filter->line + 1 ); -} - -bool GoIpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state ) -{ - bool anyWritten = false; - /* Emit any transitions that have actions and that go to this state. */ - for ( int it = 0; it < state->numInTrans; it++ ) { - RedTransAp *trans = state->inTrans[it]; - if ( trans->action != 0 && trans->labelNeeded ) { - /* Remember that we wrote an action so we know to write the - * line directive for going back to the output. */ - anyWritten = true; - /* Write the label for the transition so it can be jumped to. */ - out << "tr" << trans->id << ":\n"; - /* If the action contains a next, then we must preload the current - * state since the action may or may not set it. */ - if ( trans->action->anyNextStmt() ) - out << " " << vCS() << " = " << trans->targ->id << "\n"; - /* Write each action in the list. */ - for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) { - ACTION( out, item->value, trans->targ->id, false, - trans->action->anyNextStmt() ); - } - /* If the action contains a next then we need to reload, otherwise - * jump directly to the target state. */ - if ( trans->action->anyNextStmt() ) - out << "\tgoto _again\n"; - else - out << "\tgoto st" << trans->targ->id << "\n"; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->outNeeded ) { + testEofUsed = true; + out << " _test_eof" << st->id << ": " << vCS() << " = " << + st->id << "; goto _test_eof" << endl; } } - return anyWritten; -} - -void GoIpGotoCodeGen::ACTION( ostream &ret, GenAction *action, int targState, - bool inFinish, bool csForced ) -{ - /* Write the preprocessor line info for going into the source file. */ - gothicLineDirective( ret, action->loc.fileName, action->loc.line ); - /* Write the block and close it off. */ - ret << "\t{"; - INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced ); - ret << "}\n"; + return out; } -void GoIpGotoCodeGen::CONDITION( ostream &ret, GenAction *condition ) +std::ostream &GoIpGotoCodeGen::AGAIN_CASES( int level ) { - ret << "\n"; - gothicLineDirective( ret, condition->loc.fileName, condition->loc.line ); - INLINE_LIST( ret, condition->inlineList, 0, false, false ); + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + out << + TABS(level) << "case " << st->id << ":" << endl << + TABS(level + 1) << "goto st" << st->id << endl; + } + return out; } -ostream &GoIpGotoCodeGen::FINISH_CASES() +std::ostream &GoIpGotoCodeGen::FINISH_CASES( int level ) { bool anyWritten = false; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { if ( st->eofAction != 0 ) { if ( st->eofAction->eofRefs == 0 ) @@ -529,35 +303,177 @@ ostream &GoIpGotoCodeGen::FINISH_CASES() st->eofAction->eofRefs->insert( st->id ); } } + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { - if ( st->eofTrans != 0 ) { - out << " case " << st->id << ": goto tr" << st->eofTrans->id << "\n"; - } + if ( st->eofTrans != 0 ) + out << TABS(level) << "case " << st->id << ":" << endl << + TABS(level + 1) << "goto tr" << st->eofTrans->id << endl; } + for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) { if ( act->eofRefs != 0 ) { - /* multiple values in a case statement */ - out << " case "; - bool first = true; + out << TABS(level) << "case "; for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ ) { - if (first) { - first = false; - } else { - out << ", "; - } out << *pst; + if ( !pst.last() ) + out << ", "; } - out << ":\n"; + out << ":" << endl; + /* Remember that we wrote a trans so we know to write the * line directive for going back to the output. */ anyWritten = true; + /* Write each action in the eof action list. */ for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) ACTION( out, item->value, STATE_ERR_STATE, true, false ); - out << "\tbreak\n"; } } + if ( anyWritten ) genLineDirective( out ); return out; } + +void GoIpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList ) +{ + for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) { + switch ( item->type ) { + case GenInlineItem::Goto: case GenInlineItem::Call: { + /* Mark the target as needing a label. */ + item->targState->labelNeeded = true; + break; + } + default: break; + } + + if ( item->children != 0 ) + setLabelsNeeded( item->children ); + } +} + +/* Set up labelNeeded flag for each state. */ +void GoIpGotoCodeGen::setLabelsNeeded() +{ + /* If we use the _again label, then we the _again switch, which uses all + * labels. */ + if ( useAgainLabel() ) { + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) + st->labelNeeded = true; + } + else { + /* Do not use all labels by default, init all labelNeeded vars to false. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) + st->labelNeeded = false; + + /* Walk all transitions and set only those that have targs. */ + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) { + /* If there is no action with a next statement, then the label will be + * needed. */ + if ( trans->action == 0 || !trans->action->anyNextStmt() ) + trans->targ->labelNeeded = true; + + /* Need labels for states that have goto or calls in action code + * invoked on characters (ie, not from out action code). */ + if ( trans->action != 0 ) { + /* Loop the actions. */ + for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) { + /* Get the action and walk it's tree. */ + setLabelsNeeded( act->value->inlineList ); + } + } + } + } + + if ( !noEnd ) { + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st != redFsm->errState ) + st->outNeeded = st->labelNeeded; + } + } +} + +void GoIpGotoCodeGen::writeData() +{ + STATE_IDS(); +} + +void GoIpGotoCodeGen::writeExec() +{ + /* Must set labels immediately before writing because we may depend on the + * noend write option. */ + setLabelsNeeded(); + testEofUsed = false; + outLabelUsed = false; + + out << " {" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << " = 0" << endl; + + if ( redFsm->anyConditions() ) + out << " var _widec " << WIDE_ALPH_TYPE() << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( useAgainLabel() ) { + out << + " goto _resume" << endl << + endl << + "_again:" << endl << + " switch " << vCS() << " {" << endl; + AGAIN_CASES(1) << + " }" << endl << + endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << "++; " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl; + } + out << "_resume:" << endl; + } + + out << + " switch " << vCS() << " {" << endl; + STATE_GOTOS_SWITCH(1); + out << + " }" << endl; + out << " goto st_out" << endl; + STATE_GOTOS(1); + out << " st_out:" << endl; + EXIT_STATES() << + endl; + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl << + " switch " << vCS() << " {" << endl; + FINISH_CASES(2); + out << + " }" << endl << + " }" << endl << + endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << + " }" << endl; +} diff --git a/ragel/goipgoto.h b/ragel/goipgoto.h index 8424d064..cceaee0c 100644 --- a/ragel/goipgoto.h +++ b/ragel/goipgoto.h @@ -1,6 +1,5 @@ /* - * Copyright 2010 Justine Tunney <jtunney@gmail.com> - * 2001-2006 Adrian Thurston <thurston@complang.org> + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> * 2004 Erich Ocean <eric.ocean@ampede.com> * 2005 Alan West <alan@alanz.com> */ @@ -11,60 +10,66 @@ * 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 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _GOIPGOTO_H #define _GOIPGOTO_H -#include "cdipgoto.h" +#include <iostream> +#include "gogoto.h" -/* - * class GoIpGotoCodeGen - * - * Keep overriding methods until it works. - */ -struct GoIpGotoCodeGen - : public IpGotoCodeGen, public CCodeGen +/* Forwards. */ +struct CodeGenData; + +class GoIpGotoCodeGen + : public GoGotoCodeGen { public: - GoIpGotoCodeGen( ostream &out ) : - FsmCodeGen(out), IpGotoCodeGen(out), CCodeGen(out) {} + GoIpGotoCodeGen( ostream &out ) + : GoGotoCodeGen(out) {} - void writeExec(); - void writeData(); - void writeInit(); - void STATE_IDS(); + std::ostream &EXIT_STATES(); + std::ostream &TRANS_GOTO( RedTransAp *trans, int level ); + int TRANS_NR( RedTransAp *trans ); + std::ostream &FINISH_CASES( int level ); + std::ostream &AGAIN_CASES( int level ); + std::ostream &STATE_GOTOS_SWITCH( int level ); + + 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, GenInlineItem *ilItem, bool inFinish ); + void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ); void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ); void RET( ostream &ret, bool inFinish ); - void GOTO_HEADER( RedStateAp *state ); - void LM_SWITCH( ostream &ret, GenInlineItem *item, - int targState, int inFinish, bool csForced ); - string GET_KEY(); - void emitSingleSwitch( RedStateAp *state ); - void emitRangeBSearch( RedStateAp *state, int level, int low, int high ); - void COND_TRANSLATE( GenStateCond *stateCond, int level ); - ostream &STATE_GOTOS(); - ostream &STATIC_VAR( string type, string name ); - ostream &TRANS_GOTO( RedTransAp *trans, int level ); - void genLineDirective( ostream &out ); - bool IN_TRANS_ACTIONS( RedStateAp *state ); - void ACTION( ostream &ret, GenAction *action, int targState, - bool inFinish, bool csForced ); - void CONDITION( ostream &ret, GenAction *condition ); - ostream &FINISH_CASES(); + void CURS( ostream &ret, bool inFinish ); + void TARGS( ostream &ret, bool inFinish, int targState ); + void BREAK( ostream &ret, int targState, bool csForced ); + + virtual void writeData(); + virtual void writeExec(); protected: - bool isFirstCase; + bool useAgainLabel(); + + /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for + * each state. */ + bool IN_TRANS_ACTIONS( RedStateAp *state ); + void GOTO_HEADER( RedStateAp *state, int level ); + void STATE_GOTO_ERROR( int level ); + + /* Set up labelNeeded flag for each state. */ + void setLabelsNeeded( GenInlineList *inlineList ); + void setLabelsNeeded(); }; #endif diff --git a/ragel/gotable.cpp b/ragel/gotable.cpp new file mode 100644 index 00000000..bb2015d4 --- /dev/null +++ b/ragel/gotable.cpp @@ -0,0 +1,977 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sstream> +#include "ragel.h" +#include "gotable.h" +#include "redfsm.h" +#include "gendata.h" + +using std::endl; + +/* Determine if we should use indicies or not. */ +void GoTabCodeGen::calcIndexSize() +{ + int sizeWithInds = 0, sizeWithoutInds = 0; + + /* Calculate cost of using with indicies. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + int totalIndex = st->outSingle.length() + st->outRange.length() + + (st->defTrans == 0 ? 0 : 1); + sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex; + } + sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length(); + if ( redFsm->anyActions() ) + sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length(); + + /* Calculate the cost of not using indicies. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + int totalIndex = st->outSingle.length() + st->outRange.length() + + (st->defTrans == 0 ? 0 : 1); + sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex; + if ( redFsm->anyActions() ) + sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex; + } + + /* If using indicies reduces the size, use them. */ + useIndicies = sizeWithInds < sizeWithoutInds; +} + +std::ostream &GoTabCodeGen::TO_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->toStateAction != 0 ) + act = state->toStateAction->location+1; + out << act; + return out; +} + +std::ostream &GoTabCodeGen::FROM_STATE_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->fromStateAction != 0 ) + act = state->fromStateAction->location+1; + out << act; + return out; +} + +std::ostream &GoTabCodeGen::EOF_ACTION( RedStateAp *state ) +{ + int act = 0; + if ( state->eofAction != 0 ) + act = state->eofAction->location+1; + out << act; + return out; +} + + +std::ostream &GoTabCodeGen::TRANS_ACTION( RedTransAp *trans ) +{ + /* If there are actions, emit them. Otherwise emit zero. */ + int act = 0; + if ( trans->action != 0 ) + act = trans->action->location+1; + out << act; + return out; +} + +std::ostream &GoTabCodeGen::TO_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoTabCodeGen::FROM_STATE_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective( out ); + return out; +} + +std::ostream &GoTabCodeGen::EOF_ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, true, false ); + } + } + + genLineDirective(out); + return out; +} + + +std::ostream &GoTabCodeGen::ACTION_SWITCH( int level ) +{ + /* Walk the list of functions, printing the cases. */ + for ( GenActionList::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 << TABS(level) << "case " << act->actionId << ":" << endl; + ACTION( out, act, 0, false, false ); + } + } + + genLineDirective(out); + return out; +} + +std::ostream &GoTabCodeGen::COND_OFFSETS() +{ + out << " "; + int totalStateNum = 0, curKeyOffset = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write the key offset. */ + out << curKeyOffset; + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + + /* Move the key offset ahead. */ + curKeyOffset += st->stateCondList.length(); + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::KEY_OFFSETS() +{ + out << " "; + int totalStateNum = 0, curKeyOffset = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write the key offset. */ + out << curKeyOffset; + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + + /* Move the key offset ahead. */ + curKeyOffset += st->outSingle.length() + st->outRange.length()*2; + } + out << endl; + return out; +} + + +std::ostream &GoTabCodeGen::INDEX_OFFSETS() +{ + out << " "; + int totalStateNum = 0, curIndOffset = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write the index offset. */ + out << curIndOffset; + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + + /* Move the index offset ahead. */ + curIndOffset += st->outSingle.length() + st->outRange.length(); + if ( st->defTrans != 0 ) + curIndOffset += 1; + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::COND_LENS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write singles length. */ + out << st->stateCondList.length(); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + + +std::ostream &GoTabCodeGen::SINGLE_LENS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write singles length. */ + out << st->outSingle.length(); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::RANGE_LENS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Emit length of range index. */ + out << st->outRange.length(); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::TO_STATE_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + TO_STATE_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::FROM_STATE_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + FROM_STATE_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::EOF_ACTIONS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + EOF_ACTION(st); + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::EOF_TRANS() +{ + out << " "; + int totalStateNum = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Write any eof action. */ + long trans = 0; + if ( st->eofTrans != 0 ) { + assert( st->eofTrans->pos >= 0 ); + trans = st->eofTrans->pos+1; + } + out << trans; + + out << ", "; + if ( !st.last() ) { + if ( ++totalStateNum % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + return out; +} + + +std::ostream &GoTabCodeGen::COND_KEYS() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Loop the state's transitions. */ + for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) { + /* Lower key. */ + out << KEY( sc->lowKey ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + + /* Upper key. */ + out << KEY( sc->highKey ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::COND_SPACES() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Loop the state's transitions. */ + for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) { + /* Cond Space id. */ + out << sc->condSpace->condSpaceId << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::KEYS() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Loop the singles. */ + for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { + out << KEY( stel->lowKey ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* Loop the state's transitions. */ + for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { + /* Lower key. */ + out << KEY( rtel->lowKey ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + + /* Upper key. */ + out << KEY( rtel->highKey ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::INDICIES() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Walk the singles. */ + for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { + out << stel->value->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* Walk the ranges. */ + for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { + out << rtel->value->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* The state's default index goes next. */ + if ( st->defTrans != 0 ) { + out << st->defTrans->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::TRANS_TARGS() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Walk the singles. */ + for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { + RedTransAp *trans = stel->value; + out << trans->targ->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* Walk the ranges. */ + for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { + RedTransAp *trans = rtel->value; + out << trans->targ->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* The state's default target state. */ + if ( st->defTrans != 0 ) { + RedTransAp *trans = st->defTrans; + out << trans->targ->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + /* Add any eof transitions that have not yet been written out above. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->eofTrans != 0 ) { + RedTransAp *trans = st->eofTrans; + trans->pos = totalTrans; + out << trans->targ->id << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + + out << endl; + return out; +} + + +std::ostream &GoTabCodeGen::TRANS_ACTIONS() +{ + out << " "; + int totalTrans = 0; + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + /* Walk the singles. */ + for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) { + RedTransAp *trans = stel->value; + TRANS_ACTION( trans ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* Walk the ranges. */ + for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { + RedTransAp *trans = rtel->value; + TRANS_ACTION( trans ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + + /* The state's default index goes next. */ + if ( st->defTrans != 0 ) { + RedTransAp *trans = st->defTrans; + TRANS_ACTION( trans ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + /* Add any eof transitions that have not yet been written out above. */ + for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) { + if ( st->eofTrans != 0 ) { + RedTransAp *trans = st->eofTrans; + TRANS_ACTION( trans ) << ", "; + if ( ++totalTrans % IALL == 0 ) + out << endl << " "; + } + } + + out << endl; + return out; +} + +std::ostream &GoTabCodeGen::TRANS_TARGS_WI() +{ + /* Transitions must be written ordered by their id. */ + RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()]; + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) + transPtrs[trans->id] = trans; + + /* Keep a count of the num of items in the array written. */ + out << " "; + int totalStates = 0; + for ( int t = 0; t < redFsm->transSet.length(); t++ ) { + /* Record the position, need this for eofTrans. */ + RedTransAp *trans = transPtrs[t]; + trans->pos = t; + + /* Write out the target state. */ + out << trans->targ->id << ", "; + if ( t < redFsm->transSet.length()-1 ) { + if ( ++totalStates % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] transPtrs; + return out; +} + + +std::ostream &GoTabCodeGen::TRANS_ACTIONS_WI() +{ + /* Transitions must be written ordered by their id. */ + RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()]; + for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) + transPtrs[trans->id] = trans; + + /* Keep a count of the num of items in the array written. */ + out << " "; + int totalAct = 0; + for ( int t = 0; t < redFsm->transSet.length(); t++ ) { + /* Write the function for the transition. */ + RedTransAp *trans = transPtrs[t]; + TRANS_ACTION( trans ); + out << ", "; + if ( t < redFsm->transSet.length()-1 ) { + if ( ++totalAct % IALL == 0 ) + out << endl << " "; + } + } + out << endl; + delete[] transPtrs; + return out; +} + +void GoTabCodeGen::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() << endl; + } + + if ( redFsm->anyConditions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() ); + COND_OFFSETS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() ); + COND_LENS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() ); + COND_KEYS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() ); + COND_SPACES(); + CLOSE_ARRAY() << endl; + } + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() ); + KEY_OFFSETS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( WIDE_ALPH_TYPE(), K() ); + KEYS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() ); + SINGLE_LENS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() ); + RANGE_LENS(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() ); + INDEX_OFFSETS(); + CLOSE_ARRAY() << endl; + + if ( useIndicies ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() ); + INDICIES(); + CLOSE_ARRAY() << endl; + + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS_WI(); + CLOSE_ARRAY() << endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() ); + TRANS_ACTIONS_WI(); + CLOSE_ARRAY() << endl; + } + } + else { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() ); + TRANS_TARGS(); + CLOSE_ARRAY() << endl; + + if ( redFsm->anyActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() ); + TRANS_ACTIONS(); + CLOSE_ARRAY() << endl; + } + } + + if ( redFsm->anyToStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() ); + TO_STATE_ACTIONS(); + CLOSE_ARRAY() << endl; + } + + if ( redFsm->anyFromStateActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() ); + FROM_STATE_ACTIONS(); + CLOSE_ARRAY() << endl; + } + + if ( redFsm->anyEofActions() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() ); + EOF_ACTIONS(); + CLOSE_ARRAY() << endl; + } + + if ( redFsm->anyEofTrans() ) { + OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() ); + EOF_TRANS(); + CLOSE_ARRAY() << endl; + } + + STATE_IDS(); +} + +void GoTabCodeGen::LOCATE_TRANS() +{ + out << + " _keys = " << CAST(INT(), KO() + "[" + vCS() + "]") << endl << + " _trans = " << CAST(INT(), IO() + "[" + vCS() + "]") << endl << + endl << + " _klen = " << CAST(INT(), SL() + "[" + vCS() + "]") << endl << + " if _klen > 0 {" << endl << + " _lower := " << CAST(INT(), "_keys") << endl << + " var _mid " << INT() << endl << + " _upper := " << CAST(INT(), "_keys + _klen - 1") << endl << + " for {" << endl << + " if _upper < _lower {" << endl << + " break" << endl << + " }" << endl << + endl << + " _mid = _lower + ((_upper - _lower) >> 1)" << endl << + " switch {" << endl << + " case " << GET_WIDE_KEY() << " < " << K() << "[_mid]" << ":" << endl << + " _upper = _mid - 1" << endl << + " case " << GET_WIDE_KEY() << " > " << K() << "[_mid]" << ":" << endl << + " _lower = _mid + 1" << endl << + " default:" << endl << + " _trans += " << CAST(INT(), "_mid - " + CAST(INT(), "_keys")) << endl << + " goto _match" << endl << + " }" << endl << + " }" << endl << + " _keys += _klen" << endl << + " _trans += _klen" << endl << + " }" << endl << + endl << + " _klen = " << CAST(INT(), RL() + "[" + vCS() + "]") << endl << + " if _klen > 0 {" << endl << + " _lower := " << CAST(INT(), "_keys") << endl << + " var _mid " << INT() << endl << + " _upper := " << CAST(INT(), "_keys + (_klen << 1) - 2") << endl << + " for {" << endl << + " if _upper < _lower {" << endl << + " break" << endl << + " }" << endl << + endl << + " _mid = _lower + (((_upper - _lower) >> 1) & ^1)" << endl << + " switch {" << endl << + " case " << GET_WIDE_KEY() << " < " << K() << "[_mid]" << ":" << endl << + " _upper = _mid - 2" << endl << + " case " << GET_WIDE_KEY() << " > " << K() << "[_mid + 1]" << ":" << endl << + " _lower = _mid + 2" << endl << + " default:" << endl << + " _trans += " << CAST(INT(), "(_mid - " + CAST(INT(), "_keys") + ") >> 1") << endl << + " goto _match" << endl << + " }" << endl << + " }" << endl << + " _trans += _klen" << endl << + " }" << endl << + endl; +} + +void GoTabCodeGen::COND_TRANSLATE() +{ + out << + " _widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl << + " _klen = " << CAST(INT(), CL() + "[" + vCS() + "]") << endl << + " _keys = " << CAST(INT(), CO() + "[" + vCS() + "] * 2") << endl << + " if _klen > 0 {" << endl << + " _lower := " << CAST(INT(), "_keys") << endl << + " var _mid " << INT() << endl << + " _upper := " << CAST(INT(), "_keys + (_klen << 1) - 2") << endl << + " COND_LOOP:" << endl << + " for {" << endl << + " if _upper < _lower {" << endl << + " break" << endl << + " }" << endl << + endl << + " _mid = _lower + (((_upper - _lower) >> 1) & ^1)" << endl << + " switch {" << endl << + " case " << GET_WIDE_KEY() << " < " << CAST(WIDE_ALPH_TYPE(), CK() + "[_mid]") << ":" << endl << + " _upper = _mid - 2" << endl << + " case " << GET_WIDE_KEY() << " > " << CAST(WIDE_ALPH_TYPE(), CK() + "[_mid + 1]") << ":" << endl << + " _lower = _mid + 2" << endl << + " default:" << endl << + " switch " << C() << "[" << CAST(INT(), CO() + "[" + vCS() + "]") << + " + ((_mid - _keys)>>1)] {" << endl; + + for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) { + GenCondSpace *condSpace = csi; + out << TABS(4) << "case " << condSpace->condSpaceId << ":" << endl; + out << TABS(5) << "_widec = " << KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << + " - " << KEY(keyOps->minKey) << ")" << endl; + + for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { + out << TABS(5) << "if "; + CONDITION( out, *csi ); + Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize()); + out << " {" << endl << TABS(6) << "_widec += " << condValOffset << endl << TABS(5) << "}" << endl; + } + } + + out << + " }" << endl << + " break COND_LOOP" << endl << + " }" << endl << + " }" << endl << + " }" << endl << + endl; +} + +void GoTabCodeGen::writeExec() +{ + testEofUsed = false; + outLabelUsed = false; + + out << + " {" << endl << + " var _klen " << INT() << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " var _ps " << INT() << endl; + + out << + " var _trans " << INT() << endl; + + if ( redFsm->anyConditions() ) + out << " var _widec " << WIDE_ALPH_TYPE() << endl; + + if ( redFsm->anyToStateActions() || redFsm->anyRegActions() + || redFsm->anyFromStateActions() ) + { + out << + " var _acts " << INT() << endl << + " var _nacts " << UINT() << endl; + } + + out << + " var _keys " << INT() << endl; + + if ( !noEnd ) { + testEofUsed = true; + out << + " if " << P() << " == " << PE() << " {" << endl << + " goto _test_eof" << endl << + " }" << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + out << "_resume:" << endl; + + if ( redFsm->anyFromStateActions() ) { + out << + " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts - 1]" << " {" << endl; + FROM_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << endl; + } + + if ( redFsm->anyConditions() ) + COND_TRANSLATE(); + + LOCATE_TRANS(); + + out << "_match:" << endl; + + if ( useIndicies ) + out << " _trans = " << CAST(INT(), I() + "[_trans]") << endl; + + if ( redFsm->anyEofTrans() ) + out << "_eof_trans:" << endl; + + if ( redFsm->anyRegCurStateRef() ) + out << " _ps = " << vCS() << endl; + + out << + " " << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl << endl; + + if ( redFsm->anyRegActions() ) { + out << + " if " << TA() << "[_trans] == 0 {" << endl << + " goto _again" << endl << + " }" << endl << + endl << + " _acts = " << CAST(INT(), TA() + "[_trans]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts-1]" << " {" << endl; + ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << endl; + } + + if ( redFsm->anyRegActions() || redFsm->anyActionGotos() || + redFsm->anyActionCalls() || redFsm->anyActionRets() ) + out << "_again:" << endl; + + if ( redFsm->anyToStateActions() ) { + out << + " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl << + " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl << + " for ; _nacts > 0; _nacts-- {" << endl << + " _acts++" << endl << + " switch " << A() << "[_acts-1] {" << endl; + TO_STATE_ACTION_SWITCH(2); + out << + " }" << endl << + " }" << endl << endl; + } + + if ( redFsm->errState != 0 ) { + outLabelUsed = true; + out << + " if " << vCS() << " == " << redFsm->errState->id << " {" << endl << + " goto _out" << endl << + " }" << endl; + } + + if ( !noEnd ) { + out << + " " << P() << "++" << endl << + " if " << P() << " != " << PE() << " {" << endl << + " goto _resume" << endl << + " }" << endl; + } + else { + out << + " " << P() << "++" << endl << + " goto _resume" << endl; + } + + if ( testEofUsed ) + out << " _test_eof: {}" << endl; + + if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) { + out << + " if " << P() << " == " << vEOF() << " {" << endl; + + if ( redFsm->anyEofTrans() ) { + out << + " if " << ET() << "[" << vCS() << "] > 0 {" << endl << + " _trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl << + " goto _eof_trans" << endl << + " }" << endl; + } + + if ( redFsm->anyEofActions() ) { + out << + " __acts := " << EA() << "[" << vCS() << "]" << endl << + " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl << + " for ; __nacts > 0; __nacts-- {" << endl << + " __acts++" << endl << + " switch " << A() << "[__acts-1] {" << endl; + EOF_ACTION_SWITCH(3); + out << + " }" << endl << + " }" << endl; + } + + out << + " }" << endl << endl; + } + + if ( outLabelUsed ) + out << " _out: {}" << endl; + + out << " }" << endl; +} diff --git a/ragel/gotable.h b/ragel/gotable.h new file mode 100644 index 00000000..a62b8a09 --- /dev/null +++ b/ragel/gotable.h @@ -0,0 +1,76 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOTABLE_H +#define _GOTABLE_H + +#include <iostream> +#include "gotablish.h" + +class GoTabCodeGen + : public GoTablishCodeGen +{ +public: + GoTabCodeGen( ostream &out ) + : GoTablishCodeGen(out) {} + + virtual ~GoTabCodeGen() { } + virtual void writeData(); + virtual void writeExec(); + +protected: + std::ostream &TO_STATE_ACTION_SWITCH( int level ); + std::ostream &FROM_STATE_ACTION_SWITCH( int level ); + std::ostream &EOF_ACTION_SWITCH( int level ); + std::ostream &ACTION_SWITCH( int level ); + + 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 &EOF_TRANS(); + std::ostream &TRANS_TARGS(); + std::ostream &TRANS_ACTIONS(); + std::ostream &TRANS_TARGS_WI(); + std::ostream &TRANS_ACTIONS_WI(); + void LOCATE_TRANS(); + + void COND_TRANSLATE(); + + virtual std::ostream &TO_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &FROM_STATE_ACTION( RedStateAp *state ); + virtual std::ostream &EOF_ACTION( RedStateAp *state ); + virtual std::ostream &TRANS_ACTION( RedTransAp *trans ); + virtual void calcIndexSize(); +}; + +#endif diff --git a/ragel/gotablish.cpp b/ragel/gotablish.cpp new file mode 100644 index 00000000..218ab479 --- /dev/null +++ b/ragel/gotablish.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ragel.h" +#include "gotablish.h" + +using std::endl; + +void GoTablishCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish ) +{ + ret << vCS() << " = " << gotoDest << endl << + "goto _again" << endl; +} + +void GoTablishCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) +{ + ret << vCS() << " = ("; + INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); + ret << ")" << endl << "goto _again" << endl; +} + +void GoTablishCodeGen::CURS( ostream &ret, bool inFinish ) +{ + ret << "(_ps)"; +} + +void GoTablishCodeGen::TARGS( ostream &ret, bool inFinish, int targState ) +{ + ret << "(" << vCS() << ")"; +} + +void GoTablishCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish ) +{ + ret << vCS() << " = " << nextDest << endl; +} + +void GoTablishCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ) +{ + ret << vCS() << " = ("; + INLINE_LIST( ret, ilItem->children, 0, inFinish, false ); + ret << ")" << endl; +} + +void GoTablishCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish ) +{ + if ( prePushExpr != 0 ) { + ret << "{ "; + INLINE_LIST( ret, prePushExpr, 0, false, false ); + } + + ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << "++; " << + vCS() << " = " << callDest << "; " << "goto _again" << endl; + + if ( prePushExpr != 0 ) + ret << " }"; +} + +void GoTablishCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ) +{ + if ( prePushExpr != 0 ) { + ret << "{"; + INLINE_LIST( ret, prePushExpr, 0, false, false ); + } + + ret << STACK() << "[" << TOP() << "] = " << vCS() << "; " << TOP() << "++; " << vCS() << " = ("; + INLINE_LIST( ret, ilItem->children, targState, inFinish, false ); + ret << "); " << "goto _again" << endl; + + if ( prePushExpr != 0 ) + ret << "}"; +} + +void GoTablishCodeGen::RET( ostream &ret, bool inFinish ) +{ + ret << TOP() << "--; " << vCS() << " = " << STACK() << "[" << + TOP() << "]" << endl; + + if ( postPopExpr != 0 ) { + ret << "{ "; + INLINE_LIST( ret, postPopExpr, 0, false, false ); + ret << " }" << endl; + } + + ret << "goto _again" << endl; +} + +void GoTablishCodeGen::BREAK( ostream &ret, int targState, bool csForced ) +{ + outLabelUsed = true; + ret << P() << "++; " << "goto _out" << endl; +} diff --git a/ragel/gotablish.h b/ragel/gotablish.h new file mode 100644 index 00000000..9e79b117 --- /dev/null +++ b/ragel/gotablish.h @@ -0,0 +1,48 @@ +/* + * Copyright 2001-2006 Adrian Thurston <thurston@complang.org> + * 2004 Erich Ocean <eric.ocean@ampede.com> + * 2005 Alan West <alan@alanz.com> + */ + +/* This file is part of Ragel. + * + * Ragel is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Ragel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Ragel; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GOTABLISH_H +#define _GOTABLISH_H + +#include "gocodegen.h" + +class GoTablishCodeGen + : public GoCodeGen +{ +public: + GoTablishCodeGen( ostream &out ) + : GoCodeGen(out) {} +protected: + virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ); + virtual void CALL( ostream &ret, int callDest, int targState, bool inFinish ); + virtual void NEXT( ostream &ret, int nextDest, bool inFinish ); + virtual void GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ); + virtual void NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish ); + virtual void CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish ); + virtual void CURS( ostream &ret, bool inFinish ); + virtual void TARGS( ostream &ret, bool inFinish, int targState ); + virtual void RET( ostream &ret, bool inFinish ); + virtual void BREAK( ostream &ret, int targState, bool csForced ); +}; + +#endif |