forked from Mirrors/openclonk
C4AulCompiler: Split into separate file
parent
c8d71d47c0
commit
792e12adad
|
@ -1058,6 +1058,8 @@ src/lib/C4Real.h
|
||||||
src/lib/C4Random.cpp
|
src/lib/C4Random.cpp
|
||||||
src/lib/C4Random.h
|
src/lib/C4Random.h
|
||||||
src/script/C4Aul.cpp
|
src/script/C4Aul.cpp
|
||||||
|
src/script/C4AulCompiler.h
|
||||||
|
src/script/C4AulCompiler.cpp
|
||||||
src/script/C4AulDefFunc.h
|
src/script/C4AulDefFunc.h
|
||||||
src/script/C4AulExec.cpp
|
src/script/C4AulExec.cpp
|
||||||
src/script/C4AulExec.h
|
src/script/C4AulExec.h
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||||
|
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the ISC license; see accompanying file
|
||||||
|
* "COPYING" for details.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||||
|
* See accompanying file "TRADEMARK" for details.
|
||||||
|
*
|
||||||
|
* To redistribute this file separately, substitute the full license texts
|
||||||
|
* for the above references.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "script/C4AulCompiler.h"
|
||||||
|
|
||||||
|
#include "script/C4Aul.h"
|
||||||
|
#include "script/C4AulScriptFunc.h"
|
||||||
|
|
||||||
|
int C4AulCompiler::GetStackValue(C4AulBCCType eType, intptr_t X)
|
||||||
|
{
|
||||||
|
switch (eType)
|
||||||
|
{
|
||||||
|
case AB_INT:
|
||||||
|
case AB_BOOL:
|
||||||
|
case AB_STRING:
|
||||||
|
case AB_CPROPLIST:
|
||||||
|
case AB_CARRAY:
|
||||||
|
case AB_CFUNCTION:
|
||||||
|
case AB_NIL:
|
||||||
|
case AB_LOCALN:
|
||||||
|
case AB_GLOBALN:
|
||||||
|
case AB_DUP:
|
||||||
|
case AB_DUP_CONTEXT:
|
||||||
|
case AB_THIS:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case AB_Pow:
|
||||||
|
case AB_Div:
|
||||||
|
case AB_Mul:
|
||||||
|
case AB_Mod:
|
||||||
|
case AB_Sub:
|
||||||
|
case AB_Sum:
|
||||||
|
case AB_LeftShift:
|
||||||
|
case AB_RightShift:
|
||||||
|
case AB_LessThan:
|
||||||
|
case AB_LessThanEqual:
|
||||||
|
case AB_GreaterThan:
|
||||||
|
case AB_GreaterThanEqual:
|
||||||
|
case AB_Equal:
|
||||||
|
case AB_NotEqual:
|
||||||
|
case AB_BitAnd:
|
||||||
|
case AB_BitXOr:
|
||||||
|
case AB_BitOr:
|
||||||
|
case AB_PROP_SET:
|
||||||
|
case AB_ARRAYA:
|
||||||
|
case AB_CONDN:
|
||||||
|
case AB_COND:
|
||||||
|
case AB_POP_TO:
|
||||||
|
case AB_RETURN:
|
||||||
|
// JUMPAND/JUMPOR/JUMPNNIL are special: They either jump over instructions adding one to the stack
|
||||||
|
// or decrement the stack. Thus, for stack counting purposes, they decrement.
|
||||||
|
case AB_JUMPAND:
|
||||||
|
case AB_JUMPOR:
|
||||||
|
case AB_JUMPNNIL:
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case AB_FUNC:
|
||||||
|
return -reinterpret_cast<C4AulFunc *>(X)->GetParCount() + 1;
|
||||||
|
|
||||||
|
case AB_CALL:
|
||||||
|
case AB_CALLFS:
|
||||||
|
return -C4AUL_MAX_Par;
|
||||||
|
|
||||||
|
case AB_STACK_SET:
|
||||||
|
case AB_LOCALN_SET:
|
||||||
|
case AB_PROP:
|
||||||
|
case AB_GLOBALN_SET:
|
||||||
|
case AB_Inc:
|
||||||
|
case AB_Dec:
|
||||||
|
case AB_BitNot:
|
||||||
|
case AB_Not:
|
||||||
|
case AB_Neg:
|
||||||
|
case AB_PAR:
|
||||||
|
case AB_FOREACH_NEXT:
|
||||||
|
case AB_ERR:
|
||||||
|
case AB_EOFN:
|
||||||
|
case AB_JUMP:
|
||||||
|
case AB_DEBUG:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case AB_STACK:
|
||||||
|
return X;
|
||||||
|
|
||||||
|
case AB_NEW_ARRAY:
|
||||||
|
return -X + 1;
|
||||||
|
|
||||||
|
case AB_NEW_PROPLIST:
|
||||||
|
return -X * 2 + 1;
|
||||||
|
|
||||||
|
case AB_ARRAYA_SET:
|
||||||
|
case AB_ARRAY_SLICE:
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
case AB_ARRAY_SLICE_SET:
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int C4AulCompiler::AddBCC(const char * TokenSPos, C4AulBCCType eType, intptr_t X)
|
||||||
|
{
|
||||||
|
// Track stack size
|
||||||
|
iStack += GetStackValue(eType, X);
|
||||||
|
|
||||||
|
// Use stack operation instead of 0-Any (enable optimization)
|
||||||
|
if (eType == AB_NIL)
|
||||||
|
{
|
||||||
|
eType = AB_STACK;
|
||||||
|
X = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join checks only if it's not a jump target
|
||||||
|
if (!fJump && Fn->GetLastCode())
|
||||||
|
{
|
||||||
|
C4AulBCC *pCPos1 = Fn->GetLastCode();
|
||||||
|
|
||||||
|
// Skip noop stack operation
|
||||||
|
if (eType == AB_STACK && X == 0)
|
||||||
|
{
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join together stack operations
|
||||||
|
if (eType == AB_STACK && pCPos1->bccType == AB_STACK &&
|
||||||
|
(X <= 0 || pCPos1->Par.i >= 0))
|
||||||
|
{
|
||||||
|
pCPos1->Par.i += X;
|
||||||
|
// Empty? Remove it. This relies on the parser not issuing
|
||||||
|
// multiple negative stack operations consecutively, as
|
||||||
|
// that could result in removing a jump target bytecode.
|
||||||
|
if (!pCPos1->Par.i)
|
||||||
|
Fn->RemoveLastBCC();
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune unneeded Incs / Decs
|
||||||
|
if (eType == AB_STACK && X < 0 && (pCPos1->bccType == AB_Inc || pCPos1->bccType == AB_Dec))
|
||||||
|
{
|
||||||
|
if (!pCPos1->Par.X)
|
||||||
|
{
|
||||||
|
pCPos1->bccType = eType;
|
||||||
|
pCPos1->Par.i = X;
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If it was a result modifier, we can safely remove it knowing that it was neither
|
||||||
|
// the first chunk nor a jump target. We can therefore apply additional optimizations.
|
||||||
|
Fn->RemoveLastBCC();
|
||||||
|
pCPos1--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join STACK_SET + STACK -1 to POP_TO (equivalent)
|
||||||
|
if (eType == AB_STACK && X == -1 && pCPos1->bccType == AB_STACK_SET)
|
||||||
|
{
|
||||||
|
pCPos1->bccType = AB_POP_TO;
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join POP_TO + DUP to AB_STACK_SET if both target the same slot
|
||||||
|
if (eType == AB_DUP && pCPos1->bccType == AB_POP_TO && X == pCPos1->Par.i + 1)
|
||||||
|
{
|
||||||
|
pCPos1->bccType = AB_STACK_SET;
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce some constructs like SUM + INT 1 to INC or DEC
|
||||||
|
if ((eType == AB_Sum || eType == AB_Sub) &&
|
||||||
|
pCPos1->bccType == AB_INT &&
|
||||||
|
(pCPos1->Par.i == 1 || pCPos1->Par.i == -1))
|
||||||
|
{
|
||||||
|
if ((pCPos1->Par.i > 0) == (eType == AB_Sum))
|
||||||
|
pCPos1->bccType = AB_Inc;
|
||||||
|
else
|
||||||
|
pCPos1->bccType = AB_Dec;
|
||||||
|
pCPos1->Par.i = X;
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce Not + CONDN to COND, Not + COND to CONDN
|
||||||
|
if ((eType == AB_CONDN || eType == AB_COND) && pCPos1->bccType == AB_Not)
|
||||||
|
{
|
||||||
|
pCPos1->bccType = eType == AB_CONDN ? AB_COND : AB_CONDN;
|
||||||
|
pCPos1->Par.i = X + 1;
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
|
Fn->AddBCC(eType, X, TokenSPos);
|
||||||
|
|
||||||
|
// Reset jump flag
|
||||||
|
fJump = false;
|
||||||
|
|
||||||
|
return Fn->GetCodePos() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::RemoveLastBCC()
|
||||||
|
{
|
||||||
|
// Security: This is unsafe on anything that might get optimized away
|
||||||
|
C4AulBCC *pBCC = Fn->GetLastCode();
|
||||||
|
assert(pBCC->bccType != AB_STACK && pBCC->bccType != AB_STACK_SET && pBCC->bccType != AB_POP_TO);
|
||||||
|
// Correct stack
|
||||||
|
iStack -= GetStackValue(pBCC->bccType, pBCC->Par.X);
|
||||||
|
// Remove
|
||||||
|
Fn->RemoveLastBCC();
|
||||||
|
}
|
||||||
|
|
||||||
|
C4V_Type C4AulCompiler::GetLastRetType(C4AulScriptEngine * Engine, C4V_Type to)
|
||||||
|
{
|
||||||
|
C4V_Type from;
|
||||||
|
switch (Fn->GetLastCode()->bccType)
|
||||||
|
{
|
||||||
|
case AB_INT: from = Config.Developer.ExtraWarnings || Fn->GetLastCode()->Par.i ? C4V_Int : C4V_Any; break;
|
||||||
|
case AB_STRING: from = C4V_String; break;
|
||||||
|
case AB_NEW_ARRAY: case AB_CARRAY: case AB_ARRAY_SLICE: from = C4V_Array; break;
|
||||||
|
case AB_CFUNCTION: from = C4V_Function; break;
|
||||||
|
case AB_NEW_PROPLIST: case AB_CPROPLIST: from = C4V_PropList; break;
|
||||||
|
case AB_BOOL: from = C4V_Bool; break;
|
||||||
|
case AB_FUNC:
|
||||||
|
from = Fn->GetLastCode()->Par.f->GetRetType(); break;
|
||||||
|
case AB_CALL: case AB_CALLFS:
|
||||||
|
{
|
||||||
|
C4String * pName = Fn->GetLastCode()->Par.s;
|
||||||
|
C4AulFunc * pFunc2 = Engine->GetFirstFunc(pName->GetCStr());
|
||||||
|
bool allwarn = true;
|
||||||
|
from = C4V_Any;
|
||||||
|
while (pFunc2 && allwarn)
|
||||||
|
{
|
||||||
|
from = pFunc2->GetRetType();
|
||||||
|
if (!C4Value::WarnAboutConversion(from, to))
|
||||||
|
{
|
||||||
|
allwarn = false;
|
||||||
|
from = C4V_Any;
|
||||||
|
}
|
||||||
|
pFunc2 = Engine->GetNextSNFunc(pFunc2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AB_Inc: case AB_Dec: case AB_BitNot: case AB_Neg:
|
||||||
|
case AB_Pow: case AB_Div: case AB_Mul: case AB_Mod: case AB_Sub: case AB_Sum:
|
||||||
|
case AB_LeftShift: case AB_RightShift: case AB_BitAnd: case AB_BitXOr: case AB_BitOr:
|
||||||
|
from = C4V_Int; break;
|
||||||
|
case AB_Not: case AB_LessThan: case AB_LessThanEqual: case AB_GreaterThan: case AB_GreaterThanEqual:
|
||||||
|
case AB_Equal: case AB_NotEqual:
|
||||||
|
from = C4V_Bool; break;
|
||||||
|
case AB_DUP:
|
||||||
|
{
|
||||||
|
int pos = Fn->GetLastCode()->Par.i + iStack - 2 + Fn->VarNamed.iSize + Fn->GetParCount();
|
||||||
|
if (pos < Fn->GetParCount())
|
||||||
|
from = Fn->GetParType()[pos];
|
||||||
|
else
|
||||||
|
from = C4V_Any;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
from = C4V_Any; break;
|
||||||
|
}
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4AulBCC C4AulCompiler::MakeSetter(const char * SPos, bool fLeaveValue)
|
||||||
|
{
|
||||||
|
C4AulBCC Value = *(Fn->GetLastCode()), Setter = Value;
|
||||||
|
// Check type
|
||||||
|
switch (Value.bccType)
|
||||||
|
{
|
||||||
|
case AB_ARRAYA: Setter.bccType = AB_ARRAYA_SET; break;
|
||||||
|
case AB_ARRAY_SLICE: Setter.bccType = AB_ARRAY_SLICE_SET; break;
|
||||||
|
case AB_DUP:
|
||||||
|
Setter.bccType = AB_STACK_SET;
|
||||||
|
// the setter additionally has the new value on the stack
|
||||||
|
--Setter.Par.i;
|
||||||
|
break;
|
||||||
|
case AB_STACK_SET: Setter.bccType = AB_STACK_SET; break;
|
||||||
|
case AB_LOCALN:
|
||||||
|
Setter.bccType = AB_LOCALN_SET;
|
||||||
|
break;
|
||||||
|
case AB_PROP:
|
||||||
|
Setter.bccType = AB_PROP_SET;
|
||||||
|
break;
|
||||||
|
case AB_GLOBALN: Setter.bccType = AB_GLOBALN_SET; break;
|
||||||
|
default:
|
||||||
|
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.
|
||||||
|
// All getters push one value, so the parameter count is one more than the values they pop from the stack.
|
||||||
|
int iParCount = 1 - GetStackValue(Value.bccType, Value.Par.X);
|
||||||
|
if (Value.bccType == AB_STACK_SET)
|
||||||
|
{
|
||||||
|
// STACK_SET has a side effect, so it can't be simply removed.
|
||||||
|
// Discard the unused value the usual way instead.
|
||||||
|
if (!fLeaveValue)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else if (!fLeaveValue || iParCount)
|
||||||
|
{
|
||||||
|
RemoveLastBCC();
|
||||||
|
fJump = true; // In case the original BCC was a jump target
|
||||||
|
}
|
||||||
|
if (fLeaveValue && iParCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < iParCount; i++)
|
||||||
|
AddBCC(SPos, AB_DUP, 1 - iParCount);
|
||||||
|
// Finally re-add original BCC
|
||||||
|
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));
|
||||||
|
return Setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
int C4AulCompiler::JumpHere()
|
||||||
|
{
|
||||||
|
// Set flag so the next generated code chunk won't get joined
|
||||||
|
fJump = true;
|
||||||
|
return Fn->GetCodePos();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 C4AulCompiler::SetJumpHere(int iJumpOp)
|
||||||
|
{
|
||||||
|
// Set target
|
||||||
|
C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp);
|
||||||
|
assert(IsJump(pBCC->bccType));
|
||||||
|
pBCC->Par.i = Fn->GetCodePos() - iJumpOp;
|
||||||
|
// Set flag so the next generated code chunk won't get joined
|
||||||
|
fJump = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::SetJump(int iJumpOp, int iWhere)
|
||||||
|
{
|
||||||
|
// Set target
|
||||||
|
C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp);
|
||||||
|
assert(IsJump(pBCC->bccType));
|
||||||
|
pBCC->Par.i = iWhere - iJumpOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::AddJump(const char * SPos, C4AulBCCType eType, int iWhere)
|
||||||
|
{
|
||||||
|
AddBCC(SPos, eType, iWhere - Fn->GetCodePos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::PushLoop()
|
||||||
|
{
|
||||||
|
Loop *pNew = new Loop();
|
||||||
|
pNew->StackSize = iStack;
|
||||||
|
pNew->Controls = NULL;
|
||||||
|
pNew->Next = pLoopStack;
|
||||||
|
pLoopStack = pNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::PopLoop(int ContinueJump)
|
||||||
|
{
|
||||||
|
// Set targets for break/continue
|
||||||
|
for (Loop::Control *pCtrl = pLoopStack->Controls; pCtrl; pCtrl = pCtrl->Next)
|
||||||
|
if (pCtrl->Break)
|
||||||
|
SetJumpHere(pCtrl->Pos);
|
||||||
|
else
|
||||||
|
SetJump(pCtrl->Pos, ContinueJump);
|
||||||
|
// Delete loop controls
|
||||||
|
Loop *pLoop = pLoopStack;
|
||||||
|
while (pLoop->Controls)
|
||||||
|
{
|
||||||
|
// Unlink
|
||||||
|
Loop::Control *pCtrl = pLoop->Controls;
|
||||||
|
pLoop->Controls = pCtrl->Next;
|
||||||
|
// Delete
|
||||||
|
delete pCtrl;
|
||||||
|
}
|
||||||
|
// Unlink & delete
|
||||||
|
pLoopStack = pLoop->Next;
|
||||||
|
delete pLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::AddLoopControl(const char * SPos, bool fBreak)
|
||||||
|
{
|
||||||
|
// Insert code
|
||||||
|
if (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(SPos, AB_JUMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4AulCompiler::ErrorOut(const char * SPos, C4AulError & e)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
const char * msg = e.what();
|
||||||
|
if (SEqual2(msg, "ERROR: ")) msg += 7;
|
||||||
|
AddBCC(SPos, AB_ERR, reinterpret_cast<intptr_t>(::Strings.RegString(msg)));
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||||
|
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the ISC license; see accompanying file
|
||||||
|
* "COPYING" for details.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||||
|
* See accompanying file "TRADEMARK" for details.
|
||||||
|
*
|
||||||
|
* To redistribute this file separately, substitute the full license texts
|
||||||
|
* for the above references.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_C4AulCompiler
|
||||||
|
#define INC_C4AulCompiler
|
||||||
|
|
||||||
|
#include "script/C4Value.h"
|
||||||
|
|
||||||
|
enum C4AulBCCType : int;
|
||||||
|
|
||||||
|
class C4AulCompiler
|
||||||
|
{
|
||||||
|
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, class C4AulError & e);
|
||||||
|
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);
|
||||||
|
~C4AulCompiler()
|
||||||
|
{
|
||||||
|
while (pLoopStack) PopLoop(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -739,427 +739,17 @@ bool C4ScriptHost::Preparse()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int C4AulCompiler::GetStackValue(C4AulBCCType eType, intptr_t X)
|
|
||||||
{
|
|
||||||
switch (eType)
|
|
||||||
{
|
|
||||||
case AB_INT:
|
|
||||||
case AB_BOOL:
|
|
||||||
case AB_STRING:
|
|
||||||
case AB_CPROPLIST:
|
|
||||||
case AB_CARRAY:
|
|
||||||
case AB_CFUNCTION:
|
|
||||||
case AB_NIL:
|
|
||||||
case AB_LOCALN:
|
|
||||||
case AB_GLOBALN:
|
|
||||||
case AB_DUP:
|
|
||||||
case AB_DUP_CONTEXT:
|
|
||||||
case AB_THIS:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case AB_Pow:
|
|
||||||
case AB_Div:
|
|
||||||
case AB_Mul:
|
|
||||||
case AB_Mod:
|
|
||||||
case AB_Sub:
|
|
||||||
case AB_Sum:
|
|
||||||
case AB_LeftShift:
|
|
||||||
case AB_RightShift:
|
|
||||||
case AB_LessThan:
|
|
||||||
case AB_LessThanEqual:
|
|
||||||
case AB_GreaterThan:
|
|
||||||
case AB_GreaterThanEqual:
|
|
||||||
case AB_Equal:
|
|
||||||
case AB_NotEqual:
|
|
||||||
case AB_BitAnd:
|
|
||||||
case AB_BitXOr:
|
|
||||||
case AB_BitOr:
|
|
||||||
case AB_PROP_SET:
|
|
||||||
case AB_ARRAYA:
|
|
||||||
case AB_CONDN:
|
|
||||||
case AB_COND:
|
|
||||||
case AB_POP_TO:
|
|
||||||
case AB_RETURN:
|
|
||||||
// JUMPAND/JUMPOR/JUMPNNIL are special: They either jump over instructions adding one to the stack
|
|
||||||
// or decrement the stack. Thus, for stack counting purposes, they decrement.
|
|
||||||
case AB_JUMPAND:
|
|
||||||
case AB_JUMPOR:
|
|
||||||
case AB_JUMPNNIL:
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
case AB_FUNC:
|
|
||||||
return -reinterpret_cast<C4AulFunc *>(X)->GetParCount() + 1;
|
|
||||||
|
|
||||||
case AB_CALL:
|
|
||||||
case AB_CALLFS:
|
|
||||||
return -C4AUL_MAX_Par;
|
|
||||||
|
|
||||||
case AB_STACK_SET:
|
|
||||||
case AB_LOCALN_SET:
|
|
||||||
case AB_PROP:
|
|
||||||
case AB_GLOBALN_SET:
|
|
||||||
case AB_Inc:
|
|
||||||
case AB_Dec:
|
|
||||||
case AB_BitNot:
|
|
||||||
case AB_Not:
|
|
||||||
case AB_Neg:
|
|
||||||
case AB_PAR:
|
|
||||||
case AB_FOREACH_NEXT:
|
|
||||||
case AB_ERR:
|
|
||||||
case AB_EOFN:
|
|
||||||
case AB_JUMP:
|
|
||||||
case AB_DEBUG:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case AB_STACK:
|
|
||||||
return X;
|
|
||||||
|
|
||||||
case AB_NEW_ARRAY:
|
|
||||||
return -X+1;
|
|
||||||
|
|
||||||
case AB_NEW_PROPLIST:
|
|
||||||
return -X * 2 + 1;
|
|
||||||
|
|
||||||
case AB_ARRAYA_SET:
|
|
||||||
case AB_ARRAY_SLICE:
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
case AB_ARRAY_SLICE_SET:
|
|
||||||
return -3;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulParse::DebugChunk()
|
void C4AulParse::DebugChunk()
|
||||||
{
|
{
|
||||||
if (C4AulDebug::GetDebugger())
|
if (C4AulDebug::GetDebugger())
|
||||||
AddBCC(AB_DEBUG);
|
AddBCC(AB_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
int C4AulCompiler::AddBCC(const char * TokenSPos, C4AulBCCType eType, intptr_t X)
|
|
||||||
{
|
|
||||||
// Track stack size
|
|
||||||
iStack += GetStackValue(eType, X);
|
|
||||||
|
|
||||||
// Use stack operation instead of 0-Any (enable optimization)
|
|
||||||
if (eType == AB_NIL)
|
|
||||||
{
|
|
||||||
eType = AB_STACK;
|
|
||||||
X = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join checks only if it's not a jump target
|
|
||||||
if (!fJump && Fn->GetLastCode())
|
|
||||||
{
|
|
||||||
C4AulBCC *pCPos1 = Fn->GetLastCode();
|
|
||||||
|
|
||||||
// Skip noop stack operation
|
|
||||||
if(eType == AB_STACK && X == 0)
|
|
||||||
{
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join together stack operations
|
|
||||||
if(eType == AB_STACK && pCPos1->bccType == AB_STACK &&
|
|
||||||
(X <= 0 || pCPos1->Par.i >= 0))
|
|
||||||
{
|
|
||||||
pCPos1->Par.i += X;
|
|
||||||
// Empty? Remove it. This relies on the parser not issuing
|
|
||||||
// multiple negative stack operations consecutively, as
|
|
||||||
// that could result in removing a jump target bytecode.
|
|
||||||
if (!pCPos1->Par.i)
|
|
||||||
Fn->RemoveLastBCC();
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prune unneeded Incs / Decs
|
|
||||||
if(eType == AB_STACK && X < 0 && (pCPos1->bccType == AB_Inc || pCPos1->bccType == AB_Dec))
|
|
||||||
{
|
|
||||||
if(!pCPos1->Par.X)
|
|
||||||
{
|
|
||||||
pCPos1->bccType = eType;
|
|
||||||
pCPos1->Par.i = X;
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If it was a result modifier, we can safely remove it knowing that it was neither
|
|
||||||
// the first chunk nor a jump target. We can therefore apply additional optimizations.
|
|
||||||
Fn->RemoveLastBCC();
|
|
||||||
pCPos1--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join STACK_SET + STACK -1 to POP_TO (equivalent)
|
|
||||||
if(eType == AB_STACK && X == -1 && pCPos1->bccType == AB_STACK_SET)
|
|
||||||
{
|
|
||||||
pCPos1->bccType = AB_POP_TO;
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join POP_TO + DUP to AB_STACK_SET if both target the same slot
|
|
||||||
if(eType == AB_DUP && pCPos1->bccType == AB_POP_TO && X == pCPos1->Par.i + 1)
|
|
||||||
{
|
|
||||||
pCPos1->bccType = AB_STACK_SET;
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce some constructs like SUM + INT 1 to INC or DEC
|
|
||||||
if((eType == AB_Sum || eType == AB_Sub) &&
|
|
||||||
pCPos1->bccType == AB_INT &&
|
|
||||||
(pCPos1->Par.i == 1 || pCPos1->Par.i == -1))
|
|
||||||
{
|
|
||||||
if((pCPos1->Par.i > 0) == (eType == AB_Sum))
|
|
||||||
pCPos1->bccType = AB_Inc;
|
|
||||||
else
|
|
||||||
pCPos1->bccType = AB_Dec;
|
|
||||||
pCPos1->Par.i = X;
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce Not + CONDN to COND, Not + COND to CONDN
|
|
||||||
if((eType == AB_CONDN || eType == AB_COND) && pCPos1->bccType == AB_Not)
|
|
||||||
{
|
|
||||||
pCPos1->bccType = eType == AB_CONDN ? AB_COND : AB_CONDN;
|
|
||||||
pCPos1->Par.i = X + 1;
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add
|
|
||||||
Fn->AddBCC(eType, X, TokenSPos);
|
|
||||||
|
|
||||||
// Reset jump flag
|
|
||||||
fJump = false;
|
|
||||||
|
|
||||||
return Fn->GetCodePos() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::RemoveLastBCC()
|
|
||||||
{
|
|
||||||
// Security: This is unsafe on anything that might get optimized away
|
|
||||||
C4AulBCC *pBCC = Fn->GetLastCode();
|
|
||||||
assert(pBCC->bccType != AB_STACK && pBCC->bccType != AB_STACK_SET && pBCC->bccType != AB_POP_TO);
|
|
||||||
// Correct stack
|
|
||||||
iStack -= GetStackValue(pBCC->bccType, pBCC->Par.X);
|
|
||||||
// Remove
|
|
||||||
Fn->RemoveLastBCC();
|
|
||||||
}
|
|
||||||
|
|
||||||
C4V_Type C4AulCompiler::GetLastRetType(C4AulScriptEngine * Engine, C4V_Type to)
|
|
||||||
{
|
|
||||||
C4V_Type from;
|
|
||||||
switch (Fn->GetLastCode()->bccType)
|
|
||||||
{
|
|
||||||
case AB_INT: from = Config.Developer.ExtraWarnings || Fn->GetLastCode()->Par.i ? C4V_Int : C4V_Any; break;
|
|
||||||
case AB_STRING: from = C4V_String; break;
|
|
||||||
case AB_NEW_ARRAY: case AB_CARRAY: case AB_ARRAY_SLICE: from = C4V_Array; break;
|
|
||||||
case AB_CFUNCTION: from = C4V_Function; break;
|
|
||||||
case AB_NEW_PROPLIST: case AB_CPROPLIST: from = C4V_PropList; break;
|
|
||||||
case AB_BOOL: from = C4V_Bool; break;
|
|
||||||
case AB_FUNC:
|
|
||||||
from = Fn->GetLastCode()->Par.f->GetRetType(); break;
|
|
||||||
case AB_CALL: case AB_CALLFS:
|
|
||||||
{
|
|
||||||
C4String * pName = Fn->GetLastCode()->Par.s;
|
|
||||||
C4AulFunc * pFunc2 = Engine->GetFirstFunc(pName->GetCStr());
|
|
||||||
bool allwarn = true;
|
|
||||||
from = C4V_Any;
|
|
||||||
while (pFunc2 && allwarn)
|
|
||||||
{
|
|
||||||
from = pFunc2->GetRetType();
|
|
||||||
if (!C4Value::WarnAboutConversion(from, to))
|
|
||||||
{
|
|
||||||
allwarn = false;
|
|
||||||
from = C4V_Any;
|
|
||||||
}
|
|
||||||
pFunc2 = Engine->GetNextSNFunc(pFunc2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AB_Inc: case AB_Dec: case AB_BitNot: case AB_Neg:
|
|
||||||
case AB_Pow: case AB_Div: case AB_Mul: case AB_Mod: case AB_Sub: case AB_Sum:
|
|
||||||
case AB_LeftShift: case AB_RightShift: case AB_BitAnd: case AB_BitXOr: case AB_BitOr:
|
|
||||||
from = C4V_Int; break;
|
|
||||||
case AB_Not: case AB_LessThan: case AB_LessThanEqual: case AB_GreaterThan: case AB_GreaterThanEqual:
|
|
||||||
case AB_Equal: case AB_NotEqual:
|
|
||||||
from = C4V_Bool; break;
|
|
||||||
case AB_DUP:
|
|
||||||
{
|
|
||||||
int pos = Fn->GetLastCode()->Par.i + iStack - 2 + Fn->VarNamed.iSize + Fn->GetParCount();
|
|
||||||
if (pos < Fn->GetParCount())
|
|
||||||
from = Fn->GetParType()[pos];
|
|
||||||
else
|
|
||||||
from = C4V_Any;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
from = C4V_Any; break;
|
|
||||||
}
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
|
|
||||||
C4AulBCC C4AulCompiler::MakeSetter(const char * SPos, bool fLeaveValue)
|
|
||||||
{
|
|
||||||
C4AulBCC Value = *(Fn->GetLastCode()), Setter = Value;
|
|
||||||
// Check type
|
|
||||||
switch (Value.bccType)
|
|
||||||
{
|
|
||||||
case AB_ARRAYA: Setter.bccType = AB_ARRAYA_SET; break;
|
|
||||||
case AB_ARRAY_SLICE: Setter.bccType = AB_ARRAY_SLICE_SET; break;
|
|
||||||
case AB_DUP:
|
|
||||||
Setter.bccType = AB_STACK_SET;
|
|
||||||
// the setter additionally has the new value on the stack
|
|
||||||
--Setter.Par.i;
|
|
||||||
break;
|
|
||||||
case AB_STACK_SET: Setter.bccType = AB_STACK_SET; break;
|
|
||||||
case AB_LOCALN:
|
|
||||||
Setter.bccType = AB_LOCALN_SET;
|
|
||||||
break;
|
|
||||||
case AB_PROP:
|
|
||||||
Setter.bccType = AB_PROP_SET;
|
|
||||||
break;
|
|
||||||
case AB_GLOBALN: Setter.bccType = AB_GLOBALN_SET; break;
|
|
||||||
default:
|
|
||||||
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.
|
|
||||||
// All getters push one value, so the parameter count is one more than the values they pop from the stack.
|
|
||||||
int iParCount = 1 - GetStackValue(Value.bccType, Value.Par.X);
|
|
||||||
if (Value.bccType == AB_STACK_SET)
|
|
||||||
{
|
|
||||||
// STACK_SET has a side effect, so it can't be simply removed.
|
|
||||||
// Discard the unused value the usual way instead.
|
|
||||||
if (!fLeaveValue)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (!fLeaveValue || iParCount)
|
|
||||||
{
|
|
||||||
RemoveLastBCC();
|
|
||||||
fJump = true; // In case the original BCC was a jump target
|
|
||||||
}
|
|
||||||
if (fLeaveValue && iParCount)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < iParCount; i++)
|
|
||||||
AddBCC(SPos, AB_DUP, 1 - iParCount);
|
|
||||||
// Finally re-add original BCC
|
|
||||||
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));
|
|
||||||
return Setter;
|
|
||||||
}
|
|
||||||
|
|
||||||
int C4AulParse::AddVarAccess(C4AulBCCType eType, intptr_t varnum)
|
int C4AulParse::AddVarAccess(C4AulBCCType eType, intptr_t varnum)
|
||||||
{
|
{
|
||||||
return AddBCC(eType, 1 + varnum - (codegen.iStack + Fn->VarNamed.iSize));
|
return AddBCC(eType, 1 + varnum - (codegen.iStack + Fn->VarNamed.iSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
int C4AulCompiler::JumpHere()
|
|
||||||
{
|
|
||||||
// Set flag so the next generated code chunk won't get joined
|
|
||||||
fJump = true;
|
|
||||||
return Fn->GetCodePos();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 C4AulCompiler::SetJumpHere(int iJumpOp)
|
|
||||||
{
|
|
||||||
// Set target
|
|
||||||
C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp);
|
|
||||||
assert(IsJump(pBCC->bccType));
|
|
||||||
pBCC->Par.i = Fn->GetCodePos() - iJumpOp;
|
|
||||||
// Set flag so the next generated code chunk won't get joined
|
|
||||||
fJump = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::SetJump(int iJumpOp, int iWhere)
|
|
||||||
{
|
|
||||||
// Set target
|
|
||||||
C4AulBCC *pBCC = Fn->GetCodeByPos(iJumpOp);
|
|
||||||
assert(IsJump(pBCC->bccType));
|
|
||||||
pBCC->Par.i = iWhere - iJumpOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::AddJump(const char * SPos, C4AulBCCType eType, int iWhere)
|
|
||||||
{
|
|
||||||
AddBCC(SPos, eType, iWhere - Fn->GetCodePos());
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::PushLoop()
|
|
||||||
{
|
|
||||||
Loop *pNew = new Loop();
|
|
||||||
pNew->StackSize = iStack;
|
|
||||||
pNew->Controls = NULL;
|
|
||||||
pNew->Next = pLoopStack;
|
|
||||||
pLoopStack = pNew;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::PopLoop(int ContinueJump)
|
|
||||||
{
|
|
||||||
// Set targets for break/continue
|
|
||||||
for (Loop::Control *pCtrl = pLoopStack->Controls; pCtrl; pCtrl = pCtrl->Next)
|
|
||||||
if (pCtrl->Break)
|
|
||||||
SetJumpHere(pCtrl->Pos);
|
|
||||||
else
|
|
||||||
SetJump(pCtrl->Pos, ContinueJump);
|
|
||||||
// Delete loop controls
|
|
||||||
Loop *pLoop = pLoopStack;
|
|
||||||
while (pLoop->Controls)
|
|
||||||
{
|
|
||||||
// Unlink
|
|
||||||
Loop::Control *pCtrl = pLoop->Controls;
|
|
||||||
pLoop->Controls = pCtrl->Next;
|
|
||||||
// Delete
|
|
||||||
delete pCtrl;
|
|
||||||
}
|
|
||||||
// Unlink & delete
|
|
||||||
pLoopStack = pLoop->Next;
|
|
||||||
delete pLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::AddLoopControl(const char * SPos, bool fBreak)
|
|
||||||
{
|
|
||||||
// Insert code
|
|
||||||
if (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(SPos, AB_JUMP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C4AulCompiler::ErrorOut(const char * SPos, C4AulError & e)
|
|
||||||
{
|
|
||||||
// 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
|
|
||||||
const char * msg = e.what();
|
|
||||||
if (SEqual2(msg, "ERROR: ")) msg += 7;
|
|
||||||
AddBCC(SPos, AB_ERR, reinterpret_cast<intptr_t>(::Strings.RegString(msg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * C4AulParse::GetTokenName(C4AulTokenType TokenType)
|
const char * C4AulParse::GetTokenName(C4AulTokenType TokenType)
|
||||||
{
|
{
|
||||||
switch (TokenType)
|
switch (TokenType)
|
||||||
|
|
|
@ -18,53 +18,12 @@
|
||||||
#define INC_C4AulParse
|
#define INC_C4AulParse
|
||||||
|
|
||||||
#include "script/C4Aul.h"
|
#include "script/C4Aul.h"
|
||||||
|
#include "script/C4AulCompiler.h"
|
||||||
#include "script/C4AulScriptFunc.h"
|
#include "script/C4AulScriptFunc.h"
|
||||||
|
|
||||||
enum C4AulBCCType : int;
|
enum C4AulBCCType : int;
|
||||||
enum C4AulTokenType : int;
|
enum C4AulTokenType : int;
|
||||||
|
|
||||||
class C4AulCompiler
|
|
||||||
{
|
|
||||||
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, C4AulError & e);
|
|
||||||
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);
|
|
||||||
~C4AulCompiler()
|
|
||||||
{ while (pLoopStack) PopLoop(0); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct C4ScriptOpDef
|
struct C4ScriptOpDef
|
||||||
{
|
{
|
||||||
unsigned short Priority;
|
unsigned short Priority;
|
||||||
|
|
Loading…
Reference in New Issue