/*
* File:        ElftosbAST.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/

#include "ElftosbAST.h"
#include <stdexcept>
#include <math.h>
#include <assert.h>
#include "ElftosbErrors.h"
#include "format_string.h"

using namespace elftosb;

#pragma mark = ASTNode =

void ASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s\n", nodeName().c_str());
}

void ASTNode::printIndent(int indent) const
{
       int i;
       for (i=0; i<indent; ++i)
       {
               printf("   ");
       }
}

void ASTNode::setLocation(token_loc_t & first, token_loc_t & last)
{
       m_location.m_firstLine = first.m_firstLine;
       m_location.m_lastLine = last.m_lastLine;
}

void ASTNode::setLocation(ASTNode * first, ASTNode * last)
{
       m_location.m_firstLine = first->getLocation().m_firstLine;
       m_location.m_lastLine = last->getLocation().m_lastLine;
}

#pragma mark = ListASTNode =

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();
       }
}

void ListASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       int n = 0;
       const_iterator it = begin();
       for (; it != end(); it++, n++)
       {
               printIndent(indent + 1);
               printf("%d:\n", n);
               (*it)->printTree(indent + 2);
       }
}

void ListASTNode::updateLocation()
{
       token_loc_t current = { 0 };
       const_iterator it = begin();
       for (; it != end(); it++)
       {
               const ASTNode * node = *it;
               const token_loc_t & loc = node->getLocation();

               // handle first node
               if (current.m_firstLine == 0)
               {
                       current = loc;
                       continue;
               }

               if (loc.m_firstLine < current.m_firstLine)
               {
                       current.m_firstLine = loc.m_firstLine;
               }

               if (loc.m_lastLine > current.m_lastLine)
               {
                       current.m_lastLine = loc.m_lastLine;
               }
       }

       setLocation(current);
}

#pragma mark = CommandFileASTNode =

CommandFileASTNode::CommandFileASTNode()
:       ASTNode(), m_options(), m_constants(), m_sources(), m_sections()
{
}

CommandFileASTNode::CommandFileASTNode(const CommandFileASTNode & other)
:       ASTNode(other), m_options(), m_constants(), m_sources(), m_sections()
{
       m_options = dynamic_cast<ListASTNode*>(other.m_options->clone());
       m_constants = dynamic_cast<ListASTNode*>(other.m_constants->clone());
       m_sources = dynamic_cast<ListASTNode*>(other.m_sources->clone());
       m_sections = dynamic_cast<ListASTNode*>(other.m_sections->clone());
}

void CommandFileASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       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;
       }

       return result;
}

#pragma mark = IntConstExprASTNode =

IntConstExprASTNode::IntConstExprASTNode(const IntConstExprASTNode & other)
:       ExprASTNode(other), m_value(other.m_value), m_size(other.m_size)
{
}

void IntConstExprASTNode::printTree(int indent) const
{
       printIndent(indent);
       char sizeChar='?';
       switch (m_size)
       {
               case kWordSize:
                       sizeChar = 'w';
                       break;
               case kHalfWordSize:
                       sizeChar = 'h';
                       break;
               case kByteSize:
                       sizeChar = 'b';
                       break;
       }
       printf("%s(%d:%c)\n", nodeName().c_str(), m_value, sizeChar);
}

#pragma mark = VariableExprASTNode =

VariableExprASTNode::VariableExprASTNode(const VariableExprASTNode & other)
:       ExprASTNode(other), m_variable()
{
       m_variable = new std::string(*other.m_variable);
}

void VariableExprASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s(%s)\n", nodeName().c_str(), m_variable->c_str());
}

ExprASTNode * VariableExprASTNode::reduce(EvalContext & context)
{
       if (!context.isVariableDefined(*m_variable))
       {
               throw std::runtime_error(format_string("line %d: undefined variable '%s'", getFirstLine(), m_variable->c_str()));
       }

       uint32_t value = context.getVariableValue(*m_variable);
       int_size_t size = context.getVariableSize(*m_variable);
       return new IntConstExprASTNode(value, size);
}

#pragma mark = SymbolRefExprASTNode =

SymbolRefExprASTNode::SymbolRefExprASTNode(const SymbolRefExprASTNode & other)
:       ExprASTNode(other), m_symbol(NULL)
{
       if (other.m_symbol)
       {
               m_symbol = dynamic_cast<SymbolASTNode*>(other.m_symbol->clone());
       }
}

void SymbolRefExprASTNode::printTree(int indent) const
{
}

ExprASTNode * SymbolRefExprASTNode::reduce(EvalContext & context)
{
       EvalContext::SourceFileManager * manager = context.getSourceFileManager();
       if (!manager)
       {
               throw std::runtime_error("no source manager available");
       }

       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);
}

#pragma mark = NegativeExprASTNode =

NegativeExprASTNode::NegativeExprASTNode(const NegativeExprASTNode & other)
:       ExprASTNode(other), m_expr()
{
       m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
}

void NegativeExprASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);
       if (m_expr) m_expr->printTree(indent + 1);
}

ExprASTNode * NegativeExprASTNode::reduce(EvalContext & context)
{
       if (!m_expr)
       {
               return this;
       }

       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
       {
               return this;
       }
}

#pragma mark = BooleanNotExprASTNode =

BooleanNotExprASTNode::BooleanNotExprASTNode(const BooleanNotExprASTNode & other)
:       ExprASTNode(other), m_expr()
{
       m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
}

void BooleanNotExprASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);
       if (m_expr) m_expr->printTree(indent + 1);
}

ExprASTNode * BooleanNotExprASTNode::reduce(EvalContext & context)
{
       if (!m_expr)
       {
               return this;
       }

       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);
}

void SourceFileFunctionASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);
       printIndent(indent+1);

       // 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);
}

#pragma mark = DefinedOperatorASTNode =

DefinedOperatorASTNode::DefinedOperatorASTNode(const DefinedOperatorASTNode & other)
:       ExprASTNode(other), m_constantName()
{
       m_constantName = new std::string(*other.m_constantName);
}

void DefinedOperatorASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);
       printIndent(indent+1);

       if (m_constantName)
       {
               printf("defined ( %s )\n", m_constantName->c_str());
       }
}

ExprASTNode * DefinedOperatorASTNode::reduce(EvalContext & context)
{
       assert(m_constantName);

       // Return function result as an expression node
       return new IntConstExprASTNode(context.isVariableDefined(m_constantName) ? 1 : 0);
}

#pragma mark = SizeofOperatorASTNode =

SizeofOperatorASTNode::SizeofOperatorASTNode(const SizeofOperatorASTNode & other)
:       ExprASTNode(other), m_constantName(), m_symbol()
{
       m_constantName = new std::string(*other.m_constantName);
       m_symbol = dynamic_cast<SymbolASTNode*>(other.m_symbol->clone());
}

void SizeofOperatorASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);

       printIndent(indent+1);

       if (m_constantName)
       {
               printf("sizeof: %s\n", m_constantName->c_str());
       }
       else if (m_symbol)
       {
               printf("sizeof:\n");
               m_symbol->printTree(indent + 2);
       }
}

ExprASTNode * SizeofOperatorASTNode::reduce(EvalContext & context)
{
       // One or the other must be defined.
       assert(m_constantName || m_symbol);

       EvalContext::SourceFileManager * manager = context.getSourceFileManager();
       assert(manager);

       unsigned sizeInBytes = 0;
       SourceFile * sourceFile;

       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);
}

#pragma mark = BinaryOpExprASTNode =

BinaryOpExprASTNode::BinaryOpExprASTNode(const BinaryOpExprASTNode & other)
:       ExprASTNode(other), m_left(), m_op(other.m_op), m_right()
{
       m_left = dynamic_cast<ExprASTNode*>(other.m_left->clone());
       m_right = dynamic_cast<ExprASTNode*>(other.m_right->clone());
}

void BinaryOpExprASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);

       printIndent(indent + 1);
       printf("left:\n");
       if (m_left) m_left->printTree(indent + 2);

       printIndent(indent + 1);
       printf("op: %s\n", getOperatorName().c_str());

       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;
       }

       IntConstExprASTNode * leftIntConst = NULL;
       IntConstExprASTNode * rightIntConst = NULL;
       uint32_t leftValue;
       uint32_t rightValue;
       uint32_t result = 0;

       // 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);
}

#pragma mark = IntSizeExprASTNode =

IntSizeExprASTNode::IntSizeExprASTNode(const IntSizeExprASTNode & other)
:       ExprASTNode(other), m_expr(), m_size(other.m_size)
{
       m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
}

void IntSizeExprASTNode::printTree(int indent) const
{
       ExprASTNode::printTree(indent);

       char sizeChar='?';
       switch (m_size)
       {
               case kWordSize:
                       sizeChar = 'w';
                       break;
               case kHalfWordSize:
                       sizeChar = 'h';
                       break;
               case kByteSize:
                       sizeChar = 'b';
                       break;
       }
       printIndent(indent + 1);
       printf("size: %c\n", sizeChar);

       printIndent(indent + 1);
       printf("expr:\n");
       if (m_expr) m_expr->printTree(indent + 2);
}

ExprASTNode * IntSizeExprASTNode::reduce(EvalContext & context)
{
       if (!m_expr)
       {
               return this;
       }

       m_expr = m_expr->reduce(context);
       IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(m_expr.get());
       if (!intConst)
       {
               return this;
       }

       return new IntConstExprASTNode(intConst->getValue(), m_size);
}

#pragma mark = ExprConstASTNode =

ExprConstASTNode::ExprConstASTNode(const ExprConstASTNode & other)
:       ConstASTNode(other), m_expr()
{
       m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
}

void ExprConstASTNode::printTree(int indent) const
{
       ConstASTNode::printTree(indent);
       if (m_expr) m_expr->printTree(indent + 1);
}

#pragma mark = StringConstASTNode =

StringConstASTNode::StringConstASTNode(const StringConstASTNode & other)
:       ConstASTNode(other), m_value()
{
       m_value = new std::string(other.m_value);
}

void StringConstASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s(%s)\n", nodeName().c_str(), m_value->c_str());
}

#pragma mark = BlobConstASTNode =

BlobConstASTNode::BlobConstASTNode(const BlobConstASTNode & other)
:       ConstASTNode(other), m_blob()
{
       m_blob = new Blob(*other.m_blob);
}

void BlobConstASTNode::printTree(int indent) const
{
       printIndent(indent);

       const uint8_t * dataPtr = m_blob->getData();
       unsigned dataLen = m_blob->getLength();
       printf("%s(%p:%d)\n", nodeName().c_str(), dataPtr, dataLen);
}

#pragma mark = IVTConstASTNode =

IVTConstASTNode::IVTConstASTNode(const IVTConstASTNode & other)
:       ConstASTNode(other), m_fields()
{
       m_fields = dynamic_cast<ListASTNode*>(other.m_fields->clone());
}

void IVTConstASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s:\n", nodeName().c_str());
   if (m_fields)
   {
       m_fields->printTree(indent + 1);
   }
}

#pragma mark = AssignmentASTNode =

AssignmentASTNode::AssignmentASTNode(const AssignmentASTNode & other)
:       ASTNode(other), m_ident(), m_value()
{
       m_ident = new std::string(*other.m_ident);
       m_value = dynamic_cast<ConstASTNode*>(other.m_value->clone());
}

void AssignmentASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s(%s)\n", nodeName().c_str(), m_ident->c_str());

       if (m_value) m_value->printTree(indent + 1);
}

#pragma mark = SourceDefASTNode =

SourceDefASTNode::SourceDefASTNode(const SourceDefASTNode & other)
:       ASTNode(other), m_name()
{
       m_name = new std::string(*other.m_name);
}

#pragma mark = PathSourceDefASTNode =

PathSourceDefASTNode::PathSourceDefASTNode(const PathSourceDefASTNode & other)
:       SourceDefASTNode(other), m_path()
{
       m_path = new std::string(*other.m_path);
}

void PathSourceDefASTNode::printTree(int indent) const
{
       SourceDefASTNode::printTree(indent);

       printIndent(indent+1);
       printf("path: %s\n", m_path->c_str());

       printIndent(indent+1);
       printf("attributes:\n");
       if (m_attributes)
       {
               m_attributes->printTree(indent+2);
       }
}

#pragma mark = ExternSourceDefASTNode =

ExternSourceDefASTNode::ExternSourceDefASTNode(const ExternSourceDefASTNode & other)
:       SourceDefASTNode(other), m_expr()
{
       m_expr = dynamic_cast<ExprASTNode*>(other.m_expr->clone());
}

void ExternSourceDefASTNode::printTree(int indent) const
{
       SourceDefASTNode::printTree(indent);

       printIndent(indent+1);
       printf("expr:\n");
       if (m_expr) m_expr->printTree(indent + 2);

       printIndent(indent+1);
       printf("attributes:\n");
       if (m_attributes)
       {
               m_attributes->printTree(indent+2);
       }
}

#pragma mark = SectionContentsASTNode =

SectionContentsASTNode::SectionContentsASTNode(const SectionContentsASTNode & other)
:       ASTNode(other), m_sectionExpr()
{
       m_sectionExpr = dynamic_cast<ExprASTNode*>(other.m_sectionExpr->clone());
}

void SectionContentsASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       printIndent(indent + 1);
       printf("section#:\n");
       if (m_sectionExpr) m_sectionExpr->printTree(indent + 2);
}

#pragma mark = DataSectionContentsASTNode =

DataSectionContentsASTNode::DataSectionContentsASTNode(const DataSectionContentsASTNode & other)
:       SectionContentsASTNode(other), m_contents()
{
       m_contents = dynamic_cast<ASTNode*>(other.m_contents->clone());
}

void DataSectionContentsASTNode::printTree(int indent) const
{
       SectionContentsASTNode::printTree(indent);

       if (m_contents)
       {
               m_contents->printTree(indent + 1);
       }
}

#pragma mark = BootableSectionContentsASTNode =

BootableSectionContentsASTNode::BootableSectionContentsASTNode(const BootableSectionContentsASTNode & other)
:       SectionContentsASTNode(other), m_statements()
{
       m_statements = dynamic_cast<ListASTNode*>(other.m_statements->clone());
}

void BootableSectionContentsASTNode::printTree(int indent) const
{
       SectionContentsASTNode::printTree(indent);

       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());
}

#pragma mark = ModeStatementASTNode =

ModeStatementASTNode::ModeStatementASTNode(const ModeStatementASTNode & other)
:       StatementASTNode(other), m_modeExpr()
{
       m_modeExpr = dynamic_cast<ExprASTNode*>(other.m_modeExpr->clone());
}

void ModeStatementASTNode::printTree(int indent) const
{
       StatementASTNode::printTree(indent);
       printIndent(indent + 1);
       printf("mode:\n");
       if (m_modeExpr) m_modeExpr->printTree(indent + 2);
}

#pragma mark = MessageStatementASTNode =

MessageStatementASTNode::MessageStatementASTNode(const MessageStatementASTNode & other)
:       StatementASTNode(other), m_type(other.m_type), m_message()
{
       m_message = new std::string(*other.m_message);
}

void MessageStatementASTNode::printTree(int indent) const
{
       StatementASTNode::printTree(indent);
       printIndent(indent + 1);
       printf("%s: %s\n", getTypeName(), m_message->c_str());
}

const char * MessageStatementASTNode::getTypeName() const
{
       switch (m_type)
       {
               case kInfo:
                       return "info";

               case kWarning:
                       return "warning";

               case kError:
                       return "error";
       }

       return "unknown";
}

#pragma mark = LoadStatementASTNode =

LoadStatementASTNode::LoadStatementASTNode(const LoadStatementASTNode & other)
:       StatementASTNode(other), m_data(), m_target(), m_isDCDLoad(other.m_isDCDLoad)
{
       m_data = other.m_data->clone();
       m_target = other.m_target->clone();
}

void LoadStatementASTNode::printTree(int indent) const
{
       StatementASTNode::printTree(indent);

       printIndent(indent + 1);
       printf("data:\n");
       if (m_data) m_data->printTree(indent + 2);

       printIndent(indent + 1);
       printf("target:\n");
       if (m_target) m_target->printTree(indent + 2);
}

#pragma mark = CallStatementASTNode =

CallStatementASTNode::CallStatementASTNode(const CallStatementASTNode & other)
:       StatementASTNode(other), m_type(other.m_type), m_target(), m_arg()
{
       m_target = other.m_target->clone();
       m_arg = other.m_arg->clone();
}

void CallStatementASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s(%s)%s\n", nodeName().c_str(), (m_type == kCallType ? "call" : "jump"), (m_isHAB ? "/HAB" : ""));

       printIndent(indent + 1);
       printf("target:\n");
       if (m_target) m_target->printTree(indent + 2);

       printIndent(indent + 1);
       printf("arg:\n");
       if (m_arg) m_arg->printTree(indent + 2);
}

#pragma mark = SourceASTNode =

SourceASTNode::SourceASTNode(const SourceASTNode & other)
:       ASTNode(other), m_name()
{
       m_name = new std::string(*other.m_name);
}

void SourceASTNode::printTree(int indent) const
{
       printIndent(indent);
       printf("%s(%s)\n", nodeName().c_str(), m_name->c_str());
}

#pragma mark = SectionMatchListASTNode =

SectionMatchListASTNode::SectionMatchListASTNode(const SectionMatchListASTNode & other)
:       ASTNode(other), m_sections(), m_source()
{
       if (other.m_sections)
       {
               m_sections = dynamic_cast<ListASTNode *>(other.m_sections->clone());
       }

       if (other.m_source)
       {
               m_source = new std::string(*other.m_source);
       }
}

void SectionMatchListASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       printIndent(indent+1);
       printf("sections:\n");
       if (m_sections)
       {
               m_sections->printTree(indent+2);
       }

       printIndent(indent+1);
       printf("source: ");
       if (m_source)
       {
               printf("%s\n", m_source->c_str());
       }
       else
       {
               printf("\n");
       }
}

#pragma mark = SectionASTNode =

SectionASTNode::SectionASTNode(const SectionASTNode & other)
:       ASTNode(other), m_name(), m_source()
{
       m_action = other.m_action;

       if (other.m_name)
       {
               m_name = new std::string(*other.m_name);
       }

       if (other.m_source)
       {
               m_source = new std::string(*other.m_source);
       }
}

void SectionASTNode::printTree(int indent) const
{
       printIndent(indent);

       const char * actionName;
       switch (m_action)
       {
               case kInclude:
                       actionName = "include";
                       break;
               case kExclude:
                       actionName = "exclude";
                       break;
       }

       if (m_source)
       {
               printf("%s(%s:%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str(), m_source->c_str());
       }
       else
       {
               printf("%s(%s:%s)\n", nodeName().c_str(), actionName, m_name->c_str());
       }
}

#pragma mark = SymbolASTNode =

SymbolASTNode::SymbolASTNode(const SymbolASTNode & other)
:       ASTNode(other), m_symbol(), m_source()
{
       m_symbol = new std::string(*other.m_symbol);
       m_source = new std::string(*other.m_source);
}

void SymbolASTNode::printTree(int indent) const
{
       printIndent(indent);

       const char * symbol = NULL;
       if (m_symbol)
       {
               symbol = m_symbol->c_str();
       }

       const char * source = NULL;
       if (m_source)
       {
               source = m_source->c_str();
       }

       printf("%s(", nodeName().c_str());
       if (source)
       {
               printf("%s", source);
       }
       else
       {
               printf(".");
       }
       printf(":");
       if (symbol)
       {
               printf("%s", symbol);
       }
       else
       {
               printf(".");
       }
       printf(")\n");
}

#pragma mark = AddressRangeASTNode =

AddressRangeASTNode::AddressRangeASTNode(const AddressRangeASTNode & other)
:       ASTNode(other), m_begin(), m_end()
{
       m_begin = other.m_begin->clone();
       m_end = other.m_end->clone();
}

void AddressRangeASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       printIndent(indent + 1);
       printf("begin:\n");
       if (m_begin) m_begin->printTree(indent + 2);

       printIndent(indent + 1);
       printf("end:\n");
       if (m_end) m_end->printTree(indent + 2);
}

#pragma mark = FromStatementASTNode =

FromStatementASTNode::FromStatementASTNode(std::string * source, ListASTNode * statements)
:       StatementASTNode(), m_source(source), m_statements(statements)
{
}

FromStatementASTNode::FromStatementASTNode(const FromStatementASTNode & other)
:       StatementASTNode(), m_source(), m_statements()
{
       m_source = new std::string(*other.m_source);
       m_statements = dynamic_cast<ListASTNode*>(other.m_statements->clone());
}

void FromStatementASTNode::printTree(int indent) const
{
       ASTNode::printTree(indent);

       printIndent(indent + 1);
       printf("source: ");
       if (m_source) printf("%s\n", m_source->c_str());

       printIndent(indent + 1);
       printf("statements:\n");
       if (m_statements) m_statements->printTree(indent + 2);
}