public static void Main(string[] args) { // check that arguments have been supplied if (args.Length != 2) { Console.WriteLine("missing args"); System.Environment.Exit(1); } // attempt to open data file InFile data = new InFile(args[0]); if (data.OpenError()) { Console.WriteLine("cannot open " + args[0]); System.Environment.Exit(1); } // attempt to open results file OutFile results = new OutFile(args[1]); if (results.OpenError()) { Console.WriteLine("cannot open " + args[1]); System.Environment.Exit(1); } // various initializations int total = 0; IntSet mySet = new IntSet(); IntSet smallSet = new IntSet(1, 2, 3, 4, 5); string smallSetStr = smallSet.ToString(); // read and process data file int item = data.ReadInt(); while (!data.NoMoreData()) { total = total + item; if (item > 0) mySet.Incl(item); item = data.ReadInt(); } // write various results to output file results.Write("total = "); results.WriteLine(total, 5); results.WriteLine("unique positive numbers " + mySet.ToString()); results.WriteLine("union with " + smallSetStr + " = " + mySet.Union(smallSet).ToString()); results.WriteLine("intersection with " + smallSetStr + " = " + mySet.Intersection(smallSet).ToString()); results.Close(); }
static void Trace(OutFile results, int pcNow) { // Simple trace facility for run time debugging results.Write(" PC:"); results.Write(pcNow, 5); results.Write(" FP:"); results.Write(cpu.fp, 5); results.Write(" SP:"); results.Write(cpu.sp, 5); results.Write(" HP:"); results.Write(cpu.hp, 5); results.Write(" TOS:"); if (cpu.sp < memSize) results.Write(mem[cpu.sp], 5); else results.Write(" ????"); results.Write(" " + mnemonics[cpu.ir], -8); switch (cpu.ir) { case PVM.brn: case PVM.bze: case PVM.dsp: case PVM.lda: case PVM.ldc: case PVM.prns: results.Write(mem[cpu.pc], 7); break; default: break; } results.WriteLine(); }
static void StackDump(OutFile results, int pcNow) { // Dump local variable and stack area - useful for debugging int onLine = 0; results.Write("\nStack dump at " + pcNow); results.Write(" SP:"); results.Write(cpu.sp, 4); results.Write(" FP:"); results.Write(cpu.fp, 4); results.Write(" HP:"); results.Write(cpu.hp, 4); results.Write(" HB:"); results.WriteLine(heapBase, 4); for (int i = stackBase - 1; i >= cpu.sp; i--) { results.Write(i, 7); results.Write(mem[i], 5); onLine++; if (onLine % 8 == 0) results.WriteLine(); } results.WriteLine(); }
static void PostMortem(OutFile results, int pcNow) { // Reports run time error and position results.WriteLine(); switch (ps) { case badMem: results.Write("Memory violation"); break; case badData: results.Write("Invalid data"); break; case noData: results.Write("No more data"); break; case divZero: results.Write("Division by zero"); break; case badOp: results.Write("Illegal opcode"); break; case badInd: results.Write("Subscript out of range"); break; case badVal: results.Write("Value out of range"); break; case badAdr: results.Write("Bad address"); break; case badAll: results.Write("Heap allocation error"); break; case nullRef: results.Write("Null reference"); break; default: results.Write("Interpreter error!"); break; } results.WriteLine(" at " + pcNow); }
static void HeapDump(OutFile results, int pcNow) { // Dump heap area - useful for debugging int onLine = 0; results.Write("\nHeap dump at " + pcNow); results.Write(" SP:"); results.Write(cpu.sp, 4); results.Write(" FP:"); results.Write(cpu.fp, 4); results.Write(" HP:"); results.Write(cpu.hp, 4); results.Write(" HB:"); results.WriteLine(heapBase, 4); for (int i = heapBase; i < cpu.hp; i++) { results.Write(i, 7); results.Write(mem[i], 5); onLine++; if (onLine % 8 == 0) results.WriteLine(); } results.WriteLine(); }
public static void QuickInterpret(int codeLen, int initSP) { // Interprets the codeLen instructions stored in mem, with stack pointer // initialized to initSP. Use StdIn and StdOut without asking Console.WriteLine("\nHit <Enter> to start"); Console.ReadLine(); bool tracing = false; InFile data = new InFile(""); OutFile results = new OutFile(""); Emulator(0, codeLen, initSP, data, results, tracing); }
public static void ListCode(string fileName, int codeLen) { // Lists the codeLen instructions stored in mem on a named output file int i, j, n; if (fileName == null) return; OutFile codeFile = new OutFile(fileName); /* ------------- The following may be useful for debugging the interpreter i = 0; while (i < codeLen) { codeFile.Write(mem[i], 5); if ((i + 1) % 15 == 0) codeFile.WriteLine(); i++; } codeFile.WriteLine(); ------------- */ i = 0; codeFile.WriteLine("ASSEM\nBEGIN"); while (i < codeLen) { int o = mem[i] % (PVM.nul + 1); // force in range codeFile.Write(" {"); codeFile.Write(i, 5); codeFile.Write(" } "); codeFile.Write(mnemonics[o], -8); switch (o) { case PVM.brn: case PVM.bze: case PVM.dsp: case PVM.lda: case PVM.ldc: i = (i + 1) % memSize; codeFile.Write(mem[i]); break; case PVM.prns: i = (i + 1) % memSize; j = mem[i]; codeFile.Write(" \""); while (mem[j] != 0) { switch (mem[j]) { case '\\' : codeFile.Write("\\\\"); break; case '\"' : codeFile.Write("\\\""); break; case '\'' : codeFile.Write("\\\'"); break; case '\b' : codeFile.Write("\\b"); break; case '\t' : codeFile.Write("\\t"); break; case '\n' : codeFile.Write("\\n"); break; case '\f' : codeFile.Write("\\f"); break; case '\r' : codeFile.Write("\\r"); break; default : codeFile.Write((char) mem[j]); break; } j--; } codeFile.Write("\""); break; } i = (i + 1) % memSize; codeFile.WriteLine(); } codeFile.WriteLine("END."); codeFile.Close(); }
public static void Interpret(int codeLen, int initSP) { // Interactively opens data and results files. Then interprets the codeLen // instructions stored in mem, with stack pointer initialized to initSP Console.Write("\nTrace execution (y/N/q)? "); char reply = (Console.ReadLine() + " ").ToUpper()[0]; if (reply != 'Q') { bool tracing = reply == 'Y'; Console.Write("\nData file [STDIN] ? "); InFile data = new InFile(Console.ReadLine()); Console.Write("\nResults file [STDOUT] ? "); OutFile results = new OutFile(Console.ReadLine()); Emulator(0, codeLen, initSP, data, results, tracing); results.Close(); data.Close(); } }
public static void Emulator(int initPC, int codeLen, int initSP, InFile data, OutFile results, bool tracing) { // Emulates action of the codeLen instructions stored in mem[0 .. codeLen-1], with // program counter initialized to initPC, stack pointer initialized to initSP. // data and results are used for I/O. Tracing at the code level may be requested int pcNow; // current program counter int loop; // internal loops int tos, sos; // value popped from stack int adr; // effective address for memory accesses stackBase = initSP; heapBase = codeLen; // initialize boundaries cpu.hp = heapBase; // initialize registers cpu.sp = stackBase; cpu.gp = stackBase; cpu.mp = stackBase; cpu.fp = stackBase; cpu.pc = initPC; // initialize program counter ps = running; // prepare to execute int ops = 0; timer.Start(); do { ops++; pcNow = cpu.pc; // retain for tracing/postmortem if (cpu.pc < 0 || cpu.pc >= codeLen) { ps = badAdr; break; } cpu.ir = Next(); // fetch if (tracing) Trace(results, pcNow); switch (cpu.ir) { // execute case PVM.nop: // no operation break; case PVM.dsp: // decrement stack pointer (allocate space for variables) int localSpace = Next(); cpu.sp -= localSpace; if (InBounds(cpu.sp)) // initialize for (loop = 0; loop < localSpace; loop++) mem[cpu.sp + loop] = 0; break; case PVM.ldc: // push constant value Push(Next()); break; case PVM.lda: // push local address adr = cpu.fp - 1 - Next(); if (InBounds(adr)) Push(adr); break; case PVM.ldv: // dereference Push(mem[Pop()]); break; case PVM.sto: // store tos = Pop(); adr = Pop(); if (InBounds(adr)) mem[adr] = tos; break; case PVM.ldxa: // heap array indexing adr = Pop(); int heapPtr = Pop(); if (heapPtr == 0) ps = nullRef; else if (heapPtr < heapBase || heapPtr >= cpu.hp) ps = badMem; else if (adr < 0 || adr >= mem[heapPtr]) ps = badInd; else Push(heapPtr + adr + 1); break; case PVM.inpi: // integer input adr = Pop(); if (InBounds(adr)) { mem[adr] = data.ReadInt(); if (data.Error()) ps = badData; } break; case PVM.prni: // integer output if (tracing) results.Write(padding); results.Write(Pop(), 0); if (tracing) results.WriteLine(); break; case PVM.inpb: // boolean input adr = Pop(); if (InBounds(adr)) { mem[adr] = data.ReadBool() ? 1 : 0; if (data.Error()) ps = badData; } break; case PVM.prnb: // boolean output if (tracing) results.Write(padding); if (Pop() != 0) results.Write(" true "); else results.Write(" false "); if (tracing) results.WriteLine(); break; case PVM.prns: // string output if (tracing) results.Write(padding); loop = Next(); while (ps == running && mem[loop] != 0) { results.Write((char) mem[loop]); loop--; if (loop < stackBase) ps = badMem; } if (tracing) results.WriteLine(); break; case PVM.prnl: // newline results.WriteLine(); break; case PVM.neg: // integer negation Push(-Pop()); break; case PVM.add: // integer addition tos = Pop(); Push(Pop() + tos); break; case PVM.sub: // integer subtraction tos = Pop(); Push(Pop() - tos); break; case PVM.mul: // integer multiplication tos = Pop(); Push(Pop() * tos); break; case PVM.div: // integer division (quotient) tos = Pop(); Push(Pop() / tos); break; case PVM.rem: // integer division (remainder) tos = Pop(); Push(Pop() % tos); break; case PVM.not: // logical negation Push(Pop() == 0 ? 1 : 0); break; case PVM.and: // logical and tos = Pop(); Push(Pop() & tos); break; case PVM.or: // logical or tos = Pop(); Push(Pop() | tos); break; case PVM.ceq: // logical equality tos = Pop(); Push(Pop() == tos ? 1 : 0); break; case PVM.cne: // logical inequality tos = Pop(); Push(Pop() != tos ? 1 : 0); break; case PVM.clt: // logical less tos = Pop(); Push(Pop() < tos ? 1 : 0); break; case PVM.cle: // logical less or equal tos = Pop(); Push(Pop() <= tos ? 1 : 0); break; case PVM.cgt: // logical greater tos = Pop(); Push(Pop() > tos ? 1 : 0); break; case PVM.cge: // logical greater or equal tos = Pop(); Push(Pop() >= tos ? 1 : 0); break; case PVM.brn: // unconditional branch cpu.pc = Next(); if (cpu.pc < 0 || cpu.pc >= codeLen) ps = badAdr; break; case PVM.bze: // pop top of stack, branch if false int target = Next(); if (Pop() == 0) { cpu.pc = target; if (cpu.pc < 0 || cpu.pc >= codeLen) ps = badAdr; } break; case PVM.anew: // heap array allocation int size = Pop(); if (size <= 0 || size + 1 > cpu.sp - cpu.hp - 2) ps = badAll; else { mem[cpu.hp] = size; Push(cpu.hp); cpu.hp += size + 1; } break; case PVM.halt: // halt ps = finished; break; case PVM.stk: // stack dump (debugging) StackDump(results, pcNow); break; case PVM.heap: // heap dump (debugging) HeapDump(results, pcNow); break; case PVM.ldc_0: // push constant 0 case PVM.ldc_1: // push constant 1 case PVM.ldc_2: // push constant 2 case PVM.ldc_3: // push constant 3 case PVM.lda_0: // push local address 0 case PVM.lda_1: // push local address 1 case PVM.lda_2: // push local address 2 case PVM.lda_3: // push local address 3 case PVM.ldl: // push local value case PVM.ldl_0: // push value of local variable 0 case PVM.ldl_1: // push value of local variable 1 case PVM.ldl_2: // push value of local variable 2 case PVM.ldl_3: // push value of local variable 3 case PVM.stl: // store local value case PVM.stlc: // store local value case PVM.stl_0: // pop to local variable 0 case PVM.stl_1: // pop to local variable 1 case PVM.stl_2: // pop to local variable 2 case PVM.stl_3: // pop to local variable 3 case PVM.stoc: // character checked store case PVM.inpc: // character input case PVM.prnc: // character output case PVM.low: // toLowerCase case PVM.islet: // isLetter case PVM.inc: // ++ case PVM.dec: // -- default: // unrecognized opcode ps = badOp; break; } } while (ps == running); TimeSpan ts = timer.Elapsed; // Format and display the TimeSpan value. string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Console.WriteLine("\n\n" + ops + " operations. Run Time " + elapsedTime + "\n\n"); if (ps != finished) PostMortem(results, pcNow); timer.Reset(); timer.Stop(); }
// The interpreters and utility methods public static void Emulator(int initPC, int codeLen, int initSP, InFile data, OutFile results, bool tracing) { // Emulates action of the codeLen instructions stored in mem[0 .. codeLen-1], with // program counter initialized to initPC, stack pointer initialized to initSP. // data and results are used for I/O. Tracing at the code level may be requested int pcNow; // current program counter int loop; // internal loops int tos, sos; // value popped from stack stackBase = initSP; heapBase = codeLen; // initialize boundaries cpu.hp = heapBase; // initialize registers cpu.sp = stackBase; cpu.gp = stackBase; cpu.mp = stackBase; cpu.fp = stackBase; cpu.pc = initPC; // initialize program counter ps = running; // prepare to execute int ops = 0; timer.Start(); do { ops++; pcNow = cpu.pc; // retain for tracing/postmortem cpu.ir = mem[cpu.pc++]; // fetch // if (tracing) Trace(results, pcNow); switch (cpu.ir) { // execute case PVM.nop: // no operation break; case PVM.dsp: // decrement stack pointer (allocate space for variables) cpu.sp -= mem[cpu.pc++]; break; case PVM.ldc: // push constant value mem[--cpu.sp] = mem[cpu.pc++]; break; case PVM.lda: // push local address mem[--cpu.sp] = cpu.fp - 1 - mem[cpu.pc++]; break; case PVM.ldv: // dereference mem[cpu.sp] = mem[mem[cpu.sp]]; break; case PVM.sto: // store tos = mem[cpu.sp++]; mem[mem[cpu.sp++]] = tos; break; case PVM.ldxa: // heap array indexing tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] + tos; break; case PVM.inpi: // integer input mem[mem[cpu.sp++]] = data.ReadInt(); break; case PVM.prni: // integer output // if (tracing) results.Write(padding); results.Write(mem[cpu.sp++], 0); // if (tracing) results.WriteLine(); break; case PVM.inpb: // boolean input mem[mem[cpu.sp++]] = data.ReadBool() ? 1 : 0; break; case PVM.prnb: // boolean output // if (tracing) results.Write(padding); if (mem[cpu.sp++] != 0) results.Write(" true "); else results.Write(" false "); // if (tracing) results.WriteLine(); break; case PVM.prns: // string output // if (tracing) results.Write(padding); loop = mem[cpu.pc++]; while (mem[loop] != 0) { results.Write((char) mem[loop]); loop--; } // if (tracing) results.WriteLine(); break; case PVM.prnl: // newline results.WriteLine(); break; case PVM.neg: // integer negation mem[cpu.sp] = -mem[cpu.sp]; break; case PVM.add: // integer addition tos = mem[cpu.sp++]; mem[cpu.sp] += tos; break; case PVM.sub: // integer subtraction tos = mem[cpu.sp++]; mem[cpu.sp] -= tos; break; case PVM.mul: // integer multiplication tos = mem[cpu.sp++]; mem[cpu.sp] *= tos; break; case PVM.div: // integer division (quotient) tos = mem[cpu.sp++]; mem[cpu.sp] /= tos; break; case PVM.rem: // integer division (remainder) tos = mem[cpu.sp++]; mem[cpu.sp] %= tos; break; case PVM.not: // logical negation mem[cpu.sp] = mem[cpu.sp] == 0 ? 1 : 0; break; case PVM.and: // logical and tos = mem[cpu.sp++]; mem[cpu.sp] &= tos; break; case PVM.or: // logical or tos = mem[cpu.sp++]; mem[cpu.sp] |= tos; break; case PVM.ceq: // logical equality tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] == tos ? 1 : 0; break; case PVM.cne: // logical inequality tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] != tos ? 1 : 0; break; case PVM.clt: // logical less tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] < tos ? 1 : 0; break; case PVM.cle: // logical less or equal tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] <= tos ? 1 : 0; break; case PVM.cgt: // logical greater tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] > tos ? 1 : 0; break; case PVM.cge: // logical greater or equal tos = mem[cpu.sp++]; mem[cpu.sp] = mem[cpu.sp] >= tos ? 1 : 0; break; case PVM.brn: // unconditional branch cpu.pc = mem[cpu.pc++]; break; case PVM.bze: // pop top of stack, branch if false int target = mem[cpu.pc++]; if (mem[cpu.sp++] == 0) cpu.pc = target; break; case PVM.anew: // heap array allocation int size = mem[cpu.sp]; mem[cpu.sp] = cpu.hp; cpu.hp += size; break; case PVM.halt: // halt ps = finished; break; case PVM.stk: // stack dump (debugging) StackDump(results, pcNow); break; case PVM.heap: // heap dump (debugging) HeapDump(results, pcNow); break; case PVM.ldc_0: // push constant 0 case PVM.ldc_1: // push constant 1 case PVM.ldc_2: // push constant 2 case PVM.ldc_3: // push constant 3 case PVM.lda_0: // push local address 0 case PVM.lda_1: // push local address 1 case PVM.lda_2: // push local address 2 case PVM.lda_3: // push local address 3 case PVM.ldl: // push local value case PVM.ldl_0: // push value of local variable 0 case PVM.ldl_1: // push value of local variable 1 case PVM.ldl_2: // push value of local variable 2 case PVM.ldl_3: // push value of local variable 3 case PVM.stl: // store local value case PVM.stlc: // store local value case PVM.stl_0: // pop to local variable 0 case PVM.stl_1: // pop to local variable 1 case PVM.stl_2: // pop to local variable 2 case PVM.stl_3: // pop to local variable 3 case PVM.stoc: // character checked store case PVM.inpc: // character input case PVM.prnc: // character output case PVM.low: // toLowerCase case PVM.islet: // isLetter case PVM.inc: // ++ case PVM.dec: // -- default: // unrecognized opcode ps = badOp; break; } } while (ps == running); TimeSpan ts = timer.Elapsed; // Format and display the TimeSpan value. string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Console.WriteLine("\n\n" + ops + " operations. Run Time " + elapsedTime + "\n\n"); if (ps != finished) PostMortem(results, pcNow); timer.Reset(); timer.Stop(); }