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

📄 zasm.cpp

📁 自己开发的汇编式脚本语言编译器
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        // ---- 堆栈处理

        // Push     Source

        iInstrIndex = AddInstrLookup( "Push", INSTR_PUSH, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_MEM_REF |
                                   OP_FLAG_TYPE_REG |
                                   OP_FLAG_TYPE_INT |
                                   OP_FLAG_TYPE_FLOAT |
                                   OP_FLAG_TYPE_STRING );

        // Pop     Destination

        iInstrIndex = AddInstrLookup( "Pop", INSTR_POP, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_MEM_REF |
                                   OP_FLAG_TYPE_REG );

        // ---- 函数调用

        // Call     FunctionName

        iInstrIndex = AddInstrLookup( "Call", INSTR_CALL, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_FUNC_NAME );

        // Ret

        iInstrIndex = AddInstrLookup( "Ret", INSTR_RET, 0 );

        // CallHost FunctionName

        iInstrIndex = AddInstrLookup( "CallHost", INSTR_CALLHOST, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_HOST_API_CALL );

        // ----  程序控制

        // Pause    Duration

        iInstrIndex = AddInstrLookup( "Pause", INSTR_PAUSE, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_INT |
                                   OP_FLAG_TYPE_FLOAT |
                                   OP_FLAG_TYPE_STRING |
                                   OP_FLAG_TYPE_MEM_REF |
                                   OP_FLAG_TYPE_REG );

        // Exit     Code

        iInstrIndex = AddInstrLookup( "Exit", INSTR_EXIT, 1 );
        SetOpType( iInstrIndex, 0, OP_FLAG_TYPE_INT |
                                   OP_FLAG_TYPE_FLOAT |
                                   OP_FLAG_TYPE_STRING |
                                   OP_FLAG_TYPE_MEM_REF |
                                   OP_FLAG_TYPE_REG );
    }

    /*****************************************************************************************
    *
    *   AddInstrLookup()
    *
    *   向指令查找表添加指令
    */

    int AddInstrLookup( char *pstrMnemonic, int iOpCode, int iOpCount )
    {
        // 用静态变量保存查找表中下一条指令的索引

        static int  s_iInstrIndex   = 0;

        // 检测指令索引是否超出查找表的范围

        if( s_iInstrIndex >= MAX_INSTR_LOOKUP_COUNT )
            return  -1;

        // 设置指令助记符、操作码和操作数计数字段

        strcpy( g_InstrTable[s_iInstrIndex].pstrMnemonic, pstrMnemonic );
        _strupr( g_InstrTable[s_iInstrIndex].pstrMnemonic );
        g_InstrTable[s_iInstrIndex].iOpcode     = iOpCode;
        g_InstrTable[s_iInstrIndex].iOpCount    = iOpCount;

        // 为操作数类型数组分配空间

        g_InstrTable[s_iInstrIndex].OpList  = new OpTypes[iOpCount];

        // 返回当前指令在指令查找表中的索引,后移索引

        int     iRetInstrIndex  = s_iInstrIndex;
        ++ s_iInstrIndex;

        return  iRetInstrIndex;
    }
    
    /*****************************************************************************************
    *
    *   SetOpType()
    *
    *   设定操作数类型列表
    */

    void SetOpType( int iInstrIndex, int iOpIndex, OpTypes iOpType )
    {
        g_InstrTable[iInstrIndex].OpList[iOpIndex]  = iOpType;
    }

    /*****************************************************************************************
    *
    *   GetInstrByMnemonic
    *
    *   根据指令助记符取得指令查找表节点
    */

    bool GetInstrByMnemonic( char *pstrMnemonic, InstrLookup *pInstr )
    {
        for( int i=0 ; i<MAX_INSTR_LOOKUP_COUNT ; ++ i )
        {
            // 比较指令助记符

            if( strcmp( g_InstrTable[i].pstrMnemonic, pstrMnemonic ) == 0 )
            {
                *pInstr = g_InstrTable[i];
                
                return  true;
            }
        }

        // 匹配不成功

        return  false;
    }

    /*****************************************************************************************
    *
    *   PrintLogo()
    *
    *   打印欢迎界面
    */

    void PrintLogo()
    {
        printf ( "ZASM\n\n" );
        printf ( "ZScript 汇编器\n\n"  );
        printf ( "版本:\t%d.%d\n", VERSION_MAJOR, VERSION_MINOR );
        printf ( "作者:\t张锦\n" );
        printf ( "\n" );
    }

    /*****************************************************************************************
    *
    *   PrintUsage()
    *
    *   打印用法
    */

    void PrintUsage()
    {
        printf( "Usage:\tZASM Source.ZASM [Executable.ZSE]\n" );
        printf( "\n" );
        printf( "\t- 文件扩展名不是必须的\n" );
        printf( "\t- 可执行文件名是可选的,默认文件名为 源文件名.ZSE\n" );

        system("pause");
    }

    /*****************************************************************************************
    *
    *   void Init()
    *
    *   初始化
    */

    void Init()
    {
        // 初始化指令查找表

        InitInstrTable();

        // 初始化其他表

        InitLinkedList( &g_FuncTable ); 
        InitLinkedList( &g_StringTable );
        InitLinkedList( &g_SymbolTable );
        InitLinkedList( &g_LabelTable );
        InitLinkedList( &g_HostAPICallTable );
    }

    /*****************************************************************************************
    *
    *   void ShutDown()
    *
    *   关闭
    */

    void ShutDown()
    {
    }

    /*****************************************************************************************
    *
    *   LoadSourceFile()
    *
    *   读取源代码
    */

    void LoadSourceFile()
    {
        // 已二进制方式读取源文件

        g_pSourceFile = fopen( g_pstrSourceFileName, "rb" );
        if( !g_pSourceFile )
            ExitOnError( "无法打开源文件" );
        
        // 统计代码行数

        while( !feof(g_pSourceFile) )
        {
            if( fgetc(g_pSourceFile) == '\n' )
            {
                ++ g_iSourceCodeSize;
            }
        }
        ++ g_iSourceCodeSize;

        // 关闭二进制方式打开的源文件

        fclose( g_pSourceFile );

        // 为源代码缓存分配空间

        g_ppstrSourceCode   = new char*[ g_iSourceCodeSize ];
        if( !g_ppstrSourceCode )
            ExitOnError( "没有足够的空间非配给 g_ppstrSourceCode " ); 

        // 再次以 ASCII方式 打开源文件

        g_pSourceFile = fopen( g_pstrSourceFileName, "r" );
        if( !g_pSourceFile )
            ExitOnError( "无法打开源文件" );

        // 逐行处理源文件

        for( int iCurrLineIndex = 0 ; iCurrLineIndex < g_iSourceCodeSize ; ++ iCurrLineIndex )
        {
            // 为代码行非配空间

            g_ppstrSourceCode[ iCurrLineIndex ] = new char[ MAX_SOURCE_LINE_SIZE+1 ];
            if( !g_ppstrSourceCode[ iCurrLineIndex ] )
                ExitOnError( "没有足够的空间非配给代码行缓存" );

            // 读取代码行

            char *p   = fgets( g_ppstrSourceCode[ iCurrLineIndex ], MAX_SOURCE_LINE_SIZE, g_pSourceFile );

            // 处理末尾没有字符的情况

            if( p == 0 )
                g_ppstrSourceCode[ iCurrLineIndex ][ 0 ]    = '\0';
            

            // 去除注释和左右空格

            StripComments( g_ppstrSourceCode[ iCurrLineIndex ] );
            TrimWhitespace( g_ppstrSourceCode[ iCurrLineIndex ] );

            // 确保去除空格和去除注释后的代码行后面有换行符
            
            size_t     iCodeLineLength   = strlen( g_ppstrSourceCode[ iCurrLineIndex ] );
            if( g_ppstrSourceCode[ iCurrLineIndex ] [ iCodeLineLength-1 ] != '\n' )
            {
                 g_ppstrSourceCode[ iCurrLineIndex ] [ iCodeLineLength ]   = '\n';
                 g_ppstrSourceCode[ iCurrLineIndex ] [ iCodeLineLength+1 ] = '\0';
            }

            // test

            // printf( g_ppstrSourceCode[ iCurrLineIndex ] );
        }

        // 关闭 ASCII 方式打开的源文件

        fclose( g_pSourceFile );
    }

    /*****************************************************************************************
    *
    *   AssembleSourceFile()
    *
    *   汇编源代码
    */

    void AssembleSourceFile()
    {
        // 初始化脚本头 

        g_ScriptHeader.iStackSize       = 0;
        g_ScriptHeader.iGlobalDataSize  = 0;
        g_ScriptHeader.iIsMainFuncPresent   = false;
        
        // 设置一些初始变量 

        g_iInstrStreamSize              = 0;
        g_bIsSetStackSizeFound          = false;
        
        // 设置当前函数的标志和变量 

        bool        bIsFuncActive       = false;
        FuncNode*   pCurrFunc;
        int         iCurrFuncIndex      = 0;
        int         iCurrFuncParamCount = 0;
        int         iCurrFuncLocalDataSize  = 0;
        char        pstrCurrFuncName[ MAX_IDENT_SIZE ];

        // 用于处理指令时保存指令

        InstrLookup CurrInstr;

        // ---- 第一遍扫描

        // 重置词法分析器
        
        ResetLexer();

        // 遍历每一行代码

        while( true )
        {
            // 检测是否到达代码结尾

            if( GetNextToken() == END_OF_TOKEN_STREAM ) 
                break;
            
            // 处理Token

            switch( g_Lexer.CurrToken )
            {

                // ---- 指示符

                // SetStackSize
                    
                case TOKEN_TYPE_SETSTACKSIZE:
                    
                    // SetStackSize 只能出现在全局范围内

                    if( bIsFuncActive )
                        ExitOnCodeError( ERROR_MSG_LOCAL_SETSTACKSIZE );
                    
                    // SetStackSize 只能出现一次

                    if( g_bIsSetStackSizeFound == true )
                        ExitOnCodeError( ERROR_MSG_MULTIPLE_SETSTACKSIZE );
                    
                    // 读取下一个单词,它应该包含堆栈大小

                    if( GetNextToken() != TOKEN_TYPE_INT )
                        ExitOnCodeError( ERROR_MSG_INVALID_STACK_SIZE );

                    // 把这个单词从字符串的表示转换成一个整数值,并存储在脚本头中

                    g_ScriptHeader.iStackSize   = atoi( GetCurrLexeme() );

                    // 设置 SetStackSize 标志已经找到

                    g_bIsSetStackSizeFound  = true;

                    break;

                // Func

                case TOKEN_TYPE_FUNC:
                {
                    // 检测 Func 标签是否是出现在了函数内部

                    if( bIsFuncActive )
                        ExitOnCodeError( ERROR_MSG_NESTED_FUNC );
                    
                    // 取下一个单词,即函数名

                    if( GetNextToken() != TOKEN_TYPE_IDENT )
                        ExitOnCodeError( ERROR_MSG_IDENT_EXPECTED );
                    char    *pstrFuncName   = GetCurrLexeme();

                    // 计算函数入口点,即直接跟在当前指令后面的指令
                    // 也就相当于指令流的大小

                    int     iEntryPoint     = g_iInstrStreamSize;

                    // 把这个函数添加到函数表中,如果已经声明过了

⌨️ 快捷键说明

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