oscar64/oscar64/Constexpr.cpp

1590 lines
35 KiB
C++

#include "Constexpr.h"
#include <math.h>
ConstexprInterpreter::Value::Value(void)
: mDecType(TheVoidTypeDeclaration), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mData(mShortData), mDataSize(0)
{
}
ConstexprInterpreter::Value::Value(const Location & location)
: mLocation(location),
mDecType(TheVoidTypeDeclaration), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mData(mShortData), mDataSize(0)
{
}
ConstexprInterpreter::Value::Value(Expression* exp)
: mLocation(exp->mLocation),
mDecType(exp->mDecType), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mDataSize(exp->mDecType->mSize)
{
assert(exp->mType == EX_CONSTANT);
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
PutConst(0, exp->mDecValue);
}
void ConstexprInterpreter::Value::PutConst(int offset, Declaration* dec)
{
switch (dec->mType)
{
case DT_CONST_INTEGER:
case DT_CONST_ADDRESS:
PutIntAt(dec->mInteger, offset, dec->mBase);
break;
case DT_CONST_FLOAT:
PutFloatAt(float(dec->mNumber), offset, dec->mBase);
break;
case DT_CONST_STRUCT:
for (Declaration* pdec = dec->mParams; pdec; pdec = pdec->mNext)
PutConst(pdec->mOffset, pdec);
break;
case DT_CONST_DATA:
for (int i = 0; i < dec->mBase->mSize; i++)
PutIntAt(dec->mData[i], offset + i, TheConstCharTypeDeclaration);
break;
case DT_CONST_POINTER:
PutPtrAt(new Value(mLocation, dec->mValue->mDecValue, dec->mBase, 0), offset, dec);
break;
}
}
ConstexprInterpreter::Value::Value(const Location& location, Declaration* dec)
: mLocation(location),
mDecType(dec), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mDataSize(dec->mSize)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
}
ConstexprInterpreter::Value::Value(const Location& location, Declaration* dec, int size)
: mLocation(location),
mDecType(dec), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mDataSize(size)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
}
ConstexprInterpreter::Value::Value(const Value& value)
: mLocation(value.mLocation),
mDecType(value.mDecType), mDecValue(nullptr),
mBaseValue(value.mBaseValue), mOffset(value.mOffset),
mDataSize(value.mDataSize)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
for (int i = 0; i < mDataSize; i++)
mData[i] = value.mData[i];
}
ConstexprInterpreter::Value::Value(Value&& value)
: mLocation(value.mLocation),
mDecType(value.mDecType), mDecValue(nullptr),
mBaseValue(value.mBaseValue), mOffset(value.mOffset),
mDataSize(value.mDataSize)
{
if (mDataSize <= 4)
{
mData = mShortData;
for (int i = 0; i < mDataSize; i++)
mData[i] = value.mData[i];
}
else
{
mData = value.mData;
value.mData = value.mShortData;
}
}
ConstexprInterpreter::Value::Value(Value* value)
: mLocation(value->mLocation),
mDecType(value->mDecType), mDecValue(value->mDecValue),
mBaseValue(value), mOffset(0),
mDataSize(0), mData(mShortData)
{
}
ConstexprInterpreter::Value::Value(const Location& location, Value* value, Declaration* type, int offset)
: mLocation(location),
mDecType(type), mDecValue(nullptr),
mBaseValue(value), mOffset(offset),
mDataSize(0), mData(mShortData)
{
}
ConstexprInterpreter::Value::Value(const Location& location, Declaration* value, Declaration* type, int offset)
: mLocation(location),
mDecType(type), mDecValue(value),
mBaseValue(nullptr), mOffset(offset),
mDataSize(0), mData(mShortData)
{
}
ConstexprInterpreter::Value::Value(const Location& location, const uint8* data, Declaration* type)
: mLocation(location),
mDecType(type), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mDataSize(type->mSize)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
for (int i = 0; i < mDataSize; i++)
mData[i].mByte = data[i];
}
ConstexprInterpreter::Value::Value(const Location& location, const ValueItem* data, Declaration* type)
: mLocation(location),
mDecType(type), mDecValue(nullptr),
mBaseValue(nullptr), mOffset(0),
mDataSize(type->mSize)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
for (int i = 0; i < mDataSize; i++)
mData[i] = data[i];
}
ConstexprInterpreter::Value::~Value(void)
{
if (mData != mShortData)
delete[] mData;
}
ConstexprInterpreter::Value& ConstexprInterpreter::Value::operator=(const Value& v)
{
if (mData != mShortData)
{
delete[] mData;
mData = mShortData;
}
mLocation = v.mLocation;
mDecType = v.mDecType;
mBaseValue = v.mBaseValue;
mDataSize = v.mDataSize;
mOffset = v.mOffset;
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
for (int i = 0; i < mDataSize; i++)
mData[i] = v.mData[i];
return *this;
}
ConstexprInterpreter::Value& ConstexprInterpreter::Value::operator=(Value&& v)
{
if (mData != mShortData)
{
delete[] mData;
mData = mShortData;
}
mLocation = v.mLocation;
mDecType = v.mDecType;
mBaseValue = v.mBaseValue;
mDataSize = v.mDataSize;
mOffset = v.mOffset;
if (mDataSize <= 4)
{
mData = mShortData;
for (int i = 0; i < mDataSize; i++)
mData[i] = v.mData[i];
}
else
{
mData = v.mData;
v.mData = v.mShortData;
}
return *this;
}
ConstexprInterpreter::ValueItem* ConstexprInterpreter::Value::GetAddr(void)
{
if (mBaseValue)
return mBaseValue->mData + mOffset;
else
return mData;
}
const ConstexprInterpreter::ValueItem* ConstexprInterpreter::Value::GetAddr(void) const
{
if (mBaseValue)
return mBaseValue->mData + mOffset;
else
return mData;
}
int64 ConstexprInterpreter::Value::GetInt(void) const
{
return GetIntAt(0, mDecType);
}
double ConstexprInterpreter::Value::GetFloat(void) const
{
return GetFloatAt(0, mDecType);
}
ConstexprInterpreter::Value ConstexprInterpreter::Value::GetPtr(void) const
{
return GetPtrAt(0, mDecType->mBase);
}
void ConstexprInterpreter::Value::PutInt(int64 v)
{
PutIntAt(v, 0, mDecType);
}
void ConstexprInterpreter::Value::PutFloat(double v)
{
PutFloatAt(v, 0, mDecType);
}
void ConstexprInterpreter::Value::PutPtr(const Value& v)
{
PutPtrAt(v, 0, mDecType);
}
int64 ConstexprInterpreter::Value::GetIntAt(int at, Declaration* type) const
{
if (type->mType == DT_TYPE_FLOAT)
{
return int64(GetFloatAt(at, type));
}
else
{
const ValueItem* dp = GetAddr() + at;
if (type->mFlags & DTF_SIGNED)
{
switch (type->mSize)
{
case 1:
return int8(dp[0].mByte);
case 2:
return int16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8));
case 4:
return int32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24));
}
}
else
{
switch (type->mSize)
{
case 1:
return uint8(dp[0].mByte);
case 2:
return uint16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8));
case 4:
return uint32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24));
}
}
}
return 0;
}
double ConstexprInterpreter::Value::GetFloatAt(int at, Declaration* type) const
{
if (type->mType == DT_TYPE_FLOAT)
{
const ValueItem* dp = GetAddr() + at;
union
{
float f;
uint32 i;
} u;
u.i = uint32(dp[0].mByte | ((uint32)(dp[1].mByte) << 8) | ((uint32)(dp[2].mByte) << 16) | ((uint32)(dp[3].mByte) << 24));
return u.f;
}
else
{
int64 iv = GetIntAt(at, type);
return double(iv);
}
}
ConstexprInterpreter::Value ConstexprInterpreter::Value::GetPtrAt(int at, Declaration* type) const
{
const ValueItem* dp = GetAddr() + at;
return Value(mLocation, dp->mBaseValue, type, uint16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8)));
}
void ConstexprInterpreter::Value::PutVarAt(Declaration* var, int64 v, int at, Declaration* type)
{
ValueItem* dp = GetAddr() + at;
dp[0].mByte = uint8(v & 0xff);
dp[1].mByte = uint8((v >> 8) & 0xff);
mDecValue = var;
}
void ConstexprInterpreter::Value::PutIntAt(int64 v, int at, Declaration* type)
{
if (type->mType == DT_TYPE_FLOAT)
{
PutFloatAt(float(v), at, type);
}
else
{
ValueItem* dp = GetAddr() + at;
switch (type->mSize)
{
case 4:
dp[3].mByte = uint8((v >> 24) & 0xff);
dp[2].mByte = uint8((v >> 16) & 0xff);
case 2:
dp[1].mByte = uint8((v >> 8) & 0xff);
case 1:
dp[0].mByte = uint8(v & 0xff);
}
}
}
void ConstexprInterpreter::Value::PutFloatAt(double v, int at, Declaration* type)
{
if (type->mType == DT_TYPE_FLOAT)
{
ValueItem* dp = GetAddr() + at;
union
{
float f;
uint32 i;
} u;
u.f = float(v);
dp[3].mByte = uint8((u.i >> 24) & 0xff);
dp[2].mByte = uint8((u.i >> 16) & 0xff);
dp[1].mByte = uint8((u.i >> 8) & 0xff);
dp[0].mByte = uint8(u.i & 0xff);
}
else
{
PutIntAt(int64(v), at, type);
}
}
void ConstexprInterpreter::Value::PutPtrAt(const Value& v, int at, Declaration* type)
{
ValueItem* dp = GetAddr() + at;
dp[0].mBaseValue = v.mBaseValue;
dp[1].mByte = uint8((v.mOffset >> 8) & 0xff);
dp[0].mByte = uint8(v.mOffset & 0xff);
}
ConstexprInterpreter::Value ConstexprInterpreter::Value::ToRValue(void) const
{
if (mBaseValue)
return Value(mLocation, GetAddr(), mDecType);
else
return *this;
}
void ConstexprInterpreter::Value::Assign(const Value& v)
{
switch (mDecType->mType)
{
case DT_TYPE_INTEGER:
case DT_TYPE_BOOL:
PutInt(v.GetInt());
break;
case DT_TYPE_FLOAT:
PutFloat(v.GetFloat());
break;
case DT_TYPE_STRUCT:
case DT_TYPE_UNION:
case DT_TYPE_ARRAY:
{
const ConstexprInterpreter::ValueItem* sp = v.GetAddr();
ConstexprInterpreter::ValueItem* dp = GetAddr();
for (int i = 0; i < mDecType->mSize; i++)
dp[i] = sp[i];
} break;
case DT_TYPE_POINTER:
PutPtr(v.GetPtr());
break;
}
}
Declaration* ConstexprInterpreter::Value::GetConst(int offset, Declaration* type, LinkerSection* dataSection) const
{
Declaration* dec = nullptr;
switch (type->mType)
{
case DT_TYPE_INTEGER:
case DT_TYPE_BOOL:
case DT_TYPE_ENUM:
dec = new Declaration(mLocation, DT_CONST_INTEGER);
dec->mBase = type;
dec->mFlags = type->mFlags & DTF_SIGNED;
dec->mSize = type->mSize;
dec->mInteger = GetIntAt(offset, type);
break;
case DT_TYPE_FLOAT:
dec = new Declaration(mLocation, DT_CONST_FLOAT);
dec->mBase = type;
dec->mSize = type->mSize;
dec->mNumber = GetFloatAt(offset, type);
break;
case DT_TYPE_STRUCT:
{
dec = new Declaration(mLocation, DT_CONST_STRUCT);
dec->mBase = type;
dec->mSize = type->mSize;
dec->mSection = dataSection;
dec->mOffset = offset;
while (type)
{
for (Declaration* mdec = type->mParams; mdec; mdec = mdec->mNext)
{
Declaration* cdec = GetConst(offset + mdec->mOffset, mdec->mBase, dataSection);
cdec->mOffset = mdec->mOffset;
cdec->mNext = dec->mParams;
dec->mParams = cdec;
}
if (type->mVTable)
{
Declaration * cdec = new Declaration(mLocation, DT_CONST_INTEGER);
cdec->mBase = TheConstCharTypeDeclaration;
cdec->mSize = 1;
cdec->mInteger = type->mVTable->mDefaultConstructor->mInteger;
cdec->mOffset = offset + type->mVTable->mOffset;
cdec->mNext = dec->mParams;
dec->mParams = cdec;
}
if (type->mBase)
type = type->mBase->mBase;
else
type = nullptr;
}
break;
}
case DT_TYPE_ARRAY:
{
dec = new Declaration(mLocation, DT_CONST_STRUCT);
dec->mBase = type;
dec->mSize = type->mSize;
dec->mSection = dataSection;
dec->mOffset = offset;
Declaration* ldec = nullptr;
for (int i=0; i<type->mSize; i += type->mBase->mSize)
{
Declaration* cdec = GetConst(offset + i, type->mBase, dataSection);
if (type->mStride)
cdec->mOffset = i / type->mBase->mSize;
else
cdec->mOffset = i;
if (ldec)
ldec->mNext = cdec;
else
dec->mParams = cdec;
ldec = cdec;
}
break;
}
case DT_TYPE_POINTER:
{
Value vp = GetPtrAt(offset, type);
if (vp.mBaseValue)
{
dec = new Declaration(mLocation, DT_CONST_POINTER);
dec->mBase = type;
dec->mSize = type->mSize;
Declaration* target;
if (vp.mBaseValue->mDecValue)
{
target = new Declaration(mLocation, DT_VARIABLE_REF);
if (vp.mBaseValue->mDecValue->mType == DT_VARIABLE_REF)
{
target->mBase = vp.mBaseValue->mDecValue->mBase;
target->mOffset = vp.mBaseValue->mDecValue->mOffset;
}
else
target->mBase = vp.mBaseValue->mDecValue;
target->mOffset += vp.mOffset;
dec->mValue = new Expression(mLocation, EX_CONSTANT);
dec->mValue->mDecType = type;
dec->mValue->mDecValue = target;
return dec;
}
else if (vp.mBaseValue->mDecType->mType == DT_TYPE_ARRAY)
{
target = new Declaration(mLocation, DT_CONST_DATA);
target->mSize = vp.mBaseValue->mDataSize;
target->mBase = vp.mBaseValue->mDecType;
target->mSection = dataSection;
uint8* buffer = new uint8[target->mSize];
for (int i = 0; i < target->mSize; i++)
buffer[i] = uint8(vp.mBaseValue->GetIntAt(i, TheUnsignedCharTypeDeclaration));
target->mData = buffer;
}
else
target = vp.mBaseValue->GetConst(0, vp.mBaseValue->mDecType, dataSection);
dec->mValue = new Expression(mLocation, EX_CONSTANT);
dec->mValue->mDecType = target->mBase;
dec->mValue->mDecValue = target;
}
else if (vp.mDecValue)
{
dec = new Declaration(mLocation, DT_VARIABLE_REF);
dec->mBase = vp.mDecValue;
dec->mFlags = 0;
dec->mSize = type->mSize;
dec->mOffset = vp.mOffset;
}
else
{
dec = new Declaration(mLocation, DT_CONST_ADDRESS);
dec->mBase = type;
dec->mFlags = 0;
dec->mSize = type->mSize;
dec->mInteger = vp.mOffset;
}
break;
}
}
return dec;
}
Expression* ConstexprInterpreter::Value::ToExpression(LinkerSection* dataSection) const
{
Expression* exp = new Expression(mLocation, EX_CONSTANT);
exp->mDecType = mDecType;
exp->mDecValue = GetConst(0, mDecType, dataSection);
return exp;
}
ConstexprInterpreter::ConstexprInterpreter(const Location & location, Errors* err, LinkerSection* dataSection)
: mLocation(location), mErrors(err), mDataSection(dataSection), mParams(Value()), mLocals(Value()), mHeap(nullptr)
{
}
ConstexprInterpreter::~ConstexprInterpreter(void)
{
for (int i = 0; i < mTemps.Size(); i++)
delete mTemps[i];
}
ConstexprInterpreter::Value* ConstexprInterpreter::NewValue(Expression* exp, Declaration* type, int size)
{
Value* v = new Value(exp->mLocation, type, size);
mHeap->Push(v);
return v;
}
void ConstexprInterpreter::DeleteValue(Value* v)
{
int i = mHeap->IndexOf(v);
if (i >= 0)
{
delete v;
mHeap->Remove(i);
}
else
mErrors->Error(v->mLocation, EERR_DOUBLE_FREE, "Freeing not allocated memory");
}
Expression* ConstexprInterpreter::EvalConstructor(Expression* exp)
{
mProcType = exp->mLeft->mDecType;
Expression* pex = exp->mRight;
Declaration* cdec = exp->mLeft->mDecType->mParams;
int pos = 0;
mResult = Value(exp->mLocation, cdec->mBase->mBase);
mParams[pos] = Value(exp->mLocation, cdec->mBase);
mParams[pos].PutPtr(Value(&mResult));
pos = 2;
if (pex->mType == EX_LIST)
pex = pex->mRight;
else
pex = nullptr;
cdec = cdec->mNext;
while (pex && pex->mType == EX_LIST)
{
if (!AddParam(pos, pex->mLeft, cdec))
return exp;
pex = pex->mRight;
if (cdec)
cdec = cdec->mNext;
}
if (pex)
{
if (!AddParam(pos, pex, cdec))
return exp;
}
mHeap = new ExpandingArray<Value*>();
Execute(exp->mLeft->mDecValue->mValue);
if (mHeap->Size() > 0)
mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr");
delete mHeap;
return mResult.ToExpression(mDataSection);
}
Expression* ConstexprInterpreter::EvalTempConstructor(Expression* exp)
{
Expression* cexp = exp->mLeft->mLeft;
mProcType = cexp->mLeft->mDecType;
Expression* pex = cexp->mRight;
Declaration* dec = cexp->mLeft->mDecType->mParams;
Value othis = Value(exp->mLocation, exp->mRight->mDecType);
mParams[0] = Value(exp->mLocation, dec->mBase);
mParams[0].PutPtr(Value(&othis));
int pos = 2;
if (pex->mType == EX_LIST)
pex = pex->mRight;
else
pex = nullptr;
dec = dec->mNext;
while (pex && pex->mType == EX_LIST)
{
if (!AddParam(pos, pex->mLeft, dec))
return exp;
pex = pex->mRight;
if (dec)
dec = dec->mNext;
}
if (pex)
{
if (!AddParam(pos, pex, dec))
return exp;
}
mHeap = new ExpandingArray<Value*>();
Execute(cexp->mLeft->mDecValue->mValue);
if (mHeap->Size() > 0)
mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr");
delete mHeap;
return othis.ToExpression(mDataSection);
}
bool ConstexprInterpreter::AddParam(int& pos, Expression* pex, Declaration* dec)
{
if (dec)
pos = dec->mVarIndex;
if (pex->mType == EX_CONSTANT)
{
if (pex->mDecType->mType == DT_TYPE_ARRAY)
{
Value* tmp = new Value(pex);
mTemps.Push(tmp);
mParams[pos] = Value(pex->mLocation, pex->mDecType->BuildArrayPointer());
mParams[pos].PutPtr(Value(tmp));
}
else
mParams[pos] = Value(pex);
}
else if (pex->mType == EX_VARIABLE && (pex->mDecValue->mFlags & DTF_CONST))
{
mParams[pos] = Value(pex->mLocation, pex->mDecValue->mBase);
if (pex->mDecValue->mSize > 0)
{
if (pex->mDecValue->mValue)
mParams[pos].PutConst(0, pex->mDecValue->mValue->mDecValue);
else
return false;
}
}
else
return false;
return true;
}
Expression* ConstexprInterpreter::EvalCall(Expression* exp)
{
if (!exp->mLeft->mDecValue || !exp->mLeft->mDecValue->mValue)
return exp;
mProcType = exp->mLeft->mDecType;
Expression* pex = exp->mRight;
Declaration* dec = exp->mLeft->mDecType->mParams;
int pos = 0;
if (mProcType->mBase && mProcType->mBase->mType == DT_TYPE_STRUCT)
{
mResult = Value(exp->mLocation, mProcType->mBase);
mParams[0] = Value(&mResult);
pos = 2;
}
while (pex && pex->mType == EX_LIST)
{
if (!AddParam(pos, pex->mLeft, dec))
return exp;
pex = pex->mRight;
if (dec)
dec = dec->mNext;
}
if (pex)
{
if (!AddParam(pos, pex, dec))
return exp;
}
mHeap = new ExpandingArray<Value*>();
Execute(exp->mLeft->mDecValue->mValue);
if (mHeap->Size() > 0)
mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr");
delete mHeap;
return mResult.ToExpression(mDataSection);
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalBinary(Expression * exp, const Value& vl, const Value& vr)
{
Value v(exp->mLocation, exp->mDecType);
if (exp->mDecType->mType == DT_TYPE_FLOAT)
{
switch (exp->mToken)
{
case TK_ADD:
case TK_ASSIGN_ADD:
v.PutFloat(vl.GetFloat() + vr.GetFloat());
break;
case TK_SUB:
case TK_ASSIGN_SUB:
v.PutFloat(vl.GetFloat() - vr.GetFloat());
break;
case TK_MUL:
case TK_ASSIGN_MUL:
v.PutFloat(vl.GetFloat() * vr.GetFloat());
break;
case TK_DIV:
case TK_ASSIGN_DIV:
if (vr.GetInt() == 0)
mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero");
else
v.PutFloat(vl.GetFloat() / vr.GetFloat());
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
else if (exp->mDecType->mType == DT_TYPE_POINTER)
{
Value vlp = vl.GetPtr();
vlp.mOffset += int(vr.GetInt() * vl.mDecType->mBase->mSize);
v.PutPtr(vlp);
}
else
{
switch (exp->mToken)
{
case TK_ADD:
case TK_ASSIGN_ADD:
v.PutInt(vl.GetInt() + vr.GetInt());
break;
case TK_SUB:
case TK_ASSIGN_SUB:
v.PutInt(vl.GetInt() - vr.GetInt());
break;
case TK_MUL:
case TK_ASSIGN_MUL:
v.PutInt(vl.GetInt() * vr.GetInt());
break;
case TK_DIV:
case TK_ASSIGN_DIV:
if (vr.GetInt() == 0)
mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero");
else
v.PutInt(vl.GetInt() / vr.GetInt());
break;
case TK_MOD:
case TK_ASSIGN_MOD:
if (vr.GetInt() == 0)
mErrors->Error(exp->mLocation, EERR_INVALID_VALUE, "Constant division by zero");
else
v.PutInt(vl.GetInt() % vr.GetInt());
break;
case TK_LEFT_SHIFT:
case TK_ASSIGN_SHL:
v.PutInt(vl.GetInt() << vr.GetInt());
break;
case TK_RIGHT_SHIFT:
case TK_ASSIGN_SHR:
v.PutInt(vl.GetInt() >> vr.GetInt());
break;
case TK_BINARY_AND:
case TK_ASSIGN_AND:
v.PutInt(vl.GetInt() & vr.GetInt());
break;
case TK_BINARY_OR:
case TK_ASSIGN_OR:
v.PutInt(vl.GetInt() | vr.GetInt());
break;
case TK_BINARY_XOR:
case TK_ASSIGN_XOR:
v.PutInt(vl.GetInt() ^ vr.GetInt());
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
return v;
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalRelational(Expression* exp, const Value& vl, const Value& vr)
{
Value v(exp->mLocation, TheBoolTypeDeclaration);
bool check = false;
if (vl.mDecType->mType == DT_TYPE_FLOAT || vr.mDecType->mType == DT_TYPE_FLOAT)
{
switch (exp->mToken)
{
case TK_EQUAL:
check = vl.GetFloat() == vr.GetFloat();
break;
case TK_NOT_EQUAL:
check = vl.GetFloat() != vr.GetFloat();
break;
case TK_GREATER_THAN:
check = vl.GetFloat() > vr.GetFloat();
break;
case TK_GREATER_EQUAL:
check = vl.GetFloat() >= vr.GetFloat();
break;
case TK_LESS_THAN:
check = vl.GetFloat() < vr.GetFloat();
break;
case TK_LESS_EQUAL:
check = vl.GetFloat() <= vr.GetFloat();
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
else if (vl.mDecType->mType == DT_TYPE_POINTER && vr.mDecType->mType == DT_TYPE_POINTER)
{
Value pl = vl.GetPtr();
Value pr = vr.GetPtr();
if (pl.mBaseValue == pr.mBaseValue)
{
switch (exp->mToken)
{
case TK_EQUAL:
check = pl.mOffset == pr.mOffset;
break;
case TK_NOT_EQUAL:
check = pl.mOffset != pr.mOffset;
break;
case TK_GREATER_THAN:
check = pl.mOffset > pr.mOffset;
break;
case TK_GREATER_EQUAL:
check = pl.mOffset >= pr.mOffset;
break;
case TK_LESS_THAN:
check = pl.mOffset < pr.mOffset;
break;
case TK_LESS_EQUAL:
check = pl.mOffset <= pr.mOffset;
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
else
{
switch (exp->mToken)
{
case TK_EQUAL:
check = false;
break;
case TK_NOT_EQUAL:
check = true;
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
}
else
{
switch (exp->mToken)
{
case TK_EQUAL:
check = vl.GetInt() == vr.GetInt();
break;
case TK_NOT_EQUAL:
check = vl.GetInt() != vr.GetInt();
break;
case TK_GREATER_THAN:
check = vl.GetInt() > vr.GetInt();
break;
case TK_GREATER_EQUAL:
check = vl.GetInt() >= vr.GetInt();
break;
case TK_LESS_THAN:
check = vl.GetInt() < vr.GetInt();
break;
case TK_LESS_EQUAL:
check = vl.GetInt() <= vr.GetInt();
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
v.PutInt(check ? 1 : 0);
return v;
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalUnary(Expression* exp, const Value& vl)
{
Value v(exp->mLocation, exp->mDecType);
if (exp->mDecType->mType == DT_TYPE_FLOAT)
{
switch (exp->mToken)
{
case TK_ADD:
v.PutFloat(vl.GetFloat());
break;
case TK_SUB:
v.PutFloat(-vl.GetFloat());
break;
case TK_INC:
v.PutFloat(vl.GetFloat() + 1);
break;
case TK_DEC:
v.PutFloat(vl.GetFloat() - 1);
break;
case TK_MUL:
return vl.GetPtr();
case TK_SIZEOF:
v.PutInt(vl.mDecType->mSize);
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
else
{
switch (exp->mToken)
{
case TK_ADD:
v.PutInt(vl.GetInt());
break;
case TK_SUB:
v.PutInt(-vl.GetInt());
break;
case TK_BINARY_NOT:
v.PutInt(~vl.GetInt());
break;
case TK_INC:
v.PutInt(vl.GetInt() + 1);
break;
case TK_DEC:
v.PutInt(vl.GetInt() - 1);
break;
case TK_BINARY_AND:
if (vl.mBaseValue)
v.PutPtr(vl);
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not an addressable value");
break;
case TK_MUL:
return vl.GetPtr();
case TK_NEW:
v.PutPtr(Value(NewValue(exp, exp->mDecType->mBase, int(vl.GetInt()))));
break;
case TK_DELETE:
DeleteValue(vl.GetPtr().mBaseValue);
break;
default:
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible operator", TokenNames[exp->mToken]);
}
}
return v;
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalTypeCast(Expression* exp, const Value& vl, Declaration* type)
{
Value v(exp->mLocation, type);
if (type->mType == DT_TYPE_FLOAT)
v.PutFloat(vl.GetFloat());
else if (type->IsIntegerType())
v.PutInt(vl.GetInt());
return v;
}
ConstexprInterpreter::Value ConstexprInterpreter::REval(Expression* exp)
{
return Eval(exp).ToRValue();
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalCall(Expression* exp, ConstexprInterpreter* caller)
{
mHeap = caller->mHeap;
mProcType = exp->mLeft->mDecType;
Expression* pex = exp->mRight;
Declaration* dec = exp->mLeft->mDecType->mParams;
int pos = 0;
if (mProcType->mBase && mProcType->mBase->mType == DT_TYPE_STRUCT)
{
mResult = Value(exp->mLocation, mProcType->mBase);
mParams[0] = Value(&mResult);
pos = 2;
}
while (pex && pex->mType == EX_LIST)
{
if (dec)
pos = dec->mVarIndex;
if (dec)
mParams[pos] = caller->EvalCoerce(pex->mLeft, caller->Eval(pex->mLeft), dec->mBase);
else
mParams[pos] = caller->REval(pex->mLeft);
pos += dec->mSize;
pex = pex->mRight;
if (dec)
dec = dec->mNext;
}
if (pex)
{
if (dec)
pos = dec->mVarIndex;
if (dec)
mParams[pos] = caller->EvalCoerce(pex, caller->Eval(pex), dec->mBase);
else
mParams[pos] = caller->REval(pex);
}
if (exp->mLeft->mDecValue->mFlags & DTF_INTRINSIC)
{
const Ident* iname = exp->mLeft->mDecValue->mIdent;
if (!strcmp(iname->mString, "fabs"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(fabs(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "floor"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(floor(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "ceil"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(ceil(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "sin"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(sin(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "cos"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(cos(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "tan"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(tan(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "log"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(log(mParams[0].GetFloat()));
}
else if (!strcmp(iname->mString, "exp"))
{
mResult = Value(exp->mLocation, TheFloatTypeDeclaration);
mResult.PutFloat(::exp(mParams[0].GetFloat()));
}
else
mErrors->Error(exp->mLeft->mDecValue->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown intrinsic function", iname);
}
else
{
Execute(exp->mLeft->mDecValue->mValue);
UnwindDestructStack(0);
}
return mResult;
}
ConstexprInterpreter::Value ConstexprInterpreter::EvalCoerce(Expression* exp, const Value& vl, Declaration* type)
{
if (type->IsReference())
return vl;
else
{
Value v = vl.ToRValue();
while (v.mDecType->IsReference())
v.mDecType = v.mDecType->mBase;
if (type->mType == DT_TYPE_FLOAT && v.mDecType->IsIntegerType())
{
Value vf(exp->mLocation, type);
vf.PutFloat(v.GetFloat());
v = vf;
}
else if (v.mDecType->mType == DT_TYPE_FLOAT && type->IsIntegerType())
{
Value vf(exp->mLocation, type);
vf.PutInt(v.GetInt());
v = vf;
}
return v;
}
}
ConstexprInterpreter::Value ConstexprInterpreter::Eval(Expression* exp)
{
switch (exp->mType)
{
case EX_SCOPE:
return Eval(exp->mLeft);
case EX_CONSTANT:
return Value(exp);
case EX_VARIABLE:
if (exp->mDecValue->mType == DT_ARGUMENT)
{
if (mParams[exp->mDecValue->mVarIndex].mBaseValue)
return mParams[exp->mDecValue->mVarIndex];
else
return Value(&mParams[exp->mDecValue->mVarIndex]);
}
else if (exp->mDecValue->mType == DT_VARIABLE)
{
if (!(exp->mDecValue->mFlags & (DTF_STATIC | DTF_GLOBAL)))
{
if (!mLocals[exp->mDecValue->mVarIndex].mDataSize)
{
mLocals[exp->mDecValue->mVarIndex] = Value(exp->mDecValue->mLocation, exp->mDecValue->mBase);
return Value(&mLocals[exp->mDecValue->mVarIndex]);
}
else if (mLocals[exp->mDecValue->mVarIndex].mBaseValue)
return mLocals[exp->mDecValue->mVarIndex];
else
return Value(&mLocals[exp->mDecValue->mVarIndex]);
}
}
break;
case EX_BINARY:
return EvalBinary(exp, REval(exp->mLeft), REval(exp->mRight));
case EX_RELATIONAL:
return EvalRelational(exp, REval(exp->mLeft), REval(exp->mRight));
case EX_PREFIX:
return EvalUnary(exp, Eval(exp->mLeft));
case EX_TYPECAST:
return EvalTypeCast(exp, REval(exp->mLeft), exp->mDecType);
case EX_CALL:
{
ConstexprInterpreter cinter(exp->mLocation, mErrors, mDataSection);
return cinter.EvalCall(exp, this);
}
case EX_LIST:
case EX_COMMA:
Eval(exp->mLeft);
return Eval(exp->mRight);
case EX_CONDITIONAL:
{
Value v = REval(exp->mLeft);
if (v.GetInt())
return Eval(exp->mRight->mLeft);
else
return Eval(exp->mRight->mRight);
}
case EX_LOGICAL_AND:
{
Value v = REval(exp->mLeft);
if (!v.GetInt())
return v;
else
return REval(exp->mRight);
}
case EX_LOGICAL_OR:
{
Value v = REval(exp->mLeft);
if (v.GetInt())
return v;
else
return REval(exp->mRight);
}
case EX_LOGICAL_NOT:
{
Value v(exp->mLocation, TheBoolTypeDeclaration);
Value vr = REval(exp->mLeft);
if (v.GetInt())
v.PutInt(0);
else
v.PutInt(1);
return v;
}
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
{
Value lexp = Eval(exp->mLeft);
Value rexp = REval(exp->mRight);
if (exp->mToken != TK_ASSIGN)
rexp = EvalBinary(exp, lexp.ToRValue(), rexp);
lexp.Assign(EvalCoerce(exp, rexp, lexp.mDecType));
return lexp;
}
case EX_POSTINCDEC:
{
Value vl = Eval(exp->mLeft);
Value vr = vl.ToRValue();
vl.Assign(EvalUnary(exp, vr));
return vr;
}
case EX_PREINCDEC:
{
Value vl = Eval(exp->mLeft);
vl.Assign(EvalUnary(exp, vl.ToRValue()));
return vl;
}
case EX_QUALIFY:
{
Value v = Eval(exp->mLeft);
if (v.mBaseValue)
return Value(exp->mLocation, v.mBaseValue, exp->mDecType, v.mOffset + exp->mDecValue->mOffset);
break;
}
case EX_INDEX:
{
Value v = Eval(exp->mLeft);
Value vi = REval(exp->mRight);
if (v.mDecType->mType == DT_TYPE_ARRAY)
{
if (v.mBaseValue)
return Value(exp->mLocation, v.mBaseValue, exp->mDecType, v.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt()));
}
else if (v.mDecType->mType == DT_TYPE_POINTER)
{
Value p = v.GetPtr();
return Value(exp->mLocation, p.mBaseValue, exp->mDecType, p.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt()));
}
break;
}
case EX_RESULT:
if (mParams[0].mBaseValue)
return mParams[0];
else
return Value(&mParams[0]);
case EX_CONSTRUCT:
if (exp->mLeft->mLeft)
Eval(exp->mLeft->mLeft);
return Eval(exp->mRight);
case EX_VOID:
return Value(exp->mLocation);
}
mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr");
return Value();
}
ConstexprInterpreter::Flow ConstexprInterpreter::Execute(Expression* exp)
{
for (;;)
{
switch (exp->mType)
{
case EX_SCOPE:
{
int ds = mDestructStack.Size();
Flow f = Execute(exp->mLeft);
UnwindDestructStack(ds);
return f;
}
case EX_RETURN:
mResult = EvalCoerce(exp, Eval(exp->mLeft), mProcType->mBase);
return FLOW_RETURN;
case EX_CONSTANT:
case EX_VARIABLE:
case EX_BINARY:
case EX_RELATIONAL:
case EX_PREFIX:
case EX_TYPECAST:
case EX_CALL:
case EX_COMMA:
case EX_LIST:
case EX_CONDITIONAL:
case EX_LOGICAL_AND:
case EX_LOGICAL_OR:
case EX_LOGICAL_NOT:
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
case EX_POSTINCDEC:
case EX_PREINCDEC:
case EX_QUALIFY:
case EX_INDEX:
case EX_RESULT:
Eval(exp);
return FLOW_NEXT;
case EX_SEQUENCE:
if (exp->mRight)
{
Flow f = Execute(exp->mLeft);
if (f == FLOW_NEXT)
return Execute(exp->mRight);
return f;
}
else
return Execute(exp->mLeft);
case EX_BREAK:
return FLOW_BREAK;
case EX_CONTINUE:
return FLOW_CONTINUE;
case EX_IF:
if (REval(exp->mLeft).GetInt())
return Execute(exp->mRight->mLeft);
else if (exp->mRight->mRight)
return Execute(exp->mRight->mRight);
else
return FLOW_NEXT;
case EX_SWITCH:
{
int64 v = REval(exp->mLeft).GetInt();
bool found = false;
Expression* sexp = exp->mRight;
while (sexp)
{
Expression* cexp = sexp->mLeft;
if (found || cexp->mType == EX_DEFAULT || v == REval(cexp->mLeft).GetInt())
{
found = true;
if (cexp->mRight)
{
Flow f = Execute(cexp->mRight);
if (f == FLOW_BREAK)
return FLOW_NEXT;
else if (f != FLOW_NEXT)
return f;
}
}
sexp = sexp->mRight;
}
return FLOW_NEXT;
}
case EX_WHILE:
{
int ds = mDestructStack.Size();
while (REval(exp->mLeft).GetInt())
{
int ls = mDestructStack.Size();
Flow f = Execute(exp->mRight);
UnwindDestructStack(ls);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
}
UnwindDestructStack(ds);
return FLOW_NEXT;
}
case EX_DO:
{
int ds = mDestructStack.Size();
do {
int ls = mDestructStack.Size();
Flow f = Execute(exp->mRight);
UnwindDestructStack(ls);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
} while (REval(exp->mLeft).GetInt());
UnwindDestructStack(ds);
return FLOW_NEXT;
}
case EX_FOR:
{
int ds = mDestructStack.Size();
if (exp->mLeft->mRight)
Eval(exp->mLeft->mRight);
while (!exp->mLeft->mLeft->mLeft || REval(exp->mLeft->mLeft->mLeft).GetInt())
{
int ls = mDestructStack.Size();
Flow f = Execute(exp->mRight);
UnwindDestructStack(ls);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
if (exp->mLeft->mLeft->mRight)
Eval(exp->mLeft->mLeft->mRight);
}
UnwindDestructStack(ds);
return FLOW_NEXT;
}
case EX_CONSTRUCT:
if (exp->mLeft->mLeft)
Eval(exp->mLeft->mLeft);
if (exp->mLeft->mRight)
mDestructStack.Push(exp->mLeft->mRight);
if (exp->mRight)
return Execute(exp->mRight);
return FLOW_NEXT;
case EX_VOID:
return FLOW_NEXT;
default:
mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr");
}
}
}
void ConstexprInterpreter::UnwindDestructStack(int level)
{
while (mDestructStack.Size() > level)
Eval(mDestructStack.Pop());
}
ConstexprInterpreter::ValueItem::ValueItem(void)
: mByte(0), mBaseValue(nullptr)
{
}