@Override
  public AddressValue addressValue(ExpressionNode lhs) throws SyntaxException {
    if (lhs instanceof IdentifierExpressionNode) {
      Entity entity = ((IdentifierExpressionNode) lhs).getIdentifier().getEntity();
      EntityKind kind = entity.getEntityKind();

      if (kind == EntityKind.VARIABLE) {
        return variableReference((Variable) entity);
      } else if (kind == EntityKind.FUNCTION) {
        return functionReference((Function) entity);
      } else {
        throw error("Operand of & not variable or function identifier", lhs);
      }
    } else if (lhs instanceof DotNode) {
      AddressValue structureOrUnionReference = addressValue(((DotNode) lhs).getStructure());
      Field field = (Field) ((DotNode) lhs).getFieldName().getEntity();

      return memberReference(structureOrUnionReference, field);
    } else if (lhs instanceof OperatorNode) {
      OperatorNode opNode = (OperatorNode) lhs;
      Operator operator = ((OperatorNode) lhs).getOperator();

      if (operator == Operator.SUBSCRIPT) {
        AddressValue arrayReference = addressValue(opNode.getArgument(0));
        Value index = evaluate(opNode.getArgument(1));

        return arrayElementReference(arrayReference, index);
      } else if (operator == Operator.DEREFERENCE) {
        return (AddressValue) evaluate(opNode.getArgument(0));
      }
    }
    throw error("Cannot take address of expression", lhs);
  }
  /**
   * Evaluates a constant expression.
   *
   * <p>Should apply conversions to result.
   *
   * @param expr
   * @return
   * @throws SyntaxException
   * @throws UnsourcedException if expr is not a constant expression
   */
  private Value evaluateHelper(ExpressionNode expr) throws SyntaxException, UnsourcedException {
    if (expr instanceof AlignOfNode) {
      return alignofValue(((AlignOfNode) expr).getArgument().getType());
    } else if (expr instanceof ArrowNode) {
      ArrowNode arrowNode = (ArrowNode) expr;
      ExpressionNode structOrUnionPointer = arrowNode.getStructurePointer();
      IdentifierNode fieldIdentifier = arrowNode.getFieldName();
      Field field = (Field) fieldIdentifier.getEntity();
      Value structOrUnionValue = evaluateDereference(structOrUnionPointer);

      return evaluateMemberAccess(structOrUnionValue, field);
    } else if (expr instanceof CastNode) {
      CastNode castNode = (CastNode) expr;

      return evaluateCast(castNode.getCastType().getType(), evaluate(castNode.getArgument()));
    } else if (expr instanceof CharacterConstantNode) {
      return ((CharacterConstantNode) expr).getConstantValue();
    } else if (expr instanceof CompoundLiteralNode) {
      return evaluateCompoundLiteral((CompoundLiteralNode) expr);
    } else if (expr instanceof ConstantNode) {
      return ((ConstantNode) expr).getConstantValue();
    } else if (expr instanceof DotNode) {
      DotNode dotNode = (DotNode) expr;
      ExpressionNode structOrUnion = dotNode.getStructure();
      IdentifierNode fieldIdentifier = dotNode.getFieldName();
      Field field = (Field) fieldIdentifier.getEntity();
      Value structOrUnionValue = evaluate(structOrUnion);

      return evaluateMemberAccess(structOrUnionValue, field);
    } else if (expr instanceof OperatorNode) {
      OperatorNode opNode = (OperatorNode) expr;
      Operator operator = opNode.getOperator();

      if (operator == Operator.ADDRESSOF) return addressValue(opNode.getArgument(0));
      else { // evaluate arguments and call apply
        int numArgs = opNode.getNumberOfArguments();
        Value[] argValues = new Value[numArgs];
        Type type = expr.getInitialType();

        for (int i = 0; i < numArgs; i++) {
          ExpressionNode arg = opNode.getArgument(i);
          Value argValue = evaluate(arg);

          argValues[i] = applyConversions(arg, argValue);
        }
        return apply(type, operator, argValues);
      }
    } else if (expr instanceof SizeofNode) {
      return sizeofValue((((SizeofNode) expr).getArgument()).getType());
    } else if (expr instanceof StringLiteralNode) {
      return ((StringLiteralNode) expr).getConstantValue();
    } else if (expr instanceof EnumerationConstantNode) {
      IdentifierNode identNode = ((EnumerationConstantNode) expr).getName();
      Entity entity = identNode.getEntity();

      if (entity.getEntityKind() == EntityKind.ENUMERATOR) {
        return ((Enumerator) entity).getValue();
      }
      return null;
    }
    return null;
  }