📄 zasm.cpp
字号:
// ---- 堆栈处理
// 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 + -