📄 tm.cpp
字号:
/***** 该代码文件所包含头文件 *****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* 宏定义常量TRUE为1 */
#ifndef TRUE
#define TRUE 1
#endif
/* 宏定义常量FALSE为0 */
#ifndef FALSE
#define FALSE 0
#endif
/***************** 常量 *******************/
/* 为大型程序扩展,指令存储区大小,定义为1024 */
#define IADDR_SIZE 1024
/* 为大型程序扩展,数据存储区大小,定义为1024 */
#define DADDR_SIZE 1024
/* 寄存器数量,定义为8 */
#define NO_REGS 8
/* PC寄存器,定义为7 */
#define PC_REG 7
/* 目标代码行大小,定义为121 */
#define LINESIZE 121
/* 字大小,定义为20 */
#define WORDSIZE 20
/**************** 类型 *******************/
/* 指令寻址模式类型 */
typedef enum
{
opclRR, /* 寄存器寻址模式类型,操作数使用寄存器r,s,t */
opclRM, /* 寄存器-内存寻址模式类型,操作数使用寄存器r,内存地址d+s */
opclRA /* 寄存器-立即数寻址模式类型,操作数使用寄存器r,立即数值d+s */
} OPCLASS;
/* 操作指令标识码类型 */
typedef enum opcode{
/************* 寄存器寻址模式指令标识码 ***************/
opHALT, /* 停止指令:结束程序执行,忽略操作数 */
opIN, /* 输入指令:将外部变量读入寄存器,使用第r个寄存器,忽略s,t参数 */
opOUT, /* 输出指令:将寄存器的值输出,使用第r个寄存器,忽略s,t参数 */
opADD, /* 加法指令:寄存器r的值赋为寄存器s的值与寄存器t的值的和 */
opSUB, /* 减法指令:寄存器r的值赋为寄存器s的值与寄存器t的值的差 */
opMUL, /* 乘法指令:寄存器r的值赋为寄存器s的值与寄存器t的值的积 */
opDIV, /* 除法指令:寄存器r的值赋为寄存器s的值与寄存器t的值的商 */
/* 寄存器寻址模式指令限制标志, *
* 操作标识码枚举值小于opRRLim的指令均为寄存器寻址模式指令 */
opRRLim,
/************** 寄存器-内存寻址模式指令标识码 ****************/
opLD, /* 载入指令:寄存器r的值赋为地址为d+reg(s)的内存单元的值 */
opST, /* 设置指令:将地址为d+reg(s)的内存单元值赋为寄存器r的值 */
/* 寄存器-内存寻址模式指令限制标志 *
* 操作标识码枚举值小于opRMLim且大于opRRLim的均为寄存器-内存寻址模式指令 */
opRMLim,
/************* 寄存器-立即数寻址模式指令标识码 ****************/
opLDA, /* 载入指令:将寄存器r的值赋为立即数d与寄存器s的值的和 */
opLDC, /* 载入指令:将寄存器r的值赋为立即数d,参数s被忽略 */
opJLT, /* 如果寄存器r的值小于0,将第7个寄存器的值赋为d+reg(s) *
* 第7个寄存器为pc程序计数寄存器 */
opJLE, /* 如果寄存器r的值小于等于0,将pc寄存器的值赋为d+reg(s) */
opJGT, /* 如果寄存器r的值大于0,将pc寄存器的值赋为d+reg(s) */
opJGE, /* 如果寄存器r的值大于等于0,将pc寄存器的值赋为d+reg(s) */
opJEQ, /* 如果寄存器r的值等于0,将pc寄存器的值赋为d+reg(s) */
opJNE, /* 如果寄存器r的值不等于0,将pc寄存器的值赋为d+reg(s) */
/* 寄存器-立即数寻址模式指令限制标志
* 操作标识码枚举值小于opRALim且大于opRMLim的均为寄存器-立即数寻址模式指令 */
opRALim
} OPCODE;
/************ 指令单步执行结果类型 ************/
typedef enum {
srOKAY, /* 正常 */
srHALT, /* 停止 */
srIMEM_ERR, /* 指令存储错 */
srDMEM_ERR, /* 数据存储错 */
srZERODIVIDE /* 除数为零错 */
} STEPRESULT;
/* 指令结构类型:操作码,操作数1,操作数2,操作数3 */
typedef struct {
int iop ;
int iarg1 ;
int iarg2 ;
int iarg3 ;
} INSTRUCTION;
/******** 变量 ********/
int iloc = 0 ; /* 指令存储计数指针,初始为0 */
int dloc = 0 ; /* 数据存储计数指针,初始为0 */
int traceflag = FALSE; /* 指令执行追踪标志,初始为FALSE */
int icountflag = FALSE; /* 指令执行计数标志,初始为FALSE */
/* iMem用于指令存储,为1024长的指令结构数组 */
INSTRUCTION iMem [IADDR_SIZE];
/* dMem用于数据存储,为1024长的整数类型数组 */
int dMem [DADDR_SIZE];
/* reg用于寄存器存储,为8长的整数类型数组 */
int reg [NO_REGS];
/* 指令操作码表,对应寻址模式分为三类 */
char * opCodeTab[]
= {"HALT","IN","OUT","ADD","SUB","MUL","DIV","????",
/* 寄存器寻址模式指令类型 */
"LD","ST","????",
/* 寄存器-内存寻址模式指令类型 */
"LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????"
/* 寄存器-立即数寻址模式指令类型 */
};
/** 单步执行结果状态表 **/
char * stepResultTab[]
= {"OK","Halted","Instruction Memory Fault",
"Data Memory Fault","Division by 0"
};
char pgmName[20]; /* 用于存储程序文件名 */
FILE *pgm ; /* 程序文件指针 */
char in_Line[LINESIZE] ; /* 用于存储一行代码,为121长的字符数组 */
int lineLen ; /* in_Line中行结尾字符位置 */
int inCol ; /* 用于指出在in_Line中的当前字符位置 */
int num ; /* 用于存储当前所得数值 */
char word[WORDSIZE] ; /* 用于存储当前的字,为20长的字符数组 */
char ch ; /* 当前代码行中当前位置上的字符 */
int done ;
/****************************************************/
/* 函数名 opClass */
/* 功 能 指令寻址模式分类函数 */
/* 说 明 该函数对给定的指令操作码枚举值c进行分类 */
/* 返回指令所属寻址模式 */
/****************************************************/
int opClass( int c )
{
/* 如果枚举值c小于opRRLim,则指令为寄存器寻址模式指令类型 */
if ( c <= opRRLim) return ( opclRR );
/* 如果枚举值c小于opRMLim,则指令为寄存器-内存寻址模式指令类型 */
else if ( c <= opRMLim) return ( opclRM );
/* 为寄存器-立即数寻址模式指令类型 */
else return ( opclRA );
}
/********************************************************/
/* 函数名 writeInstruction */
/* 功 能 指令输出函数 */
/* 说 明 该函数将指令存储区中指令以指定格式输出到屏幕 */
/********************************************************/
void writeInstruction ( int loc )
{
/* loc为所要输出的指令在指令存储区中地址,输出到屏幕 */
printf( "%5d: ", loc) ;
/* 输出指令地址loc在0-1023有效的指令存储区地址范围之内 */
if ( (loc >= 0) && (loc < IADDR_SIZE) )
{
/* 输出地址为loc上的指令操作码值iMem[loc].iop和第一操作数iMem[loc].iarg1 */
printf("%6s%3d,", opCodeTab[iMem[loc].iop], iMem[loc].iarg1);
/* 根据指令的寻址模式分类处理 */
switch ( opClass(iMem[loc].iop) )
{
/* 输出指令为寄存器寻址模式指令,以给定形式输出操作数2,操作数3 */
case opclRR: printf("%1d,%1d", iMem[loc].iarg2, iMem[loc].iarg3);
break;
/* 输出指令为寄存器-立即数寻址模式指令,和寄存器-内存寻址模式指令 *
* 以给定形式输出操作数2,操作数3 */
case opclRM:
case opclRA: printf("%3d(%1d)", iMem[loc].iarg2, iMem[loc].iarg3);
break;
}
/* 向屏幕输出换行符 */
printf ("\n") ;
}
} /* writeInstruction */
/****************************************************/
/* 函数名 getCh */
/* 功 能 字符获取函数 */
/* 说 明 如果当前行中字符未读完,则函数返回当前字符 */
/* 否则,函数返回空格字符 */
/****************************************************/
void getCh (void)
{
/* 在当前代码行in_Line中,当前字符列数inCol未超过代码行实际长度lineLen *
* 取得当前行中当前位置的字符,送入ch */
if (++inCol < lineLen)
ch = in_Line[inCol] ;
/* 如果inCol超出当前代码行长度范围,则ch赋为空格 */
else ch = ' ' ;
} /* getCh */
/********************************************************/
/* 函数名 nonBlank */
/* 功 能 非空字符获取函数 */
/* 说 明 如果成功从当前行中取得非空字符,函数返回TRUE */
/* 否则,函数返回FALSE */
/********************************************************/
int nonBlank (void)
{
/* 在当前代码行in_Line中,当前字符位置inCol中为空格字符 *
* 在当前代码行in_Line中,当前字符位置inCol下移,略过空格 */
while ((inCol < lineLen)
&& (in_Line[inCol] == ' ') )
inCol++ ;
/* 在当前代码行in_Line中,遇到非空字符 */
if (inCol < lineLen)
{
/* 取当前字符位置inCol中的字符送入ch, *
* 函数返回TRUE(已定义为1),ch中得到非空字符 */
ch = in_Line[inCol] ;
return TRUE ; }
/* 当前代码行已经读完,将当前字符ch 赋为空格, *
* 函数返回FALSE(已定义为0),ch中为空格字符 */
else
{ ch = ' ' ;
return FALSE ; }
} /* nonBlank */
/****************************************************************/
/* 函数名 getNum */
/* 功 能 数值获取函数 */
/* 说 明 将代码行中连续出现的有加减运算的数term合并计数, */
/* 所的数值送入为num.如果成功得到数值,则函数返回TRUE; */
/* 否则,函数返回FALSE */
/****************************************************************/
int getNum (void)
{ int sign; /* 符号因子 */
int term; /* 用于记录当前录入的局部数值 */
int temp = FALSE; /* 记录函数返回值,初始为假 */
num = 0 ; /* 用于记录所有加减运算后的最终数值结果 */
do
{ sign = 1; /* 符号因子初始为1 */
/* 调用函数nonBlank()略过当前位置的空格后, *
* 所得到的当前非空字符ch为+或-.(+/-的连续出现处理) */
while ( nonBlank() && ((ch == '+') || (ch == '-')) )
{ temp = FALSE ;
/* 当前字符ch为"-"时,符号因子sign设为-1 */
if (ch == '-') sign = - sign ;
/* 取当前代码行中下一字符到当前字符ch中 */
getCh();
}
term = 0 ; /* 当前录入的局部数值初始为0 */
nonBlank(); /* 略过当前位置上的空格 */
/* 当前字符ch为数字,局部数值的循环处理 */
while (isdigit(ch))
{ temp = TRUE ; /* 函数返回值设为TRUE,成功得到数字 */
/* 将字符序列转化为数值形式,进行进位累加 */
term = term * 10 + ( ch - '0' ) ;
getCh(); /* 取当前代码行中下一字符到当前字符ch中 */
}
/* 将局部数值带符号累加,得到最终数值num */
num = num + (term * sign) ;
} while ( (nonBlank()) && ((ch == '+') || (ch == '-')) ) ;
return temp;
} /* getNum */
/****************************************************/
/* 函数名 getWord */
/* 功 能 单词获取函数 */
/* 说 明 函数从当前代码行中获取单词.如果得到字符, */
/* 则函数返回TRUE;否则,函数返回FALSE */
/****************************************************/
int getWord (void)
{
int temp = FALSE; /* 函数返回值初始为FALSE */
int length = 0; /* 单词长度初始为0 */
/* 在当前代码行中成功获取非空字符ch */
if (nonBlank ())
{
/* 当前非空字符ch为字母或数字 */
while (isalnum(ch))
{
/* 当前单词word未超过规定字长WORDSIZE-1(为单词结束字符留一空位) *
* 将当前字符ch读入到单词末尾 */
if (length < WORDSIZE-1) word [length++] = ch ;
getCh() ; /* 取当前代码行中下一字符 */
}
/* 给当前单词word加入结束字符 */
word[length] = '\0';
/* 设置函数返回值,当读入字word非空的时候为TRUE */
temp = (length != 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -