void ArrayIndexNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { if (!array || !index) return; array->computeType (lcontext, initInfo); index->computeType (lcontext, initInfo); if (!array->type || !index->type) return; ArrayTypePtr arrayType = array->type.cast<ArrayType>(); if (!arrayType) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) { name = arrayName->name; MESSAGE_LE (lcontext, ERR_NON_ARR_IND, array->lineNumber, "Applied [] operator to non-array (" << name << " " "is of type " << array->type->asString() << ")."); } else { MESSAGE_LE (lcontext, ERR_NON_ARR_IND, array->lineNumber, "Applied [] operator to non-array of type " << array->type->asString() << "."); } type = lcontext.newIntType(); return; } IntTypePtr intType = lcontext.newIntType (); if (!intType->canPromoteFrom (index->type)) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is not an iteger " "(index is of type " << index->type->asString() << ")."); type = lcontext.newIntType(); return; } type = arrayType->elementType(); }
ExprNodePtr SizeNode::evaluate (LContext &lcontext) { obj = obj->evaluate(lcontext); ArrayTypePtr arrayType = obj->type.cast<ArrayType>(); if( !arrayType) { return lcontext.newIntLiteralNode (lineNumber, 1); } else if( arrayType->size() != 0 ) { return lcontext.newIntLiteralNode (lineNumber, arrayType->size()); } return this; }
void MemberNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { obj->computeType (lcontext, initInfo); if (!obj->type) { type = lcontext.newIntType(); return; } StructTypePtr structType = obj->type.cast<StructType>(); if (!structType) { MESSAGE_LE (lcontext, ERR_NON_STRUCT, lineNumber, "Applied member access operator to non-struct " "of type " << obj->type->asString() << "."); type = lcontext.newIntType(); return; } // // check that the member exists and gets its type // for (MemberVectorConstIterator it = structType->members().begin(); it != structType->members().end(); it++) { if (it->name == member) { type = it->type; offset = it->offset; return; } } if (!type) { MESSAGE_LE (lcontext, ERR_MEMBER_ACCESS, lineNumber, "Unable to find member \"" << member << "\"."); type = lcontext.newIntType(); } }
ExprNodePtr BoolType::castValue (LContext &lcontext, const ExprNodePtr &expr) const { if (IntLiteralNodePtr x = expr.cast<IntLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (UIntLiteralNodePtr x = expr.cast<UIntLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (HalfLiteralNodePtr x = expr.cast<HalfLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (FloatLiteralNodePtr x = expr.cast<FloatLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); return expr; }
StringLiteralNode::StringLiteralNode (int lineNumber, const LContext &lcontext, const string &value) : LiteralNode (lineNumber), value (value) { type = lcontext.newStringType (); }
FloatLiteralNode::FloatLiteralNode (int lineNumber, const LContext &lcontext, float value) : LiteralNode (lineNumber), value (value) { type = lcontext.newFloatType (); }
HalfLiteralNode::HalfLiteralNode (int lineNumber, const LContext &lcontext, half value) : LiteralNode (lineNumber), value (value) { type = lcontext.newHalfType (); }
UIntLiteralNode::UIntLiteralNode (int lineNumber, const LContext &lcontext, unsigned int value) : LiteralNode (lineNumber), value (value) { type = lcontext.newUIntType (); }
BoolLiteralNode::BoolLiteralNode (int lineNumber, const LContext &lcontext, bool value) : LiteralNode (lineNumber), value (value) { type = lcontext.newBoolType (); }
ExprNodePtr ArrayIndexNode::evaluate (LContext &lcontext) { IntTypePtr intType = lcontext.newIntType (); array = array->evaluate (lcontext); index = index->evaluate (lcontext); if( IntLiteralNodePtr literal = index.cast<IntLiteralNode>()) { if(literal->value < 0) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is negative " "(" << literal->value << ")."); } ArrayTypePtr arrayType = array->type.cast<ArrayType>(); if(!arrayType) return this; if( literal->value >= arrayType->size() && arrayType->size() != 0) { string name = ""; if( NameNodePtr arrayName = array.cast<NameNode>() ) name = arrayName->name; MESSAGE_LE (lcontext, ERR_ARR_IND_TYPE, array->lineNumber, "Index into array " << name << " is out of range " "(index = " << literal->value << ", " "array size = " << arrayType->size() << ")."); } } if (index->type && !intType->isSameTypeAs (index->type)) index = intType->castValue (lcontext, index); return this; }
void SizeNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { obj->computeType (lcontext, initInfo); ArrayTypePtr arrayType = obj->type.cast<ArrayType>(); if( !arrayType) { string type = "unknown"; if( obj && obj->type) type = obj->type->asString(); MESSAGE_LE (lcontext, ERR_NON_ARRAY, lineNumber, "Applied size operator to non-array " " of type " << type << "."); } type = lcontext.newIntType (); }
void UnaryOpNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { if (!operand) return; operand->computeType (lcontext, initInfo); if (!operand->type) return; if (op == TK_BITNOT) { // // Operator ~ can only be applied to operands of type bool int, or // unsigned int. The operator produces a result of the same type as // the operand. // BoolTypePtr boolType = lcontext.newBoolType (); if (boolType->isSameTypeAs (operand->type)) { type = boolType; return; } IntTypePtr intType = lcontext.newIntType (); if (intType->isSameTypeAs (operand->type)) { type = intType; return; } UIntTypePtr uIntType = lcontext.newUIntType (); if (uIntType->isSameTypeAs (operand->type)) { type = uIntType; return; } } else if (op == TK_MINUS) { // // Operator - can only be applied to operands of type int, unsigned // int, half or float. The operator produces a result of the same // type as the operand, except for unsigned int where it produces a // result of type int. // IntTypePtr intType = lcontext.newIntType (); if (intType->isSameTypeAs (operand->type)) { type = intType; return; } UIntTypePtr uIntType = lcontext.newUIntType (); if (uIntType->isSameTypeAs (operand->type)) { type = intType; // not uIntType! return; } HalfTypePtr halfType = lcontext.newHalfType (); if (halfType->isSameTypeAs (operand->type)) { type = halfType; return; } FloatTypePtr floatType = lcontext.newFloatType (); if (floatType->isSameTypeAs (operand->type)) { type = floatType; return; } } else if (op == TK_NOT) { // // Operator ! can be applied to operands that can be converted // to type bool. The operator produces a result of type bool. // BoolTypePtr boolType = lcontext.newBoolType (); if (boolType->canCastFrom (operand->type)) { type = boolType; return; } } MESSAGE_LE (lcontext, ERR_OP_TYPE, lineNumber, "Invalid operand type for " << tokenAsString (op) << " operator " "(" << tokenAsString (op) << operand->type->asString() << ")."); }
void BinaryOpNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { if (!leftOperand || !rightOperand) return; leftOperand->computeType (lcontext, initInfo); rightOperand->computeType (lcontext, initInfo); if (!leftOperand->type || !rightOperand->type) return; ArrayTypePtr arrayType = leftOperand->type.cast<ArrayType>(); StructTypePtr structType = leftOperand->type.cast<StructType>(); if( arrayType || structType ) { MESSAGE_LE (lcontext, ERR_OP_TYPE, lineNumber, "Invalid operand types for " << tokenAsString (op) << " " "operator (" << leftOperand->type->asString() << " " << tokenAsString (op) << " " << rightOperand->type->asString() << ")."); } if (op == TK_AND || op == TK_OR) { // // It must be possible to cast the operands to type bool, // and the operator produces a result of type bool. // BoolTypePtr boolType = lcontext.newBoolType (); if (boolType->canCastFrom (leftOperand->type) && boolType->canCastFrom (rightOperand->type)) { operandType = boolType; type = boolType; return; } } else if (op == TK_EQUAL || op == TK_GREATER || op == TK_GREATEREQUAL || op == TK_LESS || op == TK_LESSEQUAL || op == TK_NOTEQUAL) { // // It must be possible to promote the operands to a common type. // The operator produces a result of type bool. // BoolTypePtr boolType = lcontext.newBoolType (); if (leftOperand->type->isSameTypeAs (rightOperand->type)) { operandType = leftOperand->type; type = boolType; return; } else if (leftOperand->type->canPromoteFrom (rightOperand->type)) { operandType = leftOperand->type; type = boolType; return; } else if (rightOperand->type->canPromoteFrom (leftOperand->type)) { operandType = rightOperand->type; type = boolType; return; } } else { // // It must be possible to promote the operands to a common type. // The operator produces a result of this common type. // if (leftOperand->type->isSameTypeAs (rightOperand->type)) { operandType = leftOperand->type; type = operandType; return; } else if (leftOperand->type->canPromoteFrom (rightOperand->type)) { operandType = leftOperand->type; type = operandType; return; } else if (rightOperand->type->canPromoteFrom (leftOperand->type)) { operandType = rightOperand->type; type = operandType; return; } } MESSAGE_LE (lcontext, ERR_OP_TYPE, lineNumber, "Invalid operand types for " << tokenAsString (op) << " " "operator (" << leftOperand->type->asString() << " " << tokenAsString (op) << " " << rightOperand->type->asString() << ")."); }
void Interpreter::loadModuleRecursive (const string &moduleName) { debug ("Interpreter::loadModuleRecursive " "(moduleName = " << moduleName << ")"); if (moduleIsLoadedInternal (moduleName)) { debug ("\talready loaded"); return; } // // Using the module search path, locate the file that contains the // source code for the module. Open the file. // string fileName = findModule (moduleName); ifstream file (fileName.c_str()); if (!file) { THROW_ERRNO ("Cannot load CTL module \"" << moduleName << "\". " "Opening file \"" << fileName << "\" for reading " "failed (%T)."); } debug ("\tloading from file \"" << fileName << "\""); Module *module = 0; LContext *lcontext = 0; try { // // Create a Module, an Lcontext and a Parser // module = newModule (moduleName, fileName); _data->moduleSet.addModule (module); lcontext = newLContext (file, module, _data->symtab); Parser parser (*lcontext, *this); // // Parse the source code and generate executable code // for the module // debug ("\tparsing input"); SyntaxNodePtr syntaxTree = parser.parseInput (); if (syntaxTree && lcontext->numErrors() == 0) { debug ("\tgenerating code"); syntaxTree->generateCode (*lcontext); } if (lcontext->numErrors() > 0) { lcontext->printDeclaredErrors(); THROW (LoadModuleExc, "Failed to load CTL module \"" << moduleName << "\"."); } // // Run the module's initialization code // debug ("\trunning module initialization code"); module->runInitCode(); // // Cleanup: the LContext and the module's local symbols // are no longer needed, but we keep the global symbols. // debug ("\tcleanup"); delete lcontext; _data->symtab.deleteAllLocalSymbols (module); } catch (...) { // // Something went wrong while loading the module, clean up // delete lcontext; _data->symtab.deleteAllSymbols (module); _data->moduleSet.removeModule (moduleName); throw; } }
ExprNodePtr IntType::evaluate (LContext &lcontext, const ExprNodePtr &expr) const { if (UnaryOpNodePtr unOp = expr.cast<UnaryOpNode>()) { IntLiteralNodePtr x = unOp->operand.cast<IntLiteralNode>(); if (x) { switch (unOp->op) { case TK_BITNOT: return lcontext.newIntLiteralNode (expr->lineNumber, ~x->value); case TK_MINUS: return lcontext.newIntLiteralNode (expr->lineNumber, -x->value); case TK_NOT: return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << asString() << "."); } } } if (BinaryOpNodePtr binOp = expr.cast<BinaryOpNode>()) { IntLiteralNodePtr x = evaluate(lcontext, binOp->leftOperand).cast<IntLiteralNode>(); IntLiteralNodePtr y = evaluate(lcontext, binOp->rightOperand).cast<IntLiteralNode>(); if (x && y) { switch (binOp->op) { case TK_AND: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value && y->value); case TK_BITAND: return lcontext.newIntLiteralNode (expr->lineNumber, x->value & y->value); case TK_BITOR: return lcontext.newIntLiteralNode (expr->lineNumber, x->value | y->value); case TK_BITXOR: return lcontext.newIntLiteralNode (expr->lineNumber, x->value ^ y->value); case TK_DIV: if (y->value != 0) { return lcontext.newIntLiteralNode (expr->lineNumber, x->value / y->value); } else { MESSAGE_LW (lcontext, ERR_DIV_ZERO, expr->lineNumber, "Warning: Division by zero " "(" << x->value << "/" << y->value << ")."); return lcontext.newIntLiteralNode (expr->lineNumber, 0); } case TK_EQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value == y->value); case TK_GREATER: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value > y->value); case TK_GREATEREQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value >= y->value); case TK_LEFTSHIFT: return lcontext.newIntLiteralNode (expr->lineNumber, x->value << y->value); case TK_LESS: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value < y->value); case TK_LESSEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value <= y->value); case TK_MINUS: return lcontext.newIntLiteralNode (expr->lineNumber, x->value - y->value); case TK_MOD: return lcontext.newIntLiteralNode (expr->lineNumber, x->value % y->value); case TK_NOTEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value != y->value); case TK_OR: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value || y->value); case TK_PLUS: return lcontext.newIntLiteralNode (expr->lineNumber, x->value + y->value); case TK_RIGHTSHIFT: return lcontext.newIntLiteralNode (expr->lineNumber, x->value >> y->value); case TK_TIMES: return lcontext.newIntLiteralNode (expr->lineNumber, x->value * y->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } } }
ExprNodePtr BoolType::evaluate (LContext &lcontext, const ExprNodePtr &expr) const { if (UnaryOpNodePtr unOp = expr.cast<UnaryOpNode>()) { BoolLiteralNodePtr x = unOp->operand.cast<BoolLiteralNode>(); if (x) { switch (unOp->op) { case TK_BITNOT: // // We use the C++ ! operation to evaluate the CTL expression ~x, // where x is of type bool. This ensures that ~true == false // and ~false == true. // return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); case TK_NOT: return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << asString() << "."); } } } if (BinaryOpNodePtr binOp = expr.cast<BinaryOpNode>()) { BoolLiteralNodePtr x = binOp->leftOperand.cast<BoolLiteralNode>(); BoolLiteralNodePtr y = binOp->rightOperand.cast<BoolLiteralNode>(); if (x && y) { switch (binOp->op) { case TK_AND: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value && y->value); case TK_BITAND: // // For the bit-wise &, | and ^ operators, we normalize bool // operands before applying the operators. This avoids // surprises, for example, true^true == true. // return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value & !!y->value); case TK_BITOR: return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value | !!y->value); case TK_BITXOR: return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value ^ !!y->value); case TK_EQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value == y->value); case TK_GREATER: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value > y->value); case TK_GREATEREQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value >= y->value); case TK_LESS: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value < y->value); case TK_LESSEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value <= y->value); case TK_NOTEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value != y->value); case TK_OR: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value || y->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } } } return expr; }