oscar64/oscar64/Constexpr.cpp

1196 lines
25 KiB
C++

#include "Constexpr.h"
#include <math.h>
ConstexprInterpreter::Value::Value(void)
: mDecType(TheVoidTypeDeclaration),
mBaseValue(nullptr), mOffset(0),
mData(mShortData), mDataSize(0)
{
}
ConstexprInterpreter::Value::Value(const Location & location)
: mLocation(location),
mDecType(TheVoidTypeDeclaration),
mBaseValue(nullptr), mOffset(0),
mData(mShortData), mDataSize(0)
{
}
ConstexprInterpreter::Value::Value(Expression* exp)
: mLocation(exp->mLocation),
mDecType(exp->mDecType),
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:
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;
}
}
ConstexprInterpreter::Value::Value(const Location& location, Declaration* dec)
: mLocation(location),
mDecType(dec),
mBaseValue(nullptr), mOffset(0),
mDataSize(dec->mSize)
{
if (mDataSize <= 4)
mData = mShortData;
else
mData = new ValueItem[mDataSize];
}
ConstexprInterpreter::Value::Value(const Value& value)
: mLocation(value.mLocation),
mDecType(value.mDecType),
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),
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),
mBaseValue(value), mOffset(0),
mDataSize(0), mData(mShortData)
{
}
ConstexprInterpreter::Value::Value(Value* value, Declaration* type, int offset)
: mLocation(value->mLocation),
mDecType(type),
mBaseValue(value), mOffset(offset),
mDataSize(0), mData(mShortData)
{
}
ConstexprInterpreter::Value::Value(const Location& location, const uint8* data, Declaration* type)
: mLocation(location),
mDecType(type),
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),
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(dp->mBaseValue, type, uint16(dp[0].mByte | ((uint32)(dp[1].mByte) << 8)));
}
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:
memcpy(GetAddr(), v.GetAddr(), mDecType->mSize);
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:
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;
Declaration* ldec = nullptr;
for (Declaration* mdec = type->mParams; mdec; mdec = mdec->mNext)
{
Declaration * cdec = GetConst(offset + mdec->mOffset, mdec->mBase, dataSection);
cdec->mOffset = mdec->mOffset;
if (ldec)
ldec->mNext = cdec;
else
dec->mParams = cdec;
ldec = cdec;
}
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);
cdec->mOffset = i;
if (ldec)
ldec->mNext = cdec;
else
dec->mParams = cdec;
ldec = cdec;
}
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())
{
}
ConstexprInterpreter::~ConstexprInterpreter(void)
{
}
Expression* ConstexprInterpreter::EvalCall(Expression* exp)
{
mProcType = exp->mLeft->mDecType;
Expression* pex = exp->mRight;
Declaration* dec = exp->mLeft->mDecType->mParams;
int pos = 0;
while (pex && pex->mType == EX_LIST)
{
if (dec)
pos = dec->mVarIndex;
if (pex->mLeft->mType == EX_CONSTANT)
mParams[pos] = Value(pex->mLeft);
else if (pex->mLeft->mType == EX_VARIABLE && (pex->mLeft->mDecValue->mFlags & DTF_CONST))
{
mParams[pos] = Value(pex->mLeft->mLocation, pex->mLeft->mDecValue->mBase);
mParams[pos].PutConst(0, pex->mLeft->mDecValue->mValue->mDecValue);
}
else
return exp;
pex = pex->mRight;
if (dec)
dec = dec->mNext;
}
if (pex)
{
if (dec)
pos = dec->mVarIndex;
if (pex->mType == EX_CONSTANT)
mParams[pos] = Value(pex);
else if (pex->mType == EX_VARIABLE && (pex->mDecValue->mFlags & DTF_CONST))
{
mParams[pos] = Value(pex->mLocation, pex->mDecValue->mBase);
mParams[pos].PutConst(0, pex->mDecValue->mValue->mDecValue);
}
else
return exp;
}
Execute(exp->mLeft->mDecValue->mValue);
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
{
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();
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();
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)
{
mProcType = exp->mLeft->mDecType;
Expression* pex = exp->mRight;
Declaration* dec = exp->mLeft->mDecType->mParams;
int pos = 0;
while (pex && pex->mType == EX_LIST)
{
if (dec)
pos = dec->mVarIndex;
mParams[pos] = caller->REval(pex->mLeft);
pos += dec->mSize;
pex = pex->mRight;
if (dec)
dec = dec->mNext;
}
if (pex)
{
if (dec)
pos = dec->mVarIndex;
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
mErrors->Error(exp->mLeft->mDecValue->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown intrinsic function", iname);
}
else
Execute(exp->mLeft->mDecValue->mValue);
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)
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]);
}
}
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:
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(v.mBaseValue, exp->mDecType, v.mOffset + exp->mDecValue->mOffset);
}
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(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(p.mBaseValue, exp->mDecType, p.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt()));
}
}
case EX_VOID:
return Value(exp->mLocation);
}
mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr");
return exp;
}
ConstexprInterpreter::Flow ConstexprInterpreter::Execute(Expression* exp)
{
for (;;)
{
switch (exp->mType)
{
case EX_SCOPE:
return Execute(exp->mLeft);
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_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:
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:
while (REval(exp->mLeft).GetInt())
{
Flow f = Execute(exp->mRight);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
}
return FLOW_NEXT;
case EX_DO:
do {
Flow f = Execute(exp->mRight);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
} while (REval(exp->mLeft).GetInt());
return FLOW_NEXT;
case EX_FOR:
if (exp->mLeft->mRight)
Eval(exp->mLeft->mRight);
while (!exp->mLeft->mLeft->mLeft || REval(exp->mLeft->mLeft->mLeft).GetInt())
{
Flow f = Execute(exp->mRight);
if (f == FLOW_RETURN)
return FLOW_RETURN;
else if (f == FLOW_BREAK)
break;
if (exp->mLeft->mLeft->mRight)
Eval(exp->mLeft->mLeft->mRight);
}
return FLOW_NEXT;
case EX_VOID:
return FLOW_NEXT;
default:
mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Invalid constexpr");
}
}
}
ConstexprInterpreter::ValueItem::ValueItem(void)
: mByte(0), mBaseValue(nullptr)
{
}