namespace QRScript; using DynamicExpresso; public static class Runner { public static void Interpret(string[] lines) { var env = new Dictionary(); var labels = new Dictionary(); var stack = new Stack(); var exp = new Interpreter(); int pc = 0; // First pass: record labels for (int i = 0; i < lines.Length; i++) { string line = lines[i].Trim(); if (line.StartsWith("@")) labels[line[1..]] = i; } // Main execution loop while (pc < lines.Length) { string raw = lines[pc].Trim(); pc++; if (string.IsNullOrWhiteSpace(raw) || raw.StartsWith("#") || raw.StartsWith("@")) continue; var parts = raw.Split(' ', 4, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) continue; string cmd = parts[0].ToLowerInvariant(); string arg1 = parts.Length > 1 ? parts[1] : null; string arg2 = parts.Length > 2 ? parts[2] : null; string arg3 = parts.Length > 3 ? parts[3] : null; object Eval(string expr) { foreach (var (k, v) in env) exp.SetVariable(k, v); return exp.Eval(expr); } switch (cmd) { case "say": Console.WriteLine(string.Join(' ', parts.Skip(1).Select(p => env.TryGetValue(p, out var val) ? val.ToString() : p))); break; case "set": env[arg1] = Eval(arg2); break; case "add": case "sub": case "mul": case "div": case "mod": if (!env.TryGetValue(arg1, out var val)) val = 0; var op = cmd switch { "add" => "+", "sub" => "-", "mul" => "*", "div" => "/", "mod" => "%", _ => throw new InvalidOperationException() }; env[arg1] = Eval($"{val} {op} {arg2}"); break; case "if": // Format: if x > 10 goto label if (arg2 == "goto" && arg3 != null) { var cond = string.Join(' ', parts.Skip(1).Take(2)); // x > 10 var result = Eval(cond); if (result is bool b && b) pc = labels[arg3]; } break; case "goto": if (arg1 != null && labels.TryGetValue(arg1, out var target)) pc = target; break; case "inp": Console.Write($"{arg1}: "); env[arg1] = Console.ReadLine(); break; case "def": // No-op in this basic form, handled via label + call/ret break; case "call": if (arg1 != null && labels.TryGetValue(arg1, out var fnStart)) { stack.Push(pc); pc = fnStart + 1; if (arg2 != null) env["x"] = Eval(arg2); } break; case "ret": if (stack.Count > 0) pc = stack.Pop(); else return; break; case "cmp": Console.WriteLine($"Compare: {Eval($"{arg1} == {arg2}")}"); break; case "end": return; default: Console.WriteLine($"Unknown command: {cmd}"); break; } } } }