oscar64/oscar64/InterCodeGenerator.cpp

3324 lines
98 KiB
C++

#include "InterCodeGenerator.h"
InterCodeGenerator::InterCodeGenerator(Errors* errors, Linker* linker)
: mErrors(errors), mLinker(linker), mCompilerOptions(COPT_DEFAULT)
{
}
InterCodeGenerator::~InterCodeGenerator(void)
{
}
static inline InterType InterTypeOf(const Declaration* dec)
{
switch (dec->mType)
{
default:
case DT_TYPE_VOID:
return IT_NONE;
case DT_TYPE_INTEGER:
case DT_TYPE_ENUM:
if (dec->mSize == 1)
return IT_INT8;
else if (dec->mSize == 2)
return IT_INT16;
else
return IT_INT32;
case DT_TYPE_BOOL:
return IT_BOOL;
case DT_TYPE_FLOAT:
return IT_FLOAT;
case DT_TYPE_POINTER:
case DT_TYPE_FUNCTION:
case DT_TYPE_ARRAY:
return IT_POINTER;
}
}
InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, int level)
{
while (v.mReference > level)
{
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_LOAD;
ins->mSrc[0].mMemory = IM_INDIRECT;
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = v.mTemp;
ins->mDst.mType = v.mReference == 1 ? InterTypeOf(v.mType) : IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mSrc[0].mOperandSize = v.mReference == 1 ? v.mType->mSize : 2;
if (v.mType->mFlags & DTF_VOLATILE)
ins->mVolatile = true;
block->Append(ins);
v = ExValue(v.mType, ins->mDst.mTemp, v.mReference - 1);
}
return v;
}
InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, Declaration* type)
{
int stemp = v.mTemp;
if (v.mType->IsIntegerType() && type->mType == DT_TYPE_FLOAT)
{
if (v.mType->mSize == 1)
{
if (v.mType->mFlags & DTF_SIGNED)
{
InterInstruction * xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16S;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
else
{
InterInstruction * xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16U;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
}
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONVERSION_OPERATOR;
cins->mOperator = IA_INT2FLOAT;
cins->mSrc[0].mType = IT_INT16;
cins->mSrc[0].mTemp = stemp;
cins->mDst.mType = IT_FLOAT;
cins->mDst.mTemp = proc->AddTemporary(IT_FLOAT);
block->Append(cins);
v.mTemp = cins->mDst.mTemp;
v.mType = type;
}
else if (v.mType->mType == DT_TYPE_FLOAT && type->IsIntegerType())
{
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONVERSION_OPERATOR;
cins->mOperator = IA_FLOAT2INT;
cins->mSrc[0].mType = IT_FLOAT;
cins->mSrc[0].mTemp = v.mTemp;
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(cins);
v.mTemp = cins->mDst.mTemp;
v.mType = type;
}
else if (v.mType->mSize < type->mSize)
{
if (v.mType->mSize == 1 && type->mSize == 2)
{
if (v.mType->mFlags & DTF_SIGNED)
{
InterInstruction * xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16S;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
else
{
InterInstruction * xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16U;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
}
else if (v.mType->mSize == 2 && type->mSize == 4)
{
if (v.mType->mFlags & DTF_SIGNED)
{
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT16TO32S;
xins->mSrc[0].mType = IT_INT16;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT32;
xins->mDst.mTemp = proc->AddTemporary(IT_INT32);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
else
{
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT16TO32U;
xins->mSrc[0].mType = IT_INT16;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT32;
xins->mDst.mTemp = proc->AddTemporary(IT_INT32);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
}
v.mTemp = stemp;
v.mType = type;
}
else
{
// ignore size reduction
v.mType = type;
}
return v;
}
static inline bool InterTypeTypeInteger(InterType t)
{
return t == IT_INT8 || t == IT_INT16 || t == IT_INT32 || t == IT_BOOL;
}
static inline InterType InterTypeOfArithmetic(InterType t1, InterType t2)
{
if (t1 == IT_FLOAT || t2 == IT_FLOAT)
return IT_FLOAT;
else if (InterTypeTypeInteger(t1) && InterTypeTypeInteger(t2))
return t1 > t2 ? t1 : t2;
else if (t1 == IT_POINTER && t2 == IT_POINTER)
return IT_INT16;
else if (t1 == IT_POINTER || t2 == IT_POINTER)
return IT_POINTER;
else
return IT_INT16;
}
void InterCodeGenerator::InitGlobalVariable(InterCodeModule * mod, Declaration* dec)
{
if (!dec->mLinkerObject)
{
InterVariable * var = new InterVariable();
var->mOffset = 0;
var->mSize = dec->mSize;
var->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_DATA);
var->mIdent = dec->mIdent;
Declaration* type = dec->mBase;
while (type->mType == DT_TYPE_ARRAY)
type = type->mBase;
if (type->mFlags & DTF_CONST)
var->mLinkerObject->mFlags |= LOBJF_CONST;
var->mIndex = mod->mGlobalVars.Size();
mod->mGlobalVars.Push(var);
dec->mVarIndex = var->mIndex;
dec->mLinkerObject = var->mLinkerObject;
if (dec->mFlags & DTF_SECTION_START)
dec->mLinkerObject->mType = LOT_SECTION_START;
else if (dec->mFlags & DTF_SECTION_END)
dec->mLinkerObject->mType = LOT_SECTION_END;
uint8* d = var->mLinkerObject->AddSpace(var->mSize);
if (dec->mValue)
{
if (dec->mValue->mType == EX_CONSTANT)
{
BuildInitializer(mod, d, 0, dec->mValue->mDecValue, var);
}
else
mErrors->Error(dec->mLocation, EERR_CONSTANT_INITIALIZER, "Non constant initializer");
}
}
}
void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression* exp, GrowingArray<Declaration*> * refvars)
{
int offset = 0, osize = 0;
Expression* cexp = exp;
while (cexp)
{
osize += AsmInsSize(cexp->mAsmInsType, cexp->mAsmInsMode);
cexp = cexp->mRight;
}
Declaration* dec = exp->mDecValue;
dec->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_NATIVE_CODE);
uint8* d = dec->mLinkerObject->AddSpace(osize);
GrowingArray<Declaration*> refVars(nullptr);
cexp = exp;
while (cexp)
{
if (cexp->mAsmInsType != ASMIT_BYTE)
{
int opcode = AsmInsOpcodes[cexp->mAsmInsType][cexp->mAsmInsMode];
d[offset++] = opcode;
}
Declaration* aexp = nullptr;
if (cexp->mLeft)
aexp = cexp->mLeft->mDecValue;
switch (cexp->mAsmInsMode)
{
case ASMIM_IMPLIED:
break;
case ASMIM_IMMEDIATE:
if (!aexp)
mErrors->Error(cexp->mLocation, EERR_ASM_INVALD_OPERAND, "Missing assembler operand");
else if (aexp->mType == DT_CONST_INTEGER)
d[offset] = cexp->mLeft->mDecValue->mInteger & 255;
else if (aexp->mType == DT_LABEL_REF)
{
if (aexp->mBase->mBase)
{
if (!aexp->mBase->mBase->mLinkerObject)
TranslateAssembler(mod, aexp->mBase->mBase->mValue, nullptr);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
if (aexp->mFlags & DTF_UPPER_BYTE)
ref.mFlags = LREF_HIGHBYTE;
else
ref.mFlags = LREF_LOWBYTE;
ref.mRefObject = aexp->mBase->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset + aexp->mBase->mInteger;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Undefined immediate operand", aexp->mBase->mIdent->mString);
}
else if (aexp->mType == DT_VARIABLE_REF)
{
if (aexp->mBase->mFlags & DTF_GLOBAL)
{
InitGlobalVariable(mod, aexp->mBase);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
if (aexp->mFlags & DTF_UPPER_BYTE)
ref.mFlags = LREF_HIGHBYTE;
else
ref.mFlags = LREF_LOWBYTE;
ref.mRefObject = aexp->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Invalid immediate operand");
}
else if (aexp->mType == DT_FUNCTION_REF)
{
if (!aexp->mBase->mLinkerObject)
{
InterCodeProcedure* cproc = this->TranslateProcedure(mod, aexp->mBase->mValue, aexp->mBase);
}
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
if (aexp->mFlags & DTF_UPPER_BYTE)
ref.mFlags = LREF_HIGHBYTE;
else
ref.mFlags = LREF_LOWBYTE;
ref.mRefObject = aexp->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Invalid immediate operand");
offset += 1;
break;
case ASMIM_ZERO_PAGE:
case ASMIM_ZERO_PAGE_X:
case ASMIM_INDIRECT_X:
case ASMIM_INDIRECT_Y:
if (!aexp)
mErrors->Error(cexp->mLocation, EERR_ASM_INVALD_OPERAND, "Missing assembler operand");
else if (aexp->mType == DT_VARIABLE_REF)
{
if (refvars)
{
int j = 0;
while (j < refvars->Size() && (*refvars)[j] != aexp->mBase)
j++;
if (j == refvars->Size())
refvars->Push(aexp->mBase);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_TEMPORARY;
ref.mRefObject = dec->mLinkerObject;
ref.mRefOffset = j;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
d[offset] = aexp->mOffset;
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Local variable outside scope");
}
else if (aexp->mType == DT_ARGUMENT || aexp->mType == DT_VARIABLE)
{
if (refvars)
{
int j = 0;
while (j < refvars->Size() && (*refvars)[j] != aexp)
j++;
if (j == refvars->Size())
refvars->Push(aexp);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_TEMPORARY;
ref.mRefObject = dec->mLinkerObject;
ref.mRefOffset = j;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
d[offset] = 0;
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Local variable outside scope");
}
else
d[offset] = aexp->mInteger;
offset += 1;
break;
case ASMIM_ABSOLUTE:
case ASMIM_INDIRECT:
case ASMIM_ABSOLUTE_X:
case ASMIM_ABSOLUTE_Y:
if (!aexp)
mErrors->Error(cexp->mLocation, EERR_ASM_INVALD_OPERAND, "Missing assembler operand");
else if (aexp->mType == DT_CONST_INTEGER)
{
d[offset + 0] = cexp->mLeft->mDecValue->mInteger & 255;
d[offset + 1] = cexp->mLeft->mDecValue->mInteger >> 8;
}
else if (aexp->mType == DT_LABEL)
{
if (aexp->mBase)
{
if (!aexp->mBase->mLinkerObject)
TranslateAssembler(mod, aexp->mBase->mValue, nullptr);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mBase->mLinkerObject;
ref.mRefOffset = aexp->mInteger;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Undefined label");
}
else if (aexp->mType == DT_LABEL_REF)
{
if (aexp->mBase->mBase)
{
if (!aexp->mBase->mBase->mLinkerObject)
TranslateAssembler(mod, aexp->mBase->mBase->mValue, nullptr);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mBase->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset + aexp->mBase->mInteger;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else
mErrors->Error(aexp->mLocation, EERR_ASM_INVALD_OPERAND, "Undefined label");
}
else if (aexp->mType == DT_CONST_ASSEMBLER)
{
if (!aexp->mLinkerObject)
TranslateAssembler(mod, aexp->mValue, nullptr);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mLinkerObject;
ref.mRefOffset = 0;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else if (aexp->mType == DT_VARIABLE)
{
if (aexp->mFlags & DTF_GLOBAL)
{
InitGlobalVariable(mod, aexp);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mLinkerObject;
ref.mRefOffset = 0;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
}
else if (aexp->mType == DT_VARIABLE_REF)
{
if (aexp->mBase->mFlags & DTF_GLOBAL)
{
InitGlobalVariable(mod, aexp->mBase);
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
}
else if (aexp->mType == DT_CONST_FUNCTION)
{
if (!aexp->mLinkerObject)
{
InterCodeProcedure* cproc = this->TranslateProcedure(mod, aexp->mValue, aexp);
}
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mLinkerObject;
ref.mRefOffset = 0;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
else if (aexp->mType == DT_FUNCTION_REF)
{
if (!aexp->mBase->mLinkerObject)
{
InterCodeProcedure* cproc = this->TranslateProcedure(mod, aexp->mBase->mValue, aexp->mBase);
}
LinkerReference ref;
ref.mObject = dec->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = aexp->mBase->mLinkerObject;
ref.mRefOffset = aexp->mOffset;
ref.mRefObject->mFlags |= LOBJF_RELEVANT;
dec->mLinkerObject->AddReference(ref);
}
offset += 2;
break;
case ASMIM_RELATIVE:
if (!aexp)
mErrors->Error(cexp->mLocation, EERR_ASM_INVALD_OPERAND, "Missing assembler operand");
else
d[offset] = aexp->mInteger - offset - 1;
offset++;
break;
}
cexp = cexp->mRight;
}
assert(offset == osize);
}
void InterCodeGenerator::BuildSwitchTree(InterCodeProcedure* proc, InterCodeBasicBlock* block, ExValue v, const SwitchNodeArray& nodes, int left, int right, InterCodeBasicBlock* dblock)
{
if (right - left < 5)
{
for (int i = left; i < right; i++)
{
InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
proc->Append(cblock);
InterInstruction* vins = new InterInstruction();
vins->mCode = IC_CONSTANT;
vins->mConst.mType = IT_INT16;
vins->mConst.mIntConst = nodes[i].mValue;
vins->mDst.mType = IT_INT16;
vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType);
block->Append(vins);
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_RELATIONAL_OPERATOR;
cins->mOperator = IA_CMPEQ;
cins->mSrc[0].mType = vins->mDst.mType;
cins->mSrc[0].mTemp = vins->mDst.mTemp;
cins->mSrc[1].mType = vins->mDst.mType;
cins->mSrc[1].mTemp = v.mTemp;
cins->mDst.mType = IT_BOOL;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
InterInstruction* bins = new InterInstruction();
bins->mCode = IC_BRANCH;
bins->mSrc[0].mType = IT_BOOL;
bins->mSrc[0].mTemp = cins->mDst.mTemp;
block->Append(bins);
block->Close(nodes[i].mBlock, cblock);
block = cblock;
}
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(dblock, nullptr);
}
else
{
int center = (left + right + 1) >> 1;
InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
proc->Append(cblock);
InterCodeBasicBlock* rblock = new InterCodeBasicBlock();
proc->Append(rblock);
InterCodeBasicBlock* lblock = new InterCodeBasicBlock();
proc->Append(lblock);
InterInstruction* vins = new InterInstruction();
vins->mCode = IC_CONSTANT;
vins->mConst.mType = IT_INT16;
vins->mConst.mIntConst = nodes[center].mValue;
vins->mDst.mType = IT_INT16;
vins->mDst.mTemp = proc->AddTemporary(vins->mDst.mType);
block->Append(vins);
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_RELATIONAL_OPERATOR;
cins->mOperator = IA_CMPEQ;
cins->mSrc[0].mType = vins->mDst.mType;
cins->mSrc[0].mTemp = vins->mDst.mTemp;
cins->mSrc[1].mType = vins->mDst.mType;
cins->mSrc[1].mTemp = v.mTemp;
cins->mDst.mType = IT_BOOL;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
InterInstruction* bins = new InterInstruction();
bins->mCode = IC_BRANCH;
bins->mSrc[0].mType = IT_BOOL;
bins->mSrc[0].mTemp = cins->mDst.mTemp;
block->Append(bins);
block->Close(nodes[center].mBlock, cblock);
InterInstruction* rins = new InterInstruction();
rins->mCode = IC_RELATIONAL_OPERATOR;
rins->mOperator = IA_CMPLS;
rins->mSrc[0].mType = vins->mDst.mType;
rins->mSrc[0].mTemp = vins->mDst.mTemp;
rins->mSrc[1].mType = vins->mDst.mType;
rins->mSrc[1].mTemp = v.mTemp;
rins->mDst.mType = IT_BOOL;
rins->mDst.mTemp = proc->AddTemporary(rins->mDst.mType);
cblock->Append(rins);
InterInstruction* rbins = new InterInstruction();
rbins->mCode = IC_BRANCH;
rbins->mSrc[0].mType = IT_BOOL;
rbins->mSrc[0].mTemp = rins->mDst.mTemp;
cblock->Append(rbins);
cblock->Close(lblock, rblock);
BuildSwitchTree(proc, lblock, v, nodes, left, center, dblock);
BuildSwitchTree(proc, rblock, v, nodes, center + 1, right, dblock);
}
}
InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock, InlineMapper* inlineMapper, ExValue* lrexp)
{
Declaration* dec;
ExValue vl, vr;
for (;;)
{
switch (exp->mType)
{
case EX_VOID:
return ExValue(TheVoidTypeDeclaration);
case EX_SEQUENCE:
vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
exp = exp->mRight;
if (!exp)
return ExValue(TheVoidTypeDeclaration);
break;
case EX_CONSTANT:
dec = exp->mDecValue;
switch (dec->mType)
{
case DT_CONST_INTEGER:
{
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = InterTypeOf(dec->mBase);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
if (ins->mDst.mType == IT_INT8)
{
if (dec->mBase->mFlags & DTF_SIGNED)
{
if (dec->mInteger < -128 || dec->mInteger > 127)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Integer constant truncated");
ins->mConst.mIntConst = int8(dec->mInteger);
}
else
{
if (dec->mInteger < 0 || dec->mInteger > 255)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Unsigned integer constant truncated");
ins->mConst.mIntConst = uint8(dec->mInteger);
}
}
else if (ins->mDst.mType == IT_INT16)
{
if (dec->mBase->mFlags & DTF_SIGNED)
{
if (dec->mInteger < -32768 || dec->mInteger > 32767)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Integer constant truncated");
ins->mConst.mIntConst = int16(dec->mInteger);
}
else
{
if (dec->mInteger < 0 || dec->mInteger > 65535)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Unsigned integer constant truncated");
ins->mConst.mIntConst = uint16(dec->mInteger);
}
}
else if (ins->mDst.mType == IT_INT32)
{
if (dec->mBase->mFlags & DTF_SIGNED)
{
if (dec->mInteger < -2147483648LL || dec->mInteger > 2147483647LL)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Integer constant truncated");
ins->mConst.mIntConst = int32(dec->mInteger);
}
else
{
if (dec->mInteger < 0 || dec->mInteger > 4294967296LL)
mErrors->Error(dec->mLocation, EWARN_CONSTANT_TRUNCATED, "Unsigned integer constant truncated");
ins->mConst.mIntConst = uint32(dec->mInteger);
}
}
else
{
ins->mConst.mIntConst = dec->mInteger;
}
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp);
} break;
case DT_CONST_FLOAT:
{
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = InterTypeOf(dec->mBase);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mFloatConst = dec->mNumber;
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp);
} break;
case DT_CONST_ADDRESS:
{
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
ins->mConst.mIntConst = dec->mInteger;
ins->mConst.mMemory = IM_ABSOLUTE;
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp);
} break;
case DT_CONST_FUNCTION:
{
if (!dec->mLinkerObject)
{
InterCodeProcedure* cproc = this->TranslateProcedure(proc->mModule, dec->mValue, dec);
}
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = InterTypeOf(dec->mBase);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mVarIndex = dec->mVarIndex;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mMemory = IM_PROCEDURE;
ins->mConst.mIntConst = 0;
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp);
} break;
case DT_CONST_ASSEMBLER:
{
if (!dec->mLinkerObject)
TranslateAssembler(proc->mModule, dec->mValue, nullptr);
InterInstruction* ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mVarIndex = dec->mVarIndex;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mMemory = IM_PROCEDURE;
ins->mConst.mIntConst = 0;
block->Append(ins);
return ExValue(TheVoidPointerTypeDeclaration, ins->mDst.mTemp);
}
case DT_CONST_POINTER:
{
vl = TranslateExpression(procType, proc, block, dec->mValue, breakBlock, continueBlock, inlineMapper);
return vl;
}
case DT_CONST_DATA:
{
if (!dec->mLinkerObject)
{
dec->mVarIndex = proc->mModule->mGlobalVars.Size();
InterVariable* var = new InterVariable();
var->mIndex = dec->mVarIndex;
var->mIdent = dec->mIdent;
var->mOffset = 0;
var->mSize = dec->mSize;
if ((dec->mFlags & DTF_VAR_ALIASING) || dec->mBase->mType == DT_TYPE_ARRAY)
var->mAliased = true;
var->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_DATA);
dec->mLinkerObject = var->mLinkerObject;
var->mLinkerObject->AddData(dec->mData, dec->mSize);
proc->mModule->mGlobalVars.Push(var);
}
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
ins->mConst.mIntConst = 0;
ins->mConst.mVarIndex = dec->mVarIndex;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mMemory = IM_GLOBAL;
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp, 1);
}
case DT_CONST_STRUCT:
{
if (!dec->mLinkerObject)
{
InterVariable * var = new InterVariable();
var->mOffset = 0;
var->mSize = dec->mSize;
var->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_DATA);
dec->mLinkerObject = var->mLinkerObject;
var->mIdent = dec->mIdent;
dec->mVarIndex = proc->mModule->mGlobalVars.Size();
var->mIndex = dec->mVarIndex;
proc->mModule->mGlobalVars.Push(var);
uint8* d = var->mLinkerObject->AddSpace(dec->mSize);;
BuildInitializer(proc->mModule, d, 0, dec, var);
}
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
ins->mConst.mIntConst = 0;
ins->mConst.mVarIndex = dec->mVarIndex;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mMemory = IM_GLOBAL;
block->Append(ins);
return ExValue(dec->mBase, ins->mDst.mTemp, 1);
}
default:
mErrors->Error(dec->mLocation, EERR_CONSTANT_TYPE, "Unimplemented constant type");
}
return ExValue(TheVoidTypeDeclaration);
case EX_VARIABLE:
{
dec = exp->mDecValue;
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mOperandSize = dec->mSize;
ins->mConst.mIntConst = dec->mOffset;
ins->mConst.mVarIndex = dec->mVarIndex;
int ref = 1;
if (dec->mType == DT_ARGUMENT)
{
if (inlineMapper)
{
ins->mConst.mMemory = IM_LOCAL;
ins->mConst.mVarIndex = inlineMapper->mParams[dec->mVarIndex];
}
else if (procType->mFlags & DTF_FASTCALL)
ins->mConst.mMemory = IM_FPARAM;
else
ins->mConst.mMemory = IM_PARAM;
if (dec->mBase->mType == DT_TYPE_ARRAY)
{
ref = 2;
ins->mConst.mOperandSize = 2;
}
}
else if (dec->mFlags & DTF_GLOBAL)
{
InitGlobalVariable(proc->mModule, dec);
ins->mConst.mMemory = IM_GLOBAL;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mVarIndex = dec->mVarIndex;
}
else
{
if (inlineMapper)
ins->mConst.mVarIndex += inlineMapper->mVarIndex;
ins->mConst.mMemory = IM_LOCAL;
}
block->Append(ins);
if (!(dec->mBase->mFlags & DTF_DEFINED))
mErrors->Error(dec->mLocation, EERR_VARIABLE_TYPE, "Undefined variable type");
return ExValue(dec->mBase, ins->mDst.mTemp, ref);
}
case EX_ASSIGNMENT:
{
if (exp->mLeft->mDecType && exp->mLeft->mDecType->mType == DT_TYPE_STRUCT)
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper, &vl);
}
else
{
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
}
if (exp->mToken == TK_ASSIGN || !(vl.mType->mType == DT_TYPE_POINTER && vr.mType->IsIntegerType() && (exp->mToken == TK_ASSIGN_ADD || exp->mToken == TK_ASSIGN_SUB)))
{
if (!vl.mType->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
}
if (vl.mType->mFlags & DTF_CONST)
mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot assign to const type");
if (vl.mType->mType == DT_TYPE_STRUCT || vl.mType->mType == DT_TYPE_ARRAY || vl.mType->mType == DT_TYPE_UNION)
{
vr = Dereference(proc, block, vr, 1);
vl = Dereference(proc, block, vl, 1);
if (vl.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression");
if (vr.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an adressable expression");
if (vr.mTemp != vl.mTemp)
{
InterInstruction* ins = new InterInstruction();
ins->mCode = IC_COPY;
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[0].mMemory = IM_INDIRECT;
ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vl.mTemp;
ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mConst.mOperandSize = vl.mType->mSize;
block->Append(ins);
}
}
else
{
if (vl.mType->mType == DT_TYPE_POINTER && (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION))
vr = Dereference(proc, block, vr, 1);
else
vr = Dereference(proc, block, vr);
vl = Dereference(proc, block, vl, 1);
if (vl.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression");
InterInstruction * ins = new InterInstruction();
if (exp->mToken != TK_ASSIGN)
{
ExValue vll = Dereference(proc, block, vl);
if (vl.mType->mType == DT_TYPE_POINTER)
{
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
if (exp->mToken == TK_ASSIGN_ADD)
{
cins->mConst.mIntConst = vl.mType->mBase->mSize;
}
else if (exp->mToken == TK_ASSIGN_SUB)
{
cins->mConst.mIntConst = -vl.mType->mBase->mSize;
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer assignment");
if (!vr.mType->IsIntegerType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Invalid argument for pointer inc/dec");
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
InterInstruction * mins = new InterInstruction();
mins->mCode = IC_BINARY_OPERATOR;
mins->mOperator = IA_MUL;
mins->mSrc[0].mType = IT_INT16;
mins->mSrc[0].mTemp = vr.mTemp;
mins->mSrc[1].mType = IT_INT16;
mins->mSrc[1].mTemp = cins->mDst.mTemp;
mins->mDst.mType = IT_INT16;
mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType);
block->Append(mins);
InterInstruction * ains = new InterInstruction();
ains->mCode = IC_LEA;
ains->mSrc[1].mMemory = IM_INDIRECT;
ains->mSrc[0].mType = IT_INT16;
ains->mSrc[0].mTemp = mins->mDst.mTemp;
ains->mSrc[1].mType = IT_POINTER;
ains->mSrc[1].mTemp = vll.mTemp;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
block->Append(ains);
vr.mTemp = ains->mDst.mTemp;
vr.mType = vll.mType;
}
else
{
Declaration * otype = vll.mType;
if (exp->mToken != IA_ADD && exp->mToken != IA_SUB && otype->mSize < 2)
{
if ((vll.mType->mFlags | vr.mType->mFlags) & DTF_SIGNED)
otype = TheSignedIntTypeDeclaration;
else
otype = TheUnsignedIntTypeDeclaration;
vll = CoerceType(proc, block, vll, otype);
}
vr = CoerceType(proc, block, vr, otype);
InterInstruction * oins = new InterInstruction();
oins->mCode = IC_BINARY_OPERATOR;
oins->mSrc[0].mType = InterTypeOf(otype);
oins->mSrc[0].mTemp = vr.mTemp;
oins->mSrc[1].mType = InterTypeOf(otype);
oins->mSrc[1].mTemp = vll.mTemp;
oins->mDst.mType = InterTypeOf(otype);
oins->mDst.mTemp = proc->AddTemporary(oins->mDst.mType);
if (!vll.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Left hand element type is not numeric");
if (!vr.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Right hand element type is not numeric");
switch (exp->mToken)
{
case TK_ASSIGN_ADD:
oins->mOperator = IA_ADD;
break;
case TK_ASSIGN_SUB:
oins->mOperator = IA_SUB;
break;
case TK_ASSIGN_MUL:
oins->mOperator = IA_MUL;
break;
case TK_ASSIGN_DIV:
if (vll.mType->mFlags & DTF_SIGNED)
oins->mOperator = IA_DIVS;
else
oins->mOperator = IA_DIVU;
break;
case TK_ASSIGN_MOD:
if (vll.mType->mFlags & DTF_SIGNED)
oins->mOperator = IA_MODS;
else
oins->mOperator = IA_MODU;
break;
case TK_ASSIGN_SHL:
oins->mOperator = IA_SHL;
break;
case TK_ASSIGN_SHR:
if (vll.mType->mFlags & DTF_SIGNED)
oins->mOperator = IA_SAR;
else
oins->mOperator = IA_SHR;
break;
case TK_ASSIGN_AND:
oins->mOperator = IA_AND;
break;
case TK_ASSIGN_XOR:
oins->mOperator = IA_XOR;
break;
case TK_ASSIGN_OR:
oins->mOperator = IA_OR;
break;
}
vr.mTemp = oins->mDst.mTemp;
vr.mType = otype;
block->Append(oins);
vr = CoerceType(proc, block, vr, vl.mType);
}
}
else
{
vr = CoerceType(proc, block, vr, vl.mType);
}
ins->mCode = IC_STORE;
ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mSrc[0].mType = InterTypeOf(vr.mType);
ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vl.mTemp;
ins->mSrc[1].mOperandSize = vl.mType->mSize;
block->Append(ins);
}
}
return vr;
case EX_INDEX:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
if (vl.mType->mType == DT_TYPE_ARRAY && exp->mRight->mType == EX_CONSTANT && exp->mRight->mDecValue->mType == DT_CONST_INTEGER)
{
if (vl.mType->mFlags & DTF_DEFINED)
{
int64 index = exp->mRight->mDecValue->mInteger;
if (index < 0 || index * vl.mType->mBase->mSize >= vl.mType->mSize)
mErrors->Error(exp->mLocation, EWARN_INDEX_OUT_OF_BOUNDS, "Constant array index out of bounds");
}
}
vl = Dereference(proc, block, vl, vl.mType->mType == DT_TYPE_POINTER ? 0 : 1);
vr = Dereference(proc, block, vr);
if (vl.mType->mType != DT_TYPE_ARRAY && vl.mType->mType != DT_TYPE_POINTER)
mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Invalid type for indexing");
if (!vr.mType->IsIntegerType())
mErrors->Error(exp->mLocation, EERR_INVALID_INDEX, "Index operand is not integral number");
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
cins->mConst.mIntConst = vl.mType->mBase->mSize;
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
InterInstruction * mins = new InterInstruction();
mins->mCode = IC_BINARY_OPERATOR;
mins->mOperator = IA_MUL;
mins->mSrc[0].mType = IT_INT16;
mins->mSrc[0].mTemp = vr.mTemp;
mins->mSrc[1].mType = IT_INT16;
mins->mSrc[1].mTemp = cins->mDst.mTemp;
mins->mDst.mType = IT_INT16;
mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType);
block->Append(mins);
InterInstruction * ains = new InterInstruction();
ains->mCode = IC_LEA;
ains->mSrc[1].mMemory = IM_INDIRECT;
ains->mSrc[0].mType = IT_INT16;
ains->mSrc[0].mTemp = mins->mDst.mTemp;
ains->mSrc[1].mType = IT_POINTER;
ains->mSrc[1].mTemp = vl.mTemp;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
block->Append(ains);
return ExValue(vl.mType->mBase, ains->mDst.mTemp, 1);
}
case EX_QUALIFY:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl, 1);
if (vl.mReference != 1)
mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable expression");
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
cins->mConst.mIntConst = exp->mDecValue->mOffset;
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
InterInstruction * ains = new InterInstruction();
ains->mCode = IC_LEA;
ains->mSrc[1].mMemory = IM_INDIRECT;
ains->mSrc[0].mType = IT_INT16;
ains->mSrc[0].mTemp = cins->mDst.mTemp;
ains->mSrc[1].mType = IT_POINTER;
ains->mSrc[1].mTemp = vl.mTemp;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
block->Append(ains);
return ExValue(exp->mDecValue->mBase, ains->mDst.mTemp, 1);
}
case EX_BINARY:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, block, vr);
InterInstruction * ins = new InterInstruction();
if (vl.mType->mType == DT_TYPE_POINTER || vl.mType->mType == DT_TYPE_ARRAY)
{
if (vl.mType->mType == DT_TYPE_POINTER)
vl = Dereference(proc, block, vl);
else
{
vl = Dereference(proc, block, vl, 1);
Declaration* ptype = new Declaration(exp->mLocation, DT_TYPE_POINTER);
ptype->mBase = vl.mType->mBase;
ptype->mSize = 2;
vl.mType = ptype;
}
if (vr.mType->IsIntegerType())
{
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
if (exp->mToken == TK_ADD)
{
cins->mConst.mIntConst = vl.mType->mBase->mSize;
}
else if (exp->mToken == TK_SUB)
{
cins->mConst.mIntConst = -vl.mType->mBase->mSize;
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer operation");
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
InterInstruction * mins = new InterInstruction();
mins->mCode = IC_BINARY_OPERATOR;
mins->mOperator = IA_MUL;
mins->mSrc[0].mType = IT_INT16;
mins->mSrc[0].mTemp = vr.mTemp;
mins->mSrc[1].mType = IT_INT16;
mins->mSrc[1].mTemp = cins->mDst.mTemp;
mins->mDst.mType = IT_INT16;
mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType);
block->Append(mins);
ins->mCode = IC_LEA;
ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mSrc[0].mType = IT_INT16;
ins->mSrc[0].mTemp = mins->mDst.mTemp;
ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vl.mTemp;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
}
else if (vr.mType->IsSame(vl.mType))
{
if (exp->mToken == TK_SUB)
{
InterInstruction * clins = new InterInstruction(), * crins = new InterInstruction();
clins->mCode = IC_TYPECAST;
clins->mSrc[0].mTemp = vl.mTemp;
clins->mSrc[0].mType = IT_POINTER;
clins->mDst.mType = IT_INT16;
clins->mDst.mTemp = proc->AddTemporary(clins->mDst.mType);
block->Append(clins);
crins->mCode = IC_TYPECAST;
crins->mSrc[0].mTemp = vr.mTemp;
crins->mSrc[0].mType = IT_POINTER;
crins->mDst.mType = IT_INT16;
crins->mDst.mTemp = proc->AddTemporary(crins->mDst.mType);
block->Append(crins);
InterInstruction * cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
cins->mConst.mIntConst = vl.mType->mBase->mSize;
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
InterInstruction * sins = new InterInstruction(), * dins = new InterInstruction();
sins->mCode = IC_BINARY_OPERATOR;
sins->mOperator = IA_SUB;
sins->mSrc[0].mType = IT_INT16;
sins->mSrc[0].mTemp = crins->mDst.mTemp;
sins->mSrc[1].mType = IT_INT16;
sins->mSrc[1].mTemp = clins->mDst.mTemp;
sins->mDst.mType = IT_INT16;
sins->mDst.mTemp = proc->AddTemporary(sins->mDst.mType);
block->Append(sins);
dins->mCode = IC_BINARY_OPERATOR;
dins->mOperator = IA_DIVS;
dins->mSrc[0].mType = IT_INT16;
dins->mSrc[0].mTemp = cins->mDst.mTemp;
dins->mSrc[1].mType = IT_INT16;
dins->mSrc[1].mTemp = sins->mDst.mTemp;
dins->mDst.mType = IT_INT16;
dins->mDst.mTemp = proc->AddTemporary(dins->mDst.mType);
block->Append(dins);
return ExValue(TheSignedIntTypeDeclaration, dins->mDst.mTemp);
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer operation");
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer operation");
}
else if (vr.mType->mType == DT_TYPE_POINTER || vr.mType->mType == DT_TYPE_ARRAY)
{
if (vr.mType->mType == DT_TYPE_POINTER)
vr = Dereference(proc, block, vr);
else
{
vr = Dereference(proc, block, vr, 1);
Declaration* ptype = new Declaration(exp->mLocation, DT_TYPE_POINTER);
ptype->mBase = vr.mType->mBase;
ptype->mSize = 2;
vr.mType = ptype;
}
if (vl.mType->IsIntegerType())
{
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_CONSTANT;
if (exp->mToken == TK_ADD)
{
cins->mConst.mIntConst = vr.mType->mBase->mSize;
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer operation");
cins->mDst.mType = IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
block->Append(cins);
vl = CoerceType(proc, block, vl, TheSignedIntTypeDeclaration);
InterInstruction* mins = new InterInstruction();
mins->mCode = IC_BINARY_OPERATOR;
mins->mOperator = IA_MUL;
mins->mSrc[0].mType = IT_INT16;
mins->mSrc[0].mTemp = vl.mTemp;
mins->mSrc[1].mType = IT_INT16;
mins->mSrc[1].mTemp = cins->mDst.mTemp;
mins->mDst.mType = IT_INT16;
mins->mDst.mTemp = proc->AddTemporary(mins->mDst.mType);
block->Append(mins);
ins->mCode = IC_LEA;
ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mSrc[0].mType = IT_INT16;
ins->mSrc[0].mTemp = mins->mDst.mTemp;
ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vr.mTemp;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
vl = vr;
}
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid pointer operation");
}
else
{
vl = Dereference(proc, block, vl);
if (!vl.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Left hand operand type is not numeric");
if (!vr.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Right hand operand type is not numeric");
Declaration* dtype;
if (vr.mType->mType == DT_TYPE_FLOAT || vl.mType->mType == DT_TYPE_FLOAT)
dtype = TheFloatTypeDeclaration;
else if ((exp->mToken == TK_BINARY_AND || exp->mToken == TK_BINARY_OR || exp->mToken == TK_BINARY_XOR) && vl.mType->mSize == 1 && vr.mType->mSize == 1)
{
if (vl.mType->mFlags & DTF_SIGNED)
dtype = vl.mType;
else
dtype = vr.mType;
}
else if (vr.mType->mSize < vl.mType->mSize && (vl.mType->mFlags & DTF_SIGNED))
{
if (vl.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else if (vl.mType->mSize < vr.mType->mSize && (vr.mType->mFlags & DTF_SIGNED))
{
if (vr.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else if ((vr.mType->mFlags & DTF_SIGNED) && (vl.mType->mFlags & DTF_SIGNED))
{
if (vl.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else
{
if (vl.mType->mSize == 4 || vr.mType->mSize == 4)
dtype = TheUnsignedLongTypeDeclaration;
else
dtype = TheUnsignedIntTypeDeclaration;
}
vl = CoerceType(proc, block, vl, dtype);
vr = CoerceType(proc, block, vr, dtype);
bool signedOP = dtype->mFlags & DTF_SIGNED;
ins->mCode = IC_BINARY_OPERATOR;
switch (exp->mToken)
{
case TK_ADD:
ins->mOperator = IA_ADD;
break;
case TK_SUB:
ins->mOperator = IA_SUB;
break;
case TK_MUL:
ins->mOperator = IA_MUL;
break;
case TK_DIV:
ins->mOperator = signedOP ? IA_DIVS : IA_DIVU;
break;
case TK_MOD:
ins->mOperator = signedOP ? IA_MODS : IA_MODU;
break;
case TK_LEFT_SHIFT:
ins->mOperator = IA_SHL;
break;
case TK_RIGHT_SHIFT:
ins->mOperator = (vl.mType->mFlags & DTF_SIGNED) ? IA_SAR : IA_SHR;
break;
case TK_BINARY_AND:
ins->mOperator = IA_AND;
break;
case TK_BINARY_OR:
ins->mOperator = IA_OR;
break;
case TK_BINARY_XOR:
ins->mOperator = IA_XOR;
break;
}
ins->mSrc[0].mType = InterTypeOf(vr.mType);;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[1].mType = InterTypeOf(vl.mType);;
ins->mSrc[1].mTemp = vl.mTemp;
ins->mDst.mType = InterTypeOfArithmetic(ins->mSrc[0].mType, ins->mSrc[1].mType);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
}
return ExValue(vl.mType, ins->mDst.mTemp);
}
case EX_PREINCDEC:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl, 1);
if (vl.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression");
if (vl.mType->mFlags & DTF_CONST)
mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value");
InterInstruction * cins = new InterInstruction(), * ains = new InterInstruction(), * sins = new InterInstruction();
ExValue vdl = Dereference(proc, block, vl);
bool ftype = vl.mType->mType == DT_TYPE_FLOAT;
cins->mCode = IC_CONSTANT;
cins->mDst.mType = ftype ? IT_FLOAT : IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
if (vdl.mType->mType == DT_TYPE_POINTER)
cins->mConst.mIntConst = exp->mToken == TK_INC ? vdl.mType->mBase->mSize : -(vdl.mType->mBase->mSize);
else if (vdl.mType->IsNumericType())
cins->mConst.mIntConst = exp->mToken == TK_INC ? 1 : -1;
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric value or pointer");
block->Append(cins);
InterType ttype = InterTypeOf(vdl.mType);
if (ttype == IT_POINTER)
{
ains->mCode = IC_LEA;
}
else
{
ains->mCode = IC_BINARY_OPERATOR;
ains->mOperator = IA_ADD;
}
ains->mSrc[0].mType = cins->mDst.mType;
ains->mSrc[0].mTemp = cins->mDst.mTemp;
ains->mSrc[1].mType = ttype;
ains->mSrc[1].mTemp = vdl.mTemp;
ains->mDst.mType = ttype;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
block->Append(ains);
sins->mCode = IC_STORE;
sins->mSrc[1].mMemory = IM_INDIRECT;
sins->mSrc[0].mType = ains->mDst.mType;
sins->mSrc[0].mTemp = ains->mDst.mTemp;
sins->mSrc[1].mType = IT_POINTER;
sins->mSrc[1].mTemp = vl.mTemp;
sins->mSrc[1].mOperandSize = vl.mType->mSize;
block->Append(sins);
return ExValue(vdl.mType, ains->mDst.mTemp);
}
break;
case EX_POSTINCDEC:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl, 1);
if (vl.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not a left hand expression");
if (vl.mType->mFlags & DTF_CONST)
mErrors->Error(exp->mLocation, EERR_CONST_ASSIGN, "Cannot change const value");
InterInstruction * cins = new InterInstruction(), * ains = new InterInstruction(), * sins = new InterInstruction();
ExValue vdl = Dereference(proc, block, vl);
bool ftype = vl.mType->mType == DT_TYPE_FLOAT;
cins->mCode = IC_CONSTANT;
cins->mDst.mType = ftype ? IT_FLOAT : IT_INT16;
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
if (vdl.mType->mType == DT_TYPE_POINTER)
cins->mConst.mIntConst = exp->mToken == TK_INC ? vdl.mType->mBase->mSize : -(vdl.mType->mBase->mSize);
else if (vdl.mType->IsNumericType())
cins->mConst.mIntConst = exp->mToken == TK_INC ? 1 : -1;
else
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric value or pointer");
block->Append(cins);
InterType ttype = InterTypeOf(vdl.mType);
if (ttype == IT_POINTER)
{
ains->mCode = IC_LEA;
}
else
{
ains->mCode = IC_BINARY_OPERATOR;
ains->mOperator = IA_ADD;
}
ains->mSrc[0].mType = cins->mDst.mType;
ains->mSrc[0].mTemp = cins->mDst.mTemp;
ains->mSrc[1].mType = ttype;
ains->mSrc[1].mTemp = vdl.mTemp;
ains->mDst.mType = ttype;
ains->mDst.mTemp = proc->AddTemporary(ttype);
block->Append(ains);
sins->mCode = IC_STORE;
sins->mSrc[1].mMemory = IM_INDIRECT;
sins->mSrc[0].mType = ains->mDst.mType;
sins->mSrc[0].mTemp = ains->mDst.mTemp;
sins->mSrc[1].mType = IT_POINTER;
sins->mSrc[1].mTemp = vl.mTemp;
sins->mSrc[1].mOperandSize = vl.mType->mSize;
block->Append(sins);
return ExValue(vdl.mType, vdl.mTemp);
}
break;
case EX_PREFIX:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_UNARY_OPERATOR;
switch (exp->mToken)
{
case TK_ADD:
vl = Dereference(proc, block, vl);
ins->mOperator = IA_NONE;
break;
case TK_SUB:
vl = Dereference(proc, block, vl);
if (!vl.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric type");
else if (vl.mType->mType == DT_TYPE_INTEGER && vl.mType->mSize < 2)
vl = CoerceType(proc, block, vl, TheSignedIntTypeDeclaration);
ins->mOperator = IA_NEG;
break;
case TK_BINARY_NOT:
vl = Dereference(proc, block, vl);
if (!(vl.mType->mType == DT_TYPE_POINTER || vl.mType->IsNumericType()))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric or pointer type");
else if (vl.mType->mType == DT_TYPE_INTEGER && vl.mType->mSize < 2)
vl = CoerceType(proc, block, vl, TheUnsignedIntTypeDeclaration);
ins->mOperator = IA_NOT;
break;
case TK_MUL:
if (vl.mType->mType != DT_TYPE_POINTER)
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a pointer type");
return ExValue(vl.mType->mBase, vl.mTemp, vl.mReference + 1);
case TK_BINARY_AND:
{
if (vl.mReference < 1)
mErrors->Error(exp->mLocation, EERR_NOT_AN_LVALUE, "Not an addressable value");
Declaration* dec = new Declaration(exp->mLocation, DT_TYPE_POINTER);
dec->mBase = vl.mType;
dec->mSize = 2;
dec->mFlags = DTF_DEFINED;
return ExValue(dec, vl.mTemp, vl.mReference - 1);
}
}
ins->mSrc[0].mType = InterTypeOf(vl.mType);
ins->mSrc[0].mTemp = vl.mTemp;
ins->mDst.mType = ins->mSrc[0].mType;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(vl.mType, ins->mDst.mTemp);
}
case EX_RELATIONAL:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl);
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, block, vr);
InterInstruction * ins = new InterInstruction();
Declaration* dtype = TheSignedIntTypeDeclaration;
if (vl.mType->mType == DT_TYPE_POINTER || vr.mType->mType == DT_TYPE_POINTER)
{
dtype = vl.mType;
if (vl.mType->IsIntegerType() || vr.mType->IsIntegerType())
;
else if (!vl.mType->IsSame(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible pointer types");
}
else if (!vl.mType->IsNumericType() || !vr.mType->IsNumericType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric or pointer type");
else if (vr.mType->mType == DT_TYPE_FLOAT || vl.mType->mType == DT_TYPE_FLOAT)
dtype = TheFloatTypeDeclaration;
else if (vr.mType->mSize < vl.mType->mSize && (vl.mType->mFlags & DTF_SIGNED))
{
if (vl.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else if (vl.mType->mSize < vr.mType->mSize && (vr.mType->mFlags & DTF_SIGNED))
{
if (vr.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else if ((vr.mType->mFlags & DTF_SIGNED) && (vl.mType->mFlags & DTF_SIGNED))
{
if (vl.mType->mSize == 4)
dtype = TheSignedLongTypeDeclaration;
else
dtype = TheSignedIntTypeDeclaration;
}
else
{
if (vl.mType->mSize == 4 || vr.mType->mSize == 4)
dtype = TheUnsignedLongTypeDeclaration;
else
dtype = TheUnsignedIntTypeDeclaration;
}
vl = CoerceType(proc, block, vl, dtype);
vr = CoerceType(proc, block, vr, dtype);
bool signedCompare = dtype->mFlags & DTF_SIGNED;
ins->mCode = IC_RELATIONAL_OPERATOR;
switch (exp->mToken)
{
case TK_EQUAL:
ins->mOperator = IA_CMPEQ;
break;
case TK_NOT_EQUAL:
ins->mOperator = IA_CMPNE;
break;
case TK_GREATER_THAN:
ins->mOperator = signedCompare ? IA_CMPGS : IA_CMPGU;
break;
case TK_GREATER_EQUAL:
ins->mOperator = signedCompare ? IA_CMPGES : IA_CMPGEU;
break;
case TK_LESS_THAN:
ins->mOperator = signedCompare ? IA_CMPLS : IA_CMPLU;
break;
case TK_LESS_EQUAL:
ins->mOperator = signedCompare ? IA_CMPLES : IA_CMPLEU;
break;
}
ins->mSrc[0].mType = InterTypeOf(vr.mType);;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[1].mType = InterTypeOf(vl.mType);;
ins->mSrc[1].mTemp = vl.mTemp;
ins->mDst.mType = IT_BOOL;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheBoolTypeDeclaration, ins->mDst.mTemp);
}
case EX_CALL:
{
if (exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (exp->mLeft->mDecValue->mFlags & DTF_INTRINSIC))
{
Declaration* decf = exp->mLeft->mDecValue;
const Ident * iname = decf->mIdent;
if (!strcmp(iname->mString, "fabs"))
{
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, block, vr);
if (decf->mBase->mParams->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, block, vr, decf->mBase->mParams);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_UNARY_OPERATOR;
ins->mOperator = IA_ABS;
ins->mSrc[0].mType = IT_FLOAT;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mDst.mType = IT_FLOAT;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp);
}
else if (!strcmp(iname->mString, "floor"))
{
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, block, vr);
if (decf->mBase->mParams->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, block, vr, decf->mBase->mParams);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_UNARY_OPERATOR;
ins->mOperator = IA_FLOOR;
ins->mSrc[0].mType = IT_FLOAT;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mDst.mType = IT_FLOAT;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp);
}
else if (!strcmp(iname->mString, "ceil"))
{
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
vr = Dereference(proc, block, vr);
if (decf->mBase->mParams->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, block, vr, decf->mBase->mParams);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_UNARY_OPERATOR;
ins->mOperator = IA_CEIL;
ins->mSrc[0].mType = IT_FLOAT;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mDst.mType = IT_FLOAT;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheFloatTypeDeclaration, ins->mDst.mTemp);
}
else if (!strcmp(iname->mString, "strcpy"))
{
if (exp->mRight->mType == EX_LIST)
{
Expression* tex = exp->mRight->mLeft, * sex = exp->mRight->mRight;
if ((tex->mDecType->mType == DT_TYPE_ARRAY && tex->mDecType->mSize <= 256) ||
(sex->mDecType->mType == DT_TYPE_ARRAY && sex->mDecType->mSize <= 256))
{
vl = TranslateExpression(procType, proc, block, tex, breakBlock, continueBlock, inlineMapper);
if (vl.mType->mType == DT_TYPE_ARRAY)
vl = Dereference(proc, block, vl, 1);
else
vl = Dereference(proc, block, vl);
vr = TranslateExpression(procType, proc, block, sex, breakBlock, continueBlock, inlineMapper);
if (vr.mType->mType == DT_TYPE_ARRAY)
vr = Dereference(proc, block, vr, 1);
else
vr = Dereference(proc, block, vr);
if (!TheCharPointerTypeDeclaration->CanAssign(vl.mType))
mErrors->Error(tex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
if (!TheConstCharPointerTypeDeclaration->CanAssign(vr.mType))
mErrors->Error(sex->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
InterInstruction* ins = new InterInstruction();
ins->mCode = IC_STRCPY;
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vr.mTemp;
ins->mSrc[1].mType = IT_POINTER;
ins->mSrc[1].mTemp = vl.mTemp;
block->Append(ins);
return vl;
}
}
}
else
{
mErrors->Error(exp->mLeft->mDecValue->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown intrinsic function", iname->mString);
return ExValue(TheVoidTypeDeclaration);
}
}
if (exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (exp->mLeft->mDecValue->mFlags & DTF_INLINE) && !(inlineMapper && inlineMapper->mDepth > 10))
{
Declaration* fdec = exp->mLeft->mDecValue;
Expression* fexp = fdec->mValue;
Declaration* ftype = fdec->mBase;
InlineMapper nmapper;
nmapper.mReturn = new InterCodeBasicBlock();
nmapper.mVarIndex = proc->mNumLocals;
proc->mNumLocals += fdec->mNumVars;
if (inlineMapper)
nmapper.mDepth = inlineMapper->mDepth + 1;
proc->Append(nmapper.mReturn);
Declaration* pdec = ftype->mParams;
Expression* pex = exp->mRight;
while (pex)
{
int nindex = proc->mNumLocals++;
Declaration* vdec = new Declaration(pex->mLocation, DT_VARIABLE);
InterInstruction* ains = new InterInstruction();
ains->mCode = IC_CONSTANT;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
ains->mConst.mMemory = IM_LOCAL;
ains->mConst.mVarIndex = nindex;
if (pdec)
{
nmapper.mParams[pdec->mVarIndex] = nindex;
vdec->mVarIndex = nindex;
vdec->mBase = pdec->mBase;
if (pdec->mBase->mType == DT_TYPE_ARRAY)
ains->mConst.mOperandSize = 2;
else
ains->mConst.mOperandSize = pdec->mSize;
vdec->mSize = ains->mConst.mOperandSize;
vdec->mIdent = pdec->mIdent;
}
else
{
mErrors->Error(pex->mLocation, EERR_WRONG_PARAMETER, "Too many arguments for function call");
}
block->Append(ains);
Expression* texp;
if (pex->mType == EX_LIST)
{
texp = pex->mLeft;
pex = pex->mRight;
}
else
{
texp = pex;
pex = nullptr;
}
ExValue vp(pdec ? pdec->mBase : TheSignedIntTypeDeclaration, ains->mDst.mTemp, 1);
vr = TranslateExpression(procType, proc, block, texp, breakBlock, continueBlock, inlineMapper, &vp);
if (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)
{
if (pdec && !pdec->mBase->CanAssign(vr.mType))
mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = Dereference(proc, block, vr, 1);
if (vr.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an adressable expression");
if (vp.mTemp != vr.mTemp)
{
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_COPY;
cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins);
}
}
else
{
if (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION)
vr = Dereference(proc, block, vr, 1);
else
vr = Dereference(proc, block, vr);
if (pdec)
{
if (!pdec->mBase->CanAssign(vr.mType))
mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, block, vr, pdec->mBase);
}
else if (vr.mType->IsIntegerType() && vr.mType->mSize < 2)
{
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
}
InterInstruction* wins = new InterInstruction();
wins->mCode = IC_STORE;
wins->mSrc[1].mMemory = IM_INDIRECT;
wins->mSrc[0].mType = InterTypeOf(vr.mType);;
wins->mSrc[0].mTemp = vr.mTemp;
wins->mSrc[1].mType = IT_POINTER;
wins->mSrc[1].mTemp = ains->mDst.mTemp;
if (pdec)
{
if (pdec->mBase->mType == DT_TYPE_ARRAY)
wins->mSrc[1].mOperandSize = 2;
else
wins->mSrc[1].mOperandSize = pdec->mSize;
}
else if (vr.mType->mSize > 2 && vr.mType->mType != DT_TYPE_ARRAY)
wins->mSrc[1].mOperandSize = vr.mType->mSize;
else
wins->mSrc[1].mOperandSize = 2;
block->Append(wins);
}
if (pdec)
pdec = pdec->mNext;
}
if (pdec)
mErrors->Error(exp->mLocation, EERR_WRONG_PARAMETER, "Not enough arguments for function call");
Declaration* rdec = nullptr;
if (ftype->mBase->mType != DT_TYPE_VOID)
{
int nindex = proc->mNumLocals++;
nmapper.mResult = nindex;
rdec = new Declaration(ftype->mLocation, DT_VARIABLE);
rdec->mVarIndex = nindex;
rdec->mBase = ftype->mBase;
rdec->mSize = rdec->mBase->mSize;
}
vl = TranslateExpression(ftype, proc, block, fexp, nullptr, nullptr, &nmapper);
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(nmapper.mReturn, nullptr);
block = nmapper.mReturn;
if (rdec)
{
InterInstruction* ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mOperandSize = rdec->mSize;
ins->mConst.mIntConst = rdec->mOffset;
ins->mConst.mVarIndex = rdec->mVarIndex;
ins->mConst.mMemory = IM_LOCAL;
block->Append(ins);
return ExValue(rdec->mBase, ins->mDst.mTemp, 1);
}
else
return ExValue(TheVoidTypeDeclaration);
}
else
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl);
int atotal = 0;
InterCodeBasicBlock* fblock = block;
Declaration* ftype = vl.mType;
if (ftype->mType == DT_TYPE_POINTER)
ftype = ftype->mBase;
InterInstruction* fins = nullptr;
if (ftype->mFlags & DTF_FASTCALL)
{
}
else
{
fins = new InterInstruction();
fins->mCode = IC_PUSH_FRAME;
fins->mConst.mIntConst = atotal;
block->Append(fins);
}
Declaration * decResult = nullptr;
if (ftype->mBase->mType == DT_TYPE_STRUCT)
{
int ttemp;
if (lrexp)
{
ttemp = lrexp->mTemp;
decResult = lrexp->mType;
}
else
{
int nindex = proc->mNumLocals++;
Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE);
vdec->mVarIndex = nindex;
vdec->mBase = ftype->mBase;
vdec->mSize = ftype->mBase->mSize;
decResult = vdec;
InterInstruction* vins = new InterInstruction();
vins->mCode = IC_CONSTANT;
vins->mDst.mType = IT_POINTER;
vins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
vins->mConst.mMemory = IM_LOCAL;
vins->mConst.mVarIndex = nindex;
vins->mConst.mOperandSize = ftype->mBase->mSize;
block->Append(vins);
ttemp = vins->mDst.mTemp;
}
InterInstruction* ains = new InterInstruction();
ains->mCode = IC_CONSTANT;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(IT_POINTER);
ains->mConst.mVarIndex = 0;
ains->mConst.mIntConst = 0;
ains->mConst.mOperandSize = 2;
if (ftype->mFlags & DTF_FASTCALL)
ains->mConst.mMemory = IM_FPARAM;
else
ains->mConst.mMemory = IM_FRAME;
block->Append(ains);
InterInstruction* wins = new InterInstruction();
wins->mCode = IC_STORE;
wins->mSrc[1].mMemory = IM_INDIRECT;
wins->mSrc[0].mType = IT_POINTER;
wins->mSrc[0].mTemp = ttemp;
wins->mSrc[1].mType = IT_POINTER;
wins->mSrc[1].mTemp = ains->mDst.mTemp;
wins->mSrc[1].mOperandSize = 2;
block->Append(wins);
atotal = 2;
}
if (exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION)
proc->AddCalledFunction(proc->mModule->mProcedures[exp->mLeft->mDecValue->mVarIndex]);
else
proc->CallsFunctionPointer();
GrowingArray<InterInstruction*> defins(nullptr);
Declaration* pdec = ftype->mParams;
Expression* pex = exp->mRight;
while (pex)
{
InterInstruction * ains = new InterInstruction();
ains->mCode = IC_CONSTANT;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType);
if (pdec)
{
ains->mConst.mVarIndex = pdec->mVarIndex;
ains->mConst.mIntConst = pdec->mOffset;
if (pdec->mBase->mType == DT_TYPE_ARRAY)
ains->mConst.mOperandSize = 2;
else
ains->mConst.mOperandSize = pdec->mSize;
}
else if (ftype->mFlags & DTF_VARIADIC)
{
ains->mConst.mVarIndex = atotal;
ains->mConst.mIntConst = 0;
ains->mConst.mOperandSize = 2;
}
else
{
mErrors->Error(pex->mLocation, EERR_WRONG_PARAMETER, "Too many arguments for function call");
}
if (ftype->mFlags & DTF_FASTCALL)
{
ains->mConst.mMemory = IM_FPARAM;
ains->mConst.mIntConst = 0;
}
else
ains->mConst.mMemory = IM_FRAME;
block->Append(ains);
Expression* texp;
if (pex->mType == EX_LIST)
{
texp = pex->mLeft;
pex = pex->mRight;
}
else
{
texp = pex;
pex = nullptr;
}
ExValue vp(pdec ? pdec->mBase : TheSignedIntTypeDeclaration, ains->mDst.mTemp, 1);
vr = TranslateExpression(procType, proc, block, texp, breakBlock, continueBlock, inlineMapper, &vp);
if (vr.mType->mType == DT_TYPE_STRUCT || vr.mType->mType == DT_TYPE_UNION)
{
if (pdec && !pdec->mBase->CanAssign(vr.mType))
mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = Dereference(proc, block, vr, 1);
if (vr.mReference != 1)
mErrors->Error(exp->mLeft->mLocation, EERR_NOT_AN_LVALUE, "Not an adressable expression");
if (vp.mTemp != vr.mTemp)
{
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_COPY;
cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins);
}
atotal += vr.mType->mSize;
}
else
{
if (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION)
vr = Dereference(proc, block, vr, 1);
else
vr = Dereference(proc, block, vr);
if (pdec)
{
if (!pdec->mBase->CanAssign(vr.mType))
mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
vr = CoerceType(proc, block, vr, pdec->mBase);
}
else if (vr.mType->IsIntegerType() && vr.mType->mSize < 2)
{
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
}
InterInstruction* wins = new InterInstruction();
wins->mCode = IC_STORE;
wins->mSrc[1].mMemory = IM_INDIRECT;
wins->mSrc[0].mType = InterTypeOf(vr.mType);;
wins->mSrc[0].mTemp = vr.mTemp;
wins->mSrc[1].mType = IT_POINTER;
wins->mSrc[1].mTemp = ains->mDst.mTemp;
if (pdec)
{
if (pdec->mBase->mType == DT_TYPE_ARRAY)
wins->mSrc[1].mOperandSize = 2;
else
wins->mSrc[1].mOperandSize = pdec->mSize;
}
else if (vr.mType->mSize > 2 && vr.mType->mType != DT_TYPE_ARRAY)
wins->mSrc[1].mOperandSize = vr.mType->mSize;
else
wins->mSrc[1].mOperandSize = 2;
if (ftype->mFlags & DTF_FASTCALL)
defins.Push(wins);
else
block->Append(wins);
atotal += wins->mSrc[1].mOperandSize;
}
if (pdec)
pdec = pdec->mNext;
}
if (pdec)
mErrors->Error(exp->mLocation, EERR_WRONG_PARAMETER, "Not enough arguments for function call");
for (int i = 0; i < defins.Size(); i++)
block->Append(defins[i]);
InterInstruction * cins = new InterInstruction();
if (exp->mLeft->mDecValue && exp->mLeft->mDecValue->mFlags & DTF_NATIVE)
cins->mCode = IC_CALL_NATIVE;
else
cins->mCode = IC_CALL;
cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vl.mTemp;
if (ftype->mBase->mType != DT_TYPE_VOID && ftype->mBase->mType != DT_TYPE_STRUCT)
{
cins->mDst.mType = InterTypeOf(ftype->mBase);
cins->mDst.mTemp = proc->AddTemporary(cins->mDst.mType);
}
block->Append(cins);
if (ftype->mFlags & DTF_FASTCALL)
{
}
else
{
fins->mConst.mIntConst = atotal;
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_POP_FRAME;
xins->mConst.mIntConst = atotal;
block->Append(xins);
}
if (decResult)
{
if (lrexp)
return *lrexp;
InterInstruction* vins = new InterInstruction();
vins->mCode = IC_CONSTANT;
vins->mDst.mType = IT_POINTER;
vins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
vins->mConst.mMemory = IM_LOCAL;
vins->mConst.mVarIndex = decResult->mVarIndex;
block->Append(vins);
return ExValue(ftype->mBase, vins->mDst.mTemp, 1);
}
else
return ExValue(ftype->mBase, cins->mDst.mTemp);
}
}
case EX_ASSEMBLER:
{
GrowingArray<Declaration*> refvars(nullptr);
TranslateAssembler(proc->mModule, exp, &refvars);
Declaration* dec = exp->mDecValue;
if (block)
{
dec->mLinkerObject->mFlags |= LOBJF_INLINE;
InterInstruction* ins = new InterInstruction();
ins->mCode = IC_CONSTANT;
ins->mDst.mType = IT_POINTER;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ins->mConst.mOperandSize = dec->mSize;
ins->mConst.mIntConst = 0;
ins->mConst.mMemory = IM_GLOBAL;
ins->mConst.mLinkerObject = dec->mLinkerObject;
ins->mConst.mVarIndex = dec->mVarIndex;
block->Append(ins);
InterInstruction * jins = new InterInstruction();
jins->mCode = IC_ASSEMBLER;
jins->mSrc[0].mType = IT_POINTER;
jins->mSrc[0].mTemp = ins->mDst.mTemp;
jins->mNumOperands = 1;
for (int i = 0; i < refvars.Size(); i++)
{
InterInstruction* vins = new InterInstruction();
vins->mCode = IC_CONSTANT;
vins->mDst.mType = IT_POINTER;
vins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
Declaration* vdec = refvars[i];
if (vdec->mType == DT_ARGUMENT)
{
vins->mConst.mVarIndex = vdec->mVarIndex;
if (inlineMapper)
{
vins->mConst.mMemory = IM_LOCAL;
vins->mConst.mVarIndex = inlineMapper->mParams[vdec->mVarIndex];
}
else if (procType->mFlags & DTF_FASTCALL)
vins->mConst.mMemory = IM_FPARAM;
else
vins->mConst.mMemory = IM_PARAM;
vins->mConst.mOperandSize = vdec->mSize;
vins->mConst.mIntConst = vdec->mOffset;
}
else if (vdec->mType == DT_VARIABLE)
{
vins->mConst.mMemory = IM_LOCAL;
vins->mConst.mVarIndex = vdec->mVarIndex;
vins->mConst.mOperandSize = vdec->mSize;
vins->mConst.mIntConst = vdec->mOffset;
}
block->Append(vins);
InterInstruction* lins = new InterInstruction();
lins->mCode = IC_LOAD;
lins->mSrc[0].mMemory = IM_INDIRECT;
lins->mSrc[0].mType = IT_POINTER;
lins->mSrc[0].mTemp = vins->mDst.mTemp;
lins->mDst.mType = InterTypeOf(vdec->mBase);
lins->mDst.mTemp = proc->AddTemporary(lins->mDst.mType);
lins->mSrc[0].mOperandSize = vdec->mSize;
block->Append(lins);
jins->mSrc[jins->mNumOperands].mType = InterTypeOf(vdec->mBase);
jins->mSrc[jins->mNumOperands].mTemp = lins->mDst.mTemp;
jins->mNumOperands++;
}
block->Append(jins);
}
return ExValue(TheVoidTypeDeclaration);
}
case EX_RETURN:
{
InterInstruction * ins = new InterInstruction();
if (exp->mLeft)
{
vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
if (procType->mBase->mType == DT_TYPE_STRUCT)
{
vr = Dereference(proc, block, vr, 1);
if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID)
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type");
else if (!procType->mBase->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type");
else if (vr.mReference != 1)
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Non addressable object");
InterInstruction* ains = new InterInstruction();
if (inlineMapper)
{
ains->mCode = IC_CONSTANT;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(IT_POINTER);
ains->mConst.mOperandSize = procType->mBase->mSize;
ains->mConst.mIntConst = 0;
ains->mConst.mVarIndex = inlineMapper->mResult;
ains->mConst.mMemory = IM_LOCAL;
block->Append(ains);
ins->mCode = IC_NONE;
}
else
{
InterInstruction* pins = new InterInstruction();
pins->mCode = IC_CONSTANT;
pins->mDst.mType = IT_POINTER;
pins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
pins->mConst.mVarIndex = 0;
pins->mConst.mIntConst = 0;
pins->mConst.mOperandSize = 2;
if (procType->mFlags & DTF_FASTCALL)
pins->mConst.mMemory = IM_FPARAM;
else
pins->mConst.mMemory = IM_PARAM;
block->Append(pins);
ains->mCode = IC_LOAD;
ains->mSrc[0].mMemory = IM_INDIRECT;
ains->mSrc[0].mType = IT_POINTER;
ains->mSrc[0].mTemp = pins->mDst.mTemp;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(IT_POINTER);
block->Append(ains);
ins->mCode = IC_RETURN;
}
InterInstruction* cins = new InterInstruction();
cins->mCode = IC_COPY;
cins->mSrc[0].mType = IT_POINTER;
cins->mSrc[0].mTemp = vr.mTemp;
cins->mSrc[0].mMemory = IM_INDIRECT;
cins->mSrc[1].mType = IT_POINTER;
cins->mSrc[1].mTemp = ains->mDst.mTemp;
cins->mSrc[1].mMemory = IM_INDIRECT;
cins->mConst.mOperandSize = vr.mType->mSize;
block->Append(cins);
}
else
{
vr = Dereference(proc, block, vr);
if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID)
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type");
else if (!procType->mBase->CanAssign(vr.mType))
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type");
vr = CoerceType(proc, block, vr, procType->mBase);
ins->mSrc[0].mType = InterTypeOf(vr.mType);
ins->mSrc[0].mTemp = vr.mTemp;
if (inlineMapper)
{
InterInstruction* ains = new InterInstruction();
ains->mCode = IC_CONSTANT;
ains->mDst.mType = IT_POINTER;
ains->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
ains->mConst.mOperandSize = procType->mBase->mSize;
ains->mConst.mIntConst = 0;
ains->mConst.mVarIndex = inlineMapper->mResult;;
ains->mConst.mMemory = IM_LOCAL;
block->Append(ains);
ins->mSrc[1].mType = ains->mDst.mType;
ins->mSrc[1].mTemp = ains->mDst.mTemp;
ins->mSrc[1].mMemory = IM_INDIRECT;
ins->mCode = IC_STORE;
ins->mSrc[1].mOperandSize = ains->mConst.mOperandSize;
}
else
ins->mCode = IC_RETURN_VALUE;
}
}
else
{
if (procType->mBase && procType->mBase->mType != DT_TYPE_VOID)
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has non void return type");
if (inlineMapper)
ins->mCode = IC_NONE;
else
ins->mCode = IC_RETURN;
}
if (ins->mCode != IC_NONE)
block->Append(ins);
if (inlineMapper)
{
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(inlineMapper->mReturn, nullptr);
}
else
block->Close(nullptr, nullptr);
block = new InterCodeBasicBlock();
proc->Append(block);
return ExValue(TheVoidTypeDeclaration);
}
case EX_BREAK:
{
if (breakBlock)
{
InterInstruction * jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(breakBlock, nullptr);
block = new InterCodeBasicBlock();
proc->Append(block);
}
else
mErrors->Error(exp->mLocation, EERR_INVALID_BREAK, "No break target");
return ExValue(TheVoidTypeDeclaration);
}
case EX_CONTINUE:
{
if (continueBlock)
{
InterInstruction * jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(continueBlock, nullptr);
block = new InterCodeBasicBlock();
proc->Append(block);
}
else
mErrors->Error(exp->mLocation, EERR_INVALID_CONTINUE, "No continue target");
return ExValue(TheVoidTypeDeclaration);
}
case EX_LOGICAL_NOT:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl);
InterInstruction * zins = new InterInstruction();
zins->mCode = IC_CONSTANT;
zins->mDst.mType = InterTypeOf(vl.mType);
zins->mDst.mTemp = proc->AddTemporary(zins->mDst.mType);
zins->mConst.mIntConst = 0;
block->Append(zins);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_RELATIONAL_OPERATOR;
ins->mOperator = IA_CMPEQ;
ins->mSrc[0].mType = InterTypeOf(vl.mType);
ins->mSrc[0].mTemp = zins->mDst.mTemp;
ins->mSrc[1].mType = InterTypeOf(vl.mType);
ins->mSrc[1].mTemp = vl.mTemp;
ins->mDst.mType = IT_BOOL;
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
return ExValue(TheBoolTypeDeclaration, ins->mDst.mTemp);
}
case EX_CONDITIONAL:
{
InterInstruction * jins0 = new InterInstruction();
jins0->mCode = IC_JUMP;
InterInstruction* jins1 = new InterInstruction();
jins1->mCode = IC_JUMP;
InterCodeBasicBlock* tblock = new InterCodeBasicBlock();
proc->Append(tblock);
InterCodeBasicBlock* fblock = new InterCodeBasicBlock();
proc->Append(fblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, inlineMapper);
vl = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock, inlineMapper);
vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock, inlineMapper);
int ttemp;
InterType ttype, stypel, styper;
stypel = InterTypeOf(vl.mType);
styper = InterTypeOf(vr.mType);
Declaration* dtype;
if (stypel == IT_POINTER || styper == IT_POINTER)
{
if (vl.mType->mType == DT_TYPE_ARRAY)
vl = Dereference(proc, tblock, vl, 1);
else
vl = Dereference(proc, tblock, vl);
if (vr.mType->mType == DT_TYPE_ARRAY)
vr = Dereference(proc, fblock, vr, 1);
else
vr = Dereference(proc, fblock, vr);
if (vl.mType->mBase->IsSubType(vr.mType->mBase))
dtype = vr.mType;
else if (vr.mType->mBase->IsSubType(vl.mType->mBase))
dtype = vl.mType;
else
{
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Incompatible conditional types");
dtype = vl.mType;
}
Declaration* ntype = new Declaration(dtype->mLocation, DT_TYPE_POINTER);
ntype->mBase = dtype->mBase;
dtype = ntype;
ttype = IT_POINTER;
}
else
{
vl = Dereference(proc, tblock, vl);
vr = Dereference(proc, fblock, vr);
if (stypel == styper)
{
ttype = stypel;
dtype = vl.mType;
}
else if (stypel > styper)
{
ttype = stypel;
dtype = vl.mType;
vr = CoerceType(proc, fblock, vr, dtype);
}
else
{
ttype = styper;
dtype = vr.mType;
vl = CoerceType(proc, tblock, vl, dtype);
}
}
ttemp = proc->AddTemporary(ttype);
InterInstruction * rins = new InterInstruction();
rins->mCode = IC_LOAD_TEMPORARY;
rins->mSrc[0].mType = ttype;
rins->mSrc[0].mTemp = vr.mTemp;
rins->mDst.mType = ttype;
rins->mDst.mTemp = ttemp;
fblock->Append(rins);
InterInstruction * lins = new InterInstruction();
lins->mCode = IC_LOAD_TEMPORARY;
lins->mSrc[0].mType = ttype;
lins->mSrc[0].mTemp = vl.mTemp;
lins->mDst.mType = ttype;
lins->mDst.mTemp = ttemp;
tblock->Append(lins);
tblock->Append(jins0);
tblock->Close(eblock, nullptr);
fblock->Append(jins1);
fblock->Close(eblock, nullptr);
block = eblock;
return ExValue(dtype, ttemp);
break;
}
case EX_TYPECAST:
{
vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock, inlineMapper);
InterInstruction * ins = new InterInstruction();
if (exp->mLeft->mDecType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
{
vr = Dereference(proc, block, vr);
int stemp = vr.mTemp;
if (vr.mType->mSize == 1)
{
if (vr.mType->mFlags & DTF_SIGNED)
{
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16S;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
else
{
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_CONVERSION_OPERATOR;
xins->mOperator = IA_EXT8TO16U;
xins->mSrc[0].mType = IT_INT8;
xins->mSrc[0].mTemp = stemp;
xins->mDst.mType = IT_INT16;
xins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(xins);
stemp = xins->mDst.mTemp;
}
}
ins->mCode = IC_CONVERSION_OPERATOR;
ins->mOperator = IA_INT2FLOAT;
ins->mSrc[0].mType = IT_INT16;
ins->mSrc[0].mTemp = stemp;
ins->mDst.mType = InterTypeOf(exp->mLeft->mDecType);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
}
else if (exp->mLeft->mDecType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
{
vr = Dereference(proc, block, vr);
ins->mCode = IC_CONVERSION_OPERATOR;
ins->mOperator = IA_FLOAT2INT;
ins->mSrc[0].mType = InterTypeOf(vr.mType);
ins->mSrc[0].mTemp = vr.mTemp;
ins->mDst.mType = IT_INT16;
ins->mDst.mTemp = proc->AddTemporary(IT_INT16);
block->Append(ins);
if (exp->mLeft->mDecType->mSize == 1)
{
InterInstruction* xins = new InterInstruction();
xins->mCode = IC_TYPECAST;
xins->mSrc[0].mType = IT_INT16;
xins->mSrc[0].mTemp = ins->mDst.mTemp;
xins->mDst.mType = InterTypeOf(exp->mLeft->mDecType);
xins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(xins);
ins = xins;
}
}
else if (exp->mLeft->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_POINTER)
{
// no need for actual operation when casting pointer to pointer
return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference);
}
else if (exp->mLeft->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_ARRAY)
{
// no need for actual operation when casting pointer to pointer
return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference - 1);
}
else if (exp->mLeft->mDecType->mType != DT_TYPE_VOID && vr.mType->mType == DT_TYPE_VOID)
{
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Cannot cast void object to non void object");
return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference);
}
else if (exp->mLeft->mDecType->IsIntegerType() && vr.mType->IsIntegerType())
{
vr = Dereference(proc, block, vr);
return CoerceType(proc, block, vr, exp->mLeft->mDecType);
}
else
{
vr = Dereference(proc, block, vr);
ins->mCode = IC_TYPECAST;
ins->mSrc[0].mType = InterTypeOf(vr.mType);
ins->mSrc[0].mTemp = vr.mTemp;
ins->mDst.mType = InterTypeOf(exp->mLeft->mDecType);
ins->mDst.mTemp = proc->AddTemporary(ins->mDst.mType);
block->Append(ins);
}
return ExValue(exp->mLeft->mDecType, ins->mDst.mTemp);
}
break;
case EX_LOGICAL_AND:
case EX_LOGICAL_OR:
{
InterInstruction* jins0 = new InterInstruction();
jins0->mCode = IC_JUMP;
InterInstruction* jins1 = new InterInstruction();
jins1->mCode = IC_JUMP;
InterCodeBasicBlock* tblock = new InterCodeBasicBlock();
proc->Append(tblock);
InterCodeBasicBlock* fblock = new InterCodeBasicBlock();
proc->Append(fblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
TranslateLogic(procType, proc, block, tblock, fblock, exp, inlineMapper);
int ttemp = proc->AddTemporary(IT_BOOL);
InterInstruction* tins = new InterInstruction();
tins->mCode = IC_CONSTANT;
tins->mConst.mIntConst = 1;
tins->mDst.mType = IT_BOOL;
tins->mDst.mTemp = ttemp;
tblock->Append(tins);
InterInstruction* fins = new InterInstruction();
fins->mCode = IC_CONSTANT;
fins->mConst.mIntConst = 0;
fins->mDst.mType = IT_BOOL;
fins->mDst.mTemp = ttemp;
fblock->Append(fins);
tblock->Append(jins0);
tblock->Close(eblock, nullptr);
fblock->Append(jins1);
fblock->Close(eblock, nullptr);
block = eblock;
return ExValue(TheBoolTypeDeclaration, ttemp);
} break;
case EX_WHILE:
{
InterInstruction * jins0 = new InterInstruction();
jins0->mCode = IC_JUMP;
InterInstruction* jins1 = new InterInstruction();
jins1->mCode = IC_JUMP;
InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
InterCodeBasicBlock* lblock = cblock;
proc->Append(cblock);
InterCodeBasicBlock* bblock = new InterCodeBasicBlock();
proc->Append(bblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
block->Append(jins0);
block->Close(cblock, nullptr);
TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft, inlineMapper);
vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, lblock, inlineMapper);
bblock->Append(jins1);
bblock->Close(lblock, nullptr);
block = eblock;
return ExValue(TheVoidTypeDeclaration);
}
case EX_IF:
{
InterInstruction * jins0 = new InterInstruction();
jins0->mCode = IC_JUMP;
InterInstruction* jins1 = new InterInstruction();
jins1->mCode = IC_JUMP;
InterCodeBasicBlock* tblock = new InterCodeBasicBlock();
proc->Append(tblock);
InterCodeBasicBlock* fblock = new InterCodeBasicBlock();
proc->Append(fblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft, inlineMapper);
vr = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock, inlineMapper);
tblock->Append(jins0);
tblock->Close(eblock, nullptr);
if (exp->mRight->mRight)
vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock, inlineMapper);
fblock->Append(jins1);
fblock->Close(eblock, nullptr);
block = eblock;
return ExValue(TheVoidTypeDeclaration);
}
case EX_FOR:
{
// assignment
if (exp->mLeft->mRight)
TranslateExpression(procType, proc, block, exp->mLeft->mRight, breakBlock, continueBlock, inlineMapper);
InterInstruction * jins0 = new InterInstruction();
jins0->mCode = IC_JUMP;
InterInstruction* jins1 = new InterInstruction();
jins1->mCode = IC_JUMP;
InterInstruction* jins2 = new InterInstruction();
jins2->mCode = IC_JUMP;
InterInstruction* jins3 = new InterInstruction();
jins3->mCode = IC_JUMP;
InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
InterCodeBasicBlock* lblock = cblock;
proc->Append(cblock);
InterCodeBasicBlock* bblock = new InterCodeBasicBlock();
proc->Append(bblock);
InterCodeBasicBlock* iblock = new InterCodeBasicBlock();
proc->Append(iblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
block->Append(jins0);
block->Close(cblock, nullptr);
// condition
if (exp->mLeft->mLeft->mLeft)
TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft->mLeft->mLeft, inlineMapper);
else
{
cblock->Append(jins1);
cblock->Close(bblock, nullptr);
}
vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, iblock, inlineMapper);
bblock->Append(jins2);
bblock->Close(iblock, nullptr);
// increment
if (exp->mLeft->mLeft->mRight)
TranslateExpression(procType, proc, iblock, exp->mLeft->mLeft->mRight, breakBlock, continueBlock, inlineMapper);
iblock->Append(jins3);
iblock->Close(lblock, nullptr);
block = eblock;
return ExValue(TheVoidTypeDeclaration);
}
case EX_DO:
{
InterInstruction * jins = new InterInstruction();
jins->mCode = IC_JUMP;
InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
InterCodeBasicBlock* lblock = cblock;
proc->Append(cblock);
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
block->Append(jins);
block->Close(cblock, nullptr);
vr = TranslateExpression(procType, proc, cblock, exp->mRight, eblock, cblock, inlineMapper);
TranslateLogic(procType, proc, cblock, lblock, eblock, exp->mLeft, inlineMapper);
block = eblock;
return ExValue(TheVoidTypeDeclaration);
}
case EX_SWITCH:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, block, vl);
vl = CoerceType(proc, block, vl, TheSignedIntTypeDeclaration);
InterCodeBasicBlock * dblock = nullptr;
InterCodeBasicBlock* sblock = block;
block = nullptr;
InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
proc->Append(eblock);
SwitchNodeArray switchNodes({ 0 });
Expression* sexp = exp->mRight;
while (sexp)
{
Expression* cexp = sexp->mLeft;
if (cexp->mType == EX_CASE)
{
InterCodeBasicBlock* nblock = new InterCodeBasicBlock();
proc->Append(nblock);
SwitchNode snode;
snode.mBlock = nblock;
snode.mValue = 0;
if (cexp->mLeft->mType == EX_CONSTANT && cexp->mLeft->mDecValue->mType == DT_CONST_INTEGER)
snode.mValue = cexp->mLeft->mDecValue->mInteger;
else
mErrors->Error(cexp->mLeft->mLocation, ERRR_INVALID_CASE, "Integral constant expected");
int i = 0;
while (i < switchNodes.Size() && switchNodes[i].mValue < snode.mValue)
i++;
if (i < switchNodes.Size() && switchNodes[i].mValue == snode.mValue)
mErrors->Error(exp->mLeft->mLocation, ERRR_INVALID_CASE, "Duplicate case constant");
else
switchNodes.Insert(i, snode);
if (block)
{
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(nblock, nullptr);
}
block = nblock;
}
else if (cexp->mType == EX_DEFAULT)
{
if (!dblock)
{
dblock = new InterCodeBasicBlock();
proc->Append(dblock);
if (block)
{
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(dblock, nullptr);
}
block = dblock;
}
else
mErrors->Error(cexp->mLocation, EERR_DUPLICATE_DEFAULT, "Duplicate default");
}
if (cexp->mRight)
TranslateExpression(procType, proc, block, cexp->mRight, eblock, continueBlock, inlineMapper);
sexp = sexp->mRight;
}
BuildSwitchTree(proc, sblock, vl, switchNodes, 0, switchNodes.Size(), dblock ? dblock : eblock);
if (block)
{
InterInstruction* jins = new InterInstruction();
jins->mCode = IC_JUMP;
block->Append(jins);
block->Close(eblock, nullptr);
}
block = eblock;
return ExValue(TheVoidTypeDeclaration);
}
default:
mErrors->Error(exp->mLocation, EERR_UNIMPLEMENTED, "Unimplemented expression");
return ExValue(TheVoidTypeDeclaration);
}
}
}
void InterCodeGenerator::BuildInitializer(InterCodeModule * mod, uint8* dp, int offset, Declaration* data, InterVariable * variable)
{
if (data->mType == DT_CONST_DATA)
{
memcpy(dp + offset, data->mData, data->mBase->mSize);
}
else if (data->mType == DT_CONST_STRUCT)
{
Declaration* mdec = data->mParams;
while (mdec)
{
BuildInitializer(mod, dp, offset + mdec->mOffset, mdec, variable);
mdec = mdec->mNext;
}
}
else if (data->mType == DT_CONST_INTEGER)
{
int64 t = data->mInteger;
for (int i = 0; i < data->mBase->mSize; i++)
{
dp[offset + i] = uint8(t & 0xff);
t >>= 8;
}
}
else if (data->mType == DT_CONST_ADDRESS)
{
int64 t = data->mInteger;
dp[offset + 0] = uint8(t & 0xff);
dp[offset + 1] = t >> 8;
}
else if (data->mType == DT_CONST_FLOAT)
{
union { float f; uint32 i; } cast;
cast.f = data->mNumber;
int64 t = cast.i;
for (int i = 0; i < 4; i++)
{
dp[offset + i] = t & 0xff;
t >>= 8;
}
}
else if (data->mType == DT_CONST_ASSEMBLER)
{
if (!data->mLinkerObject)
TranslateAssembler(mod, data->mValue, nullptr);
LinkerReference ref;
ref.mObject = variable->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = data->mLinkerObject;
ref.mRefOffset = 0;
variable->mLinkerObject->AddReference(ref);
}
else if (data->mType == DT_CONST_FUNCTION)
{
if (!data->mLinkerObject)
{
InterCodeProcedure* cproc = this->TranslateProcedure(mod, data->mValue, data);
}
LinkerReference ref;
ref.mObject = variable->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
ref.mRefObject = data->mLinkerObject;
ref.mRefOffset = 0;
variable->mLinkerObject->AddReference(ref);
}
else if (data->mType == DT_CONST_POINTER)
{
Expression* exp = data->mValue;
Declaration* dec = exp->mDecValue;
LinkerReference ref;
ref.mObject = variable->mLinkerObject;
ref.mOffset = offset;
ref.mFlags = LREF_LOWBYTE | LREF_HIGHBYTE;
switch (dec->mType)
{
case DT_CONST_DATA:
{
if (!dec->mLinkerObject)
{
dec->mVarIndex = mod->mGlobalVars.Size();
InterVariable* var = new InterVariable();
var->mIndex = dec->mVarIndex;
var->mOffset = 0;
var->mSize = dec->mSize;
var->mLinkerObject = mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_DATA);
dec->mLinkerObject = var->mLinkerObject;
var->mLinkerObject->AddData(dec->mData, dec->mSize);
mod->mGlobalVars.Push(var);
}
ref.mRefObject = dec->mLinkerObject;
ref.mRefOffset = 0;
variable->mLinkerObject->AddReference(ref);
break;
}
}
}
}
void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp, InlineMapper* inlineMapper)
{
switch (exp->mType)
{
case EX_LOGICAL_NOT:
TranslateLogic(procType, proc, block, fblock, tblock, exp->mLeft, inlineMapper);
break;
case EX_LOGICAL_AND:
{
InterCodeBasicBlock* ablock = new InterCodeBasicBlock();
proc->Append(ablock);
TranslateLogic(procType, proc, block, ablock, fblock, exp->mLeft, inlineMapper);
TranslateLogic(procType, proc, ablock, tblock, fblock, exp->mRight, inlineMapper);
break;
}
case EX_LOGICAL_OR:
{
InterCodeBasicBlock* oblock = new InterCodeBasicBlock();
proc->Append(oblock);
TranslateLogic(procType, proc, block, tblock, oblock, exp->mLeft, inlineMapper);
TranslateLogic(procType, proc, oblock, tblock, fblock, exp->mRight, inlineMapper);
break;
}
default:
{
ExValue vr = TranslateExpression(procType, proc, block, exp, nullptr, nullptr, inlineMapper);
vr = Dereference(proc, block, vr);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_BRANCH;
ins->mSrc[0].mType = InterTypeOf(vr.mType);
ins->mSrc[0].mTemp = vr.mTemp;
block->Append(ins);
block->Close(tblock, fblock);
}
}
}
InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod, Expression* exp, Declaration * dec)
{
InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mIdent, mLinker->AddObject(dec->mLocation, dec->mIdent, dec->mSection, LOT_BYTE_CODE));
dec->mVarIndex = proc->mID;
dec->mLinkerObject = proc->mLinkerObject;
proc->mNumLocals = dec->mNumVars;
if (mCompilerOptions & COPT_NATIVE)
dec->mFlags |= DTF_NATIVE;
if (dec->mFlags & DTF_NATIVE)
proc->mNativeProcedure = true;
if (dec->mBase->mFlags & DTF_FASTCALL)
{
proc->mFastCallProcedure = true;
dec->mLinkerObject->mNumTemporaries = 1;
dec->mLinkerObject->mTemporaries[0] = BC_REG_FPARAMS;
dec->mLinkerObject->mTempSizes[0] = BC_REG_FPARAMS_END - BC_REG_FPARAMS;
}
InterCodeBasicBlock* entryBlock = new InterCodeBasicBlock();
proc->Append(entryBlock);
InterCodeBasicBlock* exitBlock = entryBlock;
if (dec->mFlags & DTF_DEFINED)
TranslateExpression(dec->mBase, proc, exitBlock, exp, nullptr, nullptr, nullptr);
else
mErrors->Error(dec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", dec->mIdent->mString);
InterInstruction * ins = new InterInstruction();
ins->mCode = IC_RETURN;
exitBlock->Append(ins);
exitBlock->Close(nullptr, nullptr);
if (mErrors->mErrorCount == 0)
proc->Close();
return proc;
}