Esempio n. 1
0
        /// <summary>
        ///		Parses the lowest level of an expression. The lowest level is respolsible
        ///		for parsing things such as literal values and function calls, it also
        ///		deals with unary, prefix and postfix operators.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseFactorExpression()
        {
            // Declare a variable to store the data type in.
            DataTypeValue factorDataType = new DataTypeValue(DataType.Invalid, false, false);
            StringSymbol stringSymbol = null;

            #region Unary op
            // Check if there is a unary operator pending.
            bool unaryOpPending = false;
            Token unaryOpToken = LookAheadToken();
            if (unaryOpToken.ID == TokenID.OpAdd || unaryOpToken.ID == TokenID.OpSub ||
                unaryOpToken.ID == TokenID.OpLogicalNot || unaryOpToken.ID == TokenID.OpBitwiseNot ||
                unaryOpToken.ID == TokenID.OpIncrement || unaryOpToken.ID == TokenID.OpDecrement)
            {
                unaryOpPending = true;
                NextToken();
            }
            #endregion

            #region Cast Pending
            // Check if there is a explicit cast pending.
            bool castPending = false;
            DataTypeValue castType = new DataTypeValue(DataType.Invalid, false, false);
            if (LookAheadToken().ID == TokenID.CharOpenParenthesis)
            {
                castType.DataType = DataTypeFromKeywordToken(LookAheadToken(2).ID);
                if (castType.DataType != DataType.Invalid)
                {
                    NextToken(); // Read in open parenthesis.
                    NextToken(); // Read in cast keyword.
                    // Check for array.
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        NextToken();
                        castType.IsArray = true;
                        ExpectToken(TokenID.CharCloseBracket);
                    }
                    ExpectToken(TokenID.CharCloseParenthesis); // Read in closing parenthesis.
                    castPending = true;
                }
            }
            #endregion

            // Determine what factor type we are looking at
            // and act accordingly.
            NextToken();
            switch (_currentToken.ID)
            {
                #region Indexer
                case TokenID.KeywordIndexer:

                    // Check we are inside an indexer loop.
                    if (_insideIndexerLoop == false)
                        Error(ErrorCode.InvalidIndexer, "The Indexer keyword can only be used inside a valid indexable loop.");

                    // Set the factor data type as an integer (an indexer is always an integer).
                    factorDataType = new DataTypeValue(DataType.Int, false, false);

                    // Generate byte code to push indexer onto the stack.
                    if (_currentPass == 1)
                    {
                        VariableSymbol indexerVariable = _currentScope.FindSymbol("$" + _indexerLoopIndex, SymbolType.Variable) as VariableSymbol;
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        Operand.DirectStackOperand(instruction, indexerVariable.StackIndex);
                    }
                    break;

                #endregion
                #region New
                case TokenID.KeywordNew:

                    // Read in identifier specifying what we wish to create a new
                    // instance of.
                    NextToken();

                    // Check if we are detailing with a data type.
                    DataTypeValue dataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), true, false);
                    factorDataType = dataType;
                    if (dataType.DataType != DataType.Invalid)
                    {

                        // Check this is an array.
                        if (LookAheadToken().ID == TokenID.CharOpenBracket)
                        {
                            // Read in opening bracket.
                            NextToken();

                            // Parse the size expression.
                            DataTypeValue indexDataType = ParseExpression();

                            // Make sure we can convert it to an integer index.
                            if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), indexDataType))
                            {
                                // If we are in pass 2 create the byte code to allocate a
                                // new array on the heap and associate it with this variable.
                                if (_currentPass == 1)
                                {
                                    // Pop the index value into arith register 2.
                                    Instruction instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Arithmetic2);

                                    // Cast?

                                    // Allocate enough space on the heap for the array.
                                    instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.ALLOCATE_HEAP), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Arithmetic2);
                                    new Operand(instruction, Register.Reserved4);

                                    // Push the memory index onto the stack.
                                    instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Reserved4);
                                }
                            }
                            else
                                Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + indexDataType.ToString() + "\"", false, 0);

                            // Read in closing bracket.
                            ExpectToken(TokenID.CharCloseBracket);

                            if (LookAheadToken().ID == TokenID.CharOpenBrace)
                            {
                                ExpectToken(TokenID.CharOpenBrace);

                                int index = 0;
                                while (true)
                                {
                                    // Parse the expression
                                    DataTypeValue valueType = ParseExpression();
                                    if (CanImplicitlyCast(new DataTypeValue(dataType.DataType, false, false), valueType) == true)
                                    {
                                        // Its valid so insert.
                                        if (_currentPass == 1)
                                        {
                                            Instruction instruction = null;

                                            // Pop the value into arith 2.
                                            instruction = CreateInstruction(OpCodeByType(valueType, OpCodeType.POP), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Arithmetic2);

                                            // Pop the memory index off the stack.
                                            instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.POP), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved4);

                                            // Do we need to cast first?
                                            if (dataType.DataType != valueType.DataType)
                                            {
                                                // Cast value.
                                                instruction = CreateInstruction(OpCodeByType(new DataTypeValue(dataType.DataType, false, false), OpCodeType.CAST), _currentScope, _currentToken);
                                                new Operand(instruction, Register.Arithmetic2);
                                            }

                                            // Move index into arith 3.
                                            instruction = CreateInstruction(OpCode.MOV_INT, _currentScope, _currentToken);
                                            new Operand(instruction, Register.Arithmetic3);
                                            new Operand(instruction, index);

                                            // Insert!
                                            instruction = CreateInstruction(OpCodeByType(new DataTypeValue(dataType.DataType, false, false), OpCodeType.MOV), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved4, Register.Arithmetic3);
                                            new Operand(instruction, Register.Arithmetic2);

                                            // Push the memory index back onto the stack.
                                            instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved4);
                                        }
                                    }
                                    else
                                        Error(ErrorCode.InvalidDataType, "Unable to implicitly cast from type \"" + DataTypeFromTypeToken(_currentToken.ID).ToString() + "\" to type \"" + dataType.DataType.ToString() + "\".", false, 1);

                                    // Read in comma or break out of loop if there isn't one.
                                    if (LookAheadToken().ID == TokenID.CharComma)
                                    {
                                        NextToken();
                                        index++;
                                    }
                                    else
                                        break;
                                }

                                ExpectToken(TokenID.CharCloseBrace);
                            }
                        }
                        else
                            Error(ErrorCode.InvalidFactor, "Primitive data types must currently be created as arrays.", false,0);
                    }
                    else
                        Error(ErrorCode.InvalidFactor, "New keyword can currently only be used to create new primitive data arrays.", false,0);

                    break;
                #endregion
                #region Boolean
                case TokenID.TypeBoolean:
                    factorDataType = new DataTypeValue(DataType.Bool, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, bool.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Byte
                case TokenID.TypeByte:
                    factorDataType = new DataTypeValue(DataType.Byte, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, byte.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Double
                case TokenID.TypeDouble:
                    factorDataType = new DataTypeValue(DataType.Double, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, double.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Float
                case TokenID.TypeFloat:
                    factorDataType = new DataTypeValue(DataType.Float, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, float.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Integer
                case TokenID.TypeInteger:
                    factorDataType = new DataTypeValue(DataType.Int, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        if (_currentToken.Ident.Length > 2 && _currentToken.Ident.Substring(0, 2) == "0x")
                            new Operand(instruction, Convert.ToInt32(_currentToken.Ident, 16));
                        else
                            new Operand(instruction, int.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Long
                case TokenID.TypeLong:
                    factorDataType = new DataTypeValue(DataType.Long, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, Convert.ToInt64(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Short
                case TokenID.TypeShort:
                    factorDataType = new DataTypeValue(DataType.Short, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, short.Parse(_currentToken.Ident));
                    }
                    break;
                #endregion
                #region Null
                case TokenID.TypeNull:
                    factorDataType = new DataTypeValue(DataType.Null, false, false);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                    }
                    break;
                #endregion
                #region String
                case TokenID.TypeString:
                    // Always add strings to the global scope, this stops them
                    // being duplicated in multiple scopes.
                    factorDataType = new DataTypeValue(DataType.String, false, false);

                    // Check for a pre-existing string with the same value.
                    foreach (Symbol subSymbol in _globalScope.Symbols)
                    {
                        if (subSymbol.Identifier == null || subSymbol.Type != SymbolType.String) continue;
                        if (subSymbol.Identifier == _currentToken.Ident)
                        {
                            stringSymbol = subSymbol as StringSymbol;
                            break;
                        }
                    }

                    if (stringSymbol == null) stringSymbol = new StringSymbol(_globalScope, _currentToken.Ident);
                    if (_currentPass == 1)
                    {
                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, stringSymbol);
                    }
                    break;
                #endregion
                #region Identifier
                case TokenID.TypeIdentifier:
                    VariableSymbol symbol = null;
                    string symbolIdent = _currentToken.Ident;
                    int tokenIndex = _tokenIndex;
                    Token currentToken = _currentToken;
                    Symbol resolvedScope = ResolveMemberScope();
                    symbol = resolvedScope == null ? null : resolvedScope.FindSymbol(_currentToken.Ident, SymbolType.Variable) as VariableSymbol;
                    if (symbol != null)
                    {
                        // Tag the variable as used so we don't end up throwing up a warning.
                        symbol.IsUsed = true;

                        // Set the factor data type.
                        factorDataType = new DataTypeValue(symbol.DataType.DataType, symbol.DataType.IsArray, symbol.DataType.IsReference);

                        if (symbol.IsConstant == true && symbol.ConstToken != null)
                        {
                            switch (symbol.DataType.DataType)
                            {
                                case DataType.Bool:
                                    factorDataType = new DataTypeValue(DataType.Bool, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, bool.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Byte:
                                    factorDataType = new DataTypeValue(DataType.Byte, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, byte.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Double:
                                    factorDataType = new DataTypeValue(DataType.Double, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, double.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Float:
                                    factorDataType = new DataTypeValue(DataType.Float, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, float.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Int:
                                    factorDataType = new DataTypeValue(DataType.Int, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        if (symbol.ConstToken.Ident.Length > 2 && symbol.ConstToken.Ident.Substring(0, 2) == "0x")
                                            new Operand(instruction, Convert.ToInt32(symbol.ConstToken.Ident, 16));
                                        else
                                            new Operand(instruction, int.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Long:
                                    factorDataType = new DataTypeValue(DataType.Long, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, Convert.ToInt64(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.Short:
                                    factorDataType = new DataTypeValue(DataType.Short, false, false);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, short.Parse(symbol.ConstToken.Ident));
                                    }
                                    break;
                                case DataType.String:
                                    factorDataType = new DataTypeValue(DataType.String, false, false);
                                    stringSymbol = _globalScope.FindSymbol(symbol.ConstToken.Ident, SymbolType.String) as StringSymbol;
                                    if (stringSymbol == null) stringSymbol = new StringSymbol(_globalScope, symbol.ConstToken.Ident);
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        new Operand(instruction, stringSymbol);
                                    }
                                    break;
                            }
                        }
                        else
                        {
                            // Check if we are parsing an array.
                            if (LookAheadToken().ID == TokenID.CharOpenBracket)
                            {
                                // As the array is indexed we can remove array from the factor data type.
                                factorDataType.IsArray = false;

                                // Read in open bracket.
                                NextToken();

                                // Make sure it really is an array.
                                if (symbol.IsArray == false) Error(ErrorCode.InvalidArrayIndex, "Non-array variables can not be indexed.", false, 0);

                                // Check that the next token is not a closing brace otherwise
                                // its an invalid index.
                                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                                    Error(ErrorCode.InvalidArrayIndex, "Array's must be indexed.", false, 0);

                                // Parse the index expression.
                                DataTypeValue indexDataType = ParseExpression();
                                ExpectToken(TokenID.CharCloseBracket);

                                // Check the index data type can be cast to an integer index.
                                if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), indexDataType) == true)
                                {
                                    // Emit the value retrieval's byte code.
                                    if (_currentPass == 1)
                                    {
                                        // Pop the index value into register 1.
                                        Instruction instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                                        new Operand(instruction, Register.Reserved1);

                                        // Cast index value to integer
                                        if (indexDataType.DataType != DataType.Int)
                                        {
                                            instruction = CreateInstruction(OpCode.CAST_INT, _currentScope, _currentToken);
                                            new Operand(instruction, Register.Reserved1);
                                        }

                                        // Move the array's memory slot into reserved2 register.
                                        instruction = CreateInstruction(OpCode.MOV_MEMORY_INDEX, _currentScope, _currentToken);
                                        new Operand(instruction, Register.Reserved2);
                                        if (symbol.VariableType == VariableType.Constant || symbol.VariableType == VariableType.Global)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);

                                        // Push the array's data onto the stack indexed
                                        // by the register we just poped the index into.
                                        instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                        Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);

                                    }

                                    #region ++ / -- Parsing
                                    // Check if there is a increment (++) or decrement (--) operator following this value..
                                    if (LookAheadToken().ID == TokenID.OpIncrement)
                                    {
                                        // Read in increment token.
                                        NextToken();

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

                                        // Make sure the symbol is not constant.
                                        if (symbol.IsConstant == true)
                                            Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                        // Increment the variable.
                                        if (_currentPass == 1)
                                        {
                                            // Take the assumtion that the values are still in the register from the previous code.
                                            Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.INC), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);
                                        }
                                    }
                                    else if (LookAheadToken().ID == TokenID.OpDecrement)
                                    {
                                        // Read in increment token.
                                        NextToken();

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

                                        // Make sure the symbol is not constant.
                                        if (symbol.IsConstant == true)
                                            Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                        // Decrement the variable.
                                        if (_currentPass == 1)
                                        {
                                            // Take the assumtion that the values are still in the register from the previous code.
                                            Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.DEC), _currentScope, _currentToken);
                                            Operand.IndirectMemoryIndexedOperand(instruction, Register.Reserved2, Register.Reserved1);
                                        }
                                    }
                                    #endregion

                                }
                                else
                                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + indexDataType.ToString() + "\"", false, 0);

                            }

                            // Its not an array so parse it as a reqular variable.
                            else
                            {
                                // Push the variable's value onto stack.
                                if (_currentPass == 1)
                                {
                                    Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.PUSH), _currentScope, _currentToken);
                                    if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                        Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                    else
                                        Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                }

                                #region ++ / -- Parsing
                                // Check if there is a increment (++) or decrement (--) operator following this value..
                                if (LookAheadToken().ID == TokenID.OpIncrement)
                                {
                                    // Read in increment token.
                                    NextToken();

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

                                    // Make sure the symbol is not constant.
                                    if (symbol.IsConstant == true)
                                        Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                    // Increment the variable.
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.INC), _currentScope, _currentToken);
                                        if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                    }
                                }
                                else if (LookAheadToken().ID == TokenID.OpDecrement)
                                {
                                    // Read in increment token.
                                    NextToken();

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

                                    // Make sure the symbol is not constant.
                                    if (symbol.IsConstant == true)
                                        Error(ErrorCode.IllegalAssignment, "Can't modify constant value.", false, 0);

                                    // Decrement the variable.
                                    if (_currentPass == 1)
                                    {
                                        Instruction instruction = CreateInstruction(OpCodeByType(symbol.DataType, OpCodeType.DEC), _currentScope, _currentToken);
                                        if (symbol.VariableType == VariableType.Global || symbol.VariableType == VariableType.Constant)
                                            Operand.DirectMemoryOperand(instruction, symbol.MemoryIndex);
                                        else
                                            Operand.DirectStackOperand(instruction, symbol.StackIndex);
                                    }
                                }
                                #endregion

                            }
                        }
                    }

                    // It look for opening parenthesis which would make it a function call.
                    else if (EndOfTokenStream() == false && LookAheadToken().ID == TokenID.CharOpenParenthesis)
                    {
                        #region Function calling

                        _tokenIndex = tokenIndex;
                        _currentToken = currentToken;

                        // Parse the function call and remember the return type.
                        DataTypeValue functionReturnType = ParseFunctionCall();

                        // Push the return value of the function onto the stack.
                        if (_currentPass == 1)
                        {
                            Instruction instruction = CreateInstruction(OpCodeByType(functionReturnType, OpCodeType.PUSH), _currentScope, _currentToken);
                            new Operand(instruction, Register.Return);
                        }

                        // Set the factors data type.
                        factorDataType = functionReturnType;

                        #endregion
                    }

                    // WTF! Is this?
                    else
                    {
                        Error(ErrorCode.UndeclaredVariable, "Encountered attempt to access an undeclared symbol \"" + symbolIdent + "\".", false, 1);
                    }
                    break;
                #endregion
                #region Sub expression
                case TokenID.CharOpenParenthesis:
                    factorDataType = ParseExpression();
                    ExpectToken(TokenID.CharCloseParenthesis);
                    break;
                #endregion
                default:
                    Error(ErrorCode.InvalidFactor, "Invalid factor.", false, 0);
                    break;
            }

            // Create instructions for unary operator if in second pass.
            if (unaryOpPending == true && _currentPass == 1)
            {
                // Check the data types are valid with this operator.
                if (OperatorDataTypeValid(factorDataType, unaryOpToken.ID) == false)
                    Error(ErrorCode.InvalidDataType, "Operator \"" + unaryOpToken.Ident + "\" can't be apply to data type \"" + factorDataType.ToString() + "\"");

                // Pop the value of this value out of the stack
                // and preform action on it.
                Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.POP), _currentScope, _currentToken);
                new Operand(instruction, Register.Arithmetic1);

                // Create instruction based on operation code.
                switch (unaryOpToken.ID)
                {
                    case TokenID.OpAdd: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.ABS), _currentScope, _currentToken); break;
                    case TokenID.OpSub: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.NEG), _currentScope, _currentToken); break;
                    case TokenID.OpLogicalNot: instruction = CreateInstruction(OpCode.LOGICAL_NOT, _currentScope, _currentToken); break;
                    case TokenID.OpBitwiseNot: instruction = CreateInstruction(OpCode.BIT_NOT_INT, _currentScope, _currentToken); break;
                    case TokenID.OpIncrement: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.INC), _currentScope, _currentToken); break;
                    case TokenID.OpDecrement: instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.DEC), _currentScope, _currentToken); break;
                }
                new Operand(instruction, Register.Arithmetic1);

                // Push the value back onto the stack (as long as its not the logical not, which does that itself).
                if (unaryOpToken.ID != TokenID.OpLogicalNot)
                {
                    instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                }
            }

            // If a cast is pending then convert the result to the given type.
            if (castPending == true && factorDataType != castType)
            {
                if (_currentPass == 1)
                {
                    // Pop the result out of the stack.
                    Instruction instruction = CreateInstruction(OpCodeByType(factorDataType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);

                    // Cast it to the given type.
                    instruction = CreateInstruction(OpCodeByType(castType, OpCodeType.CAST), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);

                    // Push the value back onto the stack.
                    instruction = CreateInstruction(OpCodeByType(castType, OpCodeType.PUSH), _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                }
                factorDataType = castType;
            }

            return factorDataType;
        }
        /// <summary>
        ///		Loads the byte code from a given binary reader.
        /// </summary>
        /// <param name="reader">BinaryReader to load byte code from.</param>
        private void LoadByteCode(BinaryReader reader)
        {
            // Check the header is correct
            if (reader.ReadByte() == 'C' && reader.ReadByte() == 'R' && reader.ReadByte() == 'X')
            {
                // Read in header variables.
                _compileFlags			= (CompileFlags)reader.ReadInt32();
                _internalVariableIndex	= reader.ReadInt32();
                _memorySize				= reader.ReadInt32();
                int globalScopeIndex	= reader.ReadInt32();
                int memberScopeIndex = reader.ReadInt32();
                _defaultEngineStateIndex = reader.ReadInt32();
                _defaultEditorStateIndex = reader.ReadInt32();

                // Create a new memory heap of the correct size
                if (_memorySize > _memoryHeap.Length) _memoryHeap = new RuntimeValue[_memorySize];
                for (int i = 0; i < _memorySize; i++)
                    _memoryHeap[i] = new RuntimeValue(RuntimeValueType.Invalid);

                // Set the 'special' globals to their appropriate values.
                _memoryHeap[0].ValueType = RuntimeValueType.Object;
                _memoryHeap[0].ObjectIndex = 0;

                int defineCount = reader.ReadInt32();
                int symbolCount			= reader.ReadInt32();
                int instructionCount	= reader.ReadInt32();
                int debugFileCount		= 0;

                if ((_compileFlags & CompileFlags.Debug) != 0)
                    debugFileCount = reader.ReadInt32();

                // Read in debug file list.
                string[] debugFiles = new string[debugFileCount];
                if ((_compileFlags & CompileFlags.Debug) != 0)
                {
                    for (int i = 0; i < debugFileCount; i++)
                        debugFiles[i] = reader.ReadString();
                }

                // Read in the define list.
                for (int i = 0; i < defineCount; i++)
                {
                    string ident = reader.ReadString();
                    TokenID valueID = (TokenID)reader.ReadInt32();
                    string value = reader.ReadString();
                    Define define = new Define(ident, value, valueID);
                    _defineList.Add(define);
                }

                // Read in symbol list.
                _symbolList = new Symbol[symbolCount];
                for (int i = 0; i < symbolCount; i++)
                {
                    // Read in general details about symbol.
                    SymbolType type	  = (SymbolType)reader.ReadByte();
                    string identifier = reader.ReadString();
                    int scopeIndex	  = reader.ReadInt32();
                    Symbol scope	  = null;
                    Symbol symbol	  = null;

                    if (scopeIndex != -1)
                        scope = (Symbol)_symbolList[scopeIndex];

                    // Read in specialized details about symbol.
                    switch (type)
                    {
                        case SymbolType.JumpTarget:
                            continue; // Ignore jump targets.

                        case SymbolType.Namespace:
                            NamespaceSymbol namespaceSymbol = new NamespaceSymbol(scope);
                            symbol = namespaceSymbol;
                            break;

                        case SymbolType.Enumeration:
                            EnumerationSymbol enumSymbol = new EnumerationSymbol(scope);
                            symbol = enumSymbol;
                            break;

                        case SymbolType.String:
                            StringSymbol stringSymbol = new StringSymbol(scope, identifier);
                            symbol = stringSymbol;
                            break;

                        case SymbolType.Function:
                            FunctionSymbol functionSymbol = new FunctionSymbol(identifier, scope);
                            symbol = functionSymbol;
                            functionSymbol.EntryPoint = reader.ReadInt32();
                            functionSymbol.LocalDataSize = reader.ReadInt16();
                            functionSymbol.IsEvent = reader.ReadBoolean();
                            functionSymbol.IsConsole = reader.ReadBoolean();
                            functionSymbol.IsExport = reader.ReadBoolean();
                            functionSymbol.IsImport = reader.ReadBoolean();
                            functionSymbol.IsThreadSpawner = reader.ReadBoolean();
                            functionSymbol.IsMember = reader.ReadBoolean();
                            functionSymbol.ParameterCount = reader.ReadByte();
                            bool isArray = reader.ReadBoolean();
                            bool isReference = reader.ReadBoolean();
                            functionSymbol.ReturnType = new DataTypeValue((DataType)reader.ReadByte(), isArray, isReference);
                            functionSymbol.AccessModifier = (SymbolAccessModifier)reader.ReadByte();
                            break;

                        case SymbolType.State:
                            StateSymbol stateSymbol = new StateSymbol(scope);
                            symbol = stateSymbol;
                            stateSymbol.IsEngineDefault = reader.ReadBoolean();
                            stateSymbol.IsEditorDefault = reader.ReadBoolean();
                            break;

                        case SymbolType.Variable:
                            VariableSymbol variableSymbol = new VariableSymbol(scope);
                            symbol = variableSymbol;
                            variableSymbol.DataType		= new DataTypeValue((DataType)reader.ReadByte(), false, false);
                            variableSymbol.DataType.IsReference = reader.ReadBoolean();
                            variableSymbol.IsArray		= reader.ReadBoolean();
                            variableSymbol.DataType.IsArray = variableSymbol.IsArray;
                            variableSymbol.IsConstant	= reader.ReadBoolean();
                            variableSymbol.MemoryIndex	= reader.ReadInt32();
                            variableSymbol.StackIndex	= reader.ReadInt32();
                            variableSymbol.VariableType = (VariableType)reader.ReadByte();
                            variableSymbol.IsProperty = reader.ReadBoolean();
                            variableSymbol.AccessModifier = (SymbolAccessModifier)reader.ReadByte();
                            variableSymbol.ConstToken = new Token(TokenID.TypeIdentifier, reader.ReadString(), 0, 0, "");
                            break;

                        case SymbolType.MetaData:
                            MetaDataSymbol metaDataSymbol = new MetaDataSymbol(scope, identifier, "");
                            symbol = metaDataSymbol;
                            metaDataSymbol.Value = reader.ReadString();
                            break;
                    }

                    symbol.Identifier = identifier;
                    symbol.Index = i;
                    _symbolList[i] = symbol;
                }

                // Retrieve global scope.
                _globalScope = _symbolList[globalScopeIndex] as FunctionSymbol;
                _memberScope = _symbolList[memberScopeIndex] as FunctionSymbol;
                //_currentState = _symbolList[_defaultEngineStateIndex] as StateSymbol; // Force this to be declared in the engine / editor.

                // Read in instruction list.
                _instructionList = new RuntimeInstruction[instructionCount];
                for (int i = 0; i < instructionCount; i++)
                {
                    // Read in instruction details and create a new instruction.
                    OpCode opCode = (OpCode)reader.ReadByte();
                    int operandCount = reader.ReadByte();
                    RuntimeInstruction instruction = new RuntimeInstruction(opCode);
                    _instructionList[i] = instruction;

                    if ((_compileFlags & CompileFlags.Debug) != 0)
                    {
                        int fileIndex = reader.ReadSByte();
                        if (fileIndex != -1) instruction.File = debugFiles[fileIndex];
                        instruction.Offset = reader.ReadInt16();
                        instruction.Line   = reader.ReadInt16();
                    }

                    // Read in each operand attached to this instruction
                    for (int k = 0; k < operandCount; k++)
                    {
                        // Read in general details about this operand and create
                        // a new runtime value instance.
                        RuntimeValueType opType = (RuntimeValueType)reader.ReadInt32();
                        RuntimeValue operand = new RuntimeValue(opType);
                        instruction.Operands[instruction.OperandCount] = operand;
                        instruction.OperandCount++;

                        // Read in specialized info about this operand.
                        switch(opType)
                        {
                            case RuntimeValueType.BooleanLiteral:
                                operand.BooleanLiteral = reader.ReadBoolean();
                                break;
                            case RuntimeValueType.ByteLiteral:
                                operand.ByteLiteral = reader.ReadByte();
                                break;
                            case RuntimeValueType.DirectMemory:
                                operand.MemoryIndex = reader.ReadInt32();
                                break;
                            case RuntimeValueType.DirectMemoryIndexed:
                                operand.MemoryIndex = reader.ReadInt32();
                                operand.OffsetRegister = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.DirectStack:
                                operand.StackIndex = reader.ReadInt32();
                                break;
                            case RuntimeValueType.DirectStackIndexed:
                                operand.StackIndex = reader.ReadInt32();
                                operand.OffsetRegister = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.DoubleLiteral:
                                operand.DoubleLiteral = reader.ReadDouble();
                                break;
                            case RuntimeValueType.FloatLiteral:
                                operand.FloatLiteral = reader.ReadSingle();
                                break;
                            case RuntimeValueType.IndirectMemory:
                                operand.Register = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.IndirectMemoryIndexed:
                                operand.Register = (Register)reader.ReadByte();
                                operand.OffsetRegister = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.IndirectStack:
                                operand.Register = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.IndirectStackIndexed:
                                operand.Register = (Register)reader.ReadByte();
                                operand.OffsetRegister = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.InstrIndex:
                                operand.InstrIndex = reader.ReadInt32();
                                break;
                            case RuntimeValueType.IntegerLiteral:
                                operand.IntegerLiteral = reader.ReadInt32();
                                break;
                            case RuntimeValueType.LongLiteral:
                                operand.LongLiteral = reader.ReadInt64();
                                break;
                            case RuntimeValueType.Register:
                                operand.Register = (Register)reader.ReadByte();
                                break;
                            case RuntimeValueType.ShortLiteral:
                                operand.ShortLiteral = reader.ReadInt16();
                                break;
                            case RuntimeValueType.SymbolIndex:
                                operand.SymbolIndex = reader.ReadInt32();
                                operand.Symbol = (Symbol)_symbolList[operand.SymbolIndex];
                                if (operand.Symbol is StringSymbol)
                                {
                                    operand.StringLiteral = operand.Symbol.Identifier;
                                    operand.ValueType = RuntimeValueType.StringLiteral;
                                }
                                break;
                        }
                    }
                }

                // Fill the member-function hash table.
                foreach (Symbol symbol in GlobalScope.Symbols)
                    if (symbol != null && symbol.Type == SymbolType.Function && ((FunctionSymbol)symbol).AccessModifier == SymbolAccessModifier.Public)
                        _memberFunctionHashTable.Add(symbol.ToString().ToLower(), symbol);
            }
            else
                throw new Exception("Unable to load script byte code, header is invalid.");
        }