Neue Architektur
This commit is contained in:
123
STCompiler.Simulator/Program.cs
Normal file
123
STCompiler.Simulator/Program.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using STCompiler.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
class Program {
|
||||
static int Main(string[] args) {
|
||||
if (args.Length < 1) {
|
||||
Console.WriteLine("Usage: StSim <file.stbc>");
|
||||
return 1;
|
||||
}
|
||||
var path = args[0];
|
||||
if (!File.Exists(path)) { Console.WriteLine("File not found: " + path); return 2; }
|
||||
var data = File.ReadAllBytes(path);
|
||||
try { Simulate(data); } catch(Exception ex) { Console.WriteLine("Error: " + ex.Message); return 3; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Simulate(byte[] data) {
|
||||
using var ms = new MemoryStream(data);
|
||||
using var r = new BinaryReader(ms);
|
||||
|
||||
string magic = System.Text.Encoding.ASCII.GetString(r.ReadBytes(4));
|
||||
if (magic != Bytecode.Magic) throw new Exception("Invalid magic");
|
||||
ushort ver = r.ReadUInt16();
|
||||
if (ver != Bytecode.Version) throw new Exception($"Unsupported version {ver}");
|
||||
|
||||
ushort nConsts = r.ReadUInt16();
|
||||
var consts = new List<object>();
|
||||
for (int i = 0; i < nConsts; i++) {
|
||||
byte t = r.ReadByte();
|
||||
switch(t) {
|
||||
case 1: consts.Add(r.ReadInt64()); break;
|
||||
case 2: consts.Add(r.ReadDouble()); break;
|
||||
case 3: consts.Add(r.ReadSingle()); break;
|
||||
case 4: consts.Add(r.ReadInt32()); break;
|
||||
default: throw new Exception($"Unknown const type {t}");
|
||||
}
|
||||
}
|
||||
|
||||
ushort nVars = r.ReadUInt16();
|
||||
var varTypes = new VarType[nVars];
|
||||
for (int i = 0; i < nVars; i++) varTypes[i] = (VarType)r.ReadByte();
|
||||
|
||||
ushort codeLen = r.ReadUInt16();
|
||||
var code = r.ReadBytes(codeLen);
|
||||
|
||||
var stack = new Stack<object>();
|
||||
var vars = new object[nVars];
|
||||
int ip = 0;
|
||||
while (ip < code.Length) {
|
||||
byte op = code[ip++];
|
||||
switch(op) {
|
||||
case Bytecode.OpCodes.NOP: break;
|
||||
case Bytecode.OpCodes.PUSH_CONST: {
|
||||
ushort ci = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
stack.Push(consts[ci]);
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.PUSH_REAL_CONST: {
|
||||
ushort ci = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
stack.Push(consts[ci]);
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.LOAD_VAR: {
|
||||
ushort vi = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
stack.Push(vars[vi]);
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.STORE_VAR: {
|
||||
ushort vi = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
vars[vi] = stack.Pop();
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.JZ: {
|
||||
ushort target = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
var cond = stack.Pop();
|
||||
bool isFalse = cond is int ci ? ci == 0 : cond is long cl ? cl == 0L : cond is double cd ? cd == 0.0 : cond == null;
|
||||
if (isFalse) ip = target;
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.JMP: {
|
||||
ushort target = (ushort)(code[ip++] | (code[ip++] << 8));
|
||||
ip = target;
|
||||
break;
|
||||
}
|
||||
case Bytecode.OpCodes.HALT:
|
||||
Console.WriteLine("HALT");
|
||||
return;
|
||||
default:
|
||||
// Simple arithmetic handlers for some opcodes
|
||||
if (Bytecode.OpName(op).StartsWith("ADD_")) {
|
||||
dynamic b = stack.Pop(); dynamic a = stack.Pop(); stack.Push(a + b); break;
|
||||
}
|
||||
if (Bytecode.OpName(op).StartsWith("SUB_")) {
|
||||
dynamic b = stack.Pop(); dynamic a = stack.Pop(); stack.Push(a - b); break;
|
||||
}
|
||||
if (Bytecode.OpName(op).StartsWith("MUL_")) {
|
||||
dynamic b = stack.Pop(); dynamic a = stack.Pop(); stack.Push(a * b); break;
|
||||
}
|
||||
if (Bytecode.OpName(op).StartsWith("DIV_")) {
|
||||
dynamic b = stack.Pop(); dynamic a = stack.Pop(); stack.Push(a / b); break;
|
||||
}
|
||||
if (Bytecode.OpName(op).StartsWith("LT_") || Bytecode.OpName(op).StartsWith("GT_") || Bytecode.OpName(op).StartsWith("LE_") || Bytecode.OpName(op).StartsWith("GE_") || Bytecode.OpName(op).StartsWith("EQ_") || Bytecode.OpName(op).StartsWith("NEQ_")) {
|
||||
// comparisons: pop r, pop l, push int 0/1
|
||||
dynamic rVal = stack.Pop(); dynamic lVal = stack.Pop();
|
||||
bool res = Bytecode.OpName(op).StartsWith("LT_") ? (lVal < rVal) :
|
||||
Bytecode.OpName(op).StartsWith("GT_") ? (lVal > rVal) :
|
||||
Bytecode.OpName(op).StartsWith("LE_") ? (lVal <= rVal) :
|
||||
Bytecode.OpName(op).StartsWith("GE_") ? (lVal >= rVal) :
|
||||
Bytecode.OpName(op).StartsWith("EQ_") ? (lVal == rVal) :
|
||||
(lVal != rVal);
|
||||
stack.Push(res ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
throw new Exception($"Unknown opcode 0x{op:X2}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Execution finished");
|
||||
for (int i = 0; i < vars.Length; i++) Console.WriteLine($"Var[{i}] = {vars[i]}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user