home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1998-06-20 | 8.2 KB | 320 lines | [ TEXT/CWIE]
/* Problem 10 - Interpreter Write an interpreter for this simple 32-bit integer language with 26 registers labeled A-Z. type RegisterArray = array[0..25] of UInt32; procedure Interpret( source: Handle; var result: RegisterArray ); source consists of a number of lines of the form: [<label>:][<tab><instruction><tab><operand-list>]<cr> <label> is a sequence of at least two alphanumerics (0-9a-zA-Z_) (casesensitive). <operand-list> is a sequence of operators seperated by commas other than the tabs and crs, no white space is allowed. <instruction> (and appropriate operands are: MOVE <value>,<register> (set <register> to <value>) ADD <value1>,<value2>,<register> (set <register> to <value1>+<value2>) SUB <value1>,<value2>,<register> (set <register> to <value1>-<value2>) JMP <label> (jump to line labeled with <label>) JEQ <value1>,<value2>,<label> (jump to <label> if <value1> = <value2>) JLE <value1>,<value2>,<label> (jump to <label> if <value1> <= <value2>) JSR <label> (jump to subroutine at <label>) RTS (return from subroutine) PUSH <value> (push value on to stack) POP <register> (pop value from stack) [others?] <register> is a single letter <number> is an optioanl minus sign followed by decimal digits <value> is a <register> or a <number> Note that the data stack and subroutine stack are independent stacks. A RTS is used to stop the program (that is, consider that you have JSRed to the initial line of the source handle). For example: PUSH 10 JSR setA JSE setB RTS setA: POP A RTS setB: MOVE A,B RTS Interpret takes the source handle and JSRs to it, presetting the registers according to the register array. When the code returns, the register array is set to the final value of all the registers. Both subroutine and data stacks should be large (at least 1000 entries each). */ #include "Solution.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #define NOTDELIMITER(x) (((x)!='\t') && ((x)!=',') && ((x)!='\r')) // Fill in your solution and then submit this folder // Team Name: FILL IN YOUR TEAM NAME! typedef enum {kNULL=0,kMove=1,kAdd,kSub,kJmp,kJeq,kJle,kJsr,kRts,kPush,kPop} OpCode; char *OpCodeStrings[] = { " ","MOVE","ADD","SUB","JMP","JEQ","JLE","JSR","RTS","PUSH","POP" }; #define kNumCommands (sizeof(OpCodeStrings)/sizeof(char *)) typedef struct Instruction { UInt32 programCounter; UInt32 branchPC; char *label; char *branchLabel; SInt32 value1; SInt32 value2; SInt32 reg; OpCode theCode; UInt32 labelLength; Boolean value1IsRegister; Boolean value2IsRegister; } Instruction; static char *GetValue(char *p, SInt32 *value, Boolean *valueIsRegister) { char s[256]; char *q = s; if ((*p>='A') && (*p<='Z')) { *valueIsRegister = true; *value = *p-'A'; p++; } else { while (NOTDELIMITER(*p) ) *q++=*p++; *q++=0; sscanf( s, "%ld", value ); } return p+1; /* skip comma, cr, or tab */ } static char *FindLabel(char *p, UInt32 *branchPC, Instruction *program, long numInstructions) { int i; Boolean foundIt=false; for (i=0; i<numInstructions; i++,program++) { if (program->label) if (0 == strncmp(p,program->label,program->labelLength)) { foundIt = true; *branchPC = i; break; } } if (!foundIt) DebugStr("\p did not find label"); while (*p++!='\r') ; return p; } #define PUSH(pc,stack,stackCtr) \ stack[stackCtr] = pc; \ stackCtr++; #define POP(val,stack,stackCtr) \ val = stack[--stackCtr]; static void GetValue12(Instruction *pc, RegisterArray reg, SInt32 *val1, SInt32 *val2) { if (pc->value1IsRegister) { *val1 = reg[pc->value1]; } else { *val1 = pc->value1; } if (pc->value2IsRegister) { *val2 = reg[pc->value2]; } else { *val2 = pc->value2; } } static void ParseInstructions(char *sourceP, Instruction *program, int instructionCount) { char *p; int i,j,opCodeLen; Instruction *pc; p = sourceP; for (i=0; i<instructionCount; i++) { pc = &program[i]; pc->programCounter = i; pc->label = 0; pc->branchPC = 0xffffffff; pc->branchLabel = 0; pc->value1 = 0xffffffff; pc->value2 = 0xffffffff; pc->reg = 0xffffffff; pc->theCode = kNULL; pc->value1IsRegister = false; pc->value2IsRegister = false; if (*p != '\t') { char *labelStart = p; pc->label = p; while (*p!=':') p++; pc->labelLength = p - labelStart; p++; /* skip colon */ if (*p=='\t') p++; } else { p++; } opCodeLen = 0; while (NOTDELIMITER(*(p+opCodeLen))) opCodeLen++; for (j=1; j<kNumCommands; j++) { if (0==strncmp(p,OpCodeStrings[j],opCodeLen)) { pc->theCode = (OpCode)j; } } p += opCodeLen+1; switch (pc->theCode) { Boolean betterBeTrue; case kMove: p = GetValue(p,&pc->value1,&pc->value1IsRegister); p = GetValue(p,&pc->reg,&betterBeTrue); break; case kAdd: case kSub: p = GetValue(p,&pc->value1,&pc->value1IsRegister); p = GetValue(p,&pc->value2,&pc->value2IsRegister); p = GetValue(p,&pc->reg,&betterBeTrue); if (!betterBeTrue) DebugStr("\p problem parsing Add/Sub register"); break; case kJmp: case kJsr: pc->branchLabel = p; while (*p++!='\r') ; break; case kJeq: case kJle: p = GetValue(p,&pc->value1,&pc->value1IsRegister); p = GetValue(p,&pc->value2,&pc->value2IsRegister); pc->branchLabel = p; while (*p++!='\r') ; break; case kRts: break; case kPush: p = GetValue(p,&pc->value1,&pc->value1IsRegister); break; case kPop: p = GetValue(p,&pc->reg,&betterBeTrue); if (!betterBeTrue) DebugStr("\p problem parsing Pop register"); break; default: DebugStr("\p could not parse instruction"); } } /* parse labels */ for (i=0; i<instructionCount; i++) { pc = &program[i]; if (pc->branchLabel != 0) { p = FindLabel(pc->branchLabel,&pc->branchPC,program,instructionCount); } } } static void Execute(Instruction *program, RegisterArray reg) { Instruction *pc; UInt32 pcIndex = 0; SInt32 *subroutineStack,*dataStack; SInt32 subroutineStackCtr = 0; SInt32 dataStackCtr = 0; Boolean done; subroutineStack = (SInt32 *)NewPtrClear(1000*sizeof(UInt32)); if (0==subroutineStack) DebugStr("\p problem allocating subroutineStack"); dataStack = (SInt32 *)NewPtrClear(1000*sizeof(UInt32)); if (0==dataStack) DebugStr("\p problem allocating dataStack"); done = false; while (!done) { SInt32 val1,val2; pc = &program[pcIndex]; GetValue12(pc,reg,&val1,&val2); switch (pc->theCode) { case kMove: if (pc->value1IsRegister) { reg[pc->reg] = reg[pc->value1]; } else { reg[pc->reg] = pc->value1; } pcIndex++; break; case kAdd: reg[pc->reg] = val1+val2; pcIndex++; break; case kSub: reg[pc->reg] = val1-val2; pcIndex++; break; case kJmp: pcIndex = pc->branchPC; break; case kJsr: PUSH(pcIndex+1,subroutineStack,subroutineStackCtr) pcIndex = pc->branchPC; break; case kJeq: if (val1==val2) pcIndex = pc->branchPC; else pcIndex++; break; case kJle: if (val1<=val2) pcIndex = pc->branchPC; else pcIndex++; break; case kRts: if (subroutineStackCtr<=0) done=true; else POP(pcIndex,subroutineStack,subroutineStackCtr) break; case kPush: PUSH(val1,dataStack,dataStackCtr) pcIndex++; break; case kPop: POP(reg[pc->reg],dataStack,dataStackCtr) pcIndex++; break; default: DebugStr("\p should not get here"); break; } } DisposePtr((Ptr)dataStack); DisposePtr((Ptr)subroutineStack); } pascal void Interpret( Handle source, RegisterArray result ) { char *sourceP = *source; char *p; RegisterArray reg; Instruction *program; int i,instructionCount; SInt32 sourceCharCount = GetHandleSize(source); /* initialize registers */ for (i=0; i<26; i++) reg[i]=result[i]; instructionCount = 0; /* count instructions */ p = sourceP; while (p < sourceP + sourceCharCount) { if (*p++=='\r') ++instructionCount; } program = (Instruction *)NewPtrClear(instructionCount*sizeof(Instruction)); if (0==program) DebugStr("\p not enough mem for program"); /* parse instructions */ ParseInstructions(sourceP,program,instructionCount); /* execute instructions */ Execute(program,reg); DisposePtr((Ptr)program); for (i=0; i<26; i++) result[i]=reg[i]; }