/// <summary>
        ///		Parses a lower level expression. The lower level is responsible for parsing 
        ///		any sub terms and all operators apart from +- arithmetic operators.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseTermExpression()
        {
            // Parse the left hand factor expression.
            DataTypeValue factorDataType1 = ParseSubTermExpression();

            // Parse any subsequent factor expressions.
            while (true)
            {
                // Check that the next token is an arithmatic operator.
                Token operatorToken = LookAheadToken();
                if (operatorToken.ID != TokenID.OpDivide &&
                    operatorToken.ID != TokenID.OpModulus && operatorToken.ID != TokenID.OpMultiply &&
                    operatorToken.ID != TokenID.OpBitwiseXOr && operatorToken.ID != TokenID.OpBitwiseSHR &&
                    operatorToken.ID != TokenID.OpBitwiseSHL && operatorToken.ID != TokenID.OpBitwiseOr &&
                    operatorToken.ID != TokenID.OpBitwiseAnd)
                    break;
                NextToken();

                // Parse the right hand term expression.
                DataTypeValue factorDataType2 = ParseSubTermExpression();

                // Check the new data type can be cast to the main data type
                if (CanImplicitlyCast(factorDataType1, factorDataType2) == true)
                {

                    // Check the data types are valid with this operator.
                    if (OperatorDataTypeValid(factorDataType1, operatorToken.ID) == false)
                        Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + factorDataType1.ToString() + "\"", false, 1);

                    // We only want to emit byte code on the second pass.
                    if (_currentPass == 0) continue;

                    // Pop the result of the first term into arithmetic
                    // register 1.
                    Instruction instruction = CreateInstruction(OpCodeByType(factorDataType2, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);

                    // Pop the result of the second term into arithmetic
                    // register 2.
                    instruction = CreateInstruction(OpCodeByType(factorDataType1, OpCodeType.POP), _currentScope, _currentToken);
                    Operand op1 = new Operand(instruction, Register.Arithmetic1);

                    // Cast rvalue into lvalues type.
                    if (factorDataType1 != factorDataType2)
                    {
                        instruction = CreateInstruction(OpCodeByType(factorDataType1, OpCodeType.CAST), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);
                    }

                    // Create the arithmatic instruction based on the operator.
                    switch (operatorToken.ID)
                    {
                        case TokenID.OpDivide: instruction = CreateInstruction(OpCodeByType(factorDataType1, OpCodeType.DIV), _currentScope, _currentToken); break;
                        case TokenID.OpModulus: instruction = CreateInstruction(OpCode.MOD_INT, _currentScope, _currentToken); break;
                        case TokenID.OpMultiply: instruction = CreateInstruction(OpCodeByType(factorDataType1, OpCodeType.MUL), _currentScope, _currentToken); break;
                        case TokenID.OpBitwiseXOr: instruction = CreateInstruction(OpCode.BIT_XOR_INT, _currentScope, _currentToken); break;
                        case TokenID.OpBitwiseSHR: instruction = CreateInstruction(OpCode.BIT_SHL_INT, _currentScope, _currentToken); break;
                        case TokenID.OpBitwiseSHL: instruction = CreateInstruction(OpCode.BIT_SHR_INT, _currentScope, _currentToken); break;
                        case TokenID.OpBitwiseOr: instruction = CreateInstruction(OpCode.BIT_OR_INT, _currentScope, _currentToken); break;
                        case TokenID.OpBitwiseAnd: instruction = CreateInstruction(OpCode.BIT_AND_INT, _currentScope, _currentToken); break;
                    }
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, Register.Arithmetic2);

                    // Push the result onto the stack.
                    instruction = CreateInstruction(OpCodeByType(factorDataType1, OpCodeType.PUSH), _currentScope, _currentToken);
                    op1 = new Operand(instruction, Register.Arithmetic1);

                }
                else
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + factorDataType1.ToString() + "\" and \"" + factorDataType2.ToString() + "\"", false, 1);

            }

            return factorDataType1;
        }
        /// <summary>
        ///		Parses a middle level expression. The middle level is responsible for parsing 
        ///		any terms and the +- arithmetic operators.
        // </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseLeafExpression()
        {
            // Parse the left hand term expression.
            DataTypeValue termDataType1 = ParseTermExpression();

            // Parse any subsequent term expressions.
            while (true)
            {
                // Check that the next token is an arithmatic + or -.
                Token operatorToken = LookAheadToken();
                if (operatorToken.ID != TokenID.OpAdd && operatorToken.ID != TokenID.OpSub)
                    break;
                NextToken();

                // Parse the right hand term expression.
                DataTypeValue termDataType2 = ParseTermExpression();

                // Check the new data type can be cast to the main data type
                if (CanImplicitlyCast(termDataType1, termDataType2) == true)
                {

                    // Check the data types are valid with this operator.
                    if (OperatorDataTypeValid(termDataType1, operatorToken.ID) == false)
                        Error(ErrorCode.InvalidDataType, "Operator \"" + operatorToken.Ident + "\" can't be applied to data type \"" + termDataType1.ToString() + "\"", false, 1);

                    // We only want to emit byte code on the second pass.
                    if (_currentPass == 0)
                        continue;

                    // Pop the result of the second term into arithmetic
                    // register 1.
                    Instruction instruction = CreateInstruction(OpCodeByType(termDataType2, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);

                    // Pop the result of the first term into arithmetic
                    // register 2.
                    instruction = CreateInstruction(OpCodeByType(termDataType1, OpCodeType.POP), _currentScope, _currentToken);
                    Operand op1 = new Operand(instruction, Register.Arithmetic1);

                    // Cast rvalue into lvalues type.
                    if (termDataType1 != termDataType2)
                    {
                        instruction = CreateInstruction(OpCodeByType(termDataType1, OpCodeType.CAST), _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);
                    }

                    // Create the arithmatic instruction based on the operator.
                    switch (operatorToken.ID)
                    {
                        case TokenID.OpAdd: instruction = CreateInstruction(OpCodeByType(termDataType1, OpCodeType.ADD), _currentScope, _currentToken); break;
                        case TokenID.OpSub: instruction = CreateInstruction(OpCodeByType(termDataType1, OpCodeType.SUB), _currentScope, _currentToken); break;
                    }
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, Register.Arithmetic2);

                    // Push the result onto the stack.
                    instruction = CreateInstruction(OpCodeByType(termDataType1, OpCodeType.PUSH), _currentScope, _currentToken);
                    op1 = new Operand(instruction, Register.Arithmetic1);

                }
                else
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + termDataType1.ToString() + "\" and \"" + termDataType2.ToString() + "\"", false, 1);

            }

            return termDataType1;
        }
        /// <summary>
        ///		Parses a return statement, which will break out of a function call.
        ///		Syntax:
        ///			return [ Expression ] ";"
        /// </summary>
        private void ParseReturn()
        {
            // Check we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                Error(ErrorCode.InvalidScope, "Returns are only valid inside a function's or event's scope.", false, 0);

            if (_currentScope.Type == SymbolType.Function)
            {
                FunctionSymbol functionSymbol = (FunctionSymbol)_currentScope;

                // Check if there is an return expression after this.
                if (LookAheadToken().ID != TokenID.CharSemiColon)
                {
                    // Check that the function is expecting a return value.
                    if (functionSymbol.ReturnType.DataType == DataType.Void)
                        Error(ErrorCode.ExpectingReturnValue, "Void function can't return a value.", false, 0);

                    // Parse the return value's expression.
                    DataTypeValue returnValueDataType = ParseExpression();

                    // Check the return value can be implicitly cast to the given type.
                    if (CanImplicitlyCast(functionSymbol.ReturnType, returnValueDataType) == true)
                    {
                        if (_currentPass == 1)
                        {
                            // Pop the return value into the return register.
                            Instruction instruction = CreateInstruction(OpCodeByType(returnValueDataType, OpCodeType.POP), _currentScope, _currentToken);
                            Operand op1 = new Operand(instruction, Register.Return);

                            // Cast return value into correct type.
                            if (functionSymbol.ReturnType != returnValueDataType)
                            {
                                instruction = CreateInstruction(OpCodeByType(functionSymbol.ReturnType, OpCodeType.CAST), _currentScope, _currentToken);
                                new Operand(instruction, Register.Return);
                            }
                        }
                    }
                    else
                        Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + functionSymbol.ReturnType.ToString() + "\" and \"" + returnValueDataType.ToString() + "\"", false, 0);
                }
                else
                {
                    // Check if we need a return value or not.
                    if (functionSymbol.ReturnType.DataType != DataType.Void)
                        Error(ErrorCode.ExpectingReturnValue, "Function expects return value.", false, 0);

                    if (_currentPass == 1)
                    {
                        // Nullify the return register incase it contains a
                        // value from a previous function call.
                        Instruction instruction = CreateInstruction(OpCode.CAST_NULL, functionSymbol, _currentToken);
                        new Operand(instruction, Register.Return);
                    }
                }

                // Create return instruction.
                if (_currentPass == 1) CreateInstruction(OpCode.RETURN, _currentScope, _currentToken);
            }

            // Read in semi-colon at end of declaration.
            ExpectToken(TokenID.CharSemiColon);
        }
 /// <summary>
 ///		Creates a new instruction index operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="instrIndex">Index of instruction this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand InstrIndexOperand(Instruction instruction, int instrIndex)
 {
     Operand op = new Operand(instruction, OperandType.InstrIndex);
     op.InstrIndex = instrIndex;
     return op;
 }
 /// <summary>
 ///		Creates a new symbol index operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="symbolIndex">Index of symbol this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand SymbolIndexOperand(Instruction instruction, int symbolIndex)
 {
     Operand op = new Operand(instruction, OperandType.SymbolIndex);
     op.SymbolIndex = symbolIndex;
     return op;
 }
 /// <summary>
 ///		Creates a new indirect stack operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="register">Register containing stack slot this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand IndirectStackOperand(Instruction instruction, Register register)
 {
     Operand op = new Operand(instruction, OperandType.IndirectStack);
     op.Register = register;
     return op;
 }
 /// <summary>
 ///		Creates a new indirect stack indexed operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="register">Register containing stack slot this operand should point to.</param>
 /// <param name="offsetRegister">Register containing index offset this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand IndirectStackIndexedOperand(Instruction instruction, Register register, Register offsetRegister)
 {
     Operand op = new Operand(instruction, OperandType.IndirectStackIndexed);
     op.Register = register;
     op.OffsetRegister = offsetRegister;
     return op;
 }
 /// <summary>
 ///		Creates a new direct stack operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="stackIndex">Index of stack slot this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand DirectStackOperand(Instruction instruction, int stackIndex)
 {
     Operand op = new Operand(instruction, OperandType.DirectStack);
     op.StackIndex = stackIndex;
     return op;
 }
 /// <summary>
 ///		Creates a new direct stack index operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="stackIndex">Index of stack slot this operand should point to.</param>
 /// <param name="register">Register containing index offset.</param>
 /// <returns>New operand instance.</returns>
 public static Operand DirectStackIndexedOperand(Instruction instruction, int stackIndex, Register regiser)
 {
     Operand op = new Operand(instruction, OperandType.DirectStackIndexed);
     op.StackIndex = stackIndex;
     op.OffsetRegister = regiser;
     return op;
 }
 /// <summary>
 ///		Creates a new direct memory operand.
 /// </summary>
 /// <param name="instruction">Instruction to add operand to.</param>
 /// <param name="memoryIndex">Index of memory slot this operand should point to.</param>
 /// <returns>New operand instance.</returns>
 public static Operand DirectMemoryOperand(Instruction instruction, int memoryIndex)
 {
     Operand op = new Operand(instruction, OperandType.DirectMemory);
     op.MemoryIndex = memoryIndex;
     return op;
 }