#include "AST.h" #include "CtType.h" #include "code-call.h" #include "code-util.h" #include "decls.h" #include "errors.h" #include "lgMacro.h" const string ExprNode::emitBinOp( CodeContext &context, const char op[] ) { // Although we are only evaluating each operand once, the // temporaries are needed to guarantee evaluation order. const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); return operand0 + ' ' + op + ' ' + operand1; } const string MultNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "*" ); } const string DivNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "/" ); } const string RemNode::emitExpression( CodeContext &context ) { const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); if (child(0)->type()->isFloatType() || child(1)->type()->isFloatType()) return "fmod(" + operand0 + ", " + operand1 + ")"; else return operand0 + " % " + operand1; } const string PlusNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "+" ); } const string MinusNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "-" ); } const string LeftShiftLogNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<<" ); } const string RightShiftLogNode::emitExpression( CodeContext &context ) { TypeNode *exprType = child(0)->type(); assert(exprType->isPrimitive()); // CM: Actually, the formula below is not quite right. Consider what // happens if n == 0 or if sizeof(x) == 8. Instead, use the following: // x >>> n = (x >> n) & ((~((julong) 0)) >> // (n + (sizeof(julong) - sizeof(x)) * 8)); // Note that this assumes that julong is the longest type. // CM // x >>> n = (x >> n) & ((1 << (sizeof(x) * 8 - n)) - 1) // The alternative is to cast to the unsigned version of x->type() by // defining methods in code-primitives.cc that do the type conversion. // Too bad you can't stick "unsigned" on user types in C. const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); const string shiftExpr = operand0 + " >> " + operand1; const string sizeofType = "sizeof(" + string(((PrimitiveTypeNode *)exprType)->cPrimitiveTypeName()) + ")"; return string("(") + shiftExpr + ") & " + "((~((julong) 0)) >> (" + operand1 + " + (sizeof(julong) - " + sizeofType + ") * 8))"; } const string RightShiftArithNode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">>" ); } const string LTNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<" ); } const string GTNode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">" ); } const string LENode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<=" ); } const string GENode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">=" ); } /* Returns whether t is "null" or a cast of "null." */ static bool isNull(TreeNode *t) { return t->type()->isNullType() || isCastNode(t) && isNull(t->opnd0()); } static const string commonEQNode(TreeNode *opnd0, TreeNode *opnd1, bool eq, CodeContext &context) { const TypeNode &type0 = *opnd0->type(); const TypeNode &type1 = *opnd1->type(); if (type0.isTitaniumArrayType() || type1.isTitaniumArrayType()) { assert(type0.typeIdent(&type1)); return (eq?"":"!") + callGridMethod(*opnd0->type(), "equals", "(" + opnd0->emitExpression(context) + ", " + opnd1->emitExpression(context) + ")"); } const string operand0 = opnd0->emitExpression( context ); const string operand1 = opnd1->emitExpression( context ); if (type0.isPrimitive()) return operand0 + (eq?" == ":" != ") + operand1; else { const string method = type0.isImmutable() ? (eq ? MANGLE_CLASS_EQUALS(+, ((TypeNameNode &)type0).decl()->cType()) : MANGLE_CLASS_NEQUALS(+, ((TypeNameNode &)type0).decl()->cType())) : (eq?"":"!") + lgMacro( "EQUAL", type0 ); return method + '(' + operand0 + ", " + operand1 + ')'; } } const string EQNode::emitExpression( CodeContext &context ) { return commonEQNode(opnd0(), opnd1(), true, context); } const string NENode::emitExpression( CodeContext &context ) { return commonEQNode(opnd0(), opnd1(), false, context); } const string BitAndNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "&" ); } const string BitOrNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "|" ); } const string BitXorNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "^" ); }