(* BSD 2-Clause License Copyright (c) 2020-2021, Anton Krotov All rights reserved. *) (* RVMxI executor and disassembler Usage: RVMxI.exe -run [program parameters] RVMxI.exe -dis *) MODULE RVMxI; IMPORT SYSTEM, File, Args, Out, API, HOST; CONST szWORD = HOST.bit_depth DIV 8; opSTOP = 0; opRET = 1; opENTER = 2; opNEG = 3; opNOT = 4; opNOP = 5; opXCHG = 6; opLDB = 7; opLDH = 8; opLDW = 9; opPUSH = 10; opPUSHC = 11; opPOP = 12; opLABEL = 13; opLEA = 14; opLLA = 15; opLDD = 16; (* 17, 18 *) opJMP = 19; opCALL = 20; opCALLI = 21; opMOV = 22; opMUL = 24; opADD = 26; opSUB = 28; opDIV = 30; opMOD = 32; opSTB = 34; opSTH = 36; opSTW = 38; opSTD = 40; (* 42, 44 *) opAND = 46; opOR = 48; opXOR = 50; opASR = 52; opLSR = 54; opLSL = 56; opROR = 58; (* 60, 62 *) opCMP = 64; opMOVC = 23; opMULC = 25; opADDC = 27; opSUBC = 29; opDIVC = 31; opMODC = 33; opSTBC = 35; opSTHC = 37; opSTWC = 39; opSTDC = 41; (* 43, 45 *) opANDC = 47; opORC = 49; opXORC = 51; opASRC = 53; opLSRC = 55; opLSLC = 57; opRORC = 59; (* 61, 63 *) opCMPC = 65; opBIT = 66; opSYSCALL = 67; opJBT = 68; opADDRC = 69; opJEQ = 70; opJNE = 71; opJLT = 72; opJGE = 73; opJGT = 74; opJLE = 75; opSEQ = 76; opSNE = 77; opSLT = 78; opSGE = 79; opSGT = 80; opSLE = 81; nREG = 16; ACC = 0; BP = 3; SP = 4; Types = 0; Strings = 1; Global = 2; Heap = 3; Stack = 4; TYPE COMMAND = POINTER TO RECORD op, param1, param2: INTEGER; next, prev: COMMAND END; LABELS = ARRAY 30000 OF COMMAND; SECTIONS = ARRAY 5 OF INTEGER; VAR Sections: SECTIONS; first, last: COMMAND; Labels: LABELS; F: INTEGER; buf: ARRAY 65536 OF BYTE; cnt: INTEGER; PROCEDURE syscall (ptr: INTEGER); VAR fn, r, n: INTEGER; proc2: PROCEDURE (a, b: INTEGER): INTEGER; proc3: PROCEDURE (a, b, c: INTEGER): INTEGER; proc4: PROCEDURE (a, b, c, d: INTEGER): INTEGER; r1, r2: REAL; PROCEDURE GetInt (ptr, n: INTEGER): INTEGER; BEGIN SYSTEM.GET(ptr + SYSTEM.SIZE(INTEGER) * n, n) RETURN n END GetInt; PROCEDURE GetReal (ptr, n: INTEGER): REAL; VAR r: REAL; BEGIN SYSTEM.GET(ptr + SYSTEM.SIZE(INTEGER) * n, r) RETURN r END GetReal; BEGIN fn := GetInt(ptr, 0); CASE fn OF | 0: HOST.ExitProcess(GetInt(ptr, 1)) | 1: SYSTEM.PUT(SYSTEM.ADR(proc2), SYSTEM.ADR(HOST.GetCurrentDirectory)); r := proc2(GetInt(ptr, 1), GetInt(ptr, 2)) | 2: n := GetInt(ptr, 1); SYSTEM.PUT(SYSTEM.ADR(proc3), SYSTEM.ADR(HOST.GetArg)); r := proc3(n - ORD(n = 0) + 2, GetInt(ptr, 2), GetInt(ptr, 3)) | 3: SYSTEM.PUT(SYSTEM.ADR(proc4), SYSTEM.ADR(HOST.FileRead)); SYSTEM.PUT(ptr, proc4(GetInt(ptr, 1), GetInt(ptr, 2), GetInt(ptr, 3), GetInt(ptr, 4))) | 4: SYSTEM.PUT(SYSTEM.ADR(proc4), SYSTEM.ADR(HOST.FileWrite)); SYSTEM.PUT(ptr, proc4(GetInt(ptr, 1), GetInt(ptr, 2), GetInt(ptr, 3), GetInt(ptr, 4))) | 5: SYSTEM.PUT(SYSTEM.ADR(proc2), SYSTEM.ADR(HOST.FileCreate)); SYSTEM.PUT(ptr, proc2(GetInt(ptr, 1), GetInt(ptr, 2))) | 6: HOST.FileClose(GetInt(ptr, 1)) | 7: SYSTEM.PUT(SYSTEM.ADR(proc2), SYSTEM.ADR(HOST.FileOpen)); SYSTEM.PUT(ptr, proc2(GetInt(ptr, 1), GetInt(ptr, 2))) | 8: HOST.OutChar(CHR(GetInt(ptr, 1))) | 9: SYSTEM.PUT(ptr, HOST.GetTickCount()) |10: SYSTEM.PUT(ptr, HOST.UnixTime()) |11: SYSTEM.PUT(SYSTEM.ADR(proc2), SYSTEM.ADR(HOST.isRelative)); SYSTEM.PUT(ptr, proc2(GetInt(ptr, 1), GetInt(ptr, 2))) |12: SYSTEM.PUT(SYSTEM.ADR(proc2), SYSTEM.ADR(HOST.chmod)); r := proc2(GetInt(ptr, 1), GetInt(ptr, 2)) |100..103: r1 := GetReal(ptr, 1); r2 := GetReal(ptr, 2); CASE fn OF |100: SYSTEM.PUT(ptr, r2 * r1) |101: SYSTEM.PUT(ptr, r2 / r1) |102: SYSTEM.PUT(ptr, r2 + r1) |103: SYSTEM.PUT(ptr, r2 - r1) END |104: r1 := GetReal(ptr, 2); r2 := GetReal(ptr, 3); CASE GetInt(ptr, 1) OF |0: SYSTEM.PUT(ptr, ORD(r2 = r1)) |1: SYSTEM.PUT(ptr, ORD(r2 # r1)) |2: SYSTEM.PUT(ptr, ORD(r2 < r1)) |3: SYSTEM.PUT(ptr, ORD(r2 <= r1)) |4: SYSTEM.PUT(ptr, ORD(r2 > r1)) |5: SYSTEM.PUT(ptr, ORD(r2 >= r1)) END |105: SYSTEM.PUT(ptr, FLOOR(GetReal(ptr, 1))) |106: SYSTEM.PUT(ptr, FLT(GetInt(ptr, 1))) END END syscall; PROCEDURE exec (VAR Labels: LABELS; first, last: COMMAND; Sections: SECTIONS); VAR cmd: COMMAND; param1, param2, i: INTEGER; R: ARRAY nREG OF INTEGER; fe, fl, fb: BOOLEAN; BEGIN FOR i := 0 TO LEN(Labels) - 1 DO cmd := Labels[i]; IF cmd # NIL THEN REPEAT cmd := cmd.next UNTIL cmd.op # opLABEL; Labels[i] := cmd END END; cmd := first; WHILE cmd # NIL DO IF cmd.op = opLABEL THEN cmd.prev.next := cmd.next; cmd.next.prev := cmd.prev END; cmd := cmd.next END; FOR i := 0 TO LEN(Labels) - 1 DO IF Labels[i] # NIL THEN Labels[i] := Labels[i].prev END END; cmd := first; WHILE cmd # NIL DO param1 := cmd.param1; param2 := cmd.param2; CASE cmd.op OF |opSTOP: cmd := last |opRET: SYSTEM.GET(R[SP], cmd); INC(R[SP], szWORD) |opENTER: DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], R[BP]); R[BP] := R[SP]; WHILE param1 > 0 DO DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], 0); DEC(param1) END |opPOP: SYSTEM.GET(R[SP], R[param1]); INC(R[SP], szWORD) |opPUSH: DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], R[param1]) |opPUSHC: DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], param1) |opCALL: DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], cmd); cmd := Labels[param1] |opCALLI: DEC(R[SP], szWORD); SYSTEM.PUT(R[SP], cmd); SYSTEM.GET(SYSTEM.ADR(R[param1]), cmd) |opNEG: R[param1] := -R[param1] |opNOT: R[param1] := ORD(-BITS(R[param1])) |opNOP: |opXCHG: i := R[param1]; R[param1] := R[param2]; R[param2] := i |opLDB: i := param1 MOD 256; SYSTEM.GET8(R[param1 DIV 256] + param2, R[i]); R[i] := R[i] MOD 256 |opLDH: i := param1 MOD 256; SYSTEM.GET16(R[param1 DIV 256] + param2, R[i]); R[i] := R[i] MOD 65536 |opLDW: SYSTEM.GET32(R[param1 DIV 256] + param2, R[param1 MOD 256]); $IF (CPU_X8664) R[param1 MOD 256] := R[param1 MOD 256] MOD 100000000H $END |opLDD: SYSTEM.GET(R[param1 DIV 256] + param2, R[param1 MOD 256]) |opLLA: SYSTEM.GET(SYSTEM.ADR(Labels[param2]), R[param1]) |opJMP: cmd := Labels[param1] |opMOV: R[param1] := R[param2] |opMOVC: R[param1] := param2 |opMUL: R[param1] := R[param1] * R[param2] |opMULC: R[param1] := R[param1] * param2 |opADD: INC(R[param1], R[param2]) |opADDC: INC(R[param1], param2) |opSUB: DEC(R[param1], R[param2]) |opSUBC: DEC(R[param1], param2) |opDIV: R[param1] := R[param1] DIV R[param2] |opDIVC: R[param1] := R[param1] DIV param2 |opMOD: R[param1] := R[param1] MOD R[param2] |opMODC: R[param1] := R[param1] MOD param2 |opSTB: SYSTEM.PUT8(R[param1 DIV 256] + param2, R[param1 MOD 256]) |opSTH: SYSTEM.PUT16(R[param1 DIV 256] + param2, R[param1 MOD 256]) |opSTW: SYSTEM.PUT32(R[param1 DIV 256] + param2, R[param1 MOD 256]) |opSTD: SYSTEM.PUT(R[param1 DIV 256] + param2, R[param1 MOD 256]) |opSTBC: SYSTEM.PUT8(R[param1], param2) |opSTHC: SYSTEM.PUT16(R[param1], param2) |opSTWC: SYSTEM.PUT32(R[param1], param2) |opSTDC: SYSTEM.PUT(R[param1], param2) |opAND: R[param1] := ORD(BITS(R[param1]) * BITS(R[param2])) |opANDC: R[param1] := ORD(BITS(R[param1]) * BITS(param2)) |opOR: R[param1] := ORD(BITS(R[param1]) + BITS(R[param2])) |opORC: R[param1] := ORD(BITS(R[param1]) + BITS(param2)) |opXOR: R[param1] := ORD(BITS(R[param1]) / BITS(R[param2])) |opXORC: R[param1] := ORD(BITS(R[param1]) / BITS(param2)) |opASR: R[param1] := ASR(R[param1], R[param2]) |opASRC: R[param1] := ASR(R[param1], param2) |opLSR: R[param1] := LSR(R[param1], R[param2]) |opLSRC: R[param1] := LSR(R[param1], param2) |opLSL: R[param1] := LSL(R[param1], R[param2]) |opLSLC: R[param1] := LSL(R[param1], param2) |opROR: R[param1] := ROR(R[param1], R[param2]) |opRORC: R[param1] := ROR(R[param1], param2) |opLEA: R[param1 MOD 256] := Sections[param1 DIV 256] + param2 (*|opLABEL:*) |opSYSCALL: syscall(R[param1]) |opADDRC: R[param1 MOD 256] := R[param1 DIV 256] + param2 |opCMP: fl := R[param1] < R[param2]; fe := R[param1] = R[param2]; fb := fl & (R[param1] >= 0) |opCMPC: fl := R[param1] < param2; fe := R[param1] = param2; fb := fl & (R[param1] >= 0) |opJEQ: IF fe THEN cmd := Labels[param1] END |opJNE: IF ~fe THEN cmd := Labels[param1] END |opJLT: IF fl THEN cmd := Labels[param1] END |opJLE: IF fl OR fe THEN cmd := Labels[param1] END |opJGT: IF ~fl & ~fe THEN cmd := Labels[param1] END |opJGE: IF ~fl THEN cmd := Labels[param1] END |opSEQ: R[param1] := ORD(fe) |opSNE: R[param1] := ORD(~fe) |opSLT: R[param1] := ORD(fl) |opSLE: R[param1] := ORD(fl OR fe) |opSGT: R[param1] := ORD(~fl & ~fe) |opSGE: R[param1] := ORD(~fl) |opJBT: IF fb THEN cmd := Labels[param1] END |opBIT: R[param1] := ORD({R[param2]}) END; cmd := cmd.next END END exec; PROCEDURE disasm (name: ARRAY OF CHAR; t_count, c_count, glob, heap: INTEGER); VAR cmd: COMMAND; param1, param2, i, t, ptr: INTEGER; b: BYTE; Names: ARRAY 5, 16 OF CHAR; PROCEDURE String (s: ARRAY OF CHAR); VAR n: INTEGER; BEGIN n := LENGTH(s); IF n > LEN(buf) - cnt THEN ASSERT(File.Write(F, SYSTEM.ADR(buf[0]), cnt) = cnt); cnt := 0 END; SYSTEM.MOVE(SYSTEM.ADR(s[0]), SYSTEM.ADR(buf[0]) + cnt, n); INC(cnt, n) END String; PROCEDURE Ln; BEGIN String(0DX + 0AX) END Ln; PROCEDURE hexdgt (n: INTEGER): CHAR; BEGIN IF n < 10 THEN INC(n, ORD("0")) ELSE INC(n, ORD("A") - 10) END RETURN CHR(n) END hexdgt; PROCEDURE Hex (x: INTEGER); VAR str: ARRAY 19 OF CHAR; n: INTEGER; BEGIN n := szWORD * 2 + 2; str[n] := 0X; WHILE n > 2 DO str[n - 1] := hexdgt(x MOD 16); x := x DIV 16; DEC(n) END; str[1] := "x"; str[0] := "0"; String(str) END Hex; PROCEDURE Byte (x: BYTE); VAR str: ARRAY 5 OF CHAR; BEGIN str[4] := 0X; str[3] := hexdgt(x MOD 16); str[2] := hexdgt(x DIV 16); str[1] := "x"; str[0] := "0"; String(str) END Byte; PROCEDURE Reg (n: INTEGER); VAR s: ARRAY 2 OF CHAR; BEGIN IF n = BP THEN String("BP") ELSIF n = SP THEN String("SP") ELSE String("R"); s[1] := 0X; IF n >= 10 THEN s[0] := CHR(n DIV 10 + ORD("0")); String(s) END; s[0] := CHR(n MOD 10 + ORD("0")); String(s) END END Reg; PROCEDURE Reg2 (r1, r2: INTEGER); BEGIN Reg(r1); String(", "); Reg(r2) END Reg2; PROCEDURE RegC (r, c: INTEGER); BEGIN Reg(r); String(", "); Hex(c) END RegC; PROCEDURE RegL (r, label: INTEGER); BEGIN Reg(r); String(", L"); Hex(label) END RegL; BEGIN Names[Types] := "TYPES"; Names[Strings] := "STRINGS"; Names[Global] := "GLOBAL"; Names[Heap] := "HEAP"; Names[Stack] := "STACK"; F := File.Create(name); ASSERT(F > 0); cnt := 0; String("CODE:"); Ln; cmd := first; WHILE cmd # NIL DO param1 := cmd.param1; param2 := cmd.param2; CASE cmd.op OF |opSTOP: String("STOP") |opRET: String("RET") |opENTER: String("ENTER "); Hex(param1) |opPOP: String("POP "); Reg(param1) |opNEG: String("NEG "); Reg(param1) |opNOT: String("NOT "); Reg(param1) |opNOP: String("NOP") |opXCHG: String("XCHG "); Reg2(param1, param2) |opLDB: String("LDB "); Reg(param1 MOD 256); String(", ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("]") |opLDH: String("LDH "); Reg(param1 MOD 256); String(", ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("]") |opLDW: String("LDW "); Reg(param1 MOD 256); String(", ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("]") |opLDD: String("LDD "); Reg(param1 MOD 256); String(", ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("]") |opPUSH: String("PUSH "); Reg(param1) |opPUSHC: String("PUSH "); Hex(param1) |opLLA: String("LLA "); RegL(param1, param2) |opJMP: String("JMP L"); Hex(param1) |opCALL: String("CALL L"); Hex(param1) |opCALLI: String("CALL "); Reg(param1) |opMOV: String("MOV "); Reg2(param1, param2) |opMOVC: String("MOV "); RegC(param1, param2) |opMUL: String("MUL "); Reg2(param1, param2) |opMULC: String("MUL "); RegC(param1, param2) |opADD: String("ADD "); Reg2(param1, param2) |opADDC: String("ADD "); RegC(param1, param2) |opSUB: String("SUB "); Reg2(param1, param2) |opSUBC: String("SUB "); RegC(param1, param2) |opDIV: String("DIV "); Reg2(param1, param2) |opDIVC: String("DIV "); RegC(param1, param2) |opMOD: String("MOD "); Reg2(param1, param2) |opMODC: String("MOD "); RegC(param1, param2) |opSTB: String("STB ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("], "); Reg(param1 MOD 256) |opSTH: String("STH ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("], "); Reg(param1 MOD 256) |opSTW: String("STW ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("], "); Reg(param1 MOD 256) |opSTD: String("STD ["); Reg(param1 DIV 256); String(" + "); Hex(param2); String("], "); Reg(param1 MOD 256) |opSTBC: String("STB ["); Reg(param1); String("], "); Hex(param2) |opSTHC: String("STH ["); Reg(param1); String("], "); Hex(param2) |opSTWC: String("STW ["); Reg(param1); String("], "); Hex(param2) |opSTDC: String("STD ["); Reg(param1); String("], "); Hex(param2) |opAND: String("AND "); Reg2(param1, param2) |opANDC: String("AND "); RegC(param1, param2) |opOR: String("OR "); Reg2(param1, param2) |opORC: String("OR "); RegC(param1, param2) |opXOR: String("XOR "); Reg2(param1, param2) |opXORC: String("XOR "); RegC(param1, param2) |opASR: String("ASR "); Reg2(param1, param2) |opASRC: String("ASR "); RegC(param1, param2) |opLSR: String("LSR "); Reg2(param1, param2) |opLSRC: String("LSR "); RegC(param1, param2) |opLSL: String("LSL "); Reg2(param1, param2) |opLSLC: String("LSL "); RegC(param1, param2) |opROR: String("ROR "); Reg2(param1, param2) |opRORC: String("ROR "); RegC(param1, param2) |opLEA: String("LEA "); Reg(param1 MOD 256); String(", "); String(Names[param1 DIV 256]); String(" + "); Hex(param2) |opADDRC: String("ADD "); Reg(param1 MOD 256); String(", "); Reg(param1 DIV 256); String(", "); Hex(param2) |opLABEL: String("L"); Hex(param1); String(":") |opSYSCALL: String("SYSCALL "); Reg(param1) |opCMP: String("CMP "); Reg2(param1, param2) |opCMPC: String("CMP "); RegC(param1, param2) |opJEQ: String("JEQ L"); Hex(param1) |opJNE: String("JNE L"); Hex(param1) |opJLT: String("JLT L"); Hex(param1) |opJLE: String("JLE L"); Hex(param1) |opJGT: String("JGT L"); Hex(param1) |opJGE: String("JGE L"); Hex(param1) |opSEQ: String("SEQ "); Reg(param1) |opSNE: String("SNE "); Reg(param1) |opSLT: String("SLT "); Reg(param1) |opSLE: String("SLE "); Reg(param1) |opSGT: String("SGT "); Reg(param1) |opSGE: String("SGE "); Reg(param1) |opJBT: String("JBT L"); Hex(param1) |opBIT: String("BIT "); Reg2(param1, param2) END; Ln; cmd := cmd.next END; String("TYPES:"); ptr := Sections[Types]; FOR i := 0 TO t_count - 1 DO IF i MOD 4 = 0 THEN Ln; String("WORD ") ELSE String(", ") END; SYSTEM.GET(ptr, t); INC(ptr, szWORD); Hex(t) END; Ln; String("STRINGS:"); ptr := Sections[Strings]; FOR i := 0 TO c_count - 1 DO IF i MOD 8 = 0 THEN Ln; String("BYTE ") ELSE String(", ") END; SYSTEM.GET8(ptr, b); INC(ptr); Byte(b) END; Ln; String("GLOBAL:"); Ln; String("WORDS "); Hex(glob); Ln; String("HEAP:"); Ln; String("WORDS "); Hex(heap); Ln; String("STACK:"); Ln; String("WORDS 8"); Ln; ASSERT(File.Write(F, SYSTEM.ADR(buf[0]), cnt) = cnt); File.Close(F) END disasm; PROCEDURE GetCommand (adr: INTEGER): COMMAND; VAR op, param1, param2: INTEGER; res: COMMAND; BEGIN op := 0; param1 := 0; param2 := 0; SYSTEM.GET(adr, op); SYSTEM.GET(adr + szWORD, param1); SYSTEM.GET(adr + szWORD * 2, param2); NEW(res); res.op := op; res.param1 := param1; res.param2 := param2; res.next := NIL RETURN res END GetCommand; PROCEDURE main; VAR name, param: ARRAY 1024 OF CHAR; cmd: COMMAND; file, fsize, n: INTEGER; descr: ARRAY 12 OF INTEGER; offTypes, offStrings, GlobalSize, HeapStackSize, DescrSize: INTEGER; BEGIN Out.Open; Args.GetArg(1, name); F := File.Open(name, File.OPEN_R); IF F > 0 THEN DescrSize := LEN(descr) * SYSTEM.SIZE(INTEGER); fsize := File.Seek(F, 0, File.SEEK_END); ASSERT(fsize > DescrSize); file := API._NEW(fsize); ASSERT(file # 0); n := File.Seek(F, 0, File.SEEK_BEG); ASSERT(fsize = File.Read(F, file, fsize)); File.Close(F); SYSTEM.MOVE(file + fsize - DescrSize, SYSTEM.ADR(descr[0]), DescrSize); offTypes := descr[0]; ASSERT(offTypes < fsize - DescrSize); ASSERT(offTypes > 0); ASSERT(offTypes MOD (3 * szWORD) = 0); offStrings := descr[1]; ASSERT(offStrings < fsize - DescrSize); ASSERT(offStrings > 0); ASSERT(offStrings MOD szWORD = 0); ASSERT(offStrings > offTypes); GlobalSize := descr[2]; ASSERT(GlobalSize > 0); HeapStackSize := descr[3]; ASSERT(HeapStackSize > 0); Sections[Types] := API._NEW(offStrings - offTypes); ASSERT(Sections[Types] # 0); SYSTEM.MOVE(file + offTypes, Sections[Types], offStrings - offTypes); Sections[Strings] := API._NEW(fsize - offStrings - DescrSize); ASSERT(Sections[Strings] # 0); SYSTEM.MOVE(file + offStrings, Sections[Strings], fsize - offStrings - DescrSize); Sections[Global] := API._NEW(GlobalSize * szWORD); ASSERT(Sections[Global] # 0); Sections[Heap] := API._NEW(HeapStackSize * szWORD); ASSERT(Sections[Heap] # 0); Sections[Stack] := Sections[Heap] + HeapStackSize * szWORD - szWORD*8; n := offTypes DIV (3 * szWORD); first := GetCommand(file + offTypes - n * (3 * szWORD)); first.prev := NIL; last := first; DEC(n); WHILE n > 0 DO cmd := GetCommand(file + offTypes - n * (3 * szWORD)); IF cmd.op = opLABEL THEN Labels[cmd.param1] := cmd END; last.next := cmd; cmd.prev := last; last := cmd; DEC(n) END; file := API._DISPOSE(file); Args.GetArg(2, param); IF param = "-dis" THEN Args.GetArg(3, name); IF name # "" THEN disasm(name, (offStrings - offTypes) DIV szWORD, fsize - offStrings - DescrSize, GlobalSize, HeapStackSize) END ELSIF param = "-run" THEN exec(Labels, first, last, Sections) END ELSE Out.String("file not found"); Out.Ln END END main; BEGIN main END RVMxI.