From 40929113490e5a151e52bb6a17d5d3f577b34b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Sun, 24 Apr 2016 23:23:09 +0200 Subject: [PATCH] Move code generation into its own class --- src/script/C4Aul.h | 1 + src/script/C4AulParse.cpp | 130 ++++++++++++++++------------------- src/script/C4AulParse.h | 91 +++++++++++++++--------- src/script/C4AulScriptFunc.h | 2 + 4 files changed, 121 insertions(+), 103 deletions(-) diff --git a/src/script/C4Aul.h b/src/script/C4Aul.h index 220c6175a..f7ba1e1e1 100644 --- a/src/script/C4Aul.h +++ b/src/script/C4Aul.h @@ -155,6 +155,7 @@ public: friend class C4AulProfiler; friend class C4ScriptHost; friend class C4AulParse; + friend class C4CodeGen; friend class C4AulDebug; }; diff --git a/src/script/C4AulParse.cpp b/src/script/C4AulParse.cpp index a32a5264c..24a800dfb 100644 --- a/src/script/C4AulParse.cpp +++ b/src/script/C4AulParse.cpp @@ -22,7 +22,6 @@ #include "script/C4Aul.h" #include "script/C4AulDebug.h" #include "script/C4AulExec.h" -#include "script/C4AulScriptFunc.h" #include "object/C4Def.h" #include "game/C4Game.h" #include "lib/C4Log.h" @@ -120,10 +119,7 @@ C4AulParse::C4AulParse(C4ScriptHost *a, enum Type Type) : SPos(a->Script.getData()), TokenSPos(SPos), TokenType(ATT_INVALID), Type(Type), - ContextToExecIn(NULL), - fJump(false), - iStack(0), - pLoopStack(NULL) + ContextToExecIn(NULL) { } C4AulParse::C4AulParse(C4AulScriptFunc * Fn, C4AulScriptContext* context, C4AulScriptEngine *Engine) : @@ -131,15 +127,11 @@ C4AulParse::C4AulParse(C4AulScriptFunc * Fn, C4AulScriptContext* context, C4AulS SPos(Fn->Script), TokenSPos(SPos), TokenType(ATT_INVALID), Type(C4AulParse::PARSER), - ContextToExecIn(context), - fJump(false), - iStack(0), - pLoopStack(NULL) -{ } + ContextToExecIn(context) +{ codegen.Fn = Fn; } C4AulParse::~C4AulParse() { - while (pLoopStack) PopLoop(0); ClearToken(); } @@ -645,14 +637,14 @@ static const char * GetTTName(C4AulBCCType e) } } -void C4AulParse::DumpByteCode() +void C4AulScriptFunc::DumpByteCode() { - if (DEBUG_BYTECODE_DUMP && Type == PARSER) + if (DEBUG_BYTECODE_DUMP) { - fprintf(stderr, "%s:\n", Fn->GetName()); + fprintf(stderr, "%s:\n", GetName()); std::map labels; int labeln = 0; - for (C4AulBCC *pBCC = Fn->GetCode(); pBCC->bccType != AB_EOFN; pBCC++) + for (C4AulBCC *pBCC = GetCode(); pBCC->bccType != AB_EOFN; pBCC++) { switch (pBCC->bccType) { @@ -661,12 +653,12 @@ void C4AulParse::DumpByteCode() default: break; } } - for (C4AulBCC *pBCC = Fn->GetCode();; pBCC++) + for (C4AulBCC *pBCC = GetCode();; pBCC++) { C4AulBCCType eType = pBCC->bccType; if (labels.find(pBCC) != labels.end()) fprintf(stderr, "%d:\n", labels[pBCC]); - fprintf(stderr, "\t%d\t%s", Fn->GetLineOfCode(pBCC), GetTTName(eType)); + fprintf(stderr, "\t%d\t%s", GetLineOfCode(pBCC), GetTTName(eType)); if (strlen(GetTTName(eType)) < 8) fprintf(stderr, " "); switch (eType) { @@ -760,7 +752,7 @@ bool C4ScriptHost::Preparse() } -int C4AulParse::GetStackValue(C4AulBCCType eType, intptr_t X) +int C4CodeGen::GetStackValue(C4AulBCCType eType, intptr_t X) { switch (eType) { @@ -860,10 +852,8 @@ void C4AulParse::DebugChunk() AddBCC(AB_DEBUG); } -int C4AulParse::AddBCC(C4AulBCCType eType, intptr_t X) +int C4CodeGen::AddBCC(const char * TokenSPos, C4AulBCCType eType, intptr_t X) { - if (Type != PARSER) return -1; - // Track stack size iStack += GetStackValue(eType, X); @@ -962,7 +952,7 @@ int C4AulParse::AddBCC(C4AulBCCType eType, intptr_t X) return Fn->GetCodePos() - 1; } -void C4AulParse::RemoveLastBCC() +void C4CodeGen::RemoveLastBCC() { // Security: This is unsafe on anything that might get optimized away C4AulBCC *pBCC = Fn->GetLastCode(); @@ -973,7 +963,7 @@ void C4AulParse::RemoveLastBCC() Fn->RemoveLastBCC(); } -C4V_Type C4AulParse::GetLastRetType(C4V_Type to) +C4V_Type C4CodeGen::GetLastRetType(C4AulScriptEngine * Engine, C4V_Type to) { C4V_Type from; switch (Fn->GetLastCode()->bccType) @@ -1026,9 +1016,8 @@ C4V_Type C4AulParse::GetLastRetType(C4V_Type to) return from; } -C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue) +C4AulBCC C4CodeGen::MakeSetter(const char * SPos, bool fLeaveValue) { - if(Type != PARSER) { return C4AulBCC(AB_ERR, 0); } C4AulBCC Value = *(Fn->GetLastCode()), Setter = Value; // Check type switch (Value.bccType) @@ -1049,7 +1038,7 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue) break; case AB_GLOBALN: Setter.bccType = AB_GLOBALN_SET; break; default: - throw C4AulParseError(this, "assignment to a constant"); + throw C4AulParseError(Fn, SPos, "assignment to a constant"); } // If the new value is produced using the old one, the parameters to get the old one need to be duplicated. // Otherwise, the setter can just use the parameters originally meant for the getter. @@ -1060,7 +1049,7 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue) // STACK_SET has a side effect, so it can't be simply removed. // Discard the unused value the usual way instead. if (!fLeaveValue) - AddBCC(AB_STACK, -1); + AddBCC(SPos, AB_STACK, -1); // The original parameter isn't needed anymore, since in contrast to the other getters // it does not indicate a position. iParCount = 0; @@ -1073,9 +1062,9 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue) if (fLeaveValue && iParCount) { for(int i = 0; i < iParCount; i++) - AddBCC(AB_DUP, 1 - iParCount); + AddBCC(SPos, AB_DUP, 1 - iParCount); // Finally re-add original BCC - AddBCC(Value.bccType, Value.Par.X); + AddBCC(SPos, Value.bccType, Value.Par.X); } // Done. The returned BCC should be added later once the value to be set was pushed on top. assert(iParCount == -GetStackValue(Setter.bccType, Setter.Par.X)); @@ -1084,10 +1073,10 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue) int C4AulParse::AddVarAccess(C4AulBCCType eType, intptr_t varnum) { - return AddBCC(eType, 1 + varnum - (iStack + Fn->VarNamed.iSize)); + return AddBCC(eType, 1 + varnum - (codegen.iStack + Fn->VarNamed.iSize)); } -int C4AulParse::JumpHere() +int C4CodeGen::JumpHere() { // Set flag so the next generated code chunk won't get joined fJump = true; @@ -1099,9 +1088,8 @@ static bool IsJump(C4AulBCCType t) return t == AB_JUMP || t == AB_JUMPAND || t == AB_JUMPOR || t == AB_JUMPNNIL || t == AB_CONDN || t == AB_COND; } -void C4AulParse::SetJumpHere(int iJumpOp) +void C4CodeGen::SetJumpHere(int iJumpOp) { - if (Type != PARSER) return; // Set target C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp); assert(IsJump(pBCC->bccType)); @@ -1110,23 +1098,21 @@ void C4AulParse::SetJumpHere(int iJumpOp) fJump = true; } -void C4AulParse::SetJump(int iJumpOp, int iWhere) +void C4CodeGen::SetJump(int iJumpOp, int iWhere) { - if (Type != PARSER) return; // Set target C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp); assert(IsJump(pBCC->bccType)); pBCC->Par.i = iWhere - iJumpOp; } -void C4AulParse::AddJump(C4AulBCCType eType, int iWhere) +void C4CodeGen::AddJump(const char * SPos, C4AulBCCType eType, int iWhere) { - AddBCC(eType, iWhere - Fn->GetCodePos()); + AddBCC(SPos, eType, iWhere - Fn->GetCodePos()); } -void C4AulParse::PushLoop() +void C4CodeGen::PushLoop() { - if (Type != PARSER) return; Loop *pNew = new Loop(); pNew->StackSize = iStack; pNew->Controls = NULL; @@ -1134,9 +1120,8 @@ void C4AulParse::PushLoop() pLoopStack = pNew; } -void C4AulParse::PopLoop(int ContinueJump) +void C4CodeGen::PopLoop(int ContinueJump) { - if (Type != PARSER) return; // Set targets for break/continue for (Loop::Control *pCtrl = pLoopStack->Controls; pCtrl; pCtrl = pCtrl->Next) if (pCtrl->Break) @@ -1158,18 +1143,31 @@ void C4AulParse::PopLoop(int ContinueJump) delete pLoop; } -void C4AulParse::AddLoopControl(bool fBreak) +void C4CodeGen::AddLoopControl(const char * SPos, bool fBreak) { - if (Type != PARSER) return; // Insert code if (pLoopStack->StackSize != iStack) - AddBCC(AB_STACK, pLoopStack->StackSize - iStack); + AddBCC(SPos, AB_STACK, pLoopStack->StackSize - iStack); Loop::Control *pNew = new Loop::Control(); pNew->Break = fBreak; pNew->Pos = Fn->GetCodePos(); pNew->Next = pLoopStack->Controls; pLoopStack->Controls = pNew; - AddBCC(AB_JUMP); + AddBCC(SPos, AB_JUMP); +} + +void C4CodeGen::ErrorOut(const char * SPos) +{ + // make all jumps that don't have their destination yet jump here + for (unsigned int i = 0; i < Fn->Code.size(); i++) + { + C4AulBCC *pBCC = &Fn->Code[i]; + if (IsJump(pBCC->bccType)) + if (!pBCC->Par.i) + pBCC->Par.i = Fn->Code.size() - i; + } + // add an error chunk + AddBCC(SPos, AB_ERR); } const char * C4AulParse::GetTokenName(C4AulTokenType TokenType) @@ -1345,16 +1343,7 @@ void C4AulParse::Parse_Script(C4ScriptHost * scripthost) if (Fn) { - // make all jumps that don't have their destination yet jump here - for (unsigned int i = 0; i < Fn->Code.size(); i++) - { - C4AulBCC *pBCC = &Fn->Code[i]; - if (IsJump(pBCC->bccType)) - if (!pBCC->Par.i) - pBCC->Par.i = Fn->Code.size() - i; - } - // add an error chunk - AddBCC(AB_ERR); + codegen.ErrorOut(TokenSPos); } } } @@ -1425,6 +1414,7 @@ void C4AulParse::Parse_FuncBody() { // Parse function body assert(Fn); + codegen.Fn = Fn; if (Type == PREPARSER) { // This might be a reload, clear all parameters and local vars @@ -1493,21 +1483,21 @@ void C4AulParse::Parse_FuncBody() // Push variables if (Fn->VarNamed.iSize) AddBCC(AB_STACK, Fn->VarNamed.iSize); - iStack = 0; + codegen.iStack = 0; while (TokenType != ATT_BLCLOSE) { Parse_Statement(); - assert(!iStack); + assert(!codegen.iStack); } // return nil if the function doesn't return anything C4AulBCC * CPos = Fn->GetLastCode(); - if (!CPos || CPos->bccType != AB_RETURN || fJump) + if (!CPos || CPos->bccType != AB_RETURN || codegen.fJump) { AddBCC(AB_NIL); DebugChunk(); AddBCC(AB_RETURN); } - DumpByteCode(); + if (Type == PARSER) Fn->DumpByteCode(); // add separator AddBCC(AB_EOFN); // Do not blame this function for script errors between functions @@ -1638,13 +1628,13 @@ void C4AulParse::Parse_Statement() if (Type == PARSER) { // Must be inside a loop - if (!pLoopStack) + if (!codegen.pLoopStack) { Error("'break' is only allowed inside loops"); } else { - AddLoopControl(true); + codegen.AddLoopControl(TokenSPos, true); } } } @@ -1654,13 +1644,13 @@ void C4AulParse::Parse_Statement() if (Type == PARSER) { // Must be inside a loop - if (!pLoopStack) + if (!codegen.pLoopStack) { Error("'continue' is only allowed inside loops"); } else { - AddLoopControl(false); + codegen.AddLoopControl(TokenSPos, false); } } } @@ -1904,16 +1894,16 @@ void C4AulParse::Parse_DoWhile() { Shift(); // Save position for later jump back - int Start = JumpHere(); + int Start = codegen.JumpHere(); // We got a loop PushLoop(); // Execute body Parse_Statement(); int BeforeCond = -1; if (Type == PARSER) - for (Loop::Control *pCtrl2 = pLoopStack->Controls; pCtrl2; pCtrl2 = pCtrl2->Next) + for (C4CodeGen::Loop::Control *pCtrl2 = codegen.pLoopStack->Controls; pCtrl2; pCtrl2 = pCtrl2->Next) if (!pCtrl2->Break) - BeforeCond = JumpHere(); + BeforeCond = codegen.JumpHere(); // Execute condition if (TokenType != ATT_IDTF || !SEqual(Idtf, C4AUL_While)) UnexpectedToken("'while'"); @@ -1931,7 +1921,7 @@ void C4AulParse::Parse_While() { Shift(); // Save position for later jump back - int iStart = JumpHere(); + int iStart = codegen.JumpHere(); // Execute condition Match(ATT_BOPEN); Parse_Expression(); @@ -1996,7 +1986,7 @@ void C4AulParse::Parse_For() if (TokenType != ATT_SCOLON) { // Add condition code - iCondition = JumpHere(); + iCondition = codegen.JumpHere(); Parse_Expression(); // Jump out iJumpOut = AddBCC(AB_CONDN); @@ -2010,7 +2000,7 @@ void C4AulParse::Parse_For() // Must jump over incrementor iJumpBody = AddBCC(AB_JUMP); // Add incrementor code - iIncrementor = JumpHere(); + iIncrementor = codegen.JumpHere(); Parse_Expression(); AddBCC(AB_STACK, -1); // Jump to condition @@ -2022,7 +2012,7 @@ void C4AulParse::Parse_For() // Allow break/continue from now on PushLoop(); // Body - int iBody = JumpHere(); + int iBody = codegen.JumpHere(); if (iJumpBody != -1) SetJumpHere(iJumpBody); Parse_Statement(); diff --git a/src/script/C4AulParse.h b/src/script/C4AulParse.h index 9d92eb6a9..01eb326c7 100644 --- a/src/script/C4AulParse.h +++ b/src/script/C4AulParse.h @@ -18,10 +18,53 @@ #define INC_C4AulParse #include "script/C4Aul.h" +#include "script/C4AulScriptFunc.h" enum C4AulBCCType : int; enum C4AulTokenType : int; +class C4CodeGen +{ +public: + C4AulScriptFunc *Fn; + bool fJump = false; + int iStack = 0; + + int GetStackValue(C4AulBCCType eType, intptr_t X = 0); + int AddBCC(const char * SPos, C4AulBCCType eType, intptr_t X = 0); + void ErrorOut(const char * SPos); + void RemoveLastBCC(); + C4V_Type GetLastRetType(C4AulScriptEngine * Engine, C4V_Type to); // for warning purposes + + C4AulBCC MakeSetter(const char * TokenSPos, bool fLeaveValue = false); // Prepares to generate a setter for the last value that was generated + + int JumpHere(); // Get position for a later jump to next instruction added + void SetJumpHere(int iJumpOp); // Use the next inserted instruction as jump target for the given jump operation + void SetJump(int iJumpOp, int iWhere); + void AddJump(const char * SPos, C4AulBCCType eType, int iWhere); + + // Keep track of loops and break/continue usages + struct Loop + { + struct Control + { + bool Break; + int Pos; + Control *Next; + }; + Control *Controls; + int StackSize; + Loop *Next; + }; + Loop *pLoopStack = NULL; + + void PushLoop(); + void PopLoop(int ContinueJump); + void AddLoopControl(const char * SPos, bool fBreak); + ~C4CodeGen() + { while (pLoopStack) PopLoop(0); } +}; + struct C4ScriptOpDef { unsigned short Priority; @@ -94,42 +137,24 @@ private: void Error(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O; void AppendPosition(StdStrBuf & Buf); - bool fJump; - int iStack; - - int GetStackValue(C4AulBCCType eType, intptr_t X = 0); - int AddBCC(C4AulBCCType eType, intptr_t X = 0); int AddVarAccess(C4AulBCCType eType, intptr_t varnum); void DebugChunk(); - void RemoveLastBCC(); - C4V_Type GetLastRetType(C4V_Type to); // for warning purposes - void DumpByteCode(); + C4CodeGen codegen; + int AddBCC(C4AulBCCType eType, intptr_t X = 0) + { if (Type == PARSER) return codegen.AddBCC(TokenSPos, eType, X); else return -1; } + C4V_Type GetLastRetType(C4V_Type to) + { return codegen.GetLastRetType(Engine, to); } + C4AulBCC MakeSetter(bool fLeaveValue = false) + { return Type == PARSER ? codegen.MakeSetter(TokenSPos, fLeaveValue) : C4AulBCC(AB_ERR, 0); } + void SetJumpHere(int iJumpOp) + { if (Type == PARSER) codegen.SetJumpHere(iJumpOp); } + void AddJump(C4AulBCCType eType, int iWhere) + { if (Type == PARSER) codegen.AddJump(TokenSPos, eType, iWhere); } + void PushLoop() + { if (Type == PARSER) codegen.PushLoop(); } + void PopLoop(int Jump) + { if (Type == PARSER) codegen.PopLoop(Jump); } - C4AulBCC MakeSetter(bool fLeaveValue = false); // Prepares to generate a setter for the last value that was generated - - int JumpHere(); // Get position for a later jump to next instruction added - void SetJumpHere(int iJumpOp); // Use the next inserted instruction as jump target for the given jump operation - void SetJump(int iJumpOp, int iWhere); - void AddJump(C4AulBCCType eType, int iWhere); - - // Keep track of loops and break/continue usages - struct Loop - { - struct Control - { - bool Break; - int Pos; - Control *Next; - }; - Control *Controls; - int StackSize; - Loop *Next; - }; - Loop *pLoopStack; - - void PushLoop(); - void PopLoop(int ContinueJump); - void AddLoopControl(bool fBreak); friend class C4AulParseError; }; diff --git a/src/script/C4AulScriptFunc.h b/src/script/C4AulScriptFunc.h index 6430b85df..7aa4502d2 100644 --- a/src/script/C4AulScriptFunc.h +++ b/src/script/C4AulScriptFunc.h @@ -179,6 +179,7 @@ protected: int GetCodePos() const { return Code.size(); } C4AulBCC *GetCodeByPos(int iPos) { return &Code[iPos]; } C4AulBCC *GetLastCode() { return Code.empty() ? NULL : &Code.back(); } + void DumpByteCode(); std::vector Code; std::vector PosForCode; int ParCount; @@ -214,6 +215,7 @@ public: uint32_t tProfileTime; // internally set by profiler + friend class C4CodeGen; friend class C4AulParse; friend class C4ScriptHost; };