Example #1
0
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();
}
Example #2
0
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;
}
Example #3
0
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();
    }
}
Example #4
0
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;
}
Example #5
0
StringLiteralNode::StringLiteralNode
    (int lineNumber,
     const LContext &lcontext,
     const string &value)
:
    LiteralNode (lineNumber),
    value (value)
{
    type = lcontext.newStringType ();
}
Example #6
0
FloatLiteralNode::FloatLiteralNode
    (int lineNumber,
     const LContext &lcontext,
     float value)
:
    LiteralNode (lineNumber),
    value (value)
{
    type = lcontext.newFloatType ();
}
Example #7
0
HalfLiteralNode::HalfLiteralNode
    (int lineNumber,
     const LContext &lcontext,
     half value)
:
    LiteralNode (lineNumber),
    value (value)
{
    type = lcontext.newHalfType ();
}
Example #8
0
UIntLiteralNode::UIntLiteralNode
    (int lineNumber,
     const LContext &lcontext,
     unsigned int value)
:
    LiteralNode (lineNumber),
    value (value)
{
    type = lcontext.newUIntType ();
}
Example #9
0
BoolLiteralNode::BoolLiteralNode
    (int lineNumber,
     const LContext &lcontext,
     bool value)
:
    LiteralNode (lineNumber),
    value (value)
{
    type = lcontext.newBoolType ();
}
Example #10
0
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;
}
Example #11
0
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 ();
}
Example #12
0
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() << ").");
}
Example #13
0
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() << ").");
}
Example #14
0
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;
    }
}
Example #15
0
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() << ").");
	    }
	}
    }
Example #16
0
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;
}