Disammbler und Simulator angepasst. Arrays begonnen (defunct)

This commit is contained in:
2025-10-13 12:09:15 +02:00
parent 3cb6373915
commit 74f256efb2
50 changed files with 534 additions and 75 deletions

View File

@ -33,6 +33,10 @@ class Program {
try {
var emitter = new BytecodeEmitter();
// Register array types from parser
foreach (var (name, arrayType) in parser.arrayTypes) {
emitter.RegisterArrayType(name, arrayType);
}
emitter.Compile(prog);
File.WriteAllBytes(args[1], emitter.BuildBinary());
Console.WriteLine($"Wrote {args[1]}: consts={emitter.ConstantsCount}, vars={emitter.VarCount}, code={emitter.CodeLength}");
@ -52,11 +56,17 @@ public class BytecodeEmitter {
List<object> consts = new(); // Kann nun int, long, float oder double speichern
Dictionary<string,Symbol> syms = new();
List<byte> code = new();
Dictionary<string,ArrayType> arrayTypes = new();
class Symbol {
required public string Name;
public VarType Type;
public int Index;
public ArrayType? ArrayInfo; // Null for non-array types
}
public void RegisterArrayType(string name, ArrayType type) {
arrayTypes[name] = type;
}
public int ConstantsCount => consts.Count;
@ -65,8 +75,19 @@ public class BytecodeEmitter {
public void Compile(ProgramNode p){
int idx=0;
foreach(var v in p.Vars)
syms[v.Name]=new Symbol{Name=v.Name,Type=v.Type,Index=idx++};
foreach(var v in p.Vars) {
var symbol = new Symbol{Name=v.Name, Type=v.Type, Index=idx};
if (v.Type == VarType.ARRAY) {
var arrayInfo = arrayTypes[v.Name];
symbol.ArrayInfo = arrayInfo;
// For arrays, increment the index by array size
idx += arrayInfo.Length;
} else {
// For regular variables, increment by 1
idx++;
}
syms[v.Name] = symbol;
}
foreach(var v in p.Vars)
if(v.Init!=null){EmitExpr(v.Init);EmitByte(Bytecode.OpCodes.STORE_VAR);EmitU16((ushort)syms[v.Name].Index);}
@ -149,8 +170,43 @@ public class BytecodeEmitter {
if (!syms.TryGetValue(a.Target, out symbol)) {
throw new Exception($"Undeclared variable '{a.Target}'");
}
EmitExpr(a.Expr);
EmitByte(Bytecode.OpCodes.STORE_VAR); EmitU16((ushort)symbol.Index);
// If this is an array assignment, we need to evaluate the index and adjust the target address
if (symbol.Type == VarType.ARRAY && a.Index != null) {
// Evaluate array index
EmitExpr(a.Index);
// Bounds check
if (symbol.ArrayInfo == null)
throw new Exception($"Internal error: Array info missing for '{a.Target}'");
EmitByte(Bytecode.OpCodes.ARRAY_BOUNDS_CHECK);
EmitU16((ushort)symbol.ArrayInfo.Start);
EmitU16((ushort)symbol.ArrayInfo.End);
// Convert to zero-based index
if (symbol.ArrayInfo.Start != 0) {
EmitByte(Bytecode.OpCodes.PUSH_CONST);
EmitU16((ushort)AddConst(symbol.ArrayInfo.Start));
EmitByte(Bytecode.OpCodes.SUB_INT);
}
// Add base address
EmitByte(Bytecode.OpCodes.PUSH_CONST);
EmitU16((ushort)symbol.Index);
EmitByte(Bytecode.OpCodes.ADD_INT);
// Now evaluate and store the value
EmitExpr(a.Expr);
EmitByte(Bytecode.OpCodes.STORE_VAR);
EmitU16(0); // Index is already on stack
}
else {
// Regular variable assignment
EmitExpr(a.Expr);
EmitByte(Bytecode.OpCodes.STORE_VAR);
EmitU16((ushort)symbol.Index);
}
break;
case IfStmt iff:
@ -226,14 +282,12 @@ public class BytecodeEmitter {
int ci = AddConst(ie.Value);
EmitByte(Bytecode.OpCodes.PUSH_CONST); // PUSH_CONST
EmitU16((ushort)ci);
// removed emitting the type byte into code stream; type is stored with constant table
break;
case RealExpr re:
int cri = AddConst(re.Value);
EmitByte(Bytecode.OpCodes.PUSH_REAL_CONST); // PUSH_REAL_CONST
EmitU16((ushort)cri);
// removed emitting the type byte into code stream; type is stored with constant table
break;
case VarExpr ve:
@ -244,6 +298,42 @@ public class BytecodeEmitter {
EmitByte(Bytecode.OpCodes.LOAD_VAR); // LOAD_VAR
EmitU16((ushort)symbol.Index);
break;
case ArrayAccessExpr ae:
Symbol? arraySymbol = null;
if (!syms.TryGetValue(ae.ArrayName, out arraySymbol)) {
throw new Exception($"Undeclared array '{ae.ArrayName}'");
}
if (arraySymbol.Type != VarType.ARRAY || arraySymbol.ArrayInfo == null) {
throw new Exception($"Variable '{ae.ArrayName}' is not an array");
}
// Emit the index expression first
EmitExpr(ae.Index);
// Emit array bounds check
int start = arraySymbol.ArrayInfo.Start;
int end = arraySymbol.ArrayInfo.End;
EmitByte(Bytecode.OpCodes.ARRAY_BOUNDS_CHECK);
EmitU16((ushort)start);
EmitU16((ushort)end);
// Convert index to zero-based
if (start != 0) {
EmitByte(Bytecode.OpCodes.PUSH_CONST);
EmitU16((ushort)AddConst(start));
EmitByte(Bytecode.OpCodes.SUB_INT);
}
// Load array base address
EmitByte(Bytecode.OpCodes.PUSH_CONST);
EmitU16((ushort)arraySymbol.Index);
EmitByte(Bytecode.OpCodes.ADD_INT);
// Load array element
EmitByte(Bytecode.OpCodes.LOAD_VAR);
EmitU16(0); // Index is already on stack
break;
case BinaryExpr be:
EmitExpr(be.L);
@ -253,14 +343,6 @@ public class BytecodeEmitter {
if (!opCodes.ContainsKey(key)) {
throw new Exception($"Unknown operator '{be.Op}' for type {be.Type}");
}
// Wenn nötig, Typenkonvertierung vor der Operation
// Conversion opcodes removed - runtime will handle type differences using constant type markers and operation opcodes
// if (be.L.Type != be.Type)
// EmitByte((byte)(0x50 + (int)be.Type)); // CONVERT_TO_*
// if (be.R.Type != be.Type)
// EmitByte((byte)(0x50 + (int)be.Type)); // CONVERT_TO_*
EmitByte(opCodes[key]);
break;
}
@ -308,11 +390,29 @@ public class BytecodeEmitter {
}
}
// Calculate total variable space needed (accounting for arrays)
int totalVarSpace = 0;
foreach(var kv in syms) {
if (kv.Value.Type == VarType.ARRAY && kv.Value.ArrayInfo != null) {
totalVarSpace = Math.Max(totalVarSpace, kv.Value.Index + kv.Value.ArrayInfo.Length);
} else {
totalVarSpace = Math.Max(totalVarSpace, kv.Value.Index + 1);
}
}
// Variablen
w.Write((ushort)syms.Count);
var types = new byte[syms.Count];
foreach(var kv in syms)
types[kv.Value.Index] = (byte)kv.Value.Type;
w.Write((ushort)totalVarSpace);
var types = new byte[totalVarSpace];
foreach(var kv in syms) {
if (kv.Value.Type == VarType.ARRAY && kv.Value.ArrayInfo != null) {
// Fill array elements with their element type
for (int i = 0; i < kv.Value.ArrayInfo.Length; i++) {
types[kv.Value.Index + i] = (byte)kv.Value.ArrayInfo.ElementType;
}
} else {
types[kv.Value.Index] = (byte)kv.Value.Type;
}
}
foreach(var b in types)
w.Write(b);