codegen.cc (ragel-7.0.0.10) | : | codegen.cc (ragel-7.0.0.11) | ||
---|---|---|---|---|
/* | /* | |||
* Copyright 2001-2014 Adrian Thurston <thurston@colm.net> | * Copyright 2001-2018 Adrian Thurston <thurston@colm.net> | |||
* | * | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files (the "Software"), to | * of this software and associated documentation files (the "Software"), to | |||
* deal in the Software without restriction, including without limitation the | * deal in the Software without restriction, including without limitation the | |||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | * 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 | * sell copies of the Software, and to permit persons to whom the Software is | |||
* furnished to do so, subject to the following conditions: | * furnished to do so, subject to the following conditions: | |||
* | * | |||
* The above copyright notice and this permission notice shall be included in al l | * The above copyright notice and this permission notice shall be included in al l | |||
* copies or substantial portions of the Software. | * copies or substantial portions of the Software. | |||
skipping to change at line 95 | skipping to change at line 95 | |||
{ | { | |||
values += 1; | values += 1; | |||
if ( v < min ) | if ( v < min ) | |||
min = v; | min = v; | |||
if ( v > max ) | if ( v > max ) | |||
max = v; | max = v; | |||
} | } | |||
void TableArray::finishAnalyze() | void TableArray::finishAnalyze() | |||
{ | { | |||
/* Calculate the type if it is not already set. */ | if ( codeGen.backend == Direct ) { | |||
if ( type.empty() ) { | /* Calculate the type if it is not already set. */ | |||
if ( min >= S8BIT_MIN && max <= S8BIT_MAX ) { | if ( type.empty() ) { | |||
type = "char"; | if ( min >= S8BIT_MIN && max <= S8BIT_MAX ) { | |||
width = sizeof(char); | type = "char"; | |||
} | width = sizeof(char); | |||
else if ( min >= S16BIT_MIN && max <= S16BIT_MAX ) { | } | |||
type = "short"; | else if ( min >= S16BIT_MIN && max <= S16BIT_MAX ) { | |||
width = sizeof(short); | type = "short"; | |||
} | width = sizeof(short); | |||
else if ( min >= S32BIT_MIN && max <= S32BIT_MAX ) { | } | |||
type = "int"; | else if ( min >= S32BIT_MIN && max <= S32BIT_MAX ) { | |||
width = sizeof(int); | type = "int"; | |||
} | width = sizeof(int); | |||
else if ( min >= S64BIT_MAX && max <= S64BIT_MAX ) { | } | |||
type = "long"; | else if ( min >= S64BIT_MAX && max <= S64BIT_MAX ) { | |||
width = sizeof(long); | type = "long"; | |||
} | width = sizeof(long); | |||
else { | } | |||
type = "long long"; | else { | |||
width = sizeof(long long); | 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() | void TableArray::startGenerate() | |||
{ | { | |||
if ( stringTables ) { | if ( codeGen.backend == Direct ) { | |||
out << "static const char S_" << codeGen.DATA_PREFIX() << name << | if ( stringTables ) { | |||
"[] __attribute__((aligned (16))) = \n\t\""; | 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 { | else { | |||
out << "static const " << type << " " << | out << "array " << type << " " << | |||
"_" << codeGen.DATA_PREFIX() << name << | "_" << codeGen.DATA_PREFIX() << name << | |||
"[] = {\n\t"; | "( " << min << ", " << max << " ) = { "; | |||
} | } | |||
} | } | |||
void TableArray::stringGenerate( long long value ) | void TableArray::stringGenerate( long long value ) | |||
{ | { | |||
char c; | char c; | |||
short h; | short h; | |||
int i; | int i; | |||
long l; | long l; | |||
unsigned char *p = 0; | unsigned char *p = 0; | |||
skipping to change at line 181 | skipping to change at line 215 | |||
out << 'x'; | out << 'x'; | |||
out << std::setw(2) << (unsigned int) *p++; | out << std::setw(2) << (unsigned int) *p++; | |||
} | } | |||
out.flags( prevFlags ); | out.flags( prevFlags ); | |||
out.fill( prevFill ); | out.fill( prevFill ); | |||
} | } | |||
void TableArray::valueGenerate( long long v ) | void TableArray::valueGenerate( long long v ) | |||
{ | { | |||
if ( stringTables ) { | if ( codeGen.backend == Direct ) { | |||
stringGenerate( v ); | if ( stringTables ) { | |||
stringGenerate( v ); | ||||
if ( ++ln % iall == 0 ) { | ||||
out << "\"\n\t\""; | if ( ++ln % iall == 0 ) { | |||
ln = 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 { | else { | |||
if ( isChar ) | if ( isChar ) | |||
out << "c(" << v << ")"; | out << "c(" << v << ")"; | |||
else if ( !isSigned ) | else if ( !isSigned ) | |||
out << v << "u"; | out << "u(" << v << ")"; | |||
else | else | |||
out << v; | out << v; | |||
out << ", "; | ||||
if ( ( ++ln % iall ) == 0 ) { | ||||
out << ",\n\t"; | ||||
ln = 0; | ||||
} | ||||
else { | ||||
out << ", "; | ||||
} | ||||
} | } | |||
} | } | |||
void TableArray::finishGenerate() | void TableArray::finishGenerate() | |||
{ | { | |||
if ( stringTables ) { | if ( codeGen.backend == Direct ) { | |||
out << "\";\nconst " << type << " *_" << codeGen.DATA_PREFIX() << | if ( stringTables ) { | |||
name << | out << "\";\nconst " << type << " *_" << codeGen.DATA_PREFIX() << | |||
" = (const " << type << "*) S_" << codeGen.DATA_P | name << | |||
REFIX() << name << ";\n\n"; | " = (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 { | else { | |||
if ( isChar ) | if ( isChar ) | |||
out << "c(0)\n};\n\n"; | out << "c(0) };\n\n"; | |||
else if ( !isSigned ) | else if ( !isSigned ) | |||
out << "0u\n};\n\n"; | out << "u(0) };\n\n"; | |||
else | else | |||
out << "0\n};\n\n"; | out << "0 };\n\n"; | |||
} | } | |||
if ( codeGen.red->id->printStatistics ) { | if ( codeGen.red->id->printStatistics ) { | |||
codeGen.red->id->stats() << name << "\t" << values << "\t" << | codeGen.red->id->stats() << name << "\t" << values << "\t" << | |||
size() << "\t" << endl; | size() << "\t" << endl; | |||
} | } | |||
codeGen.tableData += size(); | codeGen.tableData += size(); | |||
} | } | |||
skipping to change at line 277 | skipping to change at line 332 | |||
case GeneratePass: | case GeneratePass: | |||
finishGenerate(); | finishGenerate(); | |||
break; | break; | |||
} | } | |||
} | } | |||
/* Init code gen with in parameters. */ | /* Init code gen with in parameters. */ | |||
CodeGen::CodeGen( const CodeGenArgs &args ) | CodeGen::CodeGen( const CodeGenArgs &args ) | |||
: | : | |||
CodeGenData( args ), | CodeGenData( args ), | |||
cpc( "_cpc" ), | ||||
tableData( 0 ), | tableData( 0 ), | |||
stringTables( args.id->stringTables ) | 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() | void CodeGen::statsSummary() | |||
{ | { | |||
if ( red->id->printStatistics ) | if ( red->id->printStatistics ) | |||
red->id->stats() << "table-data\t\t" << tableData << endl << endl ; | red->id->stats() << "table-data\t\t" << tableData << endl << endl ; | |||
} | } | |||
string CodeGen::CAST( string type ) | string CodeGen::CAST( string type ) | |||
{ | { | |||
return "(" + type + ")"; | if ( backend == Direct ) | |||
return "(" + type + ")"; | ||||
else | ||||
return "cast(" + type + ")"; | ||||
} | } | |||
/* Write out the fsm name. */ | /* Write out the fsm name. */ | |||
string CodeGen::FSM_NAME() | string CodeGen::FSM_NAME() | |||
{ | { | |||
return fsmName; | return fsmName; | |||
} | } | |||
/* Emit the offset of the start state as a decimal integer. */ | /* Emit the offset of the start state as a decimal integer. */ | |||
string CodeGen::START_STATE_ID() | string CodeGen::START_STATE_ID() | |||
skipping to change at line 467 | skipping to change at line 532 | |||
string result; | string result; | |||
while ( level-- > 0 ) | while ( level-- > 0 ) | |||
result += "\t"; | result += "\t"; | |||
return result; | return result; | |||
} | } | |||
/* Write out a key from the fsm code gen. Depends on wether or not the key is | /* Write out a key from the fsm code gen. Depends on wether or not the key is | |||
* signed. */ | * signed. */ | |||
string CodeGen::KEY( Key key ) | string CodeGen::KEY( Key key ) | |||
{ | { | |||
ostringstream ret; | if ( backend == Direct ) { | |||
if ( alphType->isChar ) | ostringstream ret; | |||
ret << "c(" << (unsigned long) key.getVal() << ")"; | if ( alphType->isChar ) | |||
else if ( keyOps->isSigned || !keyOps->explicitUnsigned ) | ret << "c(" << (unsigned long) key.getVal() << ")"; | |||
ret << key.getVal(); | else if ( keyOps->isSigned || !keyOps->explicitUnsigned ) | |||
else | ret << key.getVal(); | |||
ret << (unsigned long) key.getVal() << "u"; | else | |||
return ret.str(); | 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() | bool CodeGen::isAlphTypeSigned() | |||
{ | { | |||
return keyOps->isSigned; | return keyOps->isSigned; | |||
} | } | |||
void CodeGen::DECLARE( std::string type, Variable &var, std::string init ) | ||||
{ | ||||
if ( var.isReferenced ) | ||||
out << type << " " << var.name << init << ';'; | ||||
} | ||||
void CodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFini sh ) | void CodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFini sh ) | |||
{ | { | |||
/* The parser gives fexec two children. The double brackets are for D | /* 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 | * code. If the inline list is a single word it will get interpreted as a | |||
* C-style cast by the D compiler. */ | * C-style cast by the D compiler. */ | |||
ret << OPEN_GEN_BLOCK() << P() << " = (("; | ret << OPEN_GEN_BLOCK() << P() << " = (("; | |||
INLINE_LIST( ret, item->children, targState, inFinish, false ); | INLINE_LIST( ret, item->children, targState, inFinish, false ); | |||
ret << "))-1;" << CLOSE_GEN_BLOCK() << "\n"; | ret << "))-1;" << CLOSE_GEN_BLOCK() << "\n"; | |||
} | } | |||
skipping to change at line 817 | skipping to change at line 900 | |||
{ | { | |||
GenAction *action = condition->inlineList->head->wrappedAction; | GenAction *action = condition->inlineList->head->wrappedAction; | |||
ACTION( out, action, IlOpts( 0, false, false ) ); | ACTION( out, action, IlOpts( 0, false, false ) ); | |||
ret << "\n"; | ret << "\n"; | |||
} | } | |||
else if ( condition->inlineList->length() == 1 && | else if ( condition->inlineList->length() == 1 && | |||
condition->inlineList->head->type == | condition->inlineList->head->type == | |||
GenInlineItem::NfaWrapConds ) | GenInlineItem::NfaWrapConds ) | |||
{ | { | |||
ret << | ret << | |||
" _cpc = 0;\n"; | " " << cpc << " = 0;\n"; | |||
GenCondSpace *condSpace = condition->inlineList->head->condSpace; | GenCondSpace *condSpace = condition->inlineList->head->condSpace; | |||
for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { | for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) { | |||
ret << | ret << | |||
" if ( "; | " if ( "; | |||
CONDITION( out, *csi ); | CONDITION( out, *csi ); | |||
Size condValOffset = (1 << csi.pos()); | Size condValOffset = (1 << csi.pos()); | |||
ret << " ) _cpc += " << condValOffset << ";\n"; | ret << " ) " << cpc << " += " << condValOffset << ";\n"; | |||
} | } | |||
const CondKeySet &keys = condition->inlineList->head->condKeySet; | const CondKeySet &keys = condition->inlineList->head->condKeySet; | |||
if ( keys.length() > 0 ) { | if ( keys.length() > 0 ) { | |||
ret << "_pop_test = "; | ret << "_pop_test = "; | |||
for ( CondKeySet::Iter cki = keys; cki.lte(); cki++ ) { | for ( CondKeySet::Iter cki = keys; cki.lte(); cki++ ) { | |||
ret << "_cpc == " << *cki; | ret << "" << cpc << " == " << *cki; | |||
if ( !cki.last() ) | if ( !cki.last() ) | |||
ret << " || "; | ret << " || "; | |||
} | } | |||
ret << ";\n"; | ret << ";\n"; | |||
} | } | |||
else { | else { | |||
ret << "_pop_test = 0;\n"; | ret << "_pop_test = 0;\n"; | |||
} | } | |||
if ( !last ) | if ( !last ) | |||
skipping to change at line 924 | skipping to change at line 1007 | |||
string ret = alphType->data1; | string ret = alphType->data1; | |||
if ( alphType->data2 != 0 ) { | if ( alphType->data2 != 0 ) { | |||
ret += " "; | ret += " "; | |||
ret += + alphType->data2; | ret += + alphType->data2; | |||
} | } | |||
return ret; | return ret; | |||
} | } | |||
void CodeGen::VALUE( string type, string name, string value ) | void CodeGen::VALUE( string type, string name, string value ) | |||
{ | { | |||
out << "static const " << type << " " << name << " = " << value << ";\n"; | if ( backend == Direct ) | |||
out << "static const " << type << " " << name << " = " << value < | ||||
< ";\n"; | ||||
else | ||||
out << "value " << type << " " << name << " = " << value << ";\n" | ||||
; | ||||
} | } | |||
string CodeGen::STR( int v ) | string CodeGen::STR( int v ) | |||
{ | { | |||
ostringstream s; | ostringstream s; | |||
s << v; | s << v; | |||
return s.str(); | return s.str(); | |||
} | } | |||
void CodeGen::STATE_IDS() | void CodeGen::STATE_IDS() | |||
skipping to change at line 981 | skipping to change at line 1067 | |||
void CodeGen::writeExports() | void CodeGen::writeExports() | |||
{ | { | |||
if ( red->exportList.length() > 0 ) { | if ( red->exportList.length() > 0 ) { | |||
for ( ExportList::Iter ex = red->exportList; ex.lte(); ex++ ) { | for ( ExportList::Iter ex = red->exportList; ex.lte(); ex++ ) { | |||
out << EXPORT( ALPH_TYPE(), | out << EXPORT( ALPH_TYPE(), | |||
DATA_PREFIX() + "ex_" + ex->name, KEY(ex->key) ) << "\n"; | DATA_PREFIX() + "ex_" + ex->name, KEY(ex->key) ) << "\n"; | |||
} | } | |||
out << "\n"; | out << "\n"; | |||
} | } | |||
} | } | |||
void CodeGen::NFA_PUSH( std::string state ) | ||||
{ | ||||
if ( redFsm->anyNfaStates() ) { | ||||
out << | ||||
" if ( " << ARR_REF( nfaOffsets ) << "[" << state < | ||||
< "] ) {\n" | ||||
" int alt = 0; \n" | ||||
" int new_recs = " << ARR_REF( nfaTargs ) < | ||||
< "[" << CAST("int") << | ||||
ARR_REF( nfaOffsets ) << "[" << s | ||||
tate << "]];\n"; | ||||
if ( red->nfaPrePushExpr != 0 ) { | ||||
out << OPEN_HOST_BLOCK( red->nfaPrePushExpr ); | ||||
INLINE_LIST( out, red->nfaPrePushExpr->inlineList, 0, fal | ||||
se, false ); | ||||
out << CLOSE_HOST_BLOCK(); | ||||
} | ||||
out << | ||||
" while ( alt < new_recs ) { \n"; | ||||
out << | ||||
" nfa_bp[nfa_len].state = " << 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 | ||||
= " << CAST("long") << | ||||
ARR_REF( nfaOffse | ||||
ts ) << "[" << state << "] + 1 + alt;\n" | ||||
"\n" | ||||
; | ||||
} | ||||
if ( redFsm->bAnyNfaPushes ) { | ||||
out << | ||||
" switch ( " << ARR_REF( nf | ||||
aPushActions ) << "[" << CAST("int") << | ||||
ARR_REF( nfaOffse | ||||
ts ) << "[" << 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->actLis | ||||
tId+1 ) ) << " {\n"; | ||||
/* Write each action in the list of actio | ||||
n items. */ | ||||
for ( GenActionTable::Iter item = redAct- | ||||
>key; item.lte(); item++ ) | ||||
ACTION( out, item->value, IlOpts( | ||||
0, false, false ) ); | ||||
out << "\n\t" << CEND() << "}\n"; | ||||
} | ||||
} | ||||
out << | ||||
" }\n"; | ||||
} | ||||
out << | ||||
" nfa_len += 1;\n" | ||||
" alt += 1;\n" | ||||
" }\n" | ||||
" }\n" | ||||
; | ||||
} | ||||
} | ||||
End of changes. 23 change blocks. | ||||
64 lines changed or deleted | 153 lines changed or added |