📄 tm.cpp
字号:
}
return temp;
} /* getWord */
/************************************************************/
/* 函数名 skipCh */
/* 功 能 字符空过函数 */
/* 说 明 如果当前位置上字符为函数指定的字符,则空过该字符, */
/* 函数返回TRUE;否则函数返回FALSE */
/************************************************************/
int skipCh ( char c )
{ int temp = FALSE;
/* 当前位置上字符为函数指定字符c */
if ( nonBlank() && (ch == c) )
{ getCh(); /* 空过当前字符c,取下一字符 */
temp = TRUE; /* 空过指定字符c,函数返回TRUE */
}
return temp;
} /* skipCh */
/************************************/
/* 函数名 atEOL */
/* 功 能 行结束判断函数 */
/* 说 明 当前行是否结束的判断函数 */
/************************************/
int atEOL(void)
{ return ( ! nonBlank ()); /* 如果当前行中没有非空字符,则函数返回TRUE */
} /* atEOL */
/****************************************************/
/* 函数名 error */
/* 功 能 错误处理函数 */
/* 说 明 函数输出错误行号,指令地址标号和错误信息 */
/****************************************************/
int error( char * msg, int lineNo, int instNo)
{
/* 输出错误出现位置行号lineNo */
printf("Line %d",lineNo);
/* 输出错误指令地址标号instNo */
if (instNo >= 0) printf(" (Instruction %d)",instNo);
/* 输出错误信息msg */
printf(" %s\n",msg);
return FALSE;
} /* error */
/********************************************************/
/* 函数名 readInstructions */
/* 功 能 指令文件读入函数 */
/* 说 明 将指令文件中的指令逐条读入到指令存储区iMem */
/********************************************************/
int readInstructions (void)
{
OPCODE op; /* 当前指令操作码 */
int arg1, arg2, arg3; /* 当前指令操作数 */
int loc, regNo, lineNo;
/* 将8个寄存器内容初始化为0 */
for (regNo = 0 ; regNo < NO_REGS ; regNo++)
reg[regNo] = 0 ;
/* dMem为数据存储区,0地址单元dMem[0]的值赋为数据存储区高端地址1023 *
* 此数值将在目标程序运行时由程序的先驱指令读入到mp寄存器中 */
dMem[0] = DADDR_SIZE - 1 ;
/* 将数据存储数区内除0地址单元外的各单元初始化为0 */
for (loc = 1 ; loc < DADDR_SIZE ; loc++)
dMem[loc] = 0 ;
/* 将指令存储区中各单元初始化为指令;HALT 0,0,0 */
for (loc = 0 ; loc < IADDR_SIZE ; loc++)
{ iMem[loc].iop = opHALT ;
iMem[loc].iarg1 = 0 ;
iMem[loc].iarg2 = 0 ;
iMem[loc].iarg3 = 0 ;
}
lineNo = 0 ; /* lineNo用于记录当前代码指令行号 */
/* 不是指定文件pgm的文件结尾 */
while (! feof(pgm))
{
/* 从指定文件pgm中读入119个字符到当前代码行in_Line */
fgets( in_Line, LINESIZE-2, pgm ) ;
inCol = 0 ; /* 当前代码行in_Line中当前字符位置inCol初始为0 */
lineNo++; /* 当前代码行行号加1 */
/* 当前代码行in_Line行结尾字符位置赋给lineLen */
lineLen = strlen(in_Line)-1 ;
/* 如果源行结束字符是'\n',则更换行结束字符为'\0' */
if (in_Line[lineLen]=='\n') in_Line[lineLen] = '\0' ;
/* 源行没有行结束字符,加上结束字符'\0' */
else in_Line[++lineLen] = '\0';
/* 当前字符不是"*",即不是注释语句,应该是指令语句 */
if ( (nonBlank()) && (in_Line[inCol] != '*') )
{
/* 当前字符不是数字,报地址错,并给出行号lineNo */
if (! getNum())
return error("Bad location", lineNo,-1);
/* 将所得数值赋给当前代码地址标号loc */
loc = num;
/* 代码地址标号loc超出指令存储区地址IADDR_SIZE,报错 */
if (loc > IADDR_SIZE)
return error("Location too large",lineNo,loc);
/* 代码地址标号loc后面缺少冒号,报缺少冒号错 */
if (! skipCh(':'))
return error("Missing colon", lineNo,loc);
/* 当前位置不是单词,报缺少指令操作码错 */
if (! getWord ())
return error("Missing opcode", lineNo,loc);
/* 初始查表指针op,op指向操作码表表首,值为opHALT */
op = opHALT ;
/* 查操作码表opCodeTab,只比较当前字word中的前四个字符 *
* 因为所有定义的操作码中,最长操作码HALT长度只为四 */
while ((op < opRALim)
&& (strncmp(opCodeTab[op], word, 4) != 0) )
op = (enum opcode)(op+1);
/* 当前单词word中指定的操作码不在操作码表opCodeTab中,报非法操作码错误 */
if (strncmp(opCodeTab[op], word, 4) != 0)
return error("Illegal opcode", lineNo,loc);
/* 对查表得到的操作码值op的寻址模式,进行分类处理 */
switch ( opClass(op) )
{ case opclRR : /* 寄存器寻址模式操作码 */
/* 第一寄存器操作数错,非0-7之间数字, *
* 输出错误信息,行号lineNo,代码地址标号loc */
if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) )
return error("Bad first register", lineNo,loc);
/* 将第一操作数arg1赋值为当前数值num */
arg1 = num;
/* 第一操作数后漏掉","分隔符,报错 */
if ( ! skipCh(','))
return error("Missing comma", lineNo, loc);
/* 第二寄存器操作数错,非0-7之间数字, *
* 输出错误信息,行号lineNo,代码地址标号loc */
if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) )
return error("Bad second register", lineNo, loc);
/* 将第二个操作数arg2赋值为当前数值num */
arg2 = num;
/* 第二操作数后漏掉","分隔符,报错 */
if ( ! skipCh(','))
return error("Missing comma", lineNo,loc);
/* 第三寄存器操作数错,非0-7之间数字,报错 */
if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) )
return error("Bad third register", lineNo,loc);
/* 将第三操作数arg3赋值为当前数值num */
arg3 = num;
break;
/* 寄存器-内存寻址模式 *
* 寄存器-立即数寻址模式 */
case opclRM :
case opclRA :
/* 第一寄存器操作数错,非0-7之间数字,报错 */
if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) )
return error("Bad first register", lineNo,loc);
/* 将第一操作数arg1赋值为当前数值num */
arg1 = num;
/* 第一操作数后面漏掉","分隔符,报错 */
if ( ! skipCh(','))
return error("Missing comma", lineNo,loc);
/* 第二偏移地址操作数错误,非数字偏移地址,报错 */
if (! getNum ())
return error("Bad displacement", lineNo,loc);
/* 将第二偏移地址操作数arg2赋值为当前地址num */
arg2 = num;
/* 第二偏移地址操作数后漏掉"(",或者是","分隔符,报错 */
if ( ! skipCh('(') && ! skipCh(',') )
return error("Missing LParen", lineNo,loc);
/* 第二寄存器操作数错,非0-7之间数字,报错 */
if ( (! getNum ()) || (num < 0) || (num >= NO_REGS))
return error("Bad second register", lineNo,loc);
/* 将第三操作数arg3赋值为当前数值num */
arg3 = num;
break;
}
/* 按代码地址标号loc将指令存储到指令存储区iMem */
iMem[loc].iop = op;
iMem[loc].iarg1 = arg1;
iMem[loc].iarg2 = arg2;
iMem[loc].iarg3 = arg3;
}
}
return TRUE;
} /* readInstructions */
/************************************************/
/* 函数名 stepTM */
/* 功 能 TM机单步执行函数 */
/* 说 明 函数为一条指令解释执行,完成指令动作. */
/************************************************/
STEPRESULT stepTM (void)
{
/* currentinstruction 用于存储当前将执行的指令 */
INSTRUCTION currentinstruction ;
int pc ; /* 程序计数器 */
int r,s,t,m ; /* 指令操作数 */
int ok ;
/* pc设置为第7个寄存器reg[7]的值,为程序计数器 */
pc = reg[PC_REG] ;
if ( (pc < 0) || (pc > IADDR_SIZE) )
/* pc的值不是指令存储区的有效地址,报指令存储错,函数返回srIMEM_ERR */
return srIMEM_ERR ;
/* pc的值为有效指令地址,将程序计数器reg[PC_REG]的值加1 */
reg[PC_REG] = pc + 1 ;
/* 从指令存储区iMem之中取出当前指令 */
currentinstruction = iMem[ pc ] ;
/* 对取出的指令的寻址模式分类处理,初始化各个指令操作数变量 */
switch (opClass(currentinstruction.iop) )
{ case opclRR : /* 寄存器寻址模式 */
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg2 ;
t = currentinstruction.iarg3 ;
break;
case opclRM : /* 寄存器-内存寻址模式 */
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
/* 操作数m非数据存储区有效地址,报数据存储错,函数返回srDMEM_ERR */
if ( (m < 0) || (m > DADDR_SIZE))
return srDMEM_ERR ;
break;
case opclRA : /* 寄存器-立即数寻址模式 */
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
break;
} /* case */
/* 对将执行指令的操作码值进行分类处理,输出指令信息, *
* 完成指令动作,返回相应结果状态 */
switch ( currentinstruction.iop)
{
/******************** RR指令 ******************/
/* 格式化屏幕显示HALT(停止)指令,返回状态srHALT(停止) */
case opHALT :
printf("HALT: %1d,%1d,%1d\n",r,s,t);
return srHALT ;
/**********************************************/
case opIN :
do
{
/* 屏幕显示用户提示信息,提示用户为指令输入数值 */
printf("Enter value for IN instruction: ") ;
/* 刷新标准输入stdin流和标准输出stdout流 */
fflush (stdin);
fflush (stdout);
/* 从标准输入流stdin取得用户输入的数值,送入缓冲器in_Line */
gets(in_Line);
/* 取得用户输入数值的实际长度lineLen */
lineLen = strlen(in_Line) ;
inCol = 0;
/* 如从缓冲器in_Line中成功取得数字,则ok为TRUE */
ok = getNum();
/* 用户输入的不是数字,报非法IN指令输入错误 */
if ( ! ok ) printf ("Illegal value\n");
/* 将输入的数值num送入IN指令操作数r指定的寄存器reg[r] */
else reg[r] = num;
}
/* 如果用户输入不合法,重复要求用户输入,直到输入合法数值 */
while (! ok);
break;
/**********************************************/
/* 屏幕显示OUT指令执行的结果信息 */
case opOUT :
printf ("OUT instruction prints: %d\n", reg[r] ) ;
break;
/**********************************************/
/* 完成ADD指令操作 */
case opADD : reg[r] = reg[s] + reg[t] ; break;
/**********************************************/
/* 完成SUB指令操作 */
case opSUB : reg[r] = reg[s] - reg[t] ; break;
/**********************************************/
/* 完成MUL指令操作 */
case opMUL : reg[r] = reg[s] * reg[t] ; break;
/**********************************************/
case opDIV :
/* 对于除法指令,若除数为0,则报除零错误, *
* 并返回srZERODIVIDE;否则,完成除法操作 */
if ( reg[t] != 0 ) reg[r] = reg[s] / reg[t];
else return srZERODIVIDE ;
break;
/***************** RM 指令 ********************/
/* 将数据存储区dMem中的数据载入到寄存器reg[r] */
case opLD : reg[r] = dMem[m] ; break;
/**********************************************/
/* 将寄存器reg[r]中的数据写入到数据存储区dMem */
case opST : dMem[m] = reg[r] ; break;
/***************** RA 指令 ********************/
/* 将寄存器reg[r]赋值为操作数m的值 */
case opLDA : reg[r] = m ; break;
/**********************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -