ListASTNode::ListASTNode(const ListASTNode & other)
: ASTNode(other), m_list()
{
// deep copy each item of the original's list
const_iterator it = other.begin();
for (; it != other.end(); ++it)
{
m_list.push_back((*it)->clone());
}
}
//! Deletes child node in the list.
//!
ListASTNode::~ListASTNode()
{
iterator it = begin();
for (; it != end(); it++)
{
delete *it;
}
}
//! If \a node is NULL then the list is left unmodified.
//!
//! The list node's location is automatically updated after the node is added by a call
//! to updateLocation().
void ListASTNode::appendNode(ASTNode * node)
{
if (node)
{
m_list.push_back(node);
updateLocation();
}
}
printIndent(indent + 1);
printf("options:\n");
if (m_options) m_options->printTree(indent + 2);
printIndent(indent + 1);
printf("constants:\n");
if (m_constants) m_constants->printTree(indent + 2);
printIndent(indent + 1);
printf("sources:\n");
if (m_sources) m_sources->printTree(indent + 2);
printIndent(indent + 1);
printf("sections:\n");
if (m_sections) m_sections->printTree(indent + 2);
}
#pragma mark = ExprASTNode =
int_size_t ExprASTNode::resultIntSize(int_size_t a, int_size_t b)
{
int_size_t result;
switch (a)
{
case kWordSize:
result = kWordSize;
break;
case kHalfWordSize:
if (b == kWordSize)
{
result = kWordSize;
}
else
{
result = kHalfWordSize;
}
break;
case kByteSize:
if (b == kWordSize)
{
result = kWordSize;
}
else if (b == kHalfWordSize)
{
result = kHalfWordSize;
}
else
{
result = kByteSize;
}
break;
}
if (!m_symbol)
{
throw semantic_error("no symbol provided");
}
// Get the name of the symbol
std::string * symbolName = m_symbol->getSymbolName();
// if (!symbolName)
// {
// throw semantic_error(format_string("line %d: no symbol name provided", getFirstLine()));
// }
// Get the source file.
std::string * sourceName = m_symbol->getSource();
SourceFile * sourceFile;
if (sourceName)
{
sourceFile = manager->getSourceFile(*sourceName);
if (!sourceFile)
{
throw semantic_error(format_string("line %d: no source file named %s", getFirstLine(), sourceName->c_str()));
}
}
else
{
sourceFile = manager->getDefaultSourceFile();
if (!sourceFile)
{
throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
}
}
// open the file if it hasn't already been
if (!sourceFile->isOpen())
{
sourceFile->open();
}
// Make sure the source file supports symbols before going any further
if (symbolName && !sourceFile->supportsNamedSymbols())
{
throw semantic_error(format_string("line %d: source file %s does not support symbols", getFirstLine(), sourceFile->getPath().c_str()));
}
if (!symbolName && !sourceFile->hasEntryPoint())
{
throw semantic_error(format_string("line %d: source file %s does not have an entry point", getFirstLine(), sourceFile->getPath().c_str()));
}
// Returns a const expr node with the symbol's value.
uint32_t value;
if (symbolName)
{
value = sourceFile->getSymbolValue(*symbolName);
}
else
{
value = sourceFile->getEntryPointAddress();
}
return new IntConstExprASTNode(value);
}
m_expr = m_expr->reduce(context);
IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(m_expr.get());
if (intConst)
{
int32_t value = !((int32_t)intConst->getValue());
return new IntConstExprASTNode((uint32_t)value, intConst->getSize());
}
else
{
throw semantic_error(format_string("line %d: expression did not evaluate to an integer", m_expr->getFirstLine()));
}
}
#pragma mark = SourceFileFunctionASTNode =
SourceFileFunctionASTNode::SourceFileFunctionASTNode(const SourceFileFunctionASTNode & other)
: ExprASTNode(other), m_functionName(), m_sourceFile()
{
m_functionName = new std::string(*other.m_functionName);
m_sourceFile = new std::string(*other.m_sourceFile);
}
// for some stupid reason the msft C++ compiler barfs on the following line if the ".get()" parts are remove,
// even though the first line of reduce() below has the same expression, just in parentheses. stupid compiler.
if (m_functionName.get() && m_sourceFile.get())
{
printf("%s ( %s )\n", m_functionName->c_str(), m_sourceFile->c_str());
}
}
ExprASTNode * SourceFileFunctionASTNode::reduce(EvalContext & context)
{
if (!(m_functionName && m_sourceFile))
{
throw std::runtime_error("unset function name or source file");
}
// Get source file manager from evaluation context. This will be the
// conversion controller itself.
EvalContext::SourceFileManager * mgr = context.getSourceFileManager();
if (!mgr)
{
throw std::runtime_error("source file manager is not set");
}
// Perform function
uint32_t functionResult = 0;
if (*m_functionName == "exists")
{
functionResult = static_cast<uint32_t>(mgr->hasSourceFile(*m_sourceFile));
}
// Return function result as an expression node
return new IntConstExprASTNode(functionResult);
}
if (m_symbol)
{
// Get the symbol name.
std::string * symbolName = m_symbol->getSymbolName();
assert(symbolName);
// Get the source file, using the default if one is not specified.
std::string * sourceName = m_symbol->getSource();
if (sourceName)
{
sourceFile = manager->getSourceFile(*sourceName);
if (!sourceFile)
{
throw semantic_error(format_string("line %d: invalid source file: %s", getFirstLine(), sourceName->c_str()));
}
}
else
{
sourceFile = manager->getDefaultSourceFile();
if (!sourceFile)
{
throw semantic_error(format_string("line %d: no default source file is set", getFirstLine()));
}
}
// Get the size of the symbol.
if (sourceFile->hasSymbol(*symbolName))
{
sizeInBytes = sourceFile->getSymbolSize(*symbolName);
}
}
else if (m_constantName)
{
// See if the "constant" is really a constant or if it's a source name.
if (manager->hasSourceFile(m_constantName))
{
sourceFile = manager->getSourceFile(m_constantName);
if (sourceFile)
{
sizeInBytes = sourceFile->getSize();
}
}
else
{
// Regular constant.
if (!context.isVariableDefined(*m_constantName))
{
throw semantic_error(format_string("line %d: cannot get size of undefined constant %s", getFirstLine(), m_constantName->c_str()));
}
int_size_t intSize = context.getVariableSize(*m_constantName);
switch (intSize)
{
case kWordSize:
sizeInBytes = sizeof(uint32_t);
break;
case kHalfWordSize:
sizeInBytes = sizeof(uint16_t);
break;
case kByteSize:
sizeInBytes = sizeof(uint8_t);
break;
}
}
}
// Return function result as an expression node
return new IntConstExprASTNode(sizeInBytes);
}
printIndent(indent + 1);
printf("right:\n");
if (m_right) m_right->printTree(indent + 2);
}
std::string BinaryOpExprASTNode::getOperatorName() const
{
switch (m_op)
{
case kAdd:
return "+";
case kSubtract:
return "-";
case kMultiply:
return "*";
case kDivide:
return "/";
case kModulus:
return "%";
case kPower:
return "**";
case kBitwiseAnd:
return "&";
case kBitwiseOr:
return "|";
case kBitwiseXor:
return "^";
case kShiftLeft:
return "<<";
case kShiftRight:
return ">>";
case kLessThan:
return "<";
case kGreaterThan:
return ">";
case kLessThanEqual:
return "<=";
case kGreaterThanEqual:
return ">";
case kEqual:
return "==";
case kNotEqual:
return "!=";
case kBooleanAnd:
return "&&";
case kBooleanOr:
return "||";
}
return "???";
}
//! \todo Fix power operator under windows!!!
//!
ExprASTNode * BinaryOpExprASTNode::reduce(EvalContext & context)
{
if (!m_left || !m_right)
{
return this;
}
// Always reduce the left hand side.
m_left = m_left->reduce(context);
leftIntConst = dynamic_cast<IntConstExprASTNode*>(m_left.get());
if (!leftIntConst)
{
throw semantic_error(format_string("left hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
}
leftValue = leftIntConst->getValue();
// Boolean && and || operators are handled separately so that we can perform
// short-circuit evaluation.
if (m_op == kBooleanAnd || m_op == kBooleanOr)
{
// Reduce right hand side only if required to evaluate the boolean operator.
if ((m_op == kBooleanAnd && leftValue != 0) || (m_op == kBooleanOr && leftValue == 0))
{
m_right = m_right->reduce(context);
rightIntConst = dynamic_cast<IntConstExprASTNode*>(m_right.get());
if (!rightIntConst)
{
throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
}
rightValue = rightIntConst->getValue();
// Perform the boolean operation.
switch (m_op)
{
case kBooleanAnd:
result = leftValue && rightValue;
break;
case kBooleanOr:
result = leftValue && rightValue;
break;
}
}
else if (m_op == kBooleanAnd)
{
// The left hand side is false, so the && operator's result must be false
// without regard to the right hand side.
result = 0;
}
else if (m_op == kBooleanOr)
{
// The left hand value is true so the || result is automatically true.
result = 1;
}
}
else
{
// Reduce right hand side always for most operators.
m_right = m_right->reduce(context);
rightIntConst = dynamic_cast<IntConstExprASTNode*>(m_right.get());
if (!rightIntConst)
{
throw semantic_error(format_string("right hand side of %s operator failed to evaluate to an integer", getOperatorName().c_str()));
}
rightValue = rightIntConst->getValue();
switch (m_op)
{
case kAdd:
result = leftValue + rightValue;
break;
case kSubtract:
result = leftValue - rightValue;
break;
case kMultiply:
result = leftValue * rightValue;
break;
case kDivide:
result = leftValue / rightValue;
break;
case kModulus:
result = leftValue % rightValue;
break;
case kPower:
#ifdef WIN32
result = 0;
#else
result = lroundf(powf(float(leftValue), float(rightValue)));
#endif
break;
case kBitwiseAnd:
result = leftValue & rightValue;
break;
case kBitwiseOr:
result = leftValue | rightValue;
break;
case kBitwiseXor:
result = leftValue ^ rightValue;
break;
case kShiftLeft:
result = leftValue << rightValue;
break;
case kShiftRight:
result = leftValue >> rightValue;
break;
case kLessThan:
result = leftValue < rightValue;
break;
case kGreaterThan:
result = leftValue > rightValue;
break;
case kLessThanEqual:
result = leftValue <= rightValue;
break;
case kGreaterThanEqual:
result = leftValue >= rightValue;
break;
case kEqual:
result = leftValue == rightValue;
break;
case kNotEqual:
result = leftValue != rightValue;
break;
}
}
// Create the result value.
int_size_t resultSize;
if (leftIntConst && rightIntConst)
{
resultSize = resultIntSize(leftIntConst->getSize(), rightIntConst->getSize());
}
else if (leftIntConst)
{
resultSize = leftIntConst->getSize();
}
else
{
// This shouldn't really be possible, but just in case.
resultSize = kWordSize;
}
return new IntConstExprASTNode(result, resultSize);
}
printIndent(indent + 1);
printf("statements:\n");
if (m_statements) m_statements->printTree(indent + 2);
}
#pragma mark = IfStatementASTNode =
//! \warning Be careful; this method could enter an infinite loop if m_nextIf feeds
//! back onto itself. m_nextIf must be NULL at some point down the next if list.
IfStatementASTNode::IfStatementASTNode(const IfStatementASTNode & other)
: StatementASTNode(),
m_conditionExpr(),
m_ifStatements(),
m_nextIf(),
m_elseStatements()
{
m_conditionExpr = dynamic_cast<ExprASTNode*>(other.m_conditionExpr->clone());
m_ifStatements = dynamic_cast<ListASTNode*>(other.m_ifStatements->clone());
m_nextIf = dynamic_cast<IfStatementASTNode*>(other.m_nextIf->clone());
m_elseStatements = dynamic_cast<ListASTNode*>(other.m_elseStatements->clone());
}