コード例 #1
0
        /// <summary>
        ///		Parses a variable declaration. A variable is a place in memory that is used	
        ///		to store a value used by other statements.
        ///		Syntax:
        ///			DataType { Identifier [ "[" Expression "]" ] [ "=" Expression ] [ "," ] } ";"
        /// </summary>
        private void ParseVariable()
        {
            // Make sure we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function &&
                _currentScope.Type != SymbolType.State &&
                _currentScope.Type != SymbolType.Namespace) Error(ErrorCode.InvalidScope, "Variables can't be declared in this scope.", false, 0);

            // Check if we are in a states scope.
            bool inState = (_currentScope.Type == SymbolType.State);
            bool inNamespace = (_currentScope.Type == SymbolType.Namespace);
            bool inEnumeration = (_currentScope.Type == SymbolType.Enumeration);

            // Read in each flag.
            bool isStatic = false;
            bool isConst = false;
            bool isProperty = false;
            SymbolAccessModifier modifier = SymbolAccessModifier.Private;
            bool gotModifier = false;
            while (EndOfTokenStream() != true)
            {
                switch (_currentToken.ID)
                {
                    case TokenID.KeywordStatic:
                        if (isStatic == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isStatic = true;
                        break;
                    case TokenID.KeywordConst:
                        if (isConst == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isConst = true;
                        break;
                    case TokenID.KeywordProperty:
                        if (isProperty == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isProperty = true;
                        break;
                    case TokenID.KeywordPublic:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Public;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordPrivate:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Private;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordProtected:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Protected;
                        gotModifier = true;
                        break;
                    default:
                        goto outOfLoop;
                }
                NextToken();
            }
            outOfLoop:

            // Get data type by the current tokens id.
            DataType dataType = DataTypeFromKeywordToken(_currentToken.ID);
            if (dataType == DataType.Void || dataType == DataType.Invalid)
                Error(ErrorCode.InvalidDataType, "Variable can't be declared as \"" + _currentToken.Ident + "\".", false, 0);

            // Check if its an array.
            bool isArray = false;
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                ExpectToken(TokenID.CharOpenBracket);
                isArray = true;
                ExpectToken(TokenID.CharCloseBracket);
            }

            // Parse all variables seperated by a comma.
            while (true)
            {
                // Read in variable identifier and store it for later use.
                ExpectToken(TokenID.TypeIdentifier);
                string variableIdent = _currentToken.Ident;

                // Create a new variable symbol.
                VariableSymbol variableSymbol = null;
                if (_currentPass == 0)
                {
                    if (_currentScope.FindSymbol(variableIdent, SymbolType.Variable) != null)
                        Error(ErrorCode.DuplicateSymbol, "Variable \"" + variableIdent + "\" declared multiple times.", false, 0);
                    variableSymbol = new VariableSymbol(_currentScope);
                    variableSymbol.Identifier = variableIdent;
                    variableSymbol.IsArray = isArray;
                    variableSymbol.IsConstant = isConst;
                    variableSymbol.IsProperty = isProperty;
                    variableSymbol.AccessModifier = modifier;
                    variableSymbol.DataType = new DataTypeValue(dataType, isArray, false);
                    variableSymbol.VariableType = isConst == true ? VariableType.Constant : (_currentScope == _globalScope || inState == true || isStatic == true || inEnumeration == true || inNamespace == true ? VariableType.Global : VariableType.Local);
                    if (variableSymbol.VariableType == VariableType.Constant || variableSymbol.VariableType == VariableType.Global)
                    {
                        variableSymbol.MemoryIndex = _memorySize;
                        _memorySize++;
                    }
                    else
                    {
                        if (_currentScope.Type == SymbolType.Function)
                        {
                            variableSymbol.StackIndex = -(((FunctionSymbol)_currentScope).LocalDataSize + 2);
                            ((FunctionSymbol)_currentScope).LocalDataSize++;
                        }
                    }
                }
                else if (_currentPass == 1)
                {
                    variableSymbol = _currentScope.FindSymbol(variableIdent, SymbolType.Variable) as VariableSymbol;
                    if (variableSymbol == null) variableSymbol = _globalScope.FindSymbol(variableIdent, SymbolType.Variable) as VariableSymbol;
                }

                _lastMetaDataSymbol = variableSymbol;

                // Check if there is an assignment.
                if (LookAheadToken().ID == TokenID.OpAssign)
                {
                    NextToken();

                    // If we are a constant then see if we are being assigned a literal value.
                    Token LAT = LookAheadToken();
                    if (isConst == true &&
                       (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) && LookAheadToken(2).ID == TokenID.CharSemiColon)
                    {
                        NextToken();
                        if (CanImplicitlyCast(variableSymbol.DataType, new DataTypeValue(DataTypeFromTypeToken(_currentToken.ID), false, false)) == true)
                            variableSymbol.ConstToken = _currentToken;
                        else
                            Error(ErrorCode.InvalidDataType, "Unable to implicitly cast from type \"" + DataTypeFromTypeToken(_currentToken.ID).ToString() + "\" to type \"" + variableSymbol.DataType.ToString() + "\".", false, 1);
                    }
                    else
                    {
                        // This will temporarily change the state if the variable is static.
                        Symbol previousScope = null;
                        if (isStatic == true || inState == true || inNamespace == true || inEnumeration == true)
                        {
                            previousScope = _overrideInstructionScope;
                            _overrideInstructionScope = _globalScope;
                        }

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

                        if (CanImplicitlyCast(variableSymbol.DataType, expressionType) == true)
                        {
                            if (_currentPass == 1)
                            {
                                // Pop the value out of the stack and assign it to this variable.
                                Instruction instruction = CreateInstruction(OpCodeByType(expressionType, OpCodeType.POP), _currentScope, _currentToken);
                                new Operand(instruction, Register.Arithmetic1);

                                // Cast arith register 1 into the variables type.
                                if (variableSymbol.DataType != expressionType)
                                {
                                    instruction = CreateInstruction(OpCodeByType(variableSymbol.DataType, OpCodeType.CAST), _currentScope, _currentToken);
                                    new Operand(instruction, Register.Arithmetic1);
                                }

                                // Move the resulting value (stored in arithmatic register 3)
                                // into the variable.
                                instruction = CreateInstruction(OpCodeByType(variableSymbol.DataType, OpCodeType.MOV), _currentScope, _currentToken);

                                Operand op1 = null;
                                if (variableSymbol.VariableType == VariableType.Global || variableSymbol.VariableType == VariableType.Constant)
                                    op1 = Operand.DirectMemoryOperand(instruction, variableSymbol.MemoryIndex);
                                else
                                    op1 = Operand.DirectStackOperand(instruction, variableSymbol.StackIndex);
                                new Operand(instruction, Register.Arithmetic1);
                            }
                        }
                        else
                        {
                            Error(ErrorCode.InvalidDataType, "Unable to implicitly cast from type \"" + expressionType.ToString() + "\" to type \"" + variableSymbol.DataType.ToString() + "\".", false, 1);
                        }

                        // If we have changed the scope then change back.
                        if (isStatic == true || inState == true || inNamespace == true || inEnumeration == true)
                        {
                            _overrideInstructionScope = previousScope;
                        }
                    }
                }

                else
                {
                    if (isConst == true) Error(ErrorCode.IllegalAssignment, "Constant must be assigned a value.", false, 0);
                }

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

            // Read in semi-colon at end of declarations.
            ExpectToken(TokenID.CharSemiColon);
        }
コード例 #2
0
        /// <summary>
        /// 
        /// </summary>
        private void ParseMemberFunctionCall(string identifier, DataTypeValue returnDataType)
        {
            // Read the opening parenthesis.
            ExpectToken(TokenID.CharOpenParenthesis);

            // Pop the object out.
            if (_currentPass == 1)
            {
                Instruction instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                new Operand(instruction, Register.Member);
            }

            // Read in each parameter's expression.
            ArrayList parameterTypeList = new ArrayList();
            string parameterMask = "";
            while (true)
            {
                // Check for parenthesis close
                if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
                {
                    // Read in the parameters expression.
                    DataTypeValue expressionType = ParseExpression();
                    parameterMask += (parameterMask != "" ? "," : "") + expressionType.ToString();
                    parameterTypeList.Add(expressionType);

                    // Read in comma if we are not at the
                    // end of the parameter list.
                    if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
                        ExpectToken(TokenID.CharComma);
                }
                else
                    break;
            }

            // *looks arounds shiftily* ... Ok its hack like but it works.
            parameterTypeList.Reverse();

            // Read the closing parenthesis.
            ExpectToken(TokenID.CharCloseParenthesis);

            // Get the function symbol if in pass 2.
            FunctionSymbol functionSymbol = null;
            if (_currentPass == 1)
            {
                functionSymbol = _memberScope.FindFunctionByMask(identifier, parameterTypeList) as FunctionSymbol;
                if (functionSymbol == null)
                {
                    // Create the function symbol.
                    functionSymbol = new FunctionSymbol(identifier, _memberScope);
                    functionSymbol.Identifier = identifier;
                    functionSymbol.ReturnType = returnDataType;
                    functionSymbol.IsMember = true;
                    functionSymbol.ParameterCount = parameterTypeList.Count;

                    // Create a symbol for each parameters.
                    foreach (DataTypeValue value in parameterTypeList)
                    {
                        VariableSymbol variableSymbol = new VariableSymbol(functionSymbol);
                        variableSymbol.DataType = value;
                        variableSymbol.Identifier = "";
                        variableSymbol.VariableType = VariableType.Parameter;
                        variableSymbol.IsArray = value.IsArray;
                    }
                }

                Instruction instruction = CreateInstruction(OpCode.CALL_METHOD, _currentScope, _currentToken);
                new Operand(instruction, Register.Member);
                new Operand(instruction, functionSymbol);
            }
        }
コード例 #3
0
        /// <summary>
        ///		Parses a lower level expression. The lower level is responsible for parsing 
        ///		any factors and the -> operator.
        /// </summary>
        /// <returns>The data type this expression evaluates to.</returns>
        private DataTypeValue ParseSubTermExpression()
        {
            // Parse the left hand factor expression.
            DataTypeValue factorDataType1 = ParseFactorExpression();

            // Parse any subsequent factor expressions.
            while (true)
            {
                // Check that the next token is an member resolver operator.
                Token operatorToken = LookAheadToken();
                if (operatorToken.ID != TokenID.OpMemberResolver)
                    break;
                NextToken();

                // If its not an object how can we access it?
                if (factorDataType1.DataType != DataType.Object)
                    Error(ErrorCode.IllegalResolve, "Member accessing can only be preformed on objects.", false, 1);

                // ARRAY ACCESSING!

                // Parse the cast.
                ExpectToken(TokenID.CharOpenParenthesis);
                if (NextToken().IsDataType == false)
                    Error(ErrorCode.InvalidCast, "Attempt to cast member to unknown type.", false, 0);

                DataTypeValue castDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);

                // Is it an array?
                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                {
                    NextToken();
                    ExpectToken(TokenID.CharCloseBracket);
                    castDataType.IsArray = true;
                }
                ExpectToken(TokenID.CharCloseParenthesis);

                // Set the factor data type as the casts value.
                factorDataType1 = castDataType;

                // Read in the indentifier of the member.
                string identifier = ExpectToken(TokenID.TypeIdentifier).Ident;

                // Parse The member that is being called.
                if (LookAheadToken().ID != TokenID.CharOpenParenthesis)
                {
                    // Are we going to index it?
                    bool parsingArray = false;
                    DataTypeValue arrayIndexValue = new DataTypeValue(DataType.Invalid, false, false);
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        parsingArray = true;
                        arrayIndexValue = ParseExpression();
                        ExpectToken(TokenID.CharCloseBracket);
                    }

                    // Create the symbol.
                    VariableSymbol variableSymbol = null;
                    if (_currentPass == 0)
                    {
                        variableSymbol = _memberScope.FindVariableSymbol(identifier, castDataType) as VariableSymbol;
                        if (variableSymbol == null)
                        {
                            variableSymbol = new VariableSymbol(_memberScope);
                            variableSymbol.Identifier = identifier;
                            variableSymbol.DataType = castDataType;
                            variableSymbol.VariableType = VariableType.Member;
                        }
                    }
                    else if (_currentPass == 1)
                        variableSymbol = _memberScope.FindVariableSymbol(identifier, castDataType) as VariableSymbol;

                    if (_currentPass == 1)
                    {
                        Instruction instruction = null;

                        // Pop the index into arith 1.
                        if (parsingArray == true)
                        {
                            instruction = CreateInstruction(OpCodeByType(arrayIndexValue, OpCodeType.POP), _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic1);
                        }

                        // Pop the object into the member register.
                        instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic2);

                        // Call the GET_MEMBER opCode.
                        if (parsingArray)
                        {
                            instruction = CreateInstruction(OpCode.GET_MEMBER, _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic2);
                            new Operand(instruction, variableSymbol);
                        }
                        else
                        {
                            instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                            new Operand(instruction, Register.Arithmetic2);
                            new Operand(instruction, variableSymbol);
                            new Operand(instruction, Register.Arithmetic1);
                        }

                        // Push the returned value.
                        instruction = CreateInstruction(OpCodeByType(castDataType, OpCodeType.PUSH), _currentScope, _currentToken);
                        new Operand(instruction, Register.Return);
                    }
                }
                else
                {
                    #region Function calling

                    // Parse the function call and remember the return type.
                    ParseMemberFunctionCall(identifier, castDataType);

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

                    #endregion
                }
            }

            return factorDataType1;
        }
コード例 #4
0
        /// <summary>
        ///		Parses a function declaration. A function is a way of isolating code that you want
        ///		to be able to call multiple times without rewriting it each time.
        ///		Syntax:
        ///			ReturnType Identifier "(" { Identifier ["=" Expression] [ "," ] } ")" Statement
        /// </summary>
        private void ParseFunction()
        {
            // Make sure we are in a state's scope.
            if (_currentToken.ID == TokenID.KeywordEvent &&
                _currentScope.Type != SymbolType.State)
                Error(ErrorCode.InvalidScope, "Events can only be declared within a state block.", false, 0);

            // Make sure we are in the global scopes as functions can't
            // be declared anywhere else.
            if (_currentScope.Type != SymbolType.State &&
                _currentScope.Type != SymbolType.Function &&
                _currentScope.Type != SymbolType.Namespace)
                Error(ErrorCode.InvalidScope, "Functions can only be declared in a function's, state's or event's scope.", false, 0);

            // Read in each flag.
            bool isThread = false;
            bool isEvent = false;
            bool isConsole = false;
            bool isExport = false;
            bool isImport = false;
            SymbolAccessModifier modifier = SymbolAccessModifier.Private;
            bool gotModifier = false;
            while (_currentToken.IsDataType == false && EndOfTokenStream() != true)
            {
                switch (_currentToken.ID)
                {
                    case TokenID.KeywordThread:
                        if (isThread == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isThread = true;
                        break;
                    case TokenID.KeywordEvent:
                        if (isEvent == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isEvent = true;
                        break;
                    case TokenID.KeywordConsole:
                        if (isConsole == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isConsole = true;
                        break;
                    case TokenID.KeywordImport:
                        if (isImport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isImport = true;
                        break;
                    case TokenID.KeywordExport:
                        if (isExport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0);
                        isExport = true;
                        break;
                    case TokenID.KeywordPublic:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Public;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordPrivate:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Private;
                        gotModifier = true;
                        break;
                    case TokenID.KeywordProtected:
                        if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0);
                        modifier = SymbolAccessModifier.Protected;
                        gotModifier = true;
                        break;
                }
                NextToken();
            }
            if (isEvent == true && (isThread == true || isExport == true || isImport == true || isConsole == true))
                Error(ErrorCode.InvalidFlag, "Events can't be declared as native, threaded, exported, imported or console.");

            // Store the return type for later.
            DataTypeValue returnDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);
            if (returnDataType.DataType == DataType.Invalid)
                Error(ErrorCode.InvalidDataType, "Functions can't be declared as \"" + _currentToken.Ident + "\".", false, 0);

            // Check for an array reference
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                NextToken();
                returnDataType.IsArray = true;
                ExpectToken(TokenID.CharCloseBracket);
            }

            // Read in the functions identifier and store it
            // for layer use.
            ExpectToken(TokenID.TypeIdentifier);
            string functionIdentifier = _currentToken.Ident;

            // Read in the opening parenthesis used to define the paremeter list.
            ExpectToken(TokenID.CharOpenParenthesis);

            // Read in each paremeter.
            ArrayList functionParameterMask = new ArrayList();
            int parameterCount = 0;
            ArrayList paramList = new ArrayList();
            if (LookAheadToken().ID != TokenID.CharCloseParenthesis)
            {

                // Read in each parameter
                while (true)
                {

                    // Check if there is a constant keyword before this variable.
                    bool paramIsConst = false;
                    if (LookAheadToken().ID == TokenID.KeywordConst)
                    {
                        NextToken();
                        paramIsConst = true;
                    }

                    // Read in the data type keyword and store it.
                    NextToken();
                    DataTypeValue paramDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false);
                    if (paramDataType.DataType == DataType.Invalid) Error(ErrorCode.InvalidDataType, "Expecting data type keyword.", false, 0);

                    // Read in array declaration.
                    bool paramIsArray = false;
                    if (LookAheadToken().ID == TokenID.CharOpenBracket)
                    {
                        NextToken();
                        paramIsArray = true;
                        paramDataType.IsArray = true;
                        ExpectToken(TokenID.CharCloseBracket);
                    }

                    // Increase the parameter mask
                    functionParameterMask.Add(paramDataType);
                    parameterCount++;

                    // Read in the parameters identifier.
                    ExpectToken(TokenID.TypeIdentifier);
                    string paramIdentifier = _currentToken.Ident;

                    // Process parameters depending on current pass.
                    if (_currentPass == 0)
                    {
                        VariableSymbol variableSymbol = new VariableSymbol(null);
                        variableSymbol.DataType = paramDataType;
                        variableSymbol.Identifier = paramIdentifier;
                        variableSymbol.VariableType = VariableType.Parameter;
                        variableSymbol.IsArray = paramIsArray;
                        variableSymbol.IsConstant = paramIsConst;
                        paramList.Add(variableSymbol);
                    }

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

                }

            }

            // *looks arounds shiftily* ... Ok its hack like but it works.
            functionParameterMask.Reverse();

            // Create a new function symbol.
            FunctionSymbol functionSymbol;
            if (_currentPass == 0)
            {
                if (_currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) != null)
                    Error(ErrorCode.DuplicateSymbol, "Function \"" + functionIdentifier + "\" redefinition.", false, 0);

                functionSymbol = new FunctionSymbol(functionIdentifier, _currentScope);
                functionSymbol.ReturnType = returnDataType;
                functionSymbol.ParameterCount = parameterCount;
                functionSymbol.IsThreadSpawner = isThread;
                functionSymbol.IsEvent = isEvent;
                functionSymbol.IsConsole = isConsole;
                functionSymbol.IsImport = isImport;
                functionSymbol.IsExport = isExport;
                functionSymbol.AccessModifier = modifier;

                if (isConsole == true && functionSymbol.ReturnType.DataType != DataType.Void)
                    Error(ErrorCode.InvalidDataType, "Console variables cannot return a value.");

                paramList.Reverse();
                int parameterIndex = 0;
                foreach (VariableSymbol variableSymbol in paramList)
                {
                    if (functionSymbol.FindSymbol(variableSymbol.Identifier, SymbolType.Variable) != null)
                        Error(ErrorCode.DuplicateSymbol, "Variable redefinition \"" + variableSymbol.Identifier + "\"");

                    // If we're a console function we can only accept bool, int, string or float
                    if (isConsole == true &&
                        (variableSymbol.DataType.IsArray == true ||
                        variableSymbol.DataType.DataType == DataType.Byte ||
                        variableSymbol.DataType.DataType == DataType.Double ||
                        variableSymbol.DataType.DataType == DataType.Object ||
                        variableSymbol.DataType.DataType == DataType.Short))
                        Error(ErrorCode.InvalidDataType, "Console variables can only accept bool, integer, string or float parameters.");

                    functionSymbol.AddSymbol(variableSymbol);
                    variableSymbol.Scope = functionSymbol;
                    parameterIndex++;
                }
            }
            else
            {
                functionSymbol = _currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol;
                if (functionSymbol == null) functionSymbol = _globalScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol;
                if (functionSymbol == null) Error(ErrorCode.InvalidFunction, "Attempt to call undeclared function \"" + functionIdentifier + "(" + functionParameterMask + ")\".");

                for (int i = 0; i < parameterCount; i++)
                {
                    VariableSymbol variableSymbol = (VariableSymbol)functionSymbol.Symbols[i];
                    variableSymbol.StackIndex = -(functionSymbol.LocalDataSize + 2 + (i + 1));
                }
            }
            _lastMetaDataSymbol = functionSymbol;

            // Read in the closing parenthesis used to define the end of the paremeter list.
            ExpectToken(TokenID.CharCloseParenthesis);

            // Read in this function's statement block.
            if (functionSymbol.IsImport == false)
            {
                Symbol scope = _currentScope;
                Instruction instruction = null;
                _currentScope = functionSymbol;
                ParseStatement();
                _currentScope = scope;

                // Append a mandatory return instruction if we are in pass 2.
                if (_currentPass == 1)
                {
                    // Cast the return registered into the return type.
                    if (functionSymbol.ReturnType.DataType != DataType.Void)
                    {
                        instruction = CreateInstruction(OpCodeByType(functionSymbol.ReturnType, OpCodeType.CAST), functionSymbol, _currentToken);
                        new Operand(instruction, Register.Return);
                    }

                    // Return from function.
                    instruction = CreateInstruction(OpCode.RETURN, functionSymbol, _currentToken);
                }
            }
            else
                ExpectToken(TokenID.CharSemiColon);
        }
コード例 #5
0
        /// <summary>
        ///     Parses a member assignment.
        /// </summary>
        private void ParseMemberAssignment(string identifier, DataTypeValue returnDataType)
        {
            // Check we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                Error(ErrorCode.InvalidScope, "Assignments are only valid inside a function's or event's scope.", false, 0);

            #region Variable retrieving

            // If we are in pass 2 try and retrieve the variable.
            VariableSymbol variableSymbol = null;
            DataTypeValue dataType = returnDataType;
            if (_currentPass == 0)
            {
                variableSymbol = _memberScope.FindVariableSymbol(identifier, returnDataType) as VariableSymbol;
                if (variableSymbol == null)
                {
                    variableSymbol = new VariableSymbol(_memberScope);
                    variableSymbol.Identifier = identifier;
                    variableSymbol.DataType = returnDataType;
                    variableSymbol.VariableType = VariableType.Member;
                    if (variableSymbol.VariableType == VariableType.Constant)
                        Error(ErrorCode.IllegalAssignment, "Encountered attempt to assign to a constant variable \"" + identifier + "\".");
                }
            }
            else if (_currentPass == 1)
                variableSymbol = _memberScope.FindVariableSymbol(identifier, returnDataType) as VariableSymbol;

            #endregion
            #region Array index parsing

            // Check if we are assigning to an array.
            bool isArray = false;
            DataTypeValue indexDataType = null;
            if (LookAheadToken().ID == TokenID.CharOpenBracket)
            {
                // Make sure variable is an array if we are in pass 2.
                if (_currentPass == 1 && variableSymbol.DataType.IsArray == false)
                    Error(ErrorCode.InvalidArrayIndex, "Non-array variables can not be indexed.");

                // As its an array and its index we can remove the array declaration from
                // the data type.
                dataType.IsArray = false;

                // Read in opening bracket and check expression is valid
                NextToken();
                if (LookAheadToken().ID == TokenID.CharCloseBracket)
                    Error(ErrorCode.InvalidArrayIndex, "Array's must be indexed.", false, 0);

                // Read in expression and closing bracket.
                indexDataType = ParseExpression();
                ExpectToken(TokenID.CharCloseBracket);

                isArray = true;
            }
            #endregion
            #region Operator parsing

            // Check if the operator is a valid assignment operator.
            NextToken();
            if (_currentToken.ID != TokenID.OpAssign && _currentToken.ID != TokenID.OpAssignAdd &&
                _currentToken.ID != TokenID.OpAssignBitwiseAnd && _currentToken.ID != TokenID.OpAssignBitwiseNot &&
                _currentToken.ID != TokenID.OpAssignBitwiseOr && _currentToken.ID != TokenID.OpAssignBitwiseSHL &&
                _currentToken.ID != TokenID.OpAssignBitwiseSHR && _currentToken.ID != TokenID.OpAssignBitwiseXOr &&
                _currentToken.ID != TokenID.OpAssignDivide && _currentToken.ID != TokenID.OpAssignModulus &&
                _currentToken.ID != TokenID.OpAssignMultiply && _currentToken.ID != TokenID.OpAssignSub &&
                _currentToken.ID != TokenID.OpIncrement && _currentToken.ID != TokenID.OpDecrement)
                Error(ErrorCode.IllegalAssignmentOperator, "Encountered attempt to use an illegal assignment operator.");

            Token operatorToken = _currentToken;
            Instruction instruction = null;
            DataTypeValue expressionType = new DataTypeValue(DataType.Invalid, false, false);
            #endregion

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

            #region Value byte code emission and parsing

            // Read in expression if it is not a increment (++) or decrement (--) operator.
            if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
            {
                // Parse the expression.
                expressionType = ParseExpression();

                // Pop the expression into reserved register 3.
                if (_currentPass == 1)
                {
                    // Pop the value of into reserved register 3.
                    instruction = CreateInstruction(OpCodeByType(expressionType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Reserved3);

                    // Cast the value to a valid type.
                    if (dataType != expressionType)
                    {
                        instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.CAST), _currentScope, _currentToken);
                        new Operand(instruction, Register.Reserved3);
                    }
                }

                // If we are an array check that we have been indexed, unless we
                // are assigning null to it.
                if (_currentPass == 1 && variableSymbol.DataType.IsArray == true && isArray == false && expressionType.DataType != DataType.Null && expressionType.IsArray != true)
                    Error(ErrorCode.InvalidArrayIndex, "Arrays must be indexed.");
            }
            else
            {
                expressionType = new DataTypeValue(DataType.Int, false, false);
            }
            #endregion

            // Check we can cast to the expression result to the variables data type.
            if (_currentPass == 1 && CanImplicitlyCast(dataType, expressionType) == false)
                Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"" + dataType.ToString() + "\" and \"" + expressionType.ToString() + "\"");

            #region Array index byte code emission

            // If this is an array pop the index into reserved register 2.
            if (isArray == true && _currentPass == 1)
            {
                // Pop the index into reserved register 2.
                instruction = CreateInstruction(OpCodeByType(indexDataType, OpCodeType.POP), _currentScope, _currentToken);
                new Operand(instruction, Register.Reserved2);
            }

            #endregion

            #region Assignment byte code emission

            // Create assignment byte code if we are in pass 2.
            if (_currentPass == 1)
            {
                // Pop the object into the member register.
                instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken);
                new Operand(instruction, Register.Arithmetic1);

                // Call the GET_MEMBER opCode.
                if (returnDataType.IsArray)
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, variableSymbol);
                }
                else
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Arithmetic2);
                }

                switch (operatorToken.ID)
                {
                    case TokenID.OpAssign: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MOV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignAdd: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.ADD), _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseAnd: instruction = CreateInstruction(OpCode.BIT_AND_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseNot: instruction = CreateInstruction(OpCode.BIT_NOT_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseOr: instruction = CreateInstruction(OpCode.BIT_OR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHL: instruction = CreateInstruction(OpCode.BIT_SHL_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseSHR: instruction = CreateInstruction(OpCode.BIT_SHR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignBitwiseXOr: instruction = CreateInstruction(OpCode.BIT_XOR_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignDivide: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DIV), _currentScope, _currentToken); break;
                    case TokenID.OpAssignModulus: instruction = CreateInstruction(OpCode.MOD_INT, _currentScope, _currentToken); break;
                    case TokenID.OpAssignMultiply: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.MUL), _currentScope, _currentToken); break;
                    case TokenID.OpAssignSub: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.SUB), _currentScope, _currentToken); break;
                    case TokenID.OpIncrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.INC), _currentScope, _currentToken); break;
                    case TokenID.OpDecrement: instruction = CreateInstruction(OpCodeByType(dataType, OpCodeType.DEC), _currentScope, _currentToken); break;
                }

                // Generate destination operands based on if variable is array.
                new Operand(instruction, Register.Return);

                // Generate the source operand if we are not dealing with the ++ and -- operators.
                if (operatorToken.ID != TokenID.OpIncrement && operatorToken.ID != TokenID.OpDecrement)
                    new Operand(instruction, Register.Reserved3);

                // Call the SET_MEMBER opCode.
                if (returnDataType.IsArray)
                {
                    instruction = CreateInstruction(OpCode.SET_MEMBER, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Return);
                }
                else
                {
                    instruction = CreateInstruction(OpCode.GET_MEMBER_INDEXED, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic2);
                    new Operand(instruction, variableSymbol);
                    new Operand(instruction, Register.Return);
                    new Operand(instruction, Register.Arithmetic2);
                }
            }

            #endregion
        }
コード例 #6
0
        /// <summary>
        ///		Parses a do looping statment. The do loop comes in 2 flavours do and do/while; The do 
        ///		loop will loop through the statements body for x amount of times, where x is the result
        ///		of the expression. The Do/While loop works just like the While loop but gets evaluated
        ///		at the end rather than the start.
        ///		Syntax:
        ///			"Do" ["(" Expression ")"] Statement [ "While" "(" Expression ")" ]
        /// </summary>
        private void ParseDo()
        {
            // Check we are in a valid scope.
            if (_currentScope.Type != SymbolType.Function || _currentScope == _globalScope)
                Error(ErrorCode.InvalidScope, "Do statments are only valid inside a function's or event's scope.", false, 0);

            bool whileLoop = true;
            VariableSymbol doTrackerVariable = null;
            Instruction instruction = null;

            // Bind the starting jump target.
            JumpTargetSymbol startJumpTarget = null, endJumpTarget = null;
            if (_currentPass == 1)
            {
                startJumpTarget = new JumpTargetSymbol(_currentScope);
                endJumpTarget = new JumpTargetSymbol(_currentScope);
            }

            // Check if there is an expression next, if there is its a do loop.
            if (LookAheadToken().ID == TokenID.CharOpenParenthesis)
            {
                // Create an internal variable to count number of loops.
                if (_currentPass == 0)
                {
                    doTrackerVariable = new VariableSymbol(_currentScope);
                    doTrackerVariable.Identifier = "$" + _internalVariableIndex++;
                    doTrackerVariable.IsUsed = true;
                    doTrackerVariable.DataType = new DataTypeValue(DataType.Int, false, false);
                    doTrackerVariable.VariableType = VariableType.Local;
                    if (_currentScope.Type == SymbolType.Function)
                    {
                        doTrackerVariable.StackIndex = -(((FunctionSymbol)_currentScope).LocalDataSize + 2);
                        ((FunctionSymbol)_currentScope).LocalDataSize++;
                    }
                }
                else
                {
                    doTrackerVariable = _currentScope.FindSymbol("$" + _internalVariableIndex++, SymbolType.Variable) as VariableSymbol;

                    // Reset the tracker variable to 0.
                    instruction = CreateInstruction(OpCode.MOV_INT, _currentScope, _currentToken);
                    Operand.DirectStackOperand(instruction, doTrackerVariable.StackIndex);
                    new Operand(instruction, (long)0);
                }

                // Bind the jump target to here.
                if (_currentPass == 1) startJumpTarget.Bind();

                // Read in do expression.
                whileLoop = false;
                NextToken();
                DataTypeValue expressionDataType = ParseExpression();
                ExpectToken(TokenID.CharCloseParenthesis);

                // Make sure we can cast between the expression type and boolean.
                if (!CanImplicitlyCast(new DataTypeValue(DataType.Int, false, false), expressionDataType))
                    Error(ErrorCode.InvalidCast, "Can't implicitly cast between \"Int\" and \"" + expressionDataType.ToString() + "\"", false, 0);

                // If we are in pass 2 emit byte code to check value.
                if (_currentPass == 1)
                {
                    // Pop the amount of times to loop into the reserved register 1.
                    instruction = CreateInstruction(OpCodeByType(expressionDataType, OpCodeType.POP), _currentScope, _currentToken);
                    new Operand(instruction, Register.Reserved1);

                    // If the value is not a long then cast it into one.
                    if (expressionDataType != new DataTypeValue(DataType.Int, false, false))
                    {
                        instruction = CreateInstruction(OpCode.CAST_INT, _currentScope, _currentToken);
                        new Operand(instruction, Register.Reserved1);
                    }

                    // Compare the loop tracker to the number of times to loop.
                    instruction = CreateInstruction(OpCode.CMP_INT, _currentScope, _currentToken);
                    Operand.DirectStackOperand(instruction, doTrackerVariable.StackIndex);
                    new Operand(instruction, Register.Reserved1);

                    // If its above or equal to the number of times we want to loop for, then exit.
                    instruction = CreateInstruction(OpCode.JMP_GE, _currentScope, _currentToken);
                    new Operand(instruction, endJumpTarget);

                    // Increment the loop tracker variable.
                    instruction = CreateInstruction(OpCode.INC_INT, _currentScope, _currentToken);
                    Operand.DirectStackOperand(instruction, doTrackerVariable.StackIndex);
                }
            }
            else
            {
                // Bind the jump target to here.
                if (_currentPass == 1) startJumpTarget.Bind();
            }

            // Push a loop tracker onto the loop stack.
            if (_currentPass == 1)
                _loopTrackerStack.Push(new LoopTracker(startJumpTarget, endJumpTarget));

            // Parse the body of this statement.
            bool indexerLoop = _insideIndexerLoop;
            int indexerIndex = _indexerLoopIndex;
            if (whileLoop == false)
            {
                _insideIndexerLoop = true;
                _indexerLoopIndex = _internalVariableIndex - 1;
            }
            ParseStatement();
            _insideIndexerLoop = indexerLoop;
            _indexerLoopIndex = indexerIndex;

            // Pop the loop tracker of the loop stack
            if (_currentPass == 1)
                _loopTrackerStack.Pop();

            // If its a while loop then read in the while expression and output evaluation code.
            if (whileLoop == true)
            {
                // Parse the expression.
                ExpectToken(TokenID.KeywordWhile);
                ExpectToken(TokenID.CharOpenParenthesis);
                DataTypeValue expressionDataType = ParseExpression();
                ExpectToken(TokenID.CharCloseParenthesis);

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

                    // Cast it to boolean if its not already boolean
                    if (expressionDataType != new DataTypeValue(DataType.Bool, false, false))
                    {
                        instruction = CreateInstruction(OpCode.CAST_BOOL, _currentScope, _currentToken);
                        new Operand(instruction, Register.Arithmetic1);
                    }

                    // Compare the expression result to 0.
                    instruction = CreateInstruction(OpCode.CMP_BOOL, _currentScope, _currentToken);
                    new Operand(instruction, Register.Arithmetic1);
                    new Operand(instruction, false);

                    // Jump to finish jump target if comparison is equal to false.
                    instruction = CreateInstruction(OpCode.JMP_EQ, _currentScope, _currentToken);
                    new Operand(instruction, endJumpTarget);
                }
            }

            // Create an instruction to jump back to the start of the loop.
            if (_currentPass == 1)
            {
                instruction = CreateInstruction(OpCode.JMP, _currentScope, _currentToken);
                new Operand(instruction, startJumpTarget);

                // Bind the end jump target to here.
                endJumpTarget.Bind();
            }
        }
コード例 #7
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);
        }
コード例 #8
0
 /// <summary>
 ///     Invoked when a script wants to set the value of an indexed member of this object.
 /// </summary>
 /// <param name="thread">Script thread that invoked this function.</param>
 /// <param name="variable">Symbol describing the member that it wants set.</param>
 /// <param name="value">Value it wants the member to be set to.</param>
 /// <param name="index">Index of member to it wants set.</param>
 /// <returns>True if successfull or false if not.</returns>
 public virtual bool SetMember(ScriptThread thread, VariableSymbol variable, RuntimeValue value, RuntimeValue indexer)
 {
     return false;
 }
コード例 #9
0
        /// <summary>
        ///		Compiles a script from a string into byte code.
        /// </summary>
        /// <param name="data">Data of script to compile.</param>
        /// <param name="flags">Bitmask of flags defining how the script should be compiled.</param>
        /// <param name="defineList">A list of defines to use while preprocessing script.</param>
        /// <param name="includePaths">A list of directory paths to use when looking for include files.</param>
        /// <param name="fileUrl">Contains the url of the file this data comes from.</param>
        /// <returns>The number of errors or warning this script has generated duren compilation.</returns>
        public int CompileString(string data, CompileFlags flags, Define[] defineList, object[] includePaths, string fileUrl)
        {
            #if !DEBUG
            try
            {
            #endif
                // Reset all variables used to store compilation details.
                _errorList.Clear();
                _compiledSymbolList.Clear();
                _compiledInstructionList.Clear();
                _compiledDebugFileList.Clear();
                _compiledDefineList.Clear();
                _loopTrackerStack.Clear();
                _metaDataList.Clear();
                _currentToken = null;
                _currentPass = 0;
                _currentScope = null;
                _globalScope = new FunctionSymbol("$global", null); // Initialize global scope here.
                _memberScope = new FunctionSymbol("$member", null); // Initialize member scope here.
                _compileFlags = flags;
                _tokenList = null;
                _tokenIndex = 0;
                _memorySize = 1; // Reserve space for 'special' globals like 'this'.
                _internalVariableIndex = 0;
                _defaultEngineState = _defaultEditorState = null;
                _errorsOccured = false;
                _overrideInstructionScope = null;

                // Create the 'this' variable.
                VariableSymbol thisSymbol = new VariableSymbol(_globalScope);
                thisSymbol.DataType = new DataTypeValue(DataType.Object, false, false);
                thisSymbol.Identifier = "this";
                thisSymbol.IsConstant = true;
                thisSymbol.IsUsed = true;
                thisSymbol.MemoryIndex = 0;
                thisSymbol.VariableType = VariableType.Constant;

                // Create a lexer and convert script into a list
                // of tokens.
                DebugLogger.WriteLog("Preforming lexical analysis on script.");
                Lexer lexer = new Lexer();
                if (lexer.Analyse(data, _compileFlags, fileUrl) > 0)
                {
                    foreach (CompileError error in lexer.ErrorList)
                        _errorList.Add(error);
                }
                _tokenList = lexer.TokenList;

                // Add the script directory into the include path array.
                string includePath = Path.GetDirectoryName(fileUrl);
                string[] newIncludePaths = new string[includePaths.Length + 1];
                includePaths.CopyTo(newIncludePaths, 0);
                newIncludePaths[newIncludePaths.Length - 1] = includePath;
                includePaths = newIncludePaths;

                // Create a pre-processor and process the token list
                DebugLogger.WriteLog("Preforming preprocessing on script.");
                PreProcessor preProcessor = new PreProcessor();
                if (preProcessor.Process(_tokenList, _compileFlags, defineList, includePaths) > 0)
                {
                    foreach (CompileError error in preProcessor.ErrorList)
                        _errorList.Add(error);
                }
                _compiledDefineList = preProcessor.DefineList;
                _tokenList = preProcessor.TokenList;

                try
                {
                    // Pass 0: Collect infomation.
                    // Pass 1: Generate byte code.
                    DebugLogger.WriteLog("Compiling script in 2 passes.");

                    // Go over the source code in 2 passes.
                    for (int pass = 0; pass < 2; pass++)
                    {
                        _currentPass = pass;
                        _currentToken = null;
                        _tokenIndex = 0;
                        _currentScope = _globalScope;
                        _internalVariableIndex = 0; // This needs to be reset so statements using
                        // an internal variables can find them on the second pass.
                        while (!EndOfTokenStream())
                        {
                            try
                            {
                                ParseStatement();
                            }
                            catch (CompilePanicModeException)
                            {
                                DebugLogger.WriteLog("Panic mode initialized in script.");
                                // Don't do anything here, just allow the error to be
                                // forgoten and carry on as normal.
                            }

                            // If there are any errors quit compilation now.
                            if (_errorsOccured == true)
                                throw new CompileBreakException();
                        }
                    }

                    // Yell at user if no default state has been declared.
                    if (_defaultEngineState == null && (_compileFlags & CompileFlags.Library) == 0)
                        Error(ErrorCode.MissingDefaultState, "Default engine state is missing.");

                }
                catch (CompileBreakException)
                {
                    DebugLogger.WriteLog("Script compilation broken via CompileBreakException.");
                }

                // Check what errors occured.
                int fatalErrorCount = 0;
                int errorCount = 0;
                int warningCount = 0;
                int messageCount = 0;
                foreach (CompileError error in _errorList)
                {
                    switch (error.AlertLevel)
                    {
                        case ErrorAlertLevel.Error: errorCount++; break;
                        case ErrorAlertLevel.FatalError: fatalErrorCount++; break;
                        case ErrorAlertLevel.Message: messageCount++; break;
                        case ErrorAlertLevel.Warning: warningCount++; break;
                    }
                    DebugLogger.WriteLog(error.ToString(), LogAlertLevel.Warning);
                }

                DebugLogger.WriteLog("Script compiled with "+fatalErrorCount+" fatal errors, "+errorCount+" errors, "+warningCount+" warnings and "+messageCount+" messages.");

                // If there are any errors quit compilation now.
                if (_errorsOccured == true) return _errorList.Count;

                // Append an exit symbol onto the global scopes instruction list.
                CreateInstruction(OpCode.EXIT, _globalScope, _currentToken);

                DebugLogger.WriteLog("Optimizing and tweeking symbols and instructions.");

                // Compile symbol list.
                CompileSymbol(_globalScope);
                CompileSymbol(_memberScope);

                // Go through instruction list and replace placeholders with their values.
                int symbolIndex = 0;
                foreach (Symbol symbol in _compiledSymbolList)
                {
                    symbol.Index = symbolIndex;
                    symbolIndex++;

                    // Update the entry point if this is a function or event.
                    switch (symbol.Type)
                    {
                        case SymbolType.Function:
                            ((FunctionSymbol)symbol).EntryPoint = _compiledInstructionList.Count;
                            break;
                        case SymbolType.Variable:
                            bool check = true;
                            if (symbol.Scope.Type == SymbolType.Function)
                                if (((FunctionSymbol)symbol.Scope).IsImport == true) check = false;

                            // Should we remove it rather than warning?
                            if (((VariableSymbol)symbol).IsUsed == false && ((VariableSymbol)symbol).IsConstant == false && check == true)
                                Warning(ErrorCode.UnusedVariable, "Variable \"" + symbol.Identifier + "\" is declared but never used.");
                            break;
                    }

                    foreach (Instruction instruction in symbol.Instructions)
                    {
                        // Create a new debug file entry if this instruction
                        // was generated in a previously unknown file.
                        if (instruction.File != null && instruction.File != "")
                        {
                            bool found = false;
                            foreach (string file in _compiledDebugFileList)
                                if (file == instruction.File) found = true;
                            if (found == false) _compiledDebugFileList.Add(instruction.File);
                        }

                        // Go through each operand attach to this instruction
                        // and check for any trackers.
                        foreach (Operand operand in instruction.Operands)
                        {
                            if (operand == null) continue;

                            // Update operand based on type.
                            switch (operand.OpType)
                            {
                                case OperandType.JumpTarget:
                                    operand.OpType = OperandType.InstrIndex;
                                    switch (symbol.Type)
                                    {
                                        case SymbolType.Function:
                                            operand.InstrIndex = ((FunctionSymbol)symbol).EntryPoint + operand.JumpTarget.InstrIndex;
                                            break;
                                    }
                                    break;
                                case OperandType.SymbolIndexTracker:
                                    operand.OpType = OperandType.SymbolIndex;
                                    operand.SymbolIndex = _compiledSymbolList.IndexOf(operand.SymbolIndexTracker);
                                    break;
                            }
                        }
                        _compiledInstructionList.Add(instruction);
                    }
                }

                // Optimize this symbols instructions. (Currently somewhat error prone)
                //int instructionCount = _compiledInstructionList.Count;
                //ScriptOptimizer optimizer = new ScriptOptimizer();
                //optimizer.Optimize(_compiledInstructionList, _compiledSymbolList);
                //_compiledInstructionList = optimizer.OptimizedInstructions;
                //_compiledSymbolList = optimizer.OptimizedSymbols;

               // int index = 0;
                //foreach (Instruction instr in _compiledInstructionList)
                //{
                //    System.Console.WriteLine("\t"+instr.Decompile());
                //    index++;
                //}

            #if !DEBUG
            }
            catch (Exception)
            {
                _errorList.Add(new CompileError(ErrorCode.InternalError, "An internal compiler error occured.", ErrorAlertLevel.FatalError, 0, 0, ""));
            }
            #endif
            return _errorList.Count;
        }
コード例 #10
0
 /// <summary>
 ///     Invoked when a script wants to get the value of a member of this object.
 /// </summary>
 /// <param name="thread">Script thread that invoked this function.</param>
 /// <param name="variable">Symbol describing the member that it wants get.</param>
 /// <returns>True if successfull or false if not.</returns>
 public virtual bool GetMember(ScriptThread thread, VariableSymbol variable)
 {
     return false;
 }
コード例 #11
0
        /// <summary>
        ///		Resolves a local variable to a runtime value.
        /// </summary>
        /// <param name="variableSymbol">Symbol of variable to resolve.</param>
        /// <returns>Resolved local's runtime value.</returns>
        private RuntimeValue ResolveLocal(VariableSymbol variableSymbol)
        {
            RuntimeValue variableValue = null;

            if (variableSymbol.VariableType == VariableType.Global)
                variableValue = _process.MemoryHeap[variableSymbol.MemoryIndex];
            else if (variableSymbol.VariableType == VariableType.Local)
                variableValue = _runtimeStack[variableSymbol.StackIndex];
            else if (variableSymbol.VariableType == VariableType.Parameter)
                variableValue = _runtimeStack[variableSymbol.StackIndex];// ResolveParameter(_callingFunction.Symbols.Count - (_callingFunction.Symbols.IndexOf(variableSymbol) - 1));

            return variableValue;
        }
コード例 #12
0
        /// <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.");
        }
コード例 #13
0
        /// <summary>
        ///     Invoked when a script wants to get the value of an indexed member of this object.
        /// </summary>
        /// <param name="thread">Script thread that invoked this function.</param>
        /// <param name="variable">Symbol describing the member that it wants get.</param>
        /// <param name="index">Index of member it want to get.</param>
        /// <returns>True if successfull or false if not.</returns>
        public override bool SetMember(ScriptThread thread, VariableSymbol variable, RuntimeValue value, RuntimeValue indexer)
        {
            if (_nativeObject is ScriptedEntityNode)
            {
                // Check the script process is valid.
                ScriptProcess process = ((ScriptedEntityNode)_nativeObject).ScriptProcess;
                if (process == null) return false;

                // See if we can get the symbol they are after.
                VariableSymbol processSymbol = process.GetSymbol(variable.Identifier, SymbolType.Variable) as VariableSymbol;
                if (processSymbol == null)
                    return false;

                // Grab the variable runtime value. (This can probably be optimized).
                RuntimeValue runtimeValue = process[0].GetRuntimeValueGlobal(processSymbol.Identifier);

                // Check its public.
                if (processSymbol.AccessModifier != SymbolAccessModifier.Public)
                    return false;

                // Check data types are correct.
                if (variable.DataType.DataType != processSymbol.DataType.DataType || processSymbol.DataType.IsArray != true)
                    return false;

                // Grab the arrays variable.
                RuntimeValue indexValue = process[0].GetRuntimeValueArrayElement(runtimeValue.MemoryIndex, indexer.IntegerLiteral);

                // Copy value.
                RuntimeValue copiedValue = process[0].CopyValueFromThread(value, process[0], thread);

                // Set value (this can be optimized).
                process[0].SetGlobalVariable(processSymbol.Identifier, copiedValue);
            }
            else if (_nativeObject is EntityNode)
            {

            }
            else if (_nativeObject is EmitterNode)
            {

            }
            else if (_nativeObject is TilemapSegmentNode)
            {

            }
            else if ((_nativeObject as SceneNode) != null)
            {

            }

            return false;
        }
コード例 #14
0
        /// <summary>
        ///     Invoked when a script wants to set the value of a member of this object.
        /// </summary>
        /// <param name="thread">Script thread that invoked this function.</param>
        /// <param name="variable">Symbol describing the member that it wants set.</param>
        /// <param name="value">Value it wants the member to be set to.</param>
        /// <returns>True if successfull or false if not.</returns>
        public override bool GetMember(ScriptThread thread, VariableSymbol variable)
        {
            if (_nativeObject is ScriptedEntityNode)
            {
                // Check the script process is valid.
                ScriptProcess process = ((ScriptedEntityNode)_nativeObject).ScriptProcess;
                if (process == null) return false;

                // See if we can get the symbol they are after.
                VariableSymbol processSymbol = process.GetSymbol(variable.Identifier, SymbolType.Variable) as VariableSymbol;
                if (processSymbol == null)
                    return false;

                // Grab the variable runtime value. (This can probably be optimized).
                RuntimeValue runtimeValue= process[0].GetRuntimeValueGlobal(processSymbol.Identifier);

                // Check its public.
                if (processSymbol.AccessModifier != SymbolAccessModifier.Public)
                    return false;

                // Check data types are correct.
                if (variable.DataType != processSymbol.DataType)
                    return false;

                // Copy value into calling thread.
                if (variable.DataType.IsArray == true)
                {
                    thread.Registers[(int)Register.Return].MemoryIndex = (short)thread.CopyValueArrayFromThread(runtimeValue, thread, process[0]);
                }
                else
                    thread.Registers[(int)Register.Return] = thread.CopyValueFromThread(runtimeValue, thread, process[0]);

                // Set the return register to our newly copied value.

                // Return.
                return true;
            }
            else if (_nativeObject is EntityNode)
            {

            }
            else if (_nativeObject is EmitterNode)
            {

            }
            else if (_nativeObject is TilemapSegmentNode)
            {

            }
            else if ((_nativeObject as SceneNode) != null)
            {

            }

            return false;
        }