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

📄 zvm.cpp

📁 自己开发的类汇编语言脚本语言虚拟机
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        // 读取脚本版本(2字节)

        int iMajorVersion = 0;
        int iMinorVersion = 0;
        fread( &iMajorVersion, 1, 1, pScriptFile );
        fread( &iMinorVersion, 1, 1, pScriptFile );
        g_iReadSize     += 2;

        // 验证版本, 当前虚拟机版本支持 v0.0 的脚本

        if ( iMajorVersion != 0 || iMinorVersion != 0 )
            return LOAD_ERROR_UNSUPPORTED_VERS;

        // 读取堆栈大小(4字节)

        fread ( &g_Script.Stack.iSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 分配运行时堆栈空间大小

        if( g_Script.Stack.iSize == 0 )
            g_Script.Stack.iSize = DEF_STACK_SIZE;
        g_Script.Stack.pElements    = new Value [ g_Script.Stack.iSize ];
        memset ( g_Script.Stack.pElements, 0, sizeof(Value) * g_Script.Stack.iSize );

        // 读取全局数据大小(4字节)

        fread ( &g_Script.iGlobalDataSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 检查 _Main() 是否存在(1字节)

        fread ( &g_Script.iIsMainFuncPresent, 1, 1, pScriptFile );
        g_iReadSize     += 1;

        // 读取 _Main() 索引(4字节)

        fread ( &g_Script.iMainFuncIndex, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // ---- 读取指令流

        // 读取指令计数(4字节)

        fread ( &g_Script.InstrStream.iSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 分配指令流空间

        g_Script.InstrStream.pInstrs = new Instr [ g_Script.InstrStream.iSize ];
        memset ( g_Script.InstrStream.pInstrs, 0, sizeof(Instr) * g_Script.InstrStream.iSize );

        // 读取指令数据

        for ( int iCurrInstrIndex = 0;
              iCurrInstrIndex < g_Script.InstrStream.iSize;
              ++ iCurrInstrIndex )
        {
            // 读取操作码(2字节)

            g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCode = 0;
            fread( &g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCode, 2, 1, pScriptFile );
            g_iReadSize     += 2;

            // 读取操作数个数(1字节)
            g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCount = 0;
            fread( &g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCount, 1, 1, pScriptFile );
            g_iReadSize     += 1;
            
            int iOpCount = g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCount;
            
            // 为操作数列表分配空间

            Value   *pOpList    = new Value [ iOpCount ];
            memset ( pOpList, 0, sizeof(Value) * iOpCount );

            // 读取操作数列表(N字节)

            for ( int iCurrOpIndex = 0;
                  iCurrOpIndex < iOpCount;
                  ++ iCurrOpIndex )
            {
                // 把当前操作数赋值给引用 CurrOp, 方便后续编码

                Value &CurrOp = pOpList [ iCurrOpIndex ];

                // 读取操作数类型(1字节)

                CurrOp.iType = 0;
                fread ( &CurrOp.iType, 1, 1, pScriptFile );
                g_iReadSize     += 1;

                // 根据操作数类型,读取操作数数据

                switch ( CurrOp.iType )
                {
                    // int 字面量

                    case OP_TYPE_INT:
                    {
                        fread ( &CurrOp.iIntLiteral, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                    // float 字面量

                    case OP_TYPE_FLOAT:
                    {
                        fread ( &CurrOp.fFloatLiteral, sizeof(float), 1, pScriptFile );
                        g_iReadSize     += sizeof(float);
                        break;
                    }

                    // 字符串索引

                    case OP_TYPE_STRING:
                    {
                        // 字符串索引存储在 int 字面值字段中

                        fread ( &CurrOp.iIntLiteral, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                    // 指令索引

                    case OP_TYPE_INSTR_INDEX:
                    {
                        fread ( &CurrOp.iInstrIndex, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);                     
                        break;
                    }

                    // 绝对堆栈索引

                    case OP_TYPE_ABS_STACK_INDEX:
                    {
                        fread ( &CurrOp.iStackIndex, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                    // 相对堆栈索引

                    case OP_TYPE_REL_STACK_INDEX:
                    {
                        fread ( &CurrOp.iStackIndex, sizeof(int), 1, pScriptFile );
                        fread ( &CurrOp.iOffsetIndex, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int)*2;
                        break;
                    }

                    // 函数索引

                    case OP_TYPE_FUNC_INDEX:
                    {
                        fread ( &CurrOp.iFuncIndex, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                    // 主程序 API 调用索引

                    case OP_TYPE_HOST_API_CALL_INDEX:
                    {
                        fread ( &CurrOp.iHostAPICallIndex, sizeof(int), 1, pScriptFile );
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                    // 寄存器
                
                    case OP_TYPE_REG:
                    {
                        fread ( &CurrOp.iReg, sizeof(int), 1, pScriptFile ); 
                        g_iReadSize     += sizeof(int);
                        break;
                    }

                }   // end switch
            
            }   // end for

            // 为操作数列表指针赋值

            g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].pOpList = pOpList;
        
        }   // end for

        // ---- 读取字符串表

        // 读取字符串表大小(4字节)

        int iStringTableSize = 0;
        fread ( &iStringTableSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 如果字符串表不为空,读取它

        if( iStringTableSize != 0 )
        {
            // 为临时字符串表分配空间

            char **ppstrStringTable = new char* [ iStringTableSize ];

            // 读取每个字符串

            for ( int iCurrStringIndex = 0;
                  iCurrStringIndex < iStringTableSize;
                  ++ iCurrStringIndex )
            {
                // 读取字符串大小(4字节)

                int iStringSize;
                fread ( &iStringSize, 4, 1, pScriptFile );
                g_iReadSize     += 4;

                // 为字符串分配空间

                char *pstrCurrString = new char [ iStringSize + 1 ];

                // 读取字符串(N字节)

                fread( pstrCurrString, iStringSize, 1, pScriptFile );
                pstrCurrString [ iStringSize ] = '\0';

                // 把字符串指针赋给字符串表

                ppstrStringTable [ iCurrStringIndex ] = pstrCurrString;
            }

            // 遍历指令流中每个指令的所有操作数,
            // 检测字符串类型,为字符串字面值赋值

            for ( int iCurrInstrIndex = 0;
                  iCurrInstrIndex < g_Script.InstrStream.iSize; 
                  ++ iCurrInstrIndex )
            {
                // 取得操作数个数以及操作数列表

                int iOpCount = g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].iOpCount;
                Value *pOpList = g_Script.InstrStream.pInstrs [ iCurrInstrIndex ].pOpList;
            
                // 遍历各个操作数

                for ( int iCurrOpIndex = 0;
                      iCurrOpIndex < iOpCount;
                      ++ iCurrOpIndex )
                {
                    // 取得当前操作数的引用,方便后续编码

                    Value &CurrOp = pOpList [ iCurrOpIndex ];

                    // 检测操作数类型是否是字符串

                    if( CurrOp.iType == OP_TYPE_STRING )
                    {
                        // 取得当前字符串在字符串表中的索引
                        // 此索引存储在 iIntLiteral 字段中

                        int iStringIndex = CurrOp.iIntLiteral;

                        // 计算字符串大小

                        size_t iStringSize = strlen ( ppstrStringTable [ iStringIndex ] );

                        // 为当前操作数字符串字面值字段分配空间

                        CurrOp.pstrStringLiteral = new char [ iStringSize + 1 ];

                        // 拷贝字符串

                        strcpy_s( CurrOp.pstrStringLiteral, iStringSize+1, ppstrStringTable [ iStringIndex ] );
                    }
                }
            }

            // 释放临时字符串表中的字符串

            for ( int iCurrStringIndex = 0;
                  iCurrStringIndex < iStringTableSize;
                  ++ iCurrStringIndex )
            {
                delete ppstrStringTable [ iCurrStringIndex ];
            }

            // 释放临时字符串表本身

            delete ppstrStringTable;

        }   // end if

        // ---- 读取函数表

        // 读取函数表大小(4字节)

        int iFuncTableSize = 0;
        fread ( &iFuncTableSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 为函数表分配空间

        g_Script.pFuncTable = new Func [ iFuncTableSize ];

        // 读取各个函数

        for ( int iCurrFuncIndex = 0;
              iCurrFuncIndex < iFuncTableSize;
              ++ iCurrFuncIndex )
        {
            // 读取入口点(4字节)

            int iEntryPoint;
            fread ( &iEntryPoint, 4, 1, pScriptFile );
            g_iReadSize     += 4;

            // 读取参数个数(1字节)

            int iParamCount = 0;
            fread ( &iParamCount, 1, 1, pScriptFile );
            g_iReadSize     += 1;

            // 读取局部数据大小(4字节)

            int iLocalDataSize;
            fread ( &iLocalDataSize, 4, 1, pScriptFile );
            g_iReadSize     += 4;

            // 计算堆栈框架大小

            int iStackFrameSize = iParamCount + 1 + iLocalDataSize;

            // 把信息写入函数表

            g_Script.pFuncTable [ iCurrFuncIndex ].iEntryPoint      = iEntryPoint;
            g_Script.pFuncTable [ iCurrFuncIndex ].iLocalDataSize   = iLocalDataSize;
            g_Script.pFuncTable [ iCurrFuncIndex ].iParamCount      = iParamCount;
            g_Script.pFuncTable [ iCurrFuncIndex ].iStackFrameSize  = iStackFrameSize;
        }

        // ---- 读取主程序 API 调用表

        // 读取主程序 API 调用表大小(4字节)

        fread ( &g_Script.HostAPICallTable.iSize, 4, 1, pScriptFile );
        g_iReadSize     += 4;

        // 为调用表分配空间

        g_Script.HostAPICallTable.ppstrCalls = new char* [ g_Script.HostAPICallTable.iSize ];

        // 读取各个函数名

        for ( int iCurrCallIndex = 0;
              iCurrCallIndex < g_Script.HostAPICallTable.iSize;
              ++ iCurrCallIndex )
        {
            // 读取函数名长度

            int iCallLength = 0;
            fread ( &iCallLength, 4, 1, pScriptFile );
            g_iReadSize     += 4;

            // 为函数名分配空间到临时指针

            char *pstrCurrCall = new char [ iCallLength + 1 ];

            // 读取函数名

            fread ( pstrCurrCall, iCallLength, 1, pScriptFile );
            g_iReadSize     += iCallLength;
            pstrCurrCall [ iCallLength ] = '\0';

            // 将临时指针赋值给API调用表

            g_Script.HostAPICallTable.ppstrCalls [ iCurrCallIndex ] = pstrCurrCall;
        }

        // ---- 关闭文件 

        fclose( pScriptFile );

        // ---- 打印装载信息

        printf ( "%s 加载成功!\n", pstrFileName );
        printf ( "\n" );
        printf ( "脚本版本:    v%d.%d\n", iMajorVersion, iMinorVersion ); 
        printf ( "堆栈大小:    %d\n", g_Script.Stack.iSize );
        printf ( "全局数据大小:%d\n", g_Script.iGlobalDataSize );
        printf ( "字符串表大小:%d\n", iStringTableSize );
        printf ( "函数总数:     %d\n", iFuncTableSize );
        printf ( "读取字节总数:%d\n", g_iReadSize );

        printf ( "\n" );
        printf ( "_Main() 是否出现:" );
        if( g_Script.iIsMainFuncPresent )
            printf ( "是, 索引(%d)\n", g_Script.iMainFuncIndex );
        else
            printf ( "否\n" );
        
        printf ( "\n" );
        printf ( "主程序API调用总数: %d", g_Script.HostAPICallTable.iSize );
        
        printf ( "\n" );

⌨️ 快捷键说明

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