Disammbler und Simulator angepasst. Arrays begonnen (defunct)
This commit is contained in:
@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user