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

📄 parser.cpp

📁 < Game Script Mastery>> source code
💻 CPP
📖 第 1 页 / 共 4 页
字号:

        AddICodeJumpTarget ( g_iCurrScope, iStartTargetIndex );

        // 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 jump out of the loop if it's nonzero

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

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

        // Create a new loop instance structure

        Loop * pLoop = ( Loop * ) malloc ( sizeof ( Loop ) );

        // Set the starting and ending jump target indices

        pLoop->iStartTargetIndex = iStartTargetIndex;
        pLoop->iEndTargetIndex = iEndTargetIndex;

        // Push the loop structure onto the stack

        Push ( & g_LoopStack, pLoop );

        // Parse the loop body

        ParseStatement ();

        // Pop the loop instance off the stack

        Pop ( & g_LoopStack );

        // Unconditionally jump back to the start of the loop

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

        // Set a jump target for the end of the loop

        AddICodeJumpTarget ( g_iCurrScope, iEndTargetIndex );
    }

    /******************************************************************************************
    *
    *   ParseFor ()
    *
    *   Parses a for loop block.
    *
    *       for ( <Initializer>; <Condition>; <Perpetuator> ) <Statement>
    */

    void ParseFor ()
    {
        if ( g_iCurrScope == SCOPE_GLOBAL )
            ExitOnCodeError ( "for illegal in global scope" );

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        /*
            A for loop parser implementation could go here
        */
    }

    /******************************************************************************************
    *
    *   ParseBreak ()
    *
    *   Parses a break statement.
    */

    void ParseBreak ()
    {
        // Make sure we're in a loop

        if ( IsStackEmpty ( & g_LoopStack ) )
            ExitOnCodeError ( "break illegal outside loops" );

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        // Attempt to read the semicolon

        ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );

        // Get the jump target index for the end of the loop

        int iTargetIndex = ( ( Loop * ) Peek ( & g_LoopStack ) )->iEndTargetIndex;

        // Unconditionally jump to the end of the loop

        int iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
        AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iTargetIndex );        
    }

    /******************************************************************************************
    *
    *   ParseContinue ()
    *
    *   Parses a continue statement.
    */

    void ParseContinue ()
    {
        // Make sure we're inside a function

        if ( IsStackEmpty ( & g_LoopStack ) )
            ExitOnCodeError ( "continue illegal outside loops" );

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        // Attempt to read the semicolon

        ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );

        // Get the jump target index for the start of the loop

        int iTargetIndex = ( ( Loop * ) Peek ( & g_LoopStack ) )->iStartTargetIndex;

        // Unconditionally jump to the end of the loop

        int iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
        AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iTargetIndex );
    }

    /******************************************************************************************
    *
    *   ParseReturn ()
    *
    *   Parses a return statement.
    *
    *   return;
    *   return <expr>;
    */

    void ParseReturn ()
    {
        int iInstrIndex;

        // Make sure we're inside a function

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

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        // If a semicolon doesn't appear to follow, parse the expression and place it in
        // _RetVal

        if ( GetLookAheadChar () != ';' )
        {
            // Parse the expression to calculate the return value and leave the result on the stack.

            ParseExpr ();

            // Determine which function we're returning from

            if ( g_ScriptHeader.iIsMainFuncPresent && 
                 g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
            {
                // It is _Main (), so pop the result into _T0

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
                AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
            }
            else
            {
                // It's not _Main, so pop the result into the _RetVal register

                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
                AddRegICodeOp ( g_iCurrScope, iInstrIndex, REG_CODE_RETVAL );
            }
        }
        else
        {
            // Clear _T0 in case we're exiting _Main ()

            if ( g_ScriptHeader.iIsMainFuncPresent && 
                 g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
            {
            
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOV );
                AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
                AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );
            }
        }

        if ( g_ScriptHeader.iIsMainFuncPresent && 
             g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
        {
            // It's _Main, so exit the script with _T0 as the exit code

            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_EXIT );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
        }
        else
        {
            // It's not _Main, so return from the function

            AddICodeInstr ( g_iCurrScope, INSTR_RET );
        }
    }

    /******************************************************************************************
    *
    *   ParseAssign ()
    *
    *   Parses an assignment statement.
    *
    *   <Ident> <Assign-Op> <Expr>;
    */

    void ParseAssign ()
    {
        // Make sure we're inside a function

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

        int iInstrIndex;

        // Assignment operator

        int iAssignOp;

        // Annotate the line

        AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );

        // ---- Parse the variable or array

        SymbolNode * pSymbol = GetSymbolByIdent ( GetCurrLexeme (), g_iCurrScope );

        // Does an array index follow the identifier?

        int iIsArray = FALSE;
        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

            ParseExpr ();

            // Make sure the index is closed

            ReadToken ( TOKEN_TYPE_DELIM_CLOSE_BRACE );
            
            // Set the array flag

            iIsArray = TRUE;
        }
        else
        {
            // Make sure the variable isn't an array

            if ( pSymbol->iSize > 1 )
               ExitOnCodeError ( "Arrays must be indexed" );
        }

        // ---- Parse the assignment operator
        
        if ( GetNextToken () != TOKEN_TYPE_OP &&
             ( GetCurrOp () != OP_TYPE_ASSIGN &&
               GetCurrOp () != OP_TYPE_ASSIGN_ADD &&
               GetCurrOp () != OP_TYPE_ASSIGN_SUB &&
               GetCurrOp () != OP_TYPE_ASSIGN_MUL &&
               GetCurrOp () != OP_TYPE_ASSIGN_DIV &&
               GetCurrOp () != OP_TYPE_ASSIGN_MOD &&
               GetCurrOp () != OP_TYPE_ASSIGN_EXP &&
               GetCurrOp () != OP_TYPE_ASSIGN_CONCAT &&
               GetCurrOp () != OP_TYPE_ASSIGN_AND &&
               GetCurrOp () != OP_TYPE_ASSIGN_OR &&
               GetCurrOp () != OP_TYPE_ASSIGN_XOR &&
               GetCurrOp () != OP_TYPE_ASSIGN_SHIFT_LEFT &&
               GetCurrOp () != OP_TYPE_ASSIGN_SHIFT_RIGHT ) )
             ExitOnCodeError ( "Illegal assignment operator" );
        else
            iAssignOp = GetCurrOp ();

        // ---- Parse the value expression

        ParseExpr ();
        
        // Validate the presence of the semicolon

        ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );

        // Pop the value into _T0

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

        // If the variable was an array, pop the top of the stack into _T1 for use as the index

        if ( iIsArray )
        {
            iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar1SymbolIndex );   
        }

        // ---- Generate the I-code for the assignment instruction

        switch ( iAssignOp )
        {
            // =

            case OP_TYPE_ASSIGN:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOV );
                break;

            // +=

            case OP_TYPE_ASSIGN_ADD:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_ADD );
                break;

            // -=

            case OP_TYPE_ASSIGN_SUB:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SUB );
                break;

            // *=

            case OP_TYPE_ASSIGN_MUL:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MUL );
                break;

            // /=

            case OP_TYPE_ASSIGN_DIV:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_DIV );
                break;

            // %=

            case OP_TYPE_ASSIGN_MOD:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOD );
                break;

            // ^=

            case OP_TYPE_ASSIGN_EXP:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_EXP );
                break;

            // $=

            case OP_TYPE_ASSIGN_CONCAT:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_CONCAT );
                break;

            // &=

            case OP_TYPE_ASSIGN_AND:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_AND );
                break;

            // |=

            case OP_TYPE_ASSIGN_OR:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_OR );
                break;

            // #=

            case OP_TYPE_ASSIGN_XOR:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_XOR );
                break;

            // <<=

            case OP_TYPE_ASSIGN_SHIFT_LEFT:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SHL );
                break;

            // >>=

            case OP_TYPE_ASSIGN_SHIFT_RIGHT:
                iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SHR );
                break;
        }

        // Generate the destination operand

        if ( iIsArray )
            AddArrayIndexVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex, g_iTempVar1SymbolIndex );
        else
            AddVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex );

        // Generate the source

        AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
    }

    /******************************************************************************************
    *
    *   ParseFuncCall ()
    *
    *   Parses a function call
    *
    *   <Ident> ( <Expr>, <Expr> );
    */

    void ParseFuncCall ()
    {
        // Get the function by it's identifier

        FuncNode * pFunc = GetFuncByName ( GetCurrLexeme () );

        // It is, so start the parameter count at zero

        int iParamCount = 0;

        // Attempt to read the opening parenthesis

        ReadToken ( TOKEN_TYPE_DELIM_OPEN_PAREN );

        // Parse each parameter and push it onto the stack

        while ( TRUE )
        {
            // Find out if there's another parameter to push

            if ( GetLookAheadChar () != ')' )
            {
                // There is, so parse it as an expression

                ParseExpr ();

                // Increment the parameter count and make sure it's not greater than the amount
                // accepted by the function (unless it's a host API function

                ++ iParamCount;
                if ( ! pFunc->iIsHostAPI && iParamCount > pFunc->iParamCount )
                    ExitOnCodeError ( "Too many parameters" );

                // Unless this is the final parameter, attempt to read a comma

                if ( GetLookAheadChar () != ')' )
                    ReadToken ( TOKEN_TYPE_DELIM_COMMA );
            }
            else
            {
                // There isn't, so break the loop and complete the call

                break;
            }
        }

        // Attempt to read the closing parenthesis

        ReadToken ( TOKEN_TYPE_DELIM_CLOSE_PAREN );

        // Make sure the parameter wasn't passed too few parameters (unless
        // it's a host API function)

        if ( ! pFunc->iIsHostAPI && iParamCount < pFunc->iParamCount )
            ExitOnCodeError ( "Too few parameters" );

        // Call the function, but make sure the right call instruction is used

        int iCallInstr = INSTR_CALL;
        if ( pFunc->iIsHostAPI )
            iCallInstr = INSTR_CALLHOST;

        int iInstrIndex = AddICodeInstr ( g_iCurrScope, iCallInstr );
        AddFuncICodeOp ( g_iCurrScope, iInstrIndex, pFunc->iIndex );
    }

⌨️ 快捷键说明

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