private IExpressionNode argument() throws ParserException {
    if (lookahead.token == Token.FUNCTION) {
      // argument -> FUNCTION argument
      int function = FunctionExpressionNode.stringToFunction(lookahead.sequence);
      nextToken();
      IExpressionNode expr = argument();
      return new FunctionExpressionNode(function, expr);
    } else if (lookahead.token == Token.PRINT) {
      // argumement -> PRINT expression
      nextToken();
      IExpressionNode expr = expression();

      try {
        System.out.println(expr.getValue());
      } catch (EvaluationException ex) {
        Logger.getLogger(LOGGER_NAME)
            .severe("EvaulationException thrown while printing the value of: " + expr.toString());
      }

      return expr;
    } else if (lookahead.token == Token.LPAREN) {
      // argument -> LPAREN sum RPAREN
      nextToken();
      IExpressionNode expr = expression();

      if (lookahead.token != Token.RPAREN)
        throw new ParserException(String.format(ERR_RPAREN, lookahead.sequence));

      nextToken();
      return expr;
    }

    // argument -> value
    return value();
  }
  private IExpressionNode findVariableByName(String name) {
    for (IExpressionNode node : nodeList) {
      if (node.getType() == IExpressionNode.VARIABLE_NODE)
        if (((VariableExpressionNode) node).getName().equals(name)) return node;
    }

    return null;
  }
  private IExpressionNode assignmentOp(IExpressionNode variable) throws ParserException {
    if (lookahead.token == Token.EQUALS) {
      nextToken();
      IExpressionNode newVariable = expression();
      if (!(variable.getType() == IExpressionNode.VARIABLE_NODE))
        throw new ParserException(String.format(ERR_VARIABLE, variable.toString()));

      try {
        variable.accept(
            new SetVariable(((VariableExpressionNode) variable).getName(), newVariable.getValue()));
      } catch (EvaluationException ex) {
        throw new ParserException(
            String.format("The variable [%s] did not return a valid value", newVariable));
      }
    }

    return variable;
  }
  private IExpressionNode sumOp(IExpressionNode expression) throws ParserException {
    if (lookahead.token == Token.PLUSMINUS) {
      // sum_op -> PLUSMINUS term sum_op
      AdditionExpressionNode sum;
      if (expression.getType() == IExpressionNode.ADDITION_NODE)
        sum = (AdditionExpressionNode) expression;
      else sum = new AdditionExpressionNode(expression, true);

      boolean positive = lookahead.sequence.equals(PLUS);
      nextToken();
      IExpressionNode t = term();
      sum.add(t, positive);

      return sumOp(sum);
    }

    // sum_op -> EPSILON
    return expression;
  }
  private IExpressionNode termOp(IExpressionNode expression) throws ParserException {
    if (lookahead.token == Token.MULTDIV) {
      // term_op -> MULTDIV factor term_op
      MultiplicationExpressionNode prod;

      if (expression.getType() == IExpressionNode.MULTIPLICATION_NODE)
        prod = (MultiplicationExpressionNode) expression;
      else prod = new MultiplicationExpressionNode(expression, true);

      boolean positive = lookahead.sequence.equals(MULT);
      nextToken();
      IExpressionNode f = signedFactor();
      prod.add(f, positive);

      return termOp(prod);
    }

    // term_op -> EPSILON
    return expression;
  }
  private IExpressionNode booleanExpression() throws ParserException {
    IExpressionNode expr = expression();
    String comparator = lookahead.sequence;
    nextToken();
    IExpressionNode expr2 = expression();

    try {
      if (comparator.equals(LT))
        return new BooleanExpressionNode(expr.getValue() < expr2.getValue());
      if (comparator.equals(GT))
        return new BooleanExpressionNode(expr.getValue() > expr2.getValue());
      if (comparator.equals(LTEQ))
        return new BooleanExpressionNode(expr.getValue() <= expr2.getValue());
      if (comparator.equals(GTEQ))
        return new BooleanExpressionNode(expr.getValue() >= expr2.getValue());
      if (comparator.equals(NTEQ))
        return new BooleanExpressionNode(expr.getValue() != expr2.getValue());
    } catch (EvaluationException ex) {
      throw new ParserException(
          "EvaluationException caught when calculating boolean expression"
              + ": "
              + expr.toString()
              + comparator
              + expr2.toString());
    }
    throw new ParserException("No Comparator found, instead found: " + comparator);
  }