845 lines
18 KiB
C++
845 lines
18 KiB
C++
|
|
#include "nodes.hpp"
|
|
#include "std.hpp"
|
|
|
|
#include <float.h>
|
|
#include <math.h>
|
|
|
|
//////////////////////////////////
|
|
// Cast an expression to a type //
|
|
//////////////////////////////////
|
|
ExprNode* ExprNode::castTo(Type* ty, Environ* e)
|
|
{
|
|
if (!sem_type->canCastTo(ty)) {
|
|
ex("Illegal type conversion");
|
|
}
|
|
|
|
ExprNode* cast = new CastNode(this, ty);
|
|
cast->semant(e);
|
|
return cast;
|
|
}
|
|
|
|
ExprNode* CastNode::semant(Environ* e)
|
|
{
|
|
if (!expr->sem_type) {
|
|
expr = expr->semant(e);
|
|
}
|
|
|
|
if (ConstNode* c = expr->constNode()) {
|
|
ExprNode* e;
|
|
if (type == Type::int_type)
|
|
e = new IntConstNode(c->intValue());
|
|
else if (type == Type::float_type)
|
|
e = new FloatConstNode(c->floatValue());
|
|
else
|
|
e = new StringConstNode(c->stringValue());
|
|
delete this;
|
|
return e;
|
|
}
|
|
|
|
sem_type = type;
|
|
return this;
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// Cast an expression to a type //
|
|
//////////////////////////////////
|
|
TNode* CastNode::translate(Codegen* g)
|
|
{
|
|
TNode* t = expr->translate(g);
|
|
if (expr->sem_type == Type::float_type && sem_type == Type::int_type) {
|
|
//float->int
|
|
return new TNode(IR_CAST, t, 0);
|
|
}
|
|
if (expr->sem_type == Type::int_type && sem_type == Type::float_type) {
|
|
//int->float
|
|
return new TNode(IR_FCAST, t, 0);
|
|
}
|
|
if (expr->sem_type == Type::string_type && sem_type == Type::int_type) {
|
|
//str->int
|
|
return call("__bbStrToInt", t);
|
|
}
|
|
if (expr->sem_type == Type::int_type && sem_type == Type::string_type) {
|
|
//int->str
|
|
return call("__bbStrFromInt", t);
|
|
}
|
|
if (expr->sem_type == Type::string_type && sem_type == Type::float_type) {
|
|
//str->float
|
|
return fcall("__bbStrToFloat", t);
|
|
}
|
|
if (expr->sem_type == Type::float_type && sem_type == Type::string_type) {
|
|
//float->str
|
|
return call("__bbStrFromFloat", t);
|
|
}
|
|
if (expr->sem_type->structType() && sem_type == Type::string_type) {
|
|
//obj->str
|
|
return call("__bbObjToStr", t);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/////////////////////////////
|
|
// Sequence of Expressions //
|
|
/////////////////////////////
|
|
void ExprSeqNode::semant(Environ* e)
|
|
{
|
|
for (int k = 0; k < exprs.size(); ++k) {
|
|
if (exprs[k])
|
|
exprs[k] = exprs[k]->semant(e);
|
|
}
|
|
}
|
|
|
|
TNode* ExprSeqNode::translate(Codegen* g, bool cfunc)
|
|
{
|
|
TNode *t = 0, *l = 0;
|
|
for (int k = 0; k < exprs.size(); ++k) {
|
|
TNode* q = exprs[k]->translate(g);
|
|
|
|
if (cfunc) {
|
|
Type* ty = exprs[k]->sem_type;
|
|
if (ty->stringType()) {
|
|
q = call("__bbStrToCStr", q);
|
|
} else if (ty->structType()) {
|
|
q = new TNode(IR_MEM, q);
|
|
} else if (ty == Type::void_type) {
|
|
q = new TNode(IR_MEM, add(q, iconst(4)));
|
|
}
|
|
}
|
|
|
|
TNode* p;
|
|
p = new TNode(IR_ARG, 0, 0, k * 4);
|
|
p = new TNode(IR_MEM, p, 0);
|
|
p = new TNode(IR_MOVE, q, p);
|
|
p = new TNode(IR_SEQ, p, 0);
|
|
if (l)
|
|
l->r = p;
|
|
else
|
|
t = p;
|
|
l = p;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
void ExprSeqNode::castTo(DeclSeq* decls, Environ* e, bool cfunc)
|
|
{
|
|
if (exprs.size() > decls->size())
|
|
ex("Too many parameters");
|
|
for (int k = 0; k < decls->size(); ++k) {
|
|
Decl* d = decls->decls[k];
|
|
if (k < exprs.size() && exprs[k]) {
|
|
if (cfunc && d->type->structType()) {
|
|
if (exprs[k]->sem_type->structType()) {
|
|
} else if (exprs[k]->sem_type->intType()) {
|
|
exprs[k]->sem_type = Type::void_type;
|
|
} else {
|
|
ex("Illegal type conversion");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
exprs[k] = exprs[k]->castTo(d->type, e);
|
|
|
|
} else {
|
|
if (!d->defType)
|
|
ex("Not enough parameters");
|
|
ExprNode* expr = constValue(d->defType);
|
|
if (k < exprs.size())
|
|
exprs[k] = expr;
|
|
else
|
|
exprs.push_back(expr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExprSeqNode::castTo(Type* t, Environ* e)
|
|
{
|
|
for (int k = 0; k < exprs.size(); ++k) {
|
|
exprs[k] = exprs[k]->castTo(t, e);
|
|
}
|
|
}
|
|
|
|
///////////////////
|
|
// Function call //
|
|
///////////////////
|
|
ExprNode* CallNode::semant(Environ* e)
|
|
{
|
|
Type* t = e->findType(tag);
|
|
sem_decl = e->findFunc(ident);
|
|
if (!sem_decl || !(sem_decl->kind & DECL_FUNC))
|
|
ex("Function '" + ident + "' not found");
|
|
FuncType* f = sem_decl->type->funcType();
|
|
if (t && f->returnType != t)
|
|
ex("incorrect function return type");
|
|
exprs->semant(e);
|
|
exprs->castTo(f->params, e, f->cfunc);
|
|
sem_type = f->returnType;
|
|
return this;
|
|
}
|
|
|
|
TNode* CallNode::translate(Codegen* g)
|
|
{
|
|
FuncType* f = sem_decl->type->funcType();
|
|
|
|
TNode* t;
|
|
TNode* l = global("_f" + ident);
|
|
TNode* r = exprs->translate(g, f->cfunc);
|
|
|
|
if (f->userlib) {
|
|
l = new TNode(IR_MEM, l);
|
|
usedfuncs.insert(ident);
|
|
}
|
|
|
|
if (sem_type == Type::float_type) {
|
|
t = new TNode(IR_FCALL, l, r, exprs->size() * 4);
|
|
} else {
|
|
t = new TNode(IR_CALL, l, r, exprs->size() * 4);
|
|
}
|
|
|
|
if (f->returnType->stringType()) {
|
|
if (f->cfunc) {
|
|
t = call("__bbCStrToStr", t);
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/////////////////////////
|
|
// Variable expression //
|
|
/////////////////////////
|
|
ExprNode* VarExprNode::semant(Environ* e)
|
|
{
|
|
var->semant(e);
|
|
sem_type = var->sem_type;
|
|
ConstType* c = sem_type->constType();
|
|
if (!c)
|
|
return this;
|
|
ExprNode* expr = constValue(c);
|
|
delete this;
|
|
return expr;
|
|
}
|
|
|
|
TNode* VarExprNode::translate(Codegen* g)
|
|
{
|
|
return var->load(g);
|
|
}
|
|
|
|
//////////////////////
|
|
// Integer constant //
|
|
//////////////////////
|
|
IntConstNode::IntConstNode(int n) : value(n)
|
|
{
|
|
sem_type = Type::int_type;
|
|
}
|
|
|
|
TNode* IntConstNode::translate(Codegen* g)
|
|
{
|
|
return new TNode(IR_CONST, 0, 0, value);
|
|
}
|
|
|
|
int IntConstNode::intValue()
|
|
{
|
|
return value;
|
|
}
|
|
|
|
float IntConstNode::floatValue()
|
|
{
|
|
return value;
|
|
}
|
|
|
|
string IntConstNode::stringValue()
|
|
{
|
|
return itoa(value);
|
|
}
|
|
|
|
////////////////////
|
|
// Float constant //
|
|
////////////////////
|
|
FloatConstNode::FloatConstNode(float f) : value(f)
|
|
{
|
|
sem_type = Type::float_type;
|
|
}
|
|
|
|
TNode* FloatConstNode::translate(Codegen* g)
|
|
{
|
|
return new TNode(IR_CONST, 0, 0, *(int*)&value);
|
|
}
|
|
|
|
int FloatConstNode::intValue()
|
|
{
|
|
float flt = value;
|
|
int temp;
|
|
_control87(_RC_NEAR | _PC_24 | _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT
|
|
| _EM_DENORMAL,
|
|
0xfffff);
|
|
_asm {
|
|
fld[flt];
|
|
fistp[temp];
|
|
}
|
|
_control87(_CW_DEFAULT, 0xfffff);
|
|
return temp;
|
|
}
|
|
|
|
float FloatConstNode::floatValue()
|
|
{
|
|
return value;
|
|
}
|
|
|
|
string FloatConstNode::stringValue()
|
|
{
|
|
return ftoa(value);
|
|
}
|
|
|
|
/////////////////////
|
|
// String constant //
|
|
/////////////////////
|
|
StringConstNode::StringConstNode(const string& s) : value(s)
|
|
{
|
|
sem_type = Type::string_type;
|
|
}
|
|
|
|
TNode* StringConstNode::translate(Codegen* g)
|
|
{
|
|
string lab = genLabel();
|
|
g->s_data(value, lab);
|
|
return call("__bbStrConst", global(lab));
|
|
}
|
|
|
|
int StringConstNode::intValue()
|
|
{
|
|
return atoi(value);
|
|
}
|
|
|
|
float StringConstNode::floatValue()
|
|
{
|
|
return (float)atof(value);
|
|
}
|
|
|
|
string StringConstNode::stringValue()
|
|
{
|
|
return value;
|
|
}
|
|
|
|
////////////////////
|
|
// Unary operator //
|
|
////////////////////
|
|
ExprNode* UniExprNode::semant(Environ* e)
|
|
{
|
|
expr = expr->semant(e);
|
|
sem_type = expr->sem_type;
|
|
if (sem_type != Type::int_type && sem_type != Type::float_type)
|
|
ex("Illegal operator for type");
|
|
if (ConstNode* c = expr->constNode()) {
|
|
ExprNode* e;
|
|
if (sem_type == Type::int_type) {
|
|
switch (op) {
|
|
case '+':
|
|
e = new IntConstNode(+c->intValue());
|
|
break;
|
|
case '-':
|
|
e = new IntConstNode(-c->intValue());
|
|
break;
|
|
case ABS:
|
|
e = new IntConstNode(c->intValue() >= 0 ? c->intValue() : -c->intValue());
|
|
break;
|
|
case SGN:
|
|
e = new IntConstNode(c->intValue() > 0 ? 1 : (c->intValue() < 0 ? -1 : 0));
|
|
break;
|
|
}
|
|
} else {
|
|
switch (op) {
|
|
case '+':
|
|
e = new FloatConstNode(+c->floatValue());
|
|
break;
|
|
case '-':
|
|
e = new FloatConstNode(-c->floatValue());
|
|
break;
|
|
case ABS:
|
|
e = new FloatConstNode(c->floatValue() >= 0 ? c->floatValue() : -c->floatValue());
|
|
break;
|
|
case SGN:
|
|
e = new FloatConstNode(c->floatValue() > 0 ? 1 : (c->floatValue() < 0 ? -1 : 0));
|
|
break;
|
|
}
|
|
}
|
|
delete this;
|
|
return e = nullptr;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
TNode* UniExprNode::translate(Codegen* g)
|
|
{
|
|
int n = 0;
|
|
TNode* l = expr->translate(g);
|
|
if (sem_type == Type::int_type) {
|
|
switch (op) {
|
|
case '+':
|
|
return l;
|
|
case '-':
|
|
n = IR_NEG;
|
|
break;
|
|
case ABS:
|
|
return call("__bbAbs", l);
|
|
case SGN:
|
|
return call("__bbSgn", l);
|
|
}
|
|
} else {
|
|
switch (op) {
|
|
case '+':
|
|
return l;
|
|
case '-':
|
|
n = IR_FNEG;
|
|
break;
|
|
case ABS:
|
|
return fcall("__bbFAbs", l);
|
|
case SGN:
|
|
return fcall("__bbFSgn", l);
|
|
}
|
|
}
|
|
return new TNode(n, l, 0);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// boolean expression - accepts ints, returns ints //
|
|
/////////////////////////////////////////////////////
|
|
ExprNode* BinExprNode::semant(Environ* e)
|
|
{
|
|
lhs = lhs->semant(e);
|
|
lhs = lhs->castTo(Type::int_type, e);
|
|
rhs = rhs->semant(e);
|
|
rhs = rhs->castTo(Type::int_type, e);
|
|
ConstNode *lc = lhs->constNode(), *rc = rhs->constNode();
|
|
if (lc && rc) {
|
|
ExprNode* expr = nullptr;
|
|
switch (op) {
|
|
case AND:
|
|
expr = new IntConstNode(lc->intValue() & rc->intValue());
|
|
break;
|
|
case OR:
|
|
expr = new IntConstNode(lc->intValue() | rc->intValue());
|
|
break;
|
|
case XOR:
|
|
expr = new IntConstNode(lc->intValue() ^ rc->intValue());
|
|
break;
|
|
case SHL:
|
|
expr = new IntConstNode(lc->intValue() << rc->intValue());
|
|
break;
|
|
case SHR:
|
|
expr = new IntConstNode((unsigned)lc->intValue() >> rc->intValue());
|
|
break;
|
|
case SAR:
|
|
expr = new IntConstNode(lc->intValue() >> rc->intValue());
|
|
break;
|
|
}
|
|
delete this;
|
|
return expr;
|
|
}
|
|
sem_type = Type::int_type;
|
|
return this;
|
|
}
|
|
|
|
TNode* BinExprNode::translate(Codegen* g)
|
|
{
|
|
TNode* l = lhs->translate(g);
|
|
TNode* r = rhs->translate(g);
|
|
int n = 0;
|
|
switch (op) {
|
|
case AND:
|
|
n = IR_AND;
|
|
break;
|
|
case OR:
|
|
n = IR_OR;
|
|
break;
|
|
case XOR:
|
|
n = IR_XOR;
|
|
break;
|
|
case SHL:
|
|
n = IR_SHL;
|
|
break;
|
|
case SHR:
|
|
n = IR_SHR;
|
|
break;
|
|
case SAR:
|
|
n = IR_SAR;
|
|
break;
|
|
}
|
|
return new TNode(n, l, r);
|
|
}
|
|
|
|
///////////////////////////
|
|
// arithmetic expression //
|
|
///////////////////////////
|
|
ExprNode* ArithExprNode::semant(Environ* e)
|
|
{
|
|
lhs = lhs->semant(e);
|
|
rhs = rhs->semant(e);
|
|
if (lhs->sem_type->structType() || rhs->sem_type->structType()) {
|
|
ex("Arithmetic operator cannot be applied to custom type objects");
|
|
}
|
|
if (lhs->sem_type == Type::string_type || rhs->sem_type == Type::string_type) {
|
|
//one side is a string - only + operator...
|
|
if (op != '+')
|
|
ex("Operator cannot be applied to strings");
|
|
sem_type = Type::string_type;
|
|
} else if (op == '^' || lhs->sem_type == Type::float_type || rhs->sem_type == Type::float_type) {
|
|
//It's ^, or one side is a float
|
|
sem_type = Type::float_type;
|
|
} else {
|
|
//must be 2 ints
|
|
sem_type = Type::int_type;
|
|
}
|
|
lhs = lhs->castTo(sem_type, e);
|
|
rhs = rhs->castTo(sem_type, e);
|
|
ConstNode *lc = lhs->constNode(), *rc = rhs->constNode();
|
|
if (rc && (op == '/' || op == MOD)) {
|
|
if ((sem_type == Type::int_type && !rc->intValue()) || (sem_type == Type::float_type && !rc->floatValue())) {
|
|
ex("Division by zero");
|
|
}
|
|
}
|
|
if (lc && rc) {
|
|
ExprNode* expr = nullptr;
|
|
if (sem_type == Type::string_type) {
|
|
expr = new StringConstNode(lc->stringValue() + rc->stringValue());
|
|
} else if (sem_type == Type::int_type) {
|
|
switch (op) {
|
|
case '+':
|
|
expr = new IntConstNode(lc->intValue() + rc->intValue());
|
|
break;
|
|
case '-':
|
|
expr = new IntConstNode(lc->intValue() - rc->intValue());
|
|
break;
|
|
case '*':
|
|
expr = new IntConstNode(lc->intValue() * rc->intValue());
|
|
break;
|
|
case '/':
|
|
expr = new IntConstNode(lc->intValue() / rc->intValue());
|
|
break;
|
|
case MOD:
|
|
expr = new IntConstNode(lc->intValue() % rc->intValue());
|
|
break;
|
|
}
|
|
} else {
|
|
switch (op) {
|
|
case '+':
|
|
expr = new FloatConstNode(lc->floatValue() + rc->floatValue());
|
|
break;
|
|
case '-':
|
|
expr = new FloatConstNode(lc->floatValue() - rc->floatValue());
|
|
break;
|
|
case '*':
|
|
expr = new FloatConstNode(lc->floatValue() * rc->floatValue());
|
|
break;
|
|
case '/':
|
|
expr = new FloatConstNode(lc->floatValue() / rc->floatValue());
|
|
break;
|
|
case MOD:
|
|
expr = new FloatConstNode(fmod(lc->floatValue(), rc->floatValue()));
|
|
break;
|
|
case '^':
|
|
expr = new FloatConstNode(pow(lc->floatValue(), rc->floatValue()));
|
|
break;
|
|
}
|
|
}
|
|
delete this;
|
|
return expr;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
TNode* ArithExprNode::translate(Codegen* g)
|
|
{
|
|
TNode* l = lhs->translate(g);
|
|
TNode* r = rhs->translate(g);
|
|
if (sem_type == Type::string_type) {
|
|
return call("__bbStrConcat", l, r);
|
|
}
|
|
int n = 0;
|
|
if (sem_type == Type::int_type) {
|
|
switch (op) {
|
|
case '+':
|
|
n = IR_ADD;
|
|
break;
|
|
case '-':
|
|
n = IR_SUB;
|
|
break;
|
|
case '*':
|
|
n = IR_MUL;
|
|
break;
|
|
case '/':
|
|
n = IR_DIV;
|
|
break;
|
|
case MOD:
|
|
return call("__bbMod", l, r);
|
|
}
|
|
} else {
|
|
switch (op) {
|
|
case '+':
|
|
n = IR_FADD;
|
|
break;
|
|
case '-':
|
|
n = IR_FSUB;
|
|
break;
|
|
case '*':
|
|
n = IR_FMUL;
|
|
break;
|
|
case '/':
|
|
n = IR_FDIV;
|
|
break;
|
|
case MOD:
|
|
return fcall("__bbFMod", l, r);
|
|
case '^':
|
|
return fcall("__bbFPow", l, r);
|
|
}
|
|
}
|
|
return new TNode(n, l, r);
|
|
}
|
|
|
|
/////////////////////////
|
|
// relation expression //
|
|
/////////////////////////
|
|
ExprNode* RelExprNode::semant(Environ* e)
|
|
{
|
|
lhs = lhs->semant(e);
|
|
rhs = rhs->semant(e);
|
|
if (lhs->sem_type->structType() || rhs->sem_type->structType()) {
|
|
if (op != '=' && op != NE)
|
|
ex("Illegal operator for custom type objects");
|
|
opType = lhs->sem_type != Type::null_type ? lhs->sem_type : rhs->sem_type;
|
|
} else if (lhs->sem_type == Type::string_type || rhs->sem_type == Type::string_type) {
|
|
opType = Type::string_type;
|
|
} else if (lhs->sem_type == Type::float_type || rhs->sem_type == Type::float_type) {
|
|
opType = Type::float_type;
|
|
} else {
|
|
opType = Type::int_type;
|
|
}
|
|
sem_type = Type::int_type;
|
|
lhs = lhs->castTo(opType, e);
|
|
rhs = rhs->castTo(opType, e);
|
|
ConstNode *lc = lhs->constNode(), *rc = rhs->constNode();
|
|
if (lc && rc) {
|
|
ExprNode* expr = nullptr;
|
|
if (opType == Type::string_type) {
|
|
switch (op) {
|
|
case '<':
|
|
expr = new IntConstNode(lc->stringValue() < rc->stringValue());
|
|
break;
|
|
case '=':
|
|
expr = new IntConstNode(lc->stringValue() == rc->stringValue());
|
|
break;
|
|
case '>':
|
|
expr = new IntConstNode(lc->stringValue() > rc->stringValue());
|
|
break;
|
|
case LE:
|
|
expr = new IntConstNode(lc->stringValue() <= rc->stringValue());
|
|
break;
|
|
case NE:
|
|
expr = new IntConstNode(lc->stringValue() != rc->stringValue());
|
|
break;
|
|
case GE:
|
|
expr = new IntConstNode(lc->stringValue() >= rc->stringValue());
|
|
break;
|
|
}
|
|
} else if (opType == Type::float_type) {
|
|
switch (op) {
|
|
case '<':
|
|
expr = new IntConstNode(lc->floatValue() < rc->floatValue());
|
|
break;
|
|
case '=':
|
|
expr = new IntConstNode(lc->floatValue() == rc->floatValue());
|
|
break;
|
|
case '>':
|
|
expr = new IntConstNode(lc->floatValue() > rc->floatValue());
|
|
break;
|
|
case LE:
|
|
expr = new IntConstNode(lc->floatValue() <= rc->floatValue());
|
|
break;
|
|
case NE:
|
|
expr = new IntConstNode(lc->floatValue() != rc->floatValue());
|
|
break;
|
|
case GE:
|
|
expr = new IntConstNode(lc->floatValue() >= rc->floatValue());
|
|
break;
|
|
}
|
|
} else {
|
|
switch (op) {
|
|
case '<':
|
|
expr = new IntConstNode(lc->intValue() < rc->intValue());
|
|
break;
|
|
case '=':
|
|
expr = new IntConstNode(lc->intValue() == rc->intValue());
|
|
break;
|
|
case '>':
|
|
expr = new IntConstNode(lc->intValue() > rc->intValue());
|
|
break;
|
|
case LE:
|
|
expr = new IntConstNode(lc->intValue() <= rc->intValue());
|
|
break;
|
|
case NE:
|
|
expr = new IntConstNode(lc->intValue() != rc->intValue());
|
|
break;
|
|
case GE:
|
|
expr = new IntConstNode(lc->intValue() >= rc->intValue());
|
|
break;
|
|
}
|
|
}
|
|
delete this;
|
|
return expr;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
TNode* RelExprNode::translate(Codegen* g)
|
|
{
|
|
TNode* l = lhs->translate(g);
|
|
TNode* r = rhs->translate(g);
|
|
return compare(op, l, r, opType);
|
|
}
|
|
|
|
////////////////////
|
|
// New expression //
|
|
////////////////////
|
|
ExprNode* NewNode::semant(Environ* e)
|
|
{
|
|
sem_type = e->findType(ident);
|
|
if (!sem_type)
|
|
ex("custom type name not found");
|
|
if (sem_type->structType() == 0)
|
|
ex("type is not a custom type");
|
|
return this;
|
|
}
|
|
|
|
TNode* NewNode::translate(Codegen* g)
|
|
{
|
|
return call("__bbObjNew", global("_t" + ident));
|
|
}
|
|
|
|
////////////////////
|
|
// First of class //
|
|
////////////////////
|
|
ExprNode* FirstNode::semant(Environ* e)
|
|
{
|
|
sem_type = e->findType(ident);
|
|
if (!sem_type)
|
|
ex("custom type name name not found");
|
|
return this;
|
|
}
|
|
|
|
TNode* FirstNode::translate(Codegen* g)
|
|
{
|
|
return call("__bbObjFirst", global("_t" + ident));
|
|
}
|
|
|
|
///////////////////
|
|
// Last of class //
|
|
///////////////////
|
|
ExprNode* LastNode::semant(Environ* e)
|
|
{
|
|
sem_type = e->findType(ident);
|
|
if (!sem_type)
|
|
ex("custom type name not found");
|
|
return this;
|
|
}
|
|
|
|
TNode* LastNode::translate(Codegen* g)
|
|
{
|
|
return call("__bbObjLast", global("_t" + ident));
|
|
}
|
|
|
|
////////////////////
|
|
// Next of object //
|
|
////////////////////
|
|
ExprNode* AfterNode::semant(Environ* e)
|
|
{
|
|
expr = expr->semant(e);
|
|
if (expr->sem_type == Type::null_type)
|
|
ex("'After' cannot be used on 'Null'");
|
|
if (expr->sem_type->structType() == 0)
|
|
ex("'After' must be used with a custom type object");
|
|
sem_type = expr->sem_type;
|
|
return this;
|
|
}
|
|
|
|
TNode* AfterNode::translate(Codegen* g)
|
|
{
|
|
TNode* t = expr->translate(g);
|
|
if (g->debug)
|
|
t = jumpf(t, "__bbNullObjEx");
|
|
return call("__bbObjNext", t);
|
|
}
|
|
|
|
////////////////////
|
|
// Prev of object //
|
|
////////////////////
|
|
ExprNode* BeforeNode::semant(Environ* e)
|
|
{
|
|
expr = expr->semant(e);
|
|
if (expr->sem_type == Type::null_type)
|
|
ex("'Before' cannot be used with 'Null'");
|
|
if (expr->sem_type->structType() == 0)
|
|
ex("'Before' must be used with a custom type object");
|
|
sem_type = expr->sem_type;
|
|
return this;
|
|
}
|
|
|
|
TNode* BeforeNode::translate(Codegen* g)
|
|
{
|
|
TNode* t = expr->translate(g);
|
|
if (g->debug)
|
|
t = jumpf(t, "__bbNullObjEx");
|
|
return call("__bbObjPrev", t);
|
|
}
|
|
|
|
/////////////////
|
|
// Null object //
|
|
/////////////////
|
|
ExprNode* NullNode::semant(Environ* e)
|
|
{
|
|
sem_type = Type::null_type;
|
|
return this;
|
|
}
|
|
|
|
TNode* NullNode::translate(Codegen* g)
|
|
{
|
|
return new TNode(IR_CONST, 0, 0, 0);
|
|
}
|
|
|
|
/////////////////
|
|
// Object cast //
|
|
/////////////////
|
|
ExprNode* ObjectCastNode::semant(Environ* e)
|
|
{
|
|
expr = expr->semant(e);
|
|
expr = expr->castTo(Type::int_type, e);
|
|
sem_type = e->findType(type_ident);
|
|
if (!sem_type)
|
|
ex("custom type name not found");
|
|
if (!sem_type->structType())
|
|
ex("type is not a custom type");
|
|
return this;
|
|
}
|
|
|
|
TNode* ObjectCastNode::translate(Codegen* g)
|
|
{
|
|
TNode* t = expr->translate(g);
|
|
t = call("__bbObjFromHandle", t, global("_t" + sem_type->structType()->ident));
|
|
return t;
|
|
}
|
|
|
|
///////////////////
|
|
// Object Handle //
|
|
///////////////////
|
|
ExprNode* ObjectHandleNode::semant(Environ* e)
|
|
{
|
|
expr = expr->semant(e);
|
|
if (!expr->sem_type->structType())
|
|
ex("'ObjectHandle' must be used with an object");
|
|
sem_type = Type::int_type;
|
|
return this;
|
|
}
|
|
|
|
TNode* ObjectHandleNode::translate(Codegen* g)
|
|
{
|
|
TNode* t = expr->translate(g);
|
|
return call("__bbObjToHandle", t);
|
|
}
|