⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parser.cpp

📁 < Game Script Mastery>> source code
💻 CPP
📖 第 1 页 / 共 4 页
字号:
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar1SymbolIndex );

            // Push the result (stored in _T0)

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
        }
    }

    /******************************************************************************************
    *
    *   ParseTerm ()
    *
    *   Parses a term.
    */

    void ParseTerm ()
    {
        int iInstrIndex;

        // The current operator type

        int iOpType;

        // Parse the first factor

        ParseFactor (); 

        // Parse any subsequent *, /, %, ^, &, |, #, << and >> operators

        while ( TRUE )
        {
            // Get the next token

            if ( GetNextToken () != TOKEN_TYPE_OP ||
                 ( GetCurrOp () != OP_TYPE_MUL &&
                   GetCurrOp () != OP_TYPE_DIV &&
                   GetCurrOp () != OP_TYPE_MOD &&
                   GetCurrOp () != OP_TYPE_EXP &&
                   GetCurrOp () != OP_TYPE_BITWISE_AND &&
                   GetCurrOp () != OP_TYPE_BITWISE_OR &&
                   GetCurrOp () != OP_TYPE_BITWISE_XOR &&
                   GetCurrOp () != OP_TYPE_BITWISE_SHIFT_LEFT &&
                   GetCurrOp () != OP_TYPE_BITWISE_SHIFT_RIGHT ) )
            {
                RewindTokenStream ();
                break;
            }

            // Save the operator

            iOpType = GetCurrOp ();

            // Parse the second factor

            ParseFactor ();

            // Pop the first operand into _T1

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar1SymbolIndex );

            // Pop the second operand into _T0

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );

            // Perform the binary operation associated with the specified operator

            int iOpInstr;
            switch ( iOpType )
            {
                // Binary multiplication

                case OP_TYPE_MUL:
                    iOpInstr = INSTR_MUL;
                    break;

                // Binary division

                case OP_TYPE_DIV:
                    iOpInstr = INSTR_DIV;
                    break;

                // Binary modulus

                case OP_TYPE_MOD:
                    iOpInstr = INSTR_MOD;
                    break;

                // Binary exponentiation

                case OP_TYPE_EXP:
                    iOpInstr = INSTR_EXP;
                    break;

                // Binary bitwise AND

                case OP_TYPE_BITWISE_AND:
                    iOpInstr = INSTR_AND;
                    break;

                // Binary bitwise OR

                case OP_TYPE_BITWISE_OR:
                    iOpInstr = INSTR_OR;
                    break;

                // Binary bitwise XOR

                case OP_TYPE_BITWISE_XOR:
                    iOpInstr = INSTR_XOR;
                    break;

                // Binary bitwise shift left

                case OP_TYPE_BITWISE_SHIFT_LEFT:
                    iOpInstr = INSTR_SHL;
                    break;

                // Binary bitwise shift left

                case OP_TYPE_BITWISE_SHIFT_RIGHT:
                    iOpInstr = INSTR_SHR;
                    break;
            }
            iInstrIndex = AddICodeInstr ( g_iCurrScope, iOpInstr );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar1SymbolIndex );

            // Push the result (stored in _T0)

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
        }
    }

    /******************************************************************************************
    *
    *   ParseFactor ()
    *
    *   Parses a factor.
    */

    void ParseFactor ()
    {  
        int iInstrIndex;
        int iUnaryOpPending = FALSE;
        int iOpType;

        // First check for a unary operator

        if ( GetNextToken () == TOKEN_TYPE_OP &&
             ( GetCurrOp () == OP_TYPE_ADD ||
               GetCurrOp () == OP_TYPE_SUB ||
               GetCurrOp () == OP_TYPE_BITWISE_NOT ||
               GetCurrOp () == OP_TYPE_LOGICAL_NOT ) )
        {
            // If it was found, save it and set the unary operator flag

            iUnaryOpPending = TRUE;
            iOpType = GetCurrOp ();
        }
        else
        {
            // Otherwise rewind the token stream

            RewindTokenStream ();
        }

        // Determine which type of factor we're dealing with based on the next token

        switch ( GetNextToken () )
        {
            // It's a true or false constant, so push either 0 and 1 onto the stack

            case TOKEN_TYPE_RSRVD_TRUE:
            case TOKEN_TYPE_RSRVD_FALSE:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, GetCurrToken () == TOKEN_TYPE_RSRVD_TRUE ? 1 : 0 );
                break;

            // It's an integer literal, so push it onto the stack

            case TOKEN_TYPE_INT:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, atoi ( GetCurrLexeme () ) );
                break;

            // It's a float literal, so push it onto the stack

            case TOKEN_TYPE_FLOAT:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddFloatICodeOp ( g_iCurrScope, iInstrIndex, ( float ) atof ( GetCurrLexeme () ) );
                break;

            // It's a string literal, so add it to the string table and push the resulting
            // string index onto the stack

            case TOKEN_TYPE_STRING:
            {
                int iStringIndex = AddString ( & g_StringTable, GetCurrLexeme () );
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddStringICodeOp ( g_iCurrScope, iInstrIndex, iStringIndex );
                break;
            }

            // It's an identifier

            case TOKEN_TYPE_IDENT:
            {
                // First find out if the identifier is a variable or array
                
                SymbolNode * pSymbol = GetSymbolByIdent ( GetCurrLexeme (), g_iCurrScope );
                if ( pSymbol )
                {   
                    // Does an array index follow the identifier?

                    if ( GetLookAheadChar () == '[' )
                    {
                        // Ensure the variable is an array

                        if ( pSymbol->iSize == 1 )
                            ExitOnCodeError ( "Invalid array" );

                        // Verify the opening brace

                        ReadToken ( TOKEN_TYPE_DELIM_OPEN_BRACE );

                        // Make sure an expression is present

                        if ( GetLookAheadChar () == ']' )
                            ExitOnCodeError ( "Invalid expression" );

                        // Parse the index as an expression recursively

                        ParseExpr ();

                        // Make sure the index is closed

                        ReadToken ( TOKEN_TYPE_DELIM_CLOSE_BRACE );
                        
                        // Pop the resulting value into _T0 and use it as the index variable

                        iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
                        AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );   

                        // Push the original identifier onto the stack as an array, indexed
                        // with _T0

                        iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                        AddArrayIndexVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex, g_iTempVar0SymbolIndex );
                    }
                    else
                    {
                        // If not, make sure the identifier is not an array, and push it onto
                        // the stack

                        if ( pSymbol->iSize == 1 )
                        {
                            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                            AddVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex );
                        }
                        else
                        {
                            ExitOnCodeError ( "Arrays must be indexed" );
                        }
                    }
                }
                else
                {
                    // The identifier wasn't a variable or array, so find out if it's a
                    // function

                    if ( GetFuncByName ( GetCurrLexeme () ) )
                    {
                        // It is, so parse the call

                        ParseFuncCall ();

                        // Push the return value

                        iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                        AddRegICodeOp ( g_iCurrScope, iInstrIndex, REG_CODE_RETVAL );
                    }
                }

                break;
            }

            // It's a nested expression, so call ParseExpr () recursively and validate the
            // presence of the closing parenthesis

            case TOKEN_TYPE_DELIM_OPEN_PAREN:
                ParseExpr ();
                ReadToken ( TOKEN_TYPE_DELIM_CLOSE_PAREN );
                break;

            // Anything else is invalid

            default:
                ExitOnCodeError ( "Invalid input" );
        }

        // Is a unary operator pending?

        if ( iUnaryOpPending )
        {
            // If so, pop the result of the factor off the top of the stack

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );

            // Perform the unary operation

            if ( iOpType == OP_TYPE_LOGICAL_NOT )
            {
                // Get a pair of free jump target indices

                int iTrueJumpTargetIndex = GetNextJumpTargetIndex (),
                    iExitJumpTargetIndex = GetNextJumpTargetIndex ();

                // JE _T0, 0, True

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JE );
                AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );
                AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iTrueJumpTargetIndex );

                // Push 0

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );

                // Jmp L1

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
                AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iExitJumpTargetIndex );

                // L0: (True)

                AddICodeJumpTarget ( g_iCurrScope, iTrueJumpTargetIndex );

                // Push 1

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, 1 );

                // L1: (Exit)

                AddICodeJumpTarget ( g_iCurrScope, iExitJumpTargetIndex );
            }
            else
            {
                int iOpIndex;
                switch ( iOpType )
                {
                    // Negation

                    case OP_TYPE_SUB:
                        iOpIndex = INSTR_NEG;
                        break;

                    // Bitwise not

                    case OP_TYPE_BITWISE_NOT:
                        iOpIndex = INSTR_NOT;
                        break;
                }

                // Add the instruction's operand

                iInstrIndex = AddICodeInstr ( g_iCurrScope, iOpIndex );
                AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );

                // Push the result onto the stack

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_PUSH );
                AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
            }
        }
    }

    /******************************************************************************************
    *
    *   ParseIf ()
    *
    *   Parses an if block.
    *
    *       if ( <Expression> ) <Statement>
    *       if ( <Expression> ) <Statement> else <Statement>
    */

    void ParseIf ()
    {
        int iInstrIndex;

        // Make sure we're inside a function

        if ( g_iCurrScope == SCOPE_GLOBAL )
            ExitOnCodeError ( "if illegal in global scope" );

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        // Create a jump target to mark the beginning of the false block

        int iFalseJumpTargetIndex = GetNextJumpTargetIndex ();

        // Read the opening parenthesis

        ReadToken ( TOKEN_TYPE_DELIM_OPEN_PAREN );

        // Parse the expression and leave the result on the stack

        ParseExpr ();

        // Read the closing parenthesis

        ReadToken ( TOKEN_TYPE_DELIM_CLOSE_PAREN );

        // Pop the result into _T0 and compare it to zero

        iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
        AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );

        // If the result is zero, jump to the false target

        iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JE );
        AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
        AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );
        AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iFalseJumpTargetIndex );

        // Parse the true block

        ParseStatement ();

        // Look for an else clause

        if ( GetNextToken () == TOKEN_TYPE_RSRVD_ELSE )
        {
            // If it's found, append the true block with an unconditional jump past the false
            // block

            int iSkipFalseJumpTargetIndex = GetNextJumpTargetIndex ();
            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
            AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iSkipFalseJumpTargetIndex );

            // Place the false target just before the false block

            AddICodeJumpTarget ( g_iCurrScope, iFalseJumpTargetIndex );

            // Parse the false block

            ParseStatement ();

            // Set a jump target beyond the false block

            AddICodeJumpTarget ( g_iCurrScope, iSkipFalseJumpTargetIndex );
        }
        else
        {
            // Otherwise, put the token back

            RewindTokenStream ();

            // Place the false target after the true block

            AddICodeJumpTarget ( g_iCurrScope, iFalseJumpTargetIndex );
        }
    }

    /******************************************************************************************
    *
    *   ParseWhile ()
    *
    *   Parses a while loop block.
    *
    *       while ( <Expression> ) <Statement>
    */

    void ParseWhile ()
    {
        int iInstrIndex;

        // Make sure we're inside a function

        if ( g_iCurrScope == SCOPE_GLOBAL )
            ExitOnCodeError ( "Statement illegal in global scope" );

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
        
        // Get two jump targets; for the top and bottom of the loop

        int iStartTargetIndex = GetNextJumpTargetIndex (),
            iEndTargetIndex = GetNextJumpTargetIndex ();

        // Set a jump target at the top of the loop

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -