Tiny语言编译器之TM虚拟机开发

  这里的虚拟机是是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);

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值