diff options
author | Adrian Thurston <thurston@colm.net> | 2020-10-18 11:44:43 -0700 |
---|---|---|
committer | Adrian Thurston <thurston@colm.net> | 2020-10-18 11:44:43 -0700 |
commit | 85b76476de71f43d3eb25d6bef4ee6d84cb71f6c (patch) | |
tree | 65c127fbcf70e62d8a4848be2c9c4ff7d74d86a1 /src/libfsm/codegen.cc | |
parent | 86bb5882a70224a29650ccfa1e46c9b023c2a3ef (diff) | |
download | colm-85b76476de71f43d3eb25d6bef4ee6d84cb71f6c.tar.gz |
lift all source code into src/ dirinto-src
Diffstat (limited to 'src/libfsm/codegen.cc')
-rw-r--r-- | src/libfsm/codegen.cc | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/src/libfsm/codegen.cc b/src/libfsm/codegen.cc new file mode 100644 index 00000000..db8cc60a --- /dev/null +++ b/src/libfsm/codegen.cc @@ -0,0 +1,1202 @@ +/* + * Copyright 2001-2018 Adrian Thurston <thurston@colm.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "codegen.h" +#include "ragel.h" +#include "redfsm.h" +#include "gendata.h" +#include "parsedata.h" +#include <sstream> +#include <string> +#include <assert.h> +#include <iomanip> + + +using std::ostream; +using std::ostringstream; +using std::string; +using std::endl; +using std::istream; +using std::ifstream; +using std::ostream; +using std::ios; +using std::cin; +using std::endl; + +std::ostream &operator<<( std::ostream &out, Variable &v ) +{ + out << v.name; + v.isReferenced = true; + return out; +} + +std::ostream &operator<<( std::ostream &out, GotoLabel &l ) +{ + out << l.name; + l.isReferenced = true; + return out; +} + +TableArray::TableArray( const char *name, CodeGen &codeGen ) +: + state(InitialState), + name(name), + width(0), + isSigned(true), + isChar(false), + stringTables( codeGen.stringTables ), + iall( codeGen.stringTables ? IALL_STRING : IALL_INTEGRAL ), + values(0), + + /* + * Use zero for min and max because + * we we null terminate every array. + */ + min(0), + max(0), + + codeGen(codeGen), + out(codeGen.out), + ln(0), + isReferenced(false), + started(false) +{ + codeGen.arrayVector.append( this ); +} + +std::string TableArray::ref() +{ + isReferenced = true; + return string("_") + codeGen.DATA_PREFIX() + name; +} + +long long TableArray::size() +{ + return width * values; +} + +void TableArray::startAnalyze() +{ +} + +void TableArray::valueAnalyze( long long v ) +{ + values += 1; + if ( v < min ) + min = v; + if ( v > max ) + max = v; +} + +void TableArray::finishAnalyze() +{ + if ( codeGen.backend == Direct ) { + /* Calculate the type if it is not already set. */ + if ( type.empty() ) { + if ( min >= S8BIT_MIN && max <= S8BIT_MAX ) { + type = "signed char"; + width = sizeof(char); + } + else if ( min >= S16BIT_MIN && max <= S16BIT_MAX ) { + type = "short"; + width = sizeof(short); + } + else if ( min >= S32BIT_MIN && max <= S32BIT_MAX ) { + type = "int"; + width = sizeof(int); + } + else if ( min >= S64BIT_MAX && max <= S64BIT_MAX ) { + type = "long"; + width = sizeof(long); + } + else { + type = "long long"; + width = sizeof(long long); + } + } + } + else { + /* Calculate the type if it is not already set. */ + if ( type.empty() ) { + if ( min >= S8BIT_MIN && max <= S8BIT_MAX ) { + type = "s8"; + width = sizeof(char); + } + else if ( min >= S16BIT_MIN && max <= S16BIT_MAX ) { + type = "s16"; + width = sizeof(short); + } + else if ( min >= S32BIT_MIN && max <= S32BIT_MAX ) { + type = "s32"; + width = sizeof(int); + } + else if ( min >= S64BIT_MAX && max <= S64BIT_MAX ) { + type = "s64"; + width = sizeof(long); + } + else { + type = "s128"; + width = sizeof(long long); + } + } + } +} + +void TableArray::startGenerate() +{ + if ( codeGen.backend == Direct ) { + if ( stringTables ) { + out << "static const char S_" << codeGen.DATA_PREFIX() << name << + "[] __attribute__((aligned (16))) = \n\t\""; + } + else { + out << "static const " << type << " " << + "_" << codeGen.DATA_PREFIX() << name << + "[] = {\n\t"; + } + } + else { + out << "array " << type << " " << + "_" << codeGen.DATA_PREFIX() << name << + "( " << min << ", " << max << " ) = { "; + } +} + +void TableArray::stringGenerate( long long value ) +{ + char c; + short h; + int i; +#if SIZEOF_INT != SIZEOF_LONG + long l; +#endif + unsigned char *p = 0; + int n = 0; + switch ( width ) { + case sizeof( char ): + c = value; + p = (unsigned char *)&c; + n = sizeof(char); + break; + case sizeof( short ): + h = value; + p = (unsigned char *)&h; + n = sizeof(short); + break; + case sizeof( int ): + i = value; + p = (unsigned char *)&i; + n = sizeof(int); + break; +#if SIZEOF_INT != SIZEOF_LONG + case sizeof( long ): + l = value; + p = (unsigned char *)&l; + n = sizeof(long); + break; +#endif + } + + std::ios_base::fmtflags prevFlags = out.flags( std::ios::hex ); + int prevFill = out.fill( '0' ); + + while ( n-- > 0 ) { + out << '\\'; + out << 'x'; + out << std::setw(2) << (unsigned int) *p++; + } + + out.flags( prevFlags ); + out.fill( prevFill ); +} + +void TableArray::valueGenerate( long long v ) +{ + if ( codeGen.backend == Direct ) { + if ( stringTables ) { + stringGenerate( v ); + + if ( ++ln % iall == 0 ) { + out << "\"\n\t\""; + ln = 0; + } + } + else { + if ( isChar ) + out << "c(" << v << ")"; + else if ( !isSigned ) + out << v << "u"; + else + out << v; + + if ( ( ++ln % iall ) == 0 ) { + out << ",\n\t"; + ln = 0; + } + else { + out << ", "; + } + } + } + else { + if ( isChar ) + out << "c(" << v << ")"; + else if ( !isSigned ) + out << "u(" << v << ")"; + else + out << v; + out << ", "; + } +} + +void TableArray::finishGenerate() +{ + if ( codeGen.backend == Direct ) { + if ( stringTables ) { + out << "\";\nconst " << type << " *_" << codeGen.DATA_PREFIX() << name << + " = (const " << type << "*) S_" << codeGen.DATA_PREFIX() << name << ";\n\n"; + + } + else { + if ( isChar ) + out << "c(0)\n};\n\n"; + else if ( !isSigned ) + out << "0u\n};\n\n"; + else + out << "0\n};\n\n"; + } + } + else { + if ( isChar ) + out << "c(0) };\n\n"; + else if ( !isSigned ) + out << "u(0) };\n\n"; + else + out << "0 };\n\n"; + } + + if ( codeGen.red->id->printStatistics ) { + codeGen.red->id->stats() << name << "\t" << values << "\t" << + size() << "\t" << endl; + } + + codeGen.tableData += size(); +} + +void TableArray::start() +{ + assert( !started ); + started = true; + switch ( state ) { + case InitialState: + break; + case AnalyzePass: + startAnalyze(); + break; + case GeneratePass: + if ( isReferenced ) + startGenerate(); + break; + } +} + +void TableArray::value( long long v ) +{ + assert( started ); + switch ( state ) { + case InitialState: + break; + case AnalyzePass: + valueAnalyze( v ); + break; + case GeneratePass: + if ( isReferenced ) + valueGenerate( v ); + break; + } +} + +void TableArray::finish() +{ + assert( started ); + started = false; + switch ( state ) { + case InitialState: + break; + case AnalyzePass: + finishAnalyze(); + break; + case GeneratePass: + if ( isReferenced ) + finishGenerate(); + break; + } +} + +/* Init code gen with in parameters. */ +CodeGen::CodeGen( const CodeGenArgs &args ) +: + CodeGenData( args ), + cpc( "_cpc" ), + pop_test( "_pop_test" ), + new_recs( "new_recs" ), + alt( "_alt" ), + tableData( 0 ), + backend( args.id->hostLang->backend ), + stringTables( args.id->stringTables ), + + nfaTargs( "nfa_targs", *this ), + nfaOffsets( "nfa_offsets", *this ), + nfaPushActions( "nfa_push_actions", *this ), + nfaPopTrans( "nfa_pop_trans", *this ) +{ +} + +void CodeGen::statsSummary() +{ + if ( red->id->printStatistics ) + red->id->stats() << "table-data\t\t" << tableData << endl << endl; +} + + +string CodeGen::CAST( string type ) +{ + if ( backend == Direct ) + return "(" + type + ")"; + else + return "cast(" + type + ")"; +} + +/* Write out the fsm name. */ +string CodeGen::FSM_NAME() +{ + return fsmName; +} + +/* Emit the offset of the start state as a decimal integer. */ +string CodeGen::START_STATE_ID() +{ + ostringstream ret; + ret << redFsm->startState->id; + return ret.str(); +}; + + +string CodeGen::ACCESS() +{ + ostringstream ret; + if ( red->accessExpr != 0 ) { + ret << OPEN_HOST_PLAIN(); + INLINE_LIST( ret, red->accessExpr, 0, false, false ); + ret << CLOSE_HOST_PLAIN(); + ret << ACCESS_OPER(); + } + return ret.str(); +} + + +string CodeGen::P() +{ + ostringstream ret; + if ( red->pExpr == 0 ) + ret << "p"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->pExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::PE() +{ + ostringstream ret; + if ( red->peExpr == 0 ) + ret << "pe"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->peExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::vEOF() +{ + ostringstream ret; + if ( red->eofExpr == 0 ) + ret << "eof"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->eofExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::vCS() +{ + ostringstream ret; + if ( red->csExpr == 0 ) + ret << ACCESS() << "cs"; + else { + /* Emit the user supplied method of retrieving the key. */ + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->csExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::TOP() +{ + ostringstream ret; + if ( red->topExpr == 0 ) + ret << ACCESS() + "top"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->topExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::STACK() +{ + ostringstream ret; + if ( red->stackExpr == 0 ) + ret << ACCESS() + "stack"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->stackExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::ACT() +{ + ostringstream ret; + if ( red->actExpr == 0 ) + ret << ACCESS() + "act"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->actExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::TOKSTART() +{ + ostringstream ret; + if ( red->tokstartExpr == 0 ) + ret << ACCESS() + "ts"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->tokstartExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::TOKEND() +{ + ostringstream ret; + if ( red->tokendExpr == 0 ) + ret << ACCESS() + "te"; + else { + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->tokendExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + return ret.str(); +} + +string CodeGen::GET_KEY() +{ + ostringstream ret; + if ( red->getKeyExpr != 0 ) { + /* Emit the user supplied method of retrieving the key. */ + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, red->getKeyExpr, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + } + else { + /* Expression for retrieving the key, use simple dereference. */ + ret << "( " << DEREF( "data", P() ) << ")"; + } + return ret.str(); +} + +/* Write out a key from the fsm code gen. Depends on wether or not the key is + * signed. */ +string CodeGen::KEY( Key key ) +{ + if ( backend == Direct ) { + ostringstream ret; + if ( alphType->isChar ) + ret << "c(" << (unsigned long) key.getVal() << ")"; + else if ( keyOps->isSigned || !keyOps->explicitUnsigned ) + ret << key.getVal(); + else + ret << (unsigned long) key.getVal() << "u"; + return ret.str(); + } + else { + ostringstream ret; + if ( alphType->isChar ) + ret << "c(" << (unsigned long) key.getVal() << ")"; + else if ( keyOps->isSigned || !keyOps->explicitUnsigned ) + ret << key.getVal(); + else + ret << "u(" << (unsigned long) key.getVal() << ")"; + return ret.str(); + } +} + +bool CodeGen::isAlphTypeSigned() +{ + return keyOps->isSigned; +} + +void CodeGen::DECLARE( std::string type, Variable &var, std::string init ) +{ + if ( var.isReferenced ) + out << type << " " << var.name << init << ";\n"; +} + +void CodeGen::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 << OPEN_GEN_BLOCK() << P() << " = (("; + INLINE_LIST( ret, item->children, targState, inFinish, false ); + ret << "))-1;" << CLOSE_GEN_BLOCK() << "\n"; +} + +void CodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, + int targState, int inFinish, bool csForced ) +{ + ret << + OPEN_GEN_BLOCK() << "switch( " << ACT() << " ) {\n"; + + 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"; + else + ret << " " << CASE( STR(lma->lmId) ) << " {\n"; + + /* Write the block and close it off. */ + INLINE_LIST( ret, lma->children, targState, inFinish, csForced ); + + ret << CEND() << "\n}\n"; + } + + ret << + " }" << CLOSE_GEN_BLOCK() << "\n" + "\t"; +} + +void CodeGen::LM_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. This should be in the D code generator. */ + ret << P() << " = (("; + INLINE_LIST( ret, item->children, targState, inFinish, false ); + ret << "))-1;\n"; +} + +void CodeGen::SET_ACT( ostream &ret, GenInlineItem *item ) +{ + ret << ACT() << " = " << item->lmId << ";"; +} + +void CodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item ) +{ + /* The tokend action sets tokend. */ + ret << TOKEND() << " = " << P(); + if ( item->offset != 0 ) + out << "+" << item->offset; + out << ";"; +} + +void CodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item ) +{ + ret << TOKEND(); +} + +void CodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item ) +{ + ret << TOKSTART() << " = " << NIL() << ";"; +} + +void CodeGen::INIT_ACT( ostream &ret, GenInlineItem *item ) +{ + ret << ACT() << " = 0;"; +} + +void CodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item ) +{ + ret << TOKSTART() << " = " << P() << ";"; +} + +void CodeGen::HOST_STMT( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << OPEN_HOST_BLOCK( item->loc.fileName, item->loc.line ); + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << CLOSE_HOST_BLOCK(); + } +} + +#if 0 +void CodeGen::LM_CASE( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + } +} +#endif + +void CodeGen::HOST_EXPR( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << CLOSE_HOST_EXPR(); + } +} + +void CodeGen::HOST_TEXT( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << OPEN_HOST_PLAIN(); + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << CLOSE_HOST_PLAIN(); + } +} + +void CodeGen::GEN_STMT( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << OPEN_GEN_BLOCK(); + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << CLOSE_GEN_BLOCK(); + } +} + +void CodeGen::GEN_EXPR( ostream &ret, GenInlineItem *item, + int targState, bool inFinish, bool csForced ) +{ + if ( item->children->length() > 0 ) { + /* Write the block and close it off. */ + ret << OPEN_GEN_EXPR(); + INLINE_LIST( ret, item->children, targState, inFinish, csForced ); + ret << CLOSE_GEN_EXPR(); + } +} + +void CodeGen::INLINE_EXPR( ostream &ret, GenInlineList *inlineList ) +{ + ret << OPEN_HOST_EXPR(); + INLINE_LIST( ret, inlineList, 0, false, false ); + ret << CLOSE_HOST_EXPR(); +} + +void CodeGen::INLINE_BLOCK( ostream &ret, GenInlineExpr *inlineExpr ) +{ + out << OPEN_HOST_BLOCK( inlineExpr ); + INLINE_LIST( out, inlineExpr->inlineList, 0, false, false ); + out << CLOSE_HOST_BLOCK(); +} + +void CodeGen::INLINE_PLAIN( ostream &ret, GenInlineExpr *inlineExpr ) +{ + +} + +/* 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 CodeGen::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: + if ( backend == Direct ) + ret << item->data; + else + translatedHostData( 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::Ncall: + NCALL( 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::Nret: + NRET( ret, inFinish ); + break; + case GenInlineItem::PChar: + ret << P(); + break; + case GenInlineItem::Char: + ret << OPEN_GEN_EXPR() << GET_KEY() << CLOSE_GEN_EXPR(); + break; + case GenInlineItem::Hold: + ret << OPEN_GEN_BLOCK() << P() << " = " << P() << " - 1; " << CLOSE_GEN_BLOCK(); + break; + case GenInlineItem::LmHold: + ret << P() << " = " << P() << " - 1;"; + break; + case GenInlineItem::NfaClear: + ret << "nfa_len = 0; "; + 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::NcallExpr: + NCALL_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::LmExec: + LM_EXEC( ret, item, targState, inFinish ); + break; + case GenInlineItem::LmCase: + /* Not encountered here, in the lm switch. */ + 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::Break: + BREAK( ret, targState, csForced ); + break; + case GenInlineItem::Nbreak: + NBREAK( ret, targState, csForced ); + break; + case GenInlineItem::HostStmt: + HOST_STMT( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::HostExpr: + HOST_EXPR( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::HostText: + HOST_TEXT( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::GenStmt: + GEN_STMT( ret, item, targState, inFinish, csForced ); + break; + case GenInlineItem::GenExpr: + GEN_EXPR( ret, item, targState, inFinish, csForced ); + break; + /* These should not be encountered. We handle these Nfa wraps at the top level. */ + case GenInlineItem::NfaWrapAction: + case GenInlineItem::NfaWrapConds: + break; + } + } +} + +/* Write out paths in line directives. Escapes any special characters. */ +string CodeGen::LDIR_PATH( char *path ) +{ + ostringstream ret; + for ( char *pc = path; *pc != 0; pc++ ) { + if ( *pc == '\\' ) + ret << "\\\\"; + else + ret << *pc; + } + return ret.str(); +} + +void CodeGen::ACTION( ostream &ret, GenAction *action, IlOpts opts ) +{ + ret << '\t'; + ret << OPEN_HOST_BLOCK( action->loc.fileName, action->loc.line ); + INLINE_LIST( ret, action->inlineList, opts.targState, opts.inFinish, opts.csForced ); + ret << CLOSE_HOST_BLOCK(); + ret << "\n"; + genOutputLineDirective( ret ); +} + +void CodeGen::CONDITION( ostream &ret, GenAction *condition ) +{ + ret << OPEN_HOST_EXPR( condition->loc.fileName, condition->loc.line ); + INLINE_LIST( ret, condition->inlineList, 0, false, false ); + ret << CLOSE_HOST_EXPR(); + ret << "\n"; + genOutputLineDirective( ret ); +} + +void CodeGen::NFA_CONDITION( ostream &ret, GenAction *condition, bool last ) +{ + if ( condition->inlineList->length() == 1 && + condition->inlineList->head->type == + GenInlineItem::NfaWrapAction ) + { + GenAction *action = condition->inlineList->head->wrappedAction; + ACTION( out, action, IlOpts( 0, false, false ) ); + } + else if ( condition->inlineList->length() == 1 && + condition->inlineList->head->type == + GenInlineItem::NfaWrapConds ) + { + ret << + " " << cpc << " = 0;\n"; + + GenCondSpace *condSpace = condition->inlineList->head->condSpace; + for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { + ret << + " if ( "; + CONDITION( out, *csi ); + Size condValOffset = (1 << csi.pos()); + ret << " ) " << cpc << " += " << condValOffset << ";\n"; + } + + const CondKeySet &keys = condition->inlineList->head->condKeySet; + if ( keys.length() > 0 ) { + ret << pop_test << " = "; + for ( CondKeySet::Iter cki = keys; cki.lte(); cki++ ) { + ret << "" << cpc << " == " << *cki; + if ( !cki.last() ) + ret << " || "; + } + ret << ";\n"; + } + else { + ret << pop_test << " = 0;\n"; + } + + if ( !last ) { + ret << + "if ( !" << pop_test << " )\n" + " break;\n"; + } + } + else { + ret << pop_test << " = "; + CONDITION( ret, condition ); + ret << ";\n"; + + if ( !last ) { + ret << + "if ( !" << pop_test << " )\n" + " break;\n"; + } + } +} + +void CodeGen::NFA_POP_TEST_EXEC() +{ + out << + " " << pop_test << " = 1;\n" + " switch ( nfa_bp[nfa_len].popTrans ) {\n"; + + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; + redAct.lte(); redAct++ ) + { + if ( redAct->numNfaPopTestRefs > 0 ) { + /* Write the entry label. */ + out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + NFA_CONDITION( out, item->value, item.last() ); + + out << CEND() << "\n}\n"; + } + } + + out << + " }\n" + "\n"; +} + + +string CodeGen::ERROR_STATE() +{ + ostringstream ret; + if ( redFsm->errState != 0 ) + ret << redFsm->errState->id; + else + ret << "-1"; + return ret.str(); +} + +string CodeGen::FIRST_FINAL_STATE() +{ + ostringstream ret; + if ( redFsm->firstFinState != 0 ) + ret << redFsm->firstFinState->id; + else + ret << redFsm->nextStateId; + return ret.str(); +} + +void CodeGen::writeInit() +{ + out << " {\n"; + + if ( !noCS ) + out << "\t" << vCS() << " = " << CAST("int") << START() << ";\n"; + + if ( redFsm->anyNfaStates() ) + out << "\t" << "nfa_len = 0;\n"; + + /* If there are any calls, then the stack top needs initialization. */ + if ( redFsm->anyActionCalls() || redFsm->anyActionNcalls() || + redFsm->anyActionRets() || redFsm->anyActionNrets() ) + { + out << "\t" << TOP() << " = 0;\n"; + } + + if ( red->hasLongestMatch ) { + out << + " " << TOKSTART() << " = " << NIL() << ";\n" + " " << TOKEND() << " = " << NIL() << ";\n"; + + if ( redFsm->usingAct() ) { + out << + " " << ACT() << " = 0;\n"; + } + } + out << " }\n"; +} + +string CodeGen::DATA_PREFIX() +{ + if ( !noPrefix ) + return FSM_NAME() + "_"; + return ""; +} + +/* Emit the alphabet data type. */ +string CodeGen::ALPH_TYPE() +{ + string ret = alphType->data1; + if ( alphType->data2 != 0 ) { + ret += " "; + ret += + alphType->data2; + } + return ret; +} + +void CodeGen::VALUE( string type, string name, string value ) +{ + if ( backend == Direct ) + out << "static const " << type << " " << name << " = " << value << ";\n"; + else + out << "value " << type << " " << name << " = " << value << ";\n"; +} + +string CodeGen::STR( int v ) +{ + ostringstream s; + s << v; + return s.str(); +} + +void CodeGen::STATE_IDS() +{ + if ( redFsm->startState != 0 ) + VALUE( "int", START(), START_STATE_ID() ); + + if ( !noFinal ) + VALUE( "int", FIRST_FINAL(), FIRST_FINAL_STATE() ); + + if ( !noError ) + VALUE( "int", ERROR(), ERROR_STATE() ); + + out << "\n"; + + if ( red->entryPointNames.length() > 0 ) { + for ( EntryNameVect::Iter en = red->entryPointNames; en.lte(); en++ ) { + string name = DATA_PREFIX() + "en_" + *en; + VALUE( "int", name, STR( red->entryPointIds[en.pos()] ) ); + } + out << "\n"; + } +} + +void CodeGen::writeStart() +{ + out << START_STATE_ID(); +} + +void CodeGen::writeFirstFinal() +{ + out << FIRST_FINAL_STATE(); +} + +void CodeGen::writeError() +{ + out << ERROR_STATE(); +} + +void CodeGen::writeExports() +{ + if ( red->exportList.length() > 0 ) { + for ( ExportList::Iter ex = red->exportList; ex.lte(); ex++ ) { + out << EXPORT( ALPH_TYPE(), + DATA_PREFIX() + "ex_" + ex->name, KEY(ex->key) ) << "\n"; + } + out << "\n"; + } +} + +void CodeGen::NFA_PUSH( std::string state ) +{ + if ( redFsm->anyNfaStates() ) { + out << + " if ( " << ARR_REF( nfaOffsets ) << "[" << state << "] != 0 ) {\n" + " " << alt << " = 0; \n" + " " << new_recs << " = " << CAST("int") << ARR_REF( nfaTargs ) << "[" << CAST("int") << + ARR_REF( nfaOffsets ) << "[" << state << "]];\n"; + + if ( red->nfaPrePushExpr != 0 ) { + out << OPEN_HOST_BLOCK( red->nfaPrePushExpr ); + INLINE_LIST( out, red->nfaPrePushExpr->inlineList, 0, false, false ); + out << CLOSE_HOST_BLOCK(); + out << "\n"; + genOutputLineDirective( out ); + } + + out << + " while ( " << alt << " < " << new_recs << " ) { \n"; + + + out << + " nfa_bp[nfa_len].state = " << CAST("int") << ARR_REF( nfaTargs ) << "[" << CAST("int") << + ARR_REF( nfaOffsets ) << "[" << state << "] + 1 + " << alt << "];\n" + " nfa_bp[nfa_len].p = " << P() << ";\n"; + + if ( redFsm->bAnyNfaPops ) { + out << + " nfa_bp[nfa_len].popTrans = " << ARR_REF( nfaPopTrans ) << "[" << CAST("long") << + ARR_REF( nfaOffsets ) << "[" << state << "] + 1 + " << alt << "];\n" + "\n" + ; + } + + if ( redFsm->bAnyNfaPushes ) { + out << + " switch ( " << ARR_REF( nfaPushActions ) << "[" << CAST("int") << + ARR_REF( nfaOffsets ) << "[" << state << "] + 1 + " << alt << "] ) {\n"; + + /* Loop the actions. */ + for ( GenActionTableMap::Iter redAct = redFsm->actionMap; + redAct.lte(); redAct++ ) + { + if ( redAct->numNfaPushRefs > 0 ) { + /* Write the entry label. */ + out << "\t " << CASE( STR( redAct->actListId+1 ) ) << " {\n"; + + /* Write each action in the list of action items. */ + for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ ) + ACTION( out, item->value, IlOpts( 0, false, false ) ); + + out << "\n\t" << CEND() << "\n}\n"; + } + } + + out << + " }\n"; + } + + + out << + " nfa_len += 1;\n" + " " << alt << " += 1;\n" + " }\n" + " }\n" + ; + } +} + +void CodeGen::NFA_POST_POP() +{ + if ( red->nfaPostPopExpr != 0 ) { + out << OPEN_HOST_BLOCK( red->nfaPostPopExpr ); + INLINE_LIST( out, red->nfaPostPopExpr->inlineList, 0, false, false ); + out << CLOSE_HOST_BLOCK(); + } +} |