private ArithmeticExpression parseArithmeticExpression() throws CompileException {
    Term term = parseTerm();

    ASTList<TermBlock> termBlocks = new ASTList<TermBlock>();
    while (currentToken.getTokenKind() == TokenKind.TERMOPERATOR) {
      termBlocks.add(new TermBlock(parsePlusMinusOperator(), parseTerm()));
    }

    if (termBlocks.isEmpty()) return new ArithmeticExpression(term);
    else return new ArithmeticExpression(term, termBlocks);
  }
  private Term parseTerm() throws CompileException {
    ASTList<FactorBlock> factorBlocks = new ASTList<FactorBlock>();

    Factor factor = parseFactor();

    while (currentToken.getTokenKind() == TokenKind.FACTOROPERATOR) {
      factorBlocks.add(new FactorBlock(parseMultiplyDivideOperator(), parseFactor()));
    }

    if (factorBlocks.isEmpty()) return new Term(factor);
    else return new Term(factor, factorBlocks);
  }
  private Coordinates parseCoordinates() throws CompileException {
    ASTList<CoordinatePosition> coordinates = new ASTList<CoordinatePosition>();

    accept(TokenKind.LSQBRACKET);
    coordinates.add(parseCoordinatePosition());
    while (currentToken.getTokenKind() == TokenKind.COMMA) {
      acceptIt(); // COMMA
      coordinates.add(parseCoordinatePosition());
    }
    accept(TokenKind.RSQBRACKET);

    return new Coordinates(coordinates);
  }
  private Parameters parseParameters() throws CompileException {
    ASTList<ExpressionBlock> expressionBlocks = new ASTList<ExpressionBlock>();

    accept(TokenKind.LPAREN);

    if (currentToken.getTokenKind() != TokenKind.RPAREN) {
      // There must be parameters - parse them all
      expressionBlocks.add(parseExpressionBlock());
      while (currentToken.getTokenKind() == TokenKind.COMMA) {
        acceptIt();
        expressionBlocks.add(parseExpressionBlock());
      }
    }
    accept(TokenKind.RPAREN);
    return new Parameters(expressionBlocks);
  }
  private Program parseProgram() throws CompileException {
    ASTList<VarDeclaration> varDeclarations = new ASTList<VarDeclaration>();
    ASTList<EventCommand> eventCommands = new ASTList<EventCommand>();

    while (currentToken.getTokenKind() == TokenKind.TYPE)
      varDeclarations.add(parseVarDeclaration());

    while (currentToken.getTokenKind() == TokenKind.EVENT) eventCommands.add(parseEventCommand());

    accept(TokenKind.EOT);

    if (!eventCommands.isEmpty() && varDeclarations.isEmpty())
      // only eventCommands
      return new Program(
          eventCommands, true); // the boolean is garbage required as java uses type erasure
    else if (eventCommands.isEmpty() && !varDeclarations.isEmpty())
      // only varDeclarations
      return new Program(varDeclarations);
    else
      // Both
      return new Program(varDeclarations, eventCommands);
  }
  private IfStatement parseIfStatement() throws CompileException {
    ASTList<Command> commandIfs = new ASTList<Command>();
    ASTList<ElseIfBlock> elseIfBlocks = new ASTList<ElseIfBlock>();
    ASTList<Command> commandElses = new ASTList<Command>();

    accept(TokenKind.IF);
    accept(TokenKind.LPAREN);
    BooleanExpression booleanExpressionIf = parseBooleanExpression();
    accept(TokenKind.RPAREN);

    accept(TokenKind.LCRLPARAN);
    while (currentToken.getTokenKind() == TokenKind.MOVE
        || currentToken.getTokenKind() == TokenKind.GOTO
        || currentToken.getTokenKind() == TokenKind.SET
        || currentToken.getTokenKind() == TokenKind.IDENTIFIER
        || currentToken.getTokenKind() == TokenKind.IF) {
      // Its a command
      commandIfs.add(parseCommand());
    }
    accept(TokenKind.RCRLPARAN);
    // We're at the end of the IF clause
    while (currentToken.getTokenKind() == TokenKind.ELSEIF) {
      acceptIt();
      accept(TokenKind.LPAREN);
      BooleanExpression orExpression = parseBooleanExpression();
      accept(TokenKind.RPAREN);
      accept(TokenKind.LCRLPARAN);
      ASTList<Command> commandOrs = new ASTList<Command>();
      while (currentToken.getTokenKind() == TokenKind.MOVE
          || currentToken.getTokenKind() == TokenKind.GOTO
          || currentToken.getTokenKind() == TokenKind.SET
          || currentToken.getTokenKind() == TokenKind.IDENTIFIER
          || currentToken.getTokenKind() == TokenKind.IF) {
        // Its a command
        commandOrs.add(parseCommand());
      }
      elseIfBlocks.add(new ElseIfBlock(orExpression, commandOrs));
      accept(TokenKind.RCRLPARAN);
    }
    if (currentToken.getTokenKind() == TokenKind.ELSE) {
      acceptIt();
      accept(TokenKind.LCRLPARAN);
      while (currentToken.getTokenKind() == TokenKind.MOVE
          || currentToken.getTokenKind() == TokenKind.GOTO
          || currentToken.getTokenKind() == TokenKind.SET
          || currentToken.getTokenKind() == TokenKind.IDENTIFIER
          || currentToken.getTokenKind() == TokenKind.IF) {
        // Its a command
        commandElses.add(parseCommand());
      }
      accept(TokenKind.RCRLPARAN);
    }

    // Find out what constructor to call
    if (elseIfBlocks.isEmpty() && commandElses.isEmpty()) {
      return new IfStatement(booleanExpressionIf, commandIfs);
    } else if (!elseIfBlocks.isEmpty() && commandElses.isEmpty()) {
      return new IfStatement(
          booleanExpressionIf,
          commandIfs,
          elseIfBlocks,
          true); // the boolean is garbage required as java uses type erasure
    } else if (elseIfBlocks.isEmpty() && !commandElses.isEmpty()) {
      return new IfStatement(booleanExpressionIf, commandIfs, commandElses);
    } else {
      return new IfStatement(booleanExpressionIf, commandIfs, elseIfBlocks, commandElses);
    }
  }
  private EventCommand parseEventCommand() throws CompileException {
    ASTList<VarDeclaration> varDeclarations = new ASTList<VarDeclaration>();
    ASTList<Command> commands = new ASTList<Command>();
    Coordinates inCoordinates = null;
    WhereExpression whereExpression = null;
    Identifier identifierArea = null;
    Identifier identifierMethod = null;
    Parameters parameters = null;

    accept(TokenKind.EVENT);
    Type type = parseType();
    Identifier identifierEvent = parseIdentifier();
    // Does the EVENT contain an IN clause?
    if (currentToken.getTokenKind() == TokenKind.IN) {
      acceptIt(); // accept the IN token

      // Is it IN COORDINATES or an IDENTIFIER?
      if (currentToken.getTokenKind() == TokenKind.LSQBRACKET) {
        // its IN COORDINATES
        inCoordinates = parseCoordinates();
      } else if (currentToken.getTokenKind() == TokenKind.IDENTIFIER) {
        // It's IN an IDENTIFIER or a METHODCALL
        identifierArea = parseIdentifier();
        if (currentToken.getTokenKind() == TokenKind.DOT) {
          // It's a METHODCALL
          acceptIt();
          identifierMethod = parseIdentifier();
          parameters = parseParameters();
        }
      }
    }
    // Does the EVENT contain a WHERE clause?
    if (currentToken.getTokenKind() == TokenKind.WHERE) {
      whereExpression = parseWhereExpression();
    }
    // Start parsing variableDeclarations.
    accept(TokenKind.LCRLPARAN);

    while (currentToken.getTokenKind() == TokenKind.TYPE)
      varDeclarations.add(parseVarDeclaration());

    // Start parsing commands.
    while (currentToken.getTokenKind() != TokenKind.RCRLPARAN) commands.add(parseCommand());

    accept(TokenKind.RCRLPARAN);

    // Find the correct constructor.
    if (inCoordinates != null) {
      if (whereExpression != null) {
        // IN COORDINATES WHERE
        return new EventCommand(
            type, identifierEvent, inCoordinates, whereExpression, varDeclarations, commands);
      }
      // IN COORDINATES
      return new EventCommand(type, identifierEvent, inCoordinates, varDeclarations, commands);
    } else if (identifierMethod != null) {
      if (whereExpression != null) {
        // IN METHODCALL WHERE
        return new EventCommand(
            type,
            identifierEvent,
            identifierArea,
            identifierMethod,
            parameters,
            whereExpression,
            varDeclarations,
            commands);
      }
      // IN METHODCALL
      return new EventCommand(
          type,
          identifierEvent,
          identifierArea,
          identifierMethod,
          parameters,
          varDeclarations,
          commands);
    } else if (identifierArea != null) {
      if (whereExpression != null) {
        // IN IDENTIFIER WHERE
        return new EventCommand(
            type, identifierEvent, identifierArea, whereExpression, varDeclarations, commands);
      }
      // IN IDENTIFIER
      return new EventCommand(type, identifierEvent, identifierArea, varDeclarations, commands);
    } else if (whereExpression != null) {
      return new EventCommand(type, identifierEvent, whereExpression, varDeclarations, commands);
    } else {
      // We need either an IN or WHERE or Both...
      throw new CompileException(
          ErrorType.UNEXPECTED_TOKEN,
          currentToken.getPosition(),
          "parseEvent syntax error, EVENT's needs either an IN or WHERE clause, or Both, got "
              + currentToken.getTokenKind());
    }
  }