using System; using System.IO; using System.Text; using STCompiler.Common; using System.Collections.Generic; class Program { static int Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Usage: StDisasm "); return 1; } var path = args[0]; if (!File.Exists(path)) { Console.WriteLine("File not found: " + path); return 2; } var data = File.ReadAllBytes(path); try { Disasm(data); } catch(Exception ex) { Console.WriteLine("Error: " + ex.Message); return 3; } return 0; } static void Disasm(byte[] data) { using var ms = new MemoryStream(data); using var r = new BinaryReader(ms); string magic = Encoding.ASCII.GetString(r.ReadBytes(4)); Console.WriteLine($"Magic: {magic}"); ushort ver = r.ReadUInt16(); Console.WriteLine($"Version: {ver}"); ushort nConsts = r.ReadUInt16(); Console.WriteLine($"Consts: {nConsts}"); var consts = new List(); for (int i = 0; i < nConsts; i++) { byte t = r.ReadByte(); switch(t) { case 1: { long v = r.ReadInt64(); consts.Add(v); Console.WriteLine($" [{i}] (long) = {v}"); break; } case 2: { double v = r.ReadDouble(); consts.Add(v); Console.WriteLine($" [{i}] (double) = {v}"); break; } case 3: { float v = r.ReadSingle(); consts.Add(v); Console.WriteLine($" [{i}] (float) = {v}"); break; } case 4: { int v = r.ReadInt32(); consts.Add(v); Console.WriteLine($" [{i}] (int) = {v}"); break; } default: { Console.WriteLine($" [{i}] Unknown const type {t}"); break; } } } ushort nVars = r.ReadUInt16(); Console.WriteLine($"Vars: {nVars}"); var varTypes = new VarType[nVars]; for (int i = 0; i < nVars; i++) { byte tb = r.ReadByte(); var vt = (VarType)tb; varTypes[i] = vt; if (Enum.IsDefined(typeof(VarType), vt)) Console.WriteLine($" Var[{i}] type = {vt}"); else Console.WriteLine($" Var[{i}] type = {tb} (unknown)"); } ushort codeLen = r.ReadUInt16(); Console.WriteLine($"CodeLen: {codeLen} bytes"); var code = r.ReadBytes(codeLen); Console.WriteLine("\n--- Disassembly ---"); int ip = 0; while (ip < code.Length) { int addr = ip; byte op = code[ip++]; Console.Write($"{addr:0000}: 0x{op:X2} "); switch (op) { case Bytecode.OpCodes.NOP: Console.WriteLine("NOP"); break; case Bytecode.OpCodes.PUSH_CONST: { ushort ci = ReadU16(code, ref ip); Console.WriteLine($"PUSH_CONST {ci} ({consts[ci]})"); break; } case Bytecode.OpCodes.PUSH_REAL_CONST: { ushort ci = ReadU16(code, ref ip); Console.WriteLine($"PUSH_REAL_CONST {ci} ({consts[ci]})"); break; } case Bytecode.OpCodes.LOAD_VAR: { ushort vi = ReadU16(code, ref ip); Console.WriteLine($"LOAD_VAR {vi}"); break; } case Bytecode.OpCodes.STORE_VAR: { ushort vi = ReadU16(code, ref ip); Console.WriteLine($"STORE_VAR {vi}"); break; } case Bytecode.OpCodes.JZ: { ushort target = ReadU16(code, ref ip); Console.WriteLine($"JZ addr={target:0000}"); break; } case Bytecode.OpCodes.JMP: { ushort target = ReadU16(code, ref ip); Console.WriteLine($"JMP addr={target:0000}"); break; } case Bytecode.OpCodes.HALT: Console.WriteLine("HALT"); break; default: Console.WriteLine($"{Bytecode.OpName(op)}"); break; } } } static ushort ReadU16(byte[] a, ref int ip) { ushort v = (ushort)(a[ip] | (a[ip+1] << 8)); ip += 2; return v; } }