Exemplo n.º 1
0
        /// <summary>
        ///		Parses a enumeration declaration. An enumeration is a way of creating a list
        ///		of sequential integer constants without having to create and assign them.
        ///		Syntax:
        ///			"enum" "{" { Identifier [ "=" Expression ] [ "," ] } "}"
        /// </summary>
        private void ParseEnum()
        {
            // Make sure we are in a valid scope.
            if (_currentScope != _globalScope &&
                _currentScope.Type != SymbolType.Namespace)
                Error(ErrorCode.InvalidScope, "Enumerations are only valid in global scope.", false, 0);

            // Read in enumeration identifier.
            ExpectToken(TokenID.TypeIdentifier);

            // Create enumeration symbol.
            EnumerationSymbol mainEnumSymbol = null;
            if (_currentPass == 0)
            {
                if (_currentScope.FindSymbol(_currentToken.Ident) != null) Error(ErrorCode.DuplicateSymbol, "Encountered multiple declarations of the "+_currentToken.Ident+" symbol");
                mainEnumSymbol = new EnumerationSymbol(_currentScope);
                mainEnumSymbol.Identifier = _currentToken.Ident;
            }
            else
                mainEnumSymbol = _currentScope.FindSymbol(_currentToken.Ident) as EnumerationSymbol;

            // Read in opening brace.
            ExpectToken(TokenID.CharOpenBrace);

            // Read in each constant and its expression.
            int indexValue = 1;
            while (true)
            {

                // Read in constant identifier.
                ExpectToken(TokenID.TypeIdentifier);
                string enumIdentifier = _currentToken.Ident;

                // Create constant variable to store value into.
                VariableSymbol enumSymbol = null;
                if (_currentPass == 0)
                {
                    if (mainEnumSymbol.FindSymbol(_currentToken.Ident) != null) Error(ErrorCode.DuplicateSymbol, "Encountered multiple declarations of the " + _currentToken.Ident + " symbol");
                    enumSymbol = new VariableSymbol(mainEnumSymbol);
                    enumSymbol.Identifier = enumIdentifier;
                    enumSymbol.DataType = new DataTypeValue(DataType.Int, false, false);
                    enumSymbol.IsConstant = true;
                }
                else
                    enumSymbol = mainEnumSymbol.FindSymbol(enumIdentifier) as VariableSymbol;

                _lastMetaDataSymbol = enumSymbol;

                // Read in expression if its there.
                Instruction instruction;
                if (LookAheadToken().ID == TokenID.OpAssign)
                {
                    NextToken();

                    Token LAT = LookAheadToken();
                    Token LALAT = LookAheadToken(2);

                    if ((LAT.ID == TokenID.TypeBoolean || LAT.ID == TokenID.TypeByte ||
                        LAT.ID == TokenID.TypeDouble || LAT.ID == TokenID.TypeFloat ||
                        LAT.ID == TokenID.TypeInteger || LAT.ID == TokenID.TypeLong ||
                        LAT.ID == TokenID.TypeShort ||
                        LAT.ID == TokenID.TypeString) && (LALAT.ID == TokenID.CharComma || LALAT.ID == TokenID.CharCloseBrace))
                    {
                        NextToken();
                        if (CanImplicitlyCast(enumSymbol.DataType, new DataTypeValue(DataTypeFromTypeToken(_currentToken.ID), false, false)) == true)
                            enumSymbol.ConstToken = _currentToken;
                        else
                            Error(ErrorCode.InvalidDataType, "Unable to implicitly cast from type \"" + DataTypeFromTypeToken(_currentToken.ID).ToString() + "\" to type \"" + enumSymbol.DataType.ToString() + "\".", false, 1);
                    }
                    else
                    {
                        Symbol oldScope = _currentScope;
                        _currentScope = _globalScope;

                        // Parse the assignment expression.
                        DataTypeValue assignmentType = ParseExpression();

                        if (CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), assignmentType) == true)
                        {
                            // We need to allocate some memory space.
                            if (_currentPass == 0)
                            {
                                enumSymbol.MemoryIndex = _memorySize;
                                _memorySize++;
                            }

                            if (_currentPass == 1)
                            {
                                // Pop the expression value into arith register 1.
                                instruction = CreateInstruction(OpCodeByType(enumSymbol.DataType, OpCodeType.POP), _currentScope, _currentToken);
                                new Operand(instruction, Register.Arithmetic1);

                                // Move the value stored in arith register 1 into enums memory space.
                                instruction = CreateInstruction(OpCodeByType(enumSymbol.DataType, OpCodeType.MOV), _currentScope, _currentToken);
                                Operand.DirectMemoryOperand(instruction, enumSymbol.MemoryIndex);
                                new Operand(instruction, Register.Arithmetic1);
                            }
                        }
                        else
                            Error(ErrorCode.InvalidDataType, "Enumeration const of type \"" + enumSymbol.DataType.ToString() + "\" can't store type \"" + assignmentType.ToString() + "\".", false, 0);

                        _currentScope = oldScope;
                    }

                }
                else
                    enumSymbol.ConstToken = new Token(TokenID.TypeInteger, indexValue.ToString(), 0, 0, "");

                // Update index number in a *2 fashion so it can
                // be used as a bitmask.
                indexValue *= 2;

                // Read in comma if it exists.
                if (LookAheadToken().ID == TokenID.CharComma)
                    NextToken();
                else
                    break;

            }

            // Read in closing brace.
            ExpectToken(TokenID.CharCloseBrace);
        }
        /// <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.");
        }