这里的虚拟机是是Tiny语言的运行环境,源代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define IADDR_SIZE 1024 //指令存储区大小
#define DADDR_SIZE 1024 //数据区大小
#define No_REGS 8 //寄存器数量
#define PC_REG 7 //程序寄存器,只有这一个为专用寄存器
//操作符类型
typedef enum
{
opclRR, //寄存器操作
opclRM, //寄存器&内存操作
opclRA, //寄存器&地址操作
}OPCLASS;
//opCode定义
typedef enum {
opHALT,
opIN,
opOUT,
opADD,
opSUB,
opMUL,
opDIV,
opRRLim,
opLD,
opST,
opRMLim,
opLDA,
opLDC,
opJLT,
opJLE,
opJGT,
opJGE,
opJEQ,
opJNE,
opRALim
} OPCODE;
char * opCodeTab[]
= {"HALT","IN","OUT","ADD","SUB","MUL","DIV","????",
"LD","ST","????",
"LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????"
};
int iloc = 0 ;
int dloc = 0 ;
int traceflag = FALSE;
int icountflag = FALSE;
typedef enum {
srOKAY,
srHALT,
srIMEM_ERR,
srDMEM_ERR,
srZERODIVIDE
} STEPRESULT;
char * stepResultTab[]
= {"OK","Halted","Instruction Memory Fault",
"Data Memory Fault","Division by 0"
};
//指令定义
typedef struct {
int iop ;
int iarg1 ;
int iarg2 ;
int iarg3 ;
} INSTRUCTION;
//指令区
INSTRUCTION iMem[IADDR_SIZE];
//内存区
int dMem[DADDR_SIZE];
//寄存器
int reg[No_REGS];
FILE *pgm;
#define LINESIZE 256
#define WORDSIZE 20
char in_Line[LINESIZE];
int lineLen;
int inCol;
int num;
char word[WORDSIZE];
char ch;
int done;
//取得本行中下一个不是空格的字符
int nonBlank(void)
{
while((inCol<lineLen) && (in_Line[inCol]==' '))
inCol++;
if(inCol<lineLen)
{
ch=in_Line[inCol];
return TRUE;
}
else
{
ch=' ';
return FALSE;
}
}
int atEOL(void)
{ return ( ! nonBlank ());
}
//得到下一个字符
void getCh()
{
if(++inCol<lineLen)
ch=in_Line[inCol];
else
ch = ' ';
}
//跳过一个字符
int skipCh(char c)
{
int temp = FALSE;
if(nonBlank() && (ch==c))
{
getCh();
temp=TRUE;
}
return temp;
}
//得到下一个单词
int getWord()
{
int temp = FALSE;
int length=0;
if(nonBlank())
{
while(isalnum(ch))
{
if(length<WORDSIZE-1) word[length++]=ch;
getCh();
}
word[length] = '\0';
temp = (length!=0);
}
return temp;
}
//得到本行中的一个整数
int getNum()
{
int sign;
int term;
int temp=FALSE;
num=0;
do{
sign =1;
while(nonBlank() && ((ch=='+') || (ch=='-')))
{
temp = FALSE;
if(ch=='-') sign=-sign;
getCh();
}
term = 0;
nonBlank();
while(isdigit(ch))
{
temp = TRUE;
term = term * 10 + ch - '0';
getCh();
}
num = num + (term*sign);
}
while(nonBlank() && ((ch=='+') || (ch=='-')));
return temp;
}
int error( char * msg, int lineNo, int instNo)
{ printf("Line %d",lineNo);
if (instNo >= 0) printf(" (Instruction %d)",instNo);
printf(" %s\n",msg);
return FALSE;
}
int opClass( int c )
{ if ( c <= opRRLim) return ( opclRR );
else if ( c <= opRMLim) return ( opclRM );
else return ( opclRA );
}
//读取指令
int readInstructions()
{
OPCODE op;
int arg1, arg2, arg3;
int regNo;
int loc;
int lineNo;
//寄存器清零
for(regNo=0; regNo<No_REGS; regNo++)
reg[regNo]=0;
//初始化数据区
dMem[0]=DADDR_SIZE-1;
for(loc=1; loc < DADDR_SIZE; loc++)
dMem[loc]=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;
while(!feof(pgm))
{
//读入一行代码
fgets(in_Line, LINESIZE, pgm);
inCol=0;
lineNo++;
lineLen=strlen(in_Line)-1;
if(in_Line[lineLen]=='\n')
in_Line[lineLen]='\0';
if(nonBlank() && ch!='*') /
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg2 ;
t = currentinstruction.iarg3 ;
break;
case opclRM :
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ; //此时m代表数据区地址
if ( (m < 0) || (m > DADDR_SIZE))
return srDMEM_ERR ;
break;
case opclRA :
r = currentinstruction.iarg1 ;
s = currentinstruction.iarg3 ;
m = currentinstruction.iarg2 + reg[s] ;
break;
}
switch ( currentinstruction.iop)
{
case opHALT :
printf("HALT: %1d,%1d,%1d\n",r,s,t);
return srHALT ;
case opIN :
do
{ printf("Enter value for IN instruction: ") ;
fflush (stdin);
fflush (stdout);
gets(in_Line);
lineLen = strlen(in_Line) ;
inCol = 0;
ok = getNum();
if ( ! ok ) printf ("Illegal value\n");
else reg[r] = num;
}
while (! ok);
break;
case opOUT :
printf ("OUT instruction prints: %d\n", reg[r] ) ;
break;
case opADD : reg[r] = reg[s] + reg[t] ; break;
case opSUB : reg[r] = reg[s] - reg[t] ; break;
case opMUL : reg[r] = reg[s] * reg[t] ; break;
case opDIV :
if ( reg[t] != 0 ) reg[r] = reg[s] / reg[t];
else return srZERODIVIDE ;
break;
case opLD : reg[r] = dMem[m] ; break; //数据区复制给寄存器
case opST : dMem[m] = reg[r] ; break; //寄存器复制给数据区
case opLDA : reg[r] = m ; break;
case opLDC : reg[r] = currentinstruction.iarg2 ; break;
case opJLT : if ( reg[r] < 0 ) reg[PC_REG] = m ; break;
case opJLE : if ( reg[r] <= 0 ) reg[PC_REG] = m ; break;
case opJGT : if ( reg[r] > 0 ) reg[PC_REG] = m ; break;
case opJGE : if ( reg[r] >= 0 ) reg[PC_REG] = m ; break;
case opJEQ : if ( reg[r] == 0 ) reg[PC_REG] = m ; break;
case opJNE : if ( reg[r] != 0 ) reg[PC_REG] = m ; break;
}
return srOKAY ;
return srOKAY;
}
//执行指令
int doCommand (void)
{ char cmd;
int stepcnt=0, i;
int printcnt;
int stepResult;
int regNo, loc;
do
{ printf ("Enter command: ");
fflush (stdin);
fflush (stdout);
gets(in_Line);
lineLen = strlen(in_Line);
inCol = 0;
}
while (! getWord ());
cmd = word[0] ;
switch ( cmd )
{ case 't' :
traceflag = ! traceflag ;
printf("Tracing now ");
if ( traceflag ) printf("on.\n"); else printf("off.\n");
break;
case 'h' :
printf("Commands are:\n");
printf(" s(tep <n> "\
"Execute n (default 1) TM instructions\n");
printf(" g(o "\
"Execute TM instructions until HALT\n");
printf(" r(egs "\
"Print the contents of the registers\n");
printf(" i(Mem <b <n>> "\
"Print n iMem locations starting at b\n");
printf(" d(Mem <b <n>> "\
"Print n dMem locations starting at b\n");
printf(" t(race "\
"Toggle instruction trace\n");
printf(" p(rint "\
"Toggle print of total instructions executed"\
" ('go' only)\n");
printf(" c(lear "\
"Reset simulator for new execution of program\n");
printf(" h(elp "\
"Cause this list of commands to be printed\n");
printf(" q(uit "\
"Terminate the simulation\n");
break;
case 'p' :
icountflag = ! icountflag ;
printf("Printing instruction count now ");
if ( icountflag ) printf("on.\n"); else printf("off.\n");
break;
case 's' :
if ( atEOL ()) stepcnt = 1;
else if ( getNum ()) stepcnt = abs(num);
else printf("Step count?\n");
break;
case 'g' : stepcnt = 1 ; break;
case 'r' : //输出寄存器的内容
for (i = 0; i < No_REGS; i++)
{ printf("%1d: %4d ", i,reg[i]);
if ( (i % 4) == 3 ) printf ("\n");
}
break;
case 'i' : //输出指令区的内容
printcnt = 1 ;
if ( getNum ())
{ iloc = num ;
if ( getNum ()) printcnt = num ;
}
if ( ! atEOL ())
printf ("Instruction locations?\n");
else
{ while ((iloc >= 0) && (iloc < IADDR_SIZE)
&& (printcnt > 0) )
{ writeInstruction(iloc);
iloc++ ;
printcnt-- ;
}
}
break;
case 'd' : //输出数据区的内容
printcnt = 1 ;
if ( getNum ())
{ dloc = num ;
if ( getNum ()) printcnt = num ;
}
if ( ! atEOL ())
printf("Data locations?\n");
else
{ while ((dloc >= 0) && (dloc < DADDR_SIZE)
&& (printcnt > 0))
{ printf("%5d: %5d\n",dloc,dMem[dloc]);
dloc++;
printcnt--;
}
}
break;
case 'c' : //设置寄存器和数据区的内容为初始值
iloc = 0;
dloc = 0;
stepcnt = 0;
for (regNo = 0; regNo < No_REGS ; regNo++)
reg[regNo] = 0 ;
dMem[0] = DADDR_SIZE - 1 ;
for (loc = 1 ; loc < DADDR_SIZE ; loc++)
dMem[loc] = 0 ;
break;
case 'q' : return FALSE;
default : printf("Command %c unknown.\n", cmd); break;
}
stepResult = srOKAY;
if ( stepcnt > 0 )
{ if ( cmd == 'g' )
{ stepcnt = 0;
while (stepResult == srOKAY)
{ iloc = reg[PC_REG] ;
if ( traceflag ) writeInstruction( iloc ) ;
stepResult = stepTM ();
stepcnt++;
}
if ( icountflag )
printf("Number of instructions executed = %d\n",stepcnt);
}
else
{ while ((stepcnt > 0) && (stepResult == srOKAY))
{ iloc = reg[PC_REG] ;
if ( traceflag ) writeInstruction( iloc ) ;
stepResult = stepTM ();
stepcnt-- ;
}
}
printf( "%s\n",stepResultTab[stepResult] );
}
return TRUE;
}
//主函数
void main(int argc, char *argv[])
{
char pgmName[120];
if(argc != 2)
{
fprintf(stderr, "usage: %s <filename>\n", argv[0]);
exit(1);
}
strcpy(pgmName, argv[1]);
if(strchr(pgmName, '.')==NULL)
strcat(pgmName, ".tm");
pgm = fopen(pgmName, "r");
if(pgm==NULL)
{
fprintf(stderr, "File %s not found\n", pgmName);
exit(1);
}
//把指令加载到指令区
if(!readInstructions())
exit(1);
printf("TM simulation(enter h for help)...\n");
//执行指令
do
{
done=doCommand();
} while(!done);
}