The tmserver is the execution environment of compiled assembly code by the tiny language compiler. The main function of the tm is to read and execute the assembly code of TM. It has a simplified command-level CPU equivalent to a general computer. The TM assembly language is almost the same as the general Intel assembly language, including register addressing and operators. It is easy to understand. A typical code example is LD (1). 10 (1) indicates that the address in register 1 is the base address, 10 is the offset address, and the addressing result is placed in the register 0. Mul 0, 1, 0 indicates that the result of multiplying register 1 and register 2 is put into Register 0. Then, the source code of the tmserver is analyzed in part of the analysis. TM source code is as follows:
/****************************************************//* File: tm.c *//* The TM ("Tiny Machine") computer *//* Compiler Construction: Principles and Practice *//* Kenneth C. Louden *//****************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif/******* const *******/#define IADDR_SIZE 1024 /* increase for large programs */#define DADDR_SIZE 1024 /* increase for large programs */#define NO_REGS 8#define PC_REG 7#define LINESIZE 121#define WORDSIZE 20/******* type *******/typedef enum { opclRR, /* reg operands r,s,t */ opclRM, /* reg r, mem d+s */ opclRA /* reg r, int d+s */ } OPCLASS;typedef enum { /* RR instructions */ opHALT, /* RR halt, operands are ignored */ opIN, /* RR read into reg(r); s and t are ignored */ opOUT, /* RR write from reg(r), s and t are ignored */ opADD, /* RR reg(r) = reg(s)+reg(t) */ opSUB, /* RR reg(r) = reg(s)-reg(t) */ opMUL, /* RR reg(r) = reg(s)*reg(t) */ opDIV, /* RR reg(r) = reg(s)/reg(t) */ opRRLim, /* limit of RR opcodes */ /* RM instructions */ opLD, /* RM reg(r) = mem(d+reg(s)) */ opST, /* RM mem(d+reg(s)) = reg(r) */ opRMLim, /* Limit of RM opcodes */ /* RA instructions */ opLDA, /* RA reg(r) = d+reg(s) */ opLDC, /* RA reg(r) = d ; reg(s) is ignored */ opJLT, /* RA if reg(r)<0 then reg(7) = d+reg(s) */ opJLE, /* RA if reg(r)<=0 then reg(7) = d+reg(s) */ opJGT, /* RA if reg(r)>0 then reg(7) = d+reg(s) */ opJGE, /* RA if reg(r)>=0 then reg(7) = d+reg(s) */ opJEQ, /* RA if reg(r)==0 then reg(7) = d+reg(s) */ opJNE, /* RA if reg(r)!=0 then reg(7) = d+reg(s) */ opRALim /* Limit of RA opcodes */ } OPCODE;typedef enum { srOKAY, srHALT, srIMEM_ERR, srDMEM_ERR, srZERODIVIDE } STEPRESULT;typedef struct { int iop ; int iarg1 ; int iarg2 ; int iarg3 ; } INSTRUCTION;/******** vars ********/int iloc = 0 ;int dloc = 0 ;int traceflag = FALSE;int icountflag = FALSE;INSTRUCTION iMem [IADDR_SIZE];int dMem [DADDR_SIZE];int reg [NO_REGS];char * opCodeTab[] = {"HALT","IN","OUT","ADD","SUB","MUL","DIV","????", /* RR opcodes */ "LD","ST","????", /* RM opcodes */ "LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????" /* RA opcodes */ };char * stepResultTab[] = {"OK","Halted","Instruction Memory Fault", "Data Memory Fault","Division by 0" };char pgmName[20];FILE *pgm ;char in_Line[LINESIZE] ;int lineLen ;int inCol ;int num ;char word[WORDSIZE] ;char ch ;int done ;/********************************************/int opClass( int c ){ if ( c <= opRRLim) return ( opclRR ); else if ( c <= opRMLim) return ( opclRM ); else return ( opclRA );} /* opClass *//********************************************/void writeInstruction ( int loc ){ printf( "%5d: ", loc) ; if ( (loc >= 0) && (loc < IADDR_SIZE) ) { printf("%6s%3d,", opCodeTab[iMem[loc].iop], iMem[loc].iarg1); switch ( opClass(iMem[loc].iop) ) { case opclRR: printf("%1d,%1d", iMem[loc].iarg2, iMem[loc].iarg3); break; case opclRM: case opclRA: printf("%3d(%1d)", iMem[loc].iarg2, iMem[loc].iarg3); break; } printf ("\n") ; }} /* writeInstruction *//********************************************/void getCh (void){ if (++inCol < lineLen) ch = in_Line[inCol] ; else ch = ‘ ‘ ;} /* getCh *//********************************************/int nonBlank (void){ while ((inCol < lineLen) && (in_Line[inCol] == ‘ ‘) ) inCol++ ; if (inCol < lineLen) { ch = in_Line[inCol] ; return TRUE ; } else { ch = ‘ ‘ ; return FALSE ; }} /* nonBlank *//********************************************/int getNum (void){ 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;} /* getNum *//********************************************/int getWord (void){ 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;} /* getWord *//********************************************/int skipCh ( char c ){ int temp = FALSE; if ( nonBlank() && (ch == c) ) { getCh(); temp = TRUE; } return temp;} /* skipCh *//********************************************/int atEOL(void){ return ( ! nonBlank ());} /* atEOL *//********************************************/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;} /* error *//********************************************/int readInstructions (void){ OPCODE op; int arg1, arg2, arg3; int loc, regNo, 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-2, pgm ) ; inCol = 0 ; lineNo++; lineLen = strlen(in_Line)-1 ; if (in_Line[lineLen]==‘\n‘) in_Line[lineLen] = ‘\0‘ ; else in_Line[++lineLen] = ‘\0‘; if ( (nonBlank()) && (in_Line[inCol] != ‘*‘) ) { if (! getNum()) return error("Bad location", lineNo,-1); loc = num; if (loc > IADDR_SIZE) return error("Location too large",lineNo,loc); if (! skipCh(‘:‘)) return error("Missing colon", lineNo,loc); if (! getWord ()) return error("Missing opcode", lineNo,loc); op = opHALT ; while ((op < opRALim) && (strncmp(opCodeTab[op], word, 4) != 0) ) op++ ; if (strncmp(opCodeTab[op], word, 4) != 0) return error("Illegal opcode", lineNo,loc); switch ( opClass(op) ) { case opclRR : /***********************************/ if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) return error("Bad first register", lineNo,loc); arg1 = num; if ( ! skipCh(‘,‘)) return error("Missing comma", lineNo, loc); if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) return error("Bad second register", lineNo, loc); arg2 = num; if ( ! skipCh(‘,‘)) return error("Missing comma", lineNo,loc); if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) return error("Bad third register", lineNo,loc); arg3 = num; break; case opclRM : case opclRA : /***********************************/ if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) return error("Bad first register", lineNo,loc); arg1 = num; if ( ! skipCh(‘,‘)) return error("Missing comma", lineNo,loc); if (! getNum ()) return error("Bad displacement", lineNo,loc); arg2 = num; if ( ! skipCh(‘(‘) && ! skipCh(‘,‘) ) return error("Missing LParen", lineNo,loc); if ( (! getNum ()) || (num < 0) || (num >= NO_REGS)) return error("Bad second register", lineNo,loc); arg3 = num; break; } iMem[loc].iop = op; iMem[loc].iarg1 = arg1; iMem[loc].iarg2 = arg2; iMem[loc].iarg3 = arg3; } } return TRUE;} /* readInstructions *//********************************************/STEPRESULT stepTM (void){ INSTRUCTION currentinstruction ; int pc ; int r,s,t,m ; int ok ; pc = reg[PC_REG] ; if ( (pc < 0) || (pc > IADDR_SIZE) ) return srIMEM_ERR ; reg[PC_REG] = pc + 1 ; 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] ; 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 instructions */ case opHALT : /***********************************/ printf("HALT: %1d,%1d,%1d\n",r,s,t); return srHALT ; /* break; */ 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; /*************** RM instructions ********************/ case opLD : reg[r] = dMem[m] ; break; case opST : dMem[m] = reg[r] ; break; /*************** RA instructions ********************/ 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; /* end of legal instructions */ } /* case */ return srOKAY ;} /* stepTM *//********************************************/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; /* break; */ default : printf("Command %c unknown.\n", cmd); break; } /* case */ 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;} /* doCommand *//********************************************//* E X E C U T I O N B E G I N S H E R E *//********************************************/main( int argc, char * argv[] ){ if (argc != 2) { printf("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) { printf("file ‘%s‘ not found\n",pgmName); exit(1); } /* read the program */ if ( ! readInstructions ()) exit(1) ; /* switch input file to terminal */ /* reset( input ); */ /* read-eval-print */ printf("TM simulation (enter h for help)...\n"); do done = ! doCommand (); while (! done ); printf("Simulation done.\n"); return 0;}