Example #1
0
        private static void DebuggerLoop(ZMachine zm, string[] sourcePath)
        {
            var console = new DebuggingConsole(zm, zm.IO, sourcePath);

            console.Activate();

            TimedInputCallback cb = () => false;
            byte[] terminatingKeys = { };

            while (console.Active)
            {
                byte terminator;
                string cmd = zm.IO.ReadLine(string.Empty, 0, cb, terminatingKeys, out terminator);

                console.HandleCommand(cmd);
            }
        }
Example #2
0
 public Opcode(ZMachine zm, OpcodeCompiler compiler, OpcodeAttribute attribute,
               int pc, int zCodeLength,
               int argc, OperandType[] operandTypes, short[] operandValues,
               string operandText, int resultStorage, bool branchIfTrue, int branchOffset)
 {
     this.zm           = zm;
     this.compiler     = compiler;
     this.attribute    = attribute;
     this.PC           = pc;
     this.ZCodeLength  = zCodeLength;
     this.argc         = argc;
     this.operandTypes = new OperandType[argc];
     Array.Copy(operandTypes, this.operandTypes, argc);
     this.operandValues = new short[argc];
     Array.Copy(operandValues, this.operandValues, argc);
     this.operandText   = operandText;
     this.resultStorage = resultStorage;
     this.branchIfTrue  = branchIfTrue;
     this.branchOffset  = branchOffset;
 }
Example #3
0
 public Opcode(ZMachine zm, OpcodeCompiler compiler, OpcodeAttribute attribute,
     int pc, int zCodeLength,
     int argc, OperandType[] operandTypes, short[] operandValues,
     string operandText, int resultStorage, bool branchIfTrue, int branchOffset)
 {
     this.zm = zm;
     this.compiler = compiler;
     this.attribute = attribute;
     this.PC = pc;
     this.ZCodeLength = zCodeLength;
     this.argc = argc;
     this.operandTypes = new OperandType[argc];
     Array.Copy(operandTypes, this.operandTypes, argc);
     this.operandValues = new short[argc];
     Array.Copy(operandValues, this.operandValues, argc);
     this.operandText = operandText;
     this.resultStorage = resultStorage;
     this.branchIfTrue = branchIfTrue;
     this.branchOffset = branchOffset;
 }
Example #4
0
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Stream gameFile;
            string storyName;

            if (args.Length > 0)
            {
                if (!File.Exists(args[0]))
                {
                    MessageBox.Show("File not found: " + args[0]);
                    return;
                }

                try
                {
                    gameFile = new FileStream(args[0], System.IO.FileMode.Open, FileAccess.Read);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
                storyName = Path.GetFileName(args[0]);
            }
            else
            {
                using (OpenFileDialog dlg = new OpenFileDialog())
                {
                    dlg.Title = "Select Game File";
                    dlg.Filter = "Supported Z-code files (*.z5;*.z8;*.zblorb;*.zlb)|*.z5;*.z8;*.zblorb;*.zlb|All files (*.*)|*.*";
                    dlg.CheckFileExists = true;
                    if (dlg.ShowDialog() != DialogResult.OK)
                        return;

                    try
                    {
                        gameFile = dlg.OpenFile();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "Error Loading Game");
                        return;
                    }
                    storyName = Path.GetFileName(dlg.FileName);
                }
            }

            using (GlkIO io = new GlkIO(args, storyName))
            {
            #if !DEBUG
                try
                {
            #endif
                    try
                    {
                        ZMachine engine = new ZMachine(gameFile, io);
                        engine.Run();
                    }
                    finally
                    {
                        gameFile.Close();
                    }
            #if !DEBUG
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error Running Game");
                    return;
                }
            #endif
            }
        }
Example #5
0
        static int Main(string[] args)
        {
            try
            {
                Console.Title = "ConsoleZLR";

                Stream gameStream = null, debugStream = null;
                string gameDir = null, debugDir = null;
                string fileName = null, commandFile = null;
                DisplayType displayType = DisplayType.FullScreen;
                bool debugger = false, predictable = false;
                bool wait = true;

                if (args.Length >= 1 && args[0].Length > 0)
                {
                    int n = 0;

                    bool parsing = true;
                    do
                    {
                        switch (args[n].ToLower())
                        {
                            case "-commands":
                                if (args.Length > n + 1)
                                {
                                    commandFile = args[n + 1];
                                    n += 2;
                                    if (args.Length <= n)
                                        return Usage();
                                }
                                else
                                    return Usage();
                                break;
                            case "-dumb":
                                n++;
                                displayType = DisplayType.Dumb;
                                break;
                            case "-dumb2":
                                n++;
                                displayType = DisplayType.DumbBottomWinOnly;
                                break;
                            case "-debug":
                                n++;
                                debugger = true;
                                break;
                            case "-predictable":
                                n++;
                                predictable = true;
                                break;
                            case "-nowait":
                                n++;
                                wait = false;
                                break;
                            default:
                                parsing = false;
                                break;
                        }
                    } while (parsing);

                    gameStream = new FileStream(args[n], FileMode.Open, FileAccess.Read);
                    gameDir = Path.GetDirectoryName(Path.GetFullPath(args[n]));
                    fileName = Path.GetFileName(args[n]);

                    if (args.Length > n + 1)
                    {
                        debugStream = new FileStream(args[n + 1], FileMode.Open, FileAccess.Read);
                        debugDir = Path.GetDirectoryName(Path.GetFullPath(args[n + 1]));
                    }
                }
                else
                {
                    return Usage();
                }

                IZMachineIO io;

                switch (displayType)
                {
                    case DisplayType.Dumb:
                        io = new DumbIO(false, commandFile);
                        break;

                    case DisplayType.DumbBottomWinOnly:
                        io = new DumbIO(true, commandFile);
                        break;

                    case DisplayType.FullScreen:
                        ConsoleIO cio = new ConsoleIO(fileName);
                        if (commandFile != null)
                        {
                            cio.SuppliedCommandFile = commandFile;
                            cio.HideMorePrompts = true;
                        }
                        io = cio;
                        break;

                    default:
                        throw new NotImplementedException();
                }

                ZMachine zm = new ZMachine(gameStream, io);
                zm.PredictableRandom = predictable;
                if (commandFile != null)
                    zm.ReadingCommandsFromFile = true;
                if (debugStream != null)
                    zm.LoadDebugInfo(debugStream);

                if (debugger)
                {
                    List<string> sourcePath = new List<string>(3);
                    if (debugDir != null)
                        sourcePath.Add(debugDir);
                    sourcePath.Add(gameDir);
                    sourcePath.Add(Directory.GetCurrentDirectory());

                    DebuggerLoop(zm, sourcePath.ToArray());
                }
                else
                {
            #if DEBUG
                    zm.Run();
            #else
                try
                {
                    zm.Run();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            #endif
                    if (wait)
                    {
                        Console.WriteLine("Press any key to exit...");
                        Console.ReadKey(true);
                    }
                }
                return 0;
            }
            catch (Exception ex)
            {
                return Error(ex.Message + " (" + ex.GetType().Name + ")");
            }
        }
Example #6
0
        private static int ParseAddress(ZMachine zm, IDebugger dbg, string spec)
        {
            if (!string.IsNullOrEmpty(spec))
            {
                if (spec[0] == '$')
                    return Convert.ToInt32(spec.Substring(1), 16);

                if (char.IsDigit(spec[0]))
                    return Convert.ToInt32(spec);

                if (zm.DebugInfo != null)
                {
                    int idx = spec.LastIndexOf(':');
                    if (idx >= 0)
                    {
                        try
                        {
                            int result = zm.DebugInfo.FindCodeAddress(
                                spec.Substring(0, idx),
                                Convert.ToInt32(spec.Substring(idx + 1)));
                            if (result >= 0)
                                return result;
                        }
                        catch (FormatException) { }
                        catch (OverflowException) { }
                    }

                    RoutineInfo rtn;

                    idx = spec.LastIndexOf('+');
                    if (idx >= 0)
                    {
                        try
                        {
                            rtn = zm.DebugInfo.FindRoutine(spec.Substring(0, idx));
                            if (rtn != null)
                                return rtn.CodeStart + Convert.ToInt32(spec.Substring(idx + 1));
                        }
                        catch (FormatException) { }
                        catch (OverflowException) { }
                    }

                    rtn = zm.DebugInfo.FindRoutine(spec);
                    if (rtn != null && rtn.LineOffsets.Length > 0)
                        return rtn.CodeStart + rtn.LineOffsets[0];
                }
            }

            return -1;
        }
Example #7
0
 public DebuggingConsole(ZMachine zm, IZMachineIO io, string[] sourcePath)
 {
     this.zm = zm;
     this.io = io;
     this.sourcePath = sourcePath;
 }
Example #8
0
        private static void DebuggerLoop(ZMachine zm, string[] sourcePath)
        {
            IDebugger dbg = zm.Debug();
            RoutineInfo rtn;
            SourceCache src = new SourceCache(sourcePath);

            Console.WriteLine("ConsoleZLR Debugger");
            dbg.Restart();

            string lastCmd = null;
            char[] delim = new char[] { ' ' };
            while (true)
            {
                Console.WriteLine();
                if (dbg.State == DebuggerState.Paused)
                {
                    if (zm.DebugInfo != null &&
                        (rtn = zm.DebugInfo.FindRoutine(dbg.CurrentPC)) != null)
                    {
                        Console.Write("${0:x5} ({1}+{2})   ",
                            dbg.CurrentPC,
                            rtn.Name,
                            dbg.CurrentPC - rtn.CodeStart);
                        Console.WriteLine(dbg.Disassemble(dbg.CurrentPC));

                        LineInfo? li = zm.DebugInfo.FindLine(dbg.CurrentPC);
                        if (li != null)
                            Console.WriteLine("{0}:{1}: {2}",
                                li.Value.File,
                                li.Value.Line,
                                src.Load(li.Value));
                    }
                    else
                    {
                        Console.Write("${0:x5}   ", dbg.CurrentPC);
                        Console.WriteLine(dbg.Disassemble(dbg.CurrentPC));
                    }
                }
                else if (dbg.State == DebuggerState.Stopped)
                {
                    Console.WriteLine("Debugger is stopped.");
                }

                Console.Write("D> ");

                string cmd = Console.ReadLine();
                if (cmd.Trim() == "")
                {
                    if (lastCmd == null)
                    {
                        Console.WriteLine("No last command.");
                        continue;
                    }
                    cmd = lastCmd;
                }
                else
                {
                    lastCmd = cmd;
                }

                string[] parts = cmd.Split(delim, StringSplitOptions.RemoveEmptyEntries);
                int address;
                ICallFrame[] frames;
                switch (parts[0].ToLower())
                {
                    case "reset":
                        dbg.Restart();
                        break;

                    case "s":
                    case "step":
                        if (dbg.State == DebuggerState.Paused)
                            dbg.StepInto();
                        break;

                    case "o":
                    case "over":
                        if (dbg.State == DebuggerState.Paused)
                            dbg.StepOver();
                        break;

                    case "up":
                        if (dbg.State == DebuggerState.Paused)
                            dbg.StepUp();
                        break;

                    case "sl":
                    case "stepline":
                        if (dbg.State == DebuggerState.Paused)
                        {
                            if (zm.DebugInfo == null)
                            {
                                Console.WriteLine("No line information.");
                            }
                            else
                            {
                                LineInfo? oldLI = zm.DebugInfo.FindLine(dbg.CurrentPC);
                                LineInfo? newLI;
                                do
                                {
                                    dbg.StepInto();
                                    if (dbg.State != DebuggerState.Paused)
                                        break;

                                    newLI = zm.DebugInfo.FindLine(dbg.CurrentPC);
                                } while (newLI != null && newLI == oldLI);
                            }
                        }
                        break;

                    case "ol":
                    case "overline":
                        if (dbg.State == DebuggerState.Paused)
                        {
                            if (zm.DebugInfo == null)
                            {
                                Console.WriteLine("No line information.");
                            }
                            else
                            {
                                LineInfo? oldLI = zm.DebugInfo.FindLine(dbg.CurrentPC);
                                LineInfo? newLI;
                                do
                                {
                                    dbg.StepOver();
                                    if (dbg.State != DebuggerState.Paused)
                                        break;

                                    newLI = zm.DebugInfo.FindLine(dbg.CurrentPC);
                                } while (newLI != null && newLI == oldLI);
                            }
                        }
                        break;

                    case "r":
                    case "run":
                        if (dbg.State == DebuggerState.Stopped)
                            dbg.Restart();
                        dbg.Run();
                        break;

                    case "b":
                    case "break":
                        if (parts.Length < 2 || (address = ParseAddress(zm, dbg, parts[1])) < 0)
                        {
                            Console.WriteLine("Usage: break <addrspec>");
                        }
                        else
                        {
                            dbg.SetBreakpoint(address, true);
                            Console.WriteLine("Set breakpoint at {0}.", DumpCodeAddress(zm, dbg, address));
                        }
                        break;

                    case "c":
                    case "clear":
                        if (parts.Length < 2 || (address = ParseAddress(zm, dbg, parts[1])) < 0)
                        {
                            Console.WriteLine("Usage: clear <addrspec>");
                        }
                        else
                        {
                            dbg.SetBreakpoint(address, false);
                            Console.WriteLine("Cleared breakpoint at {0}.", DumpCodeAddress(zm, dbg, address));
                        }
                        break;

                    case "bps":
                    case "breakpoints":
                        int[] breakpoints = dbg.GetBreakpoints();
                        if (breakpoints.Length == 0)
                        {
                            Console.WriteLine("No breakpoints.");
                        }
                        else
                        {
                            Console.WriteLine("{0} breakpoint{1}:",
                                breakpoints.Length,
                                breakpoints.Length == 1 ? "" : "s");

                            Array.Sort(breakpoints);
                            foreach (int bp in breakpoints)
                                Console.WriteLine("    {0}", DumpCodeAddress(zm, dbg, bp));
                        }
                        break;

                    case "bt":
                    case "backtrace":
                        frames = dbg.GetCallFrames();
                        Console.WriteLine("Call depth: {0}", frames.Length);
                        Console.WriteLine("PC = {0}", DumpCodeAddress(zm, dbg, dbg.CurrentPC));

                        for (int i = 0; i < frames.Length; i++)
                        {
                            ICallFrame cf = frames[i];
                            Console.WriteLine("==========");
                            Console.WriteLine("[{0}] return PC = {1}", i + 1, DumpCodeAddress(zm, dbg, cf.ReturnPC));
                            Console.WriteLine("called with {0} arg{1}, stack depth {2}",
                                cf.ArgCount,
                                cf.ArgCount == 1 ? "" : "s",
                                cf.PrevStackDepth);

                            if (cf.ResultStorage < 16)
                            {
                                if (cf.ResultStorage == -1)
                                {
                                    Console.WriteLine("discarding result");
                                }
                                else if (cf.ResultStorage == 0)
                                {
                                    Console.WriteLine("storing result to stack");
                                }
                                else
                                {
                                    rtn = null;
                                    if (zm.DebugInfo != null)
                                        rtn = zm.DebugInfo.FindRoutine(cf.ReturnPC);
                                    if (rtn != null && cf.ResultStorage - 1 < rtn.Locals.Length)
                                        Console.WriteLine("storing result to local {0} ({1})",
                                            cf.ResultStorage,
                                            rtn.Locals[cf.ResultStorage - 1]);
                                    else
                                        Console.WriteLine("storing result to local {0}", cf.ResultStorage);
                                }
                            }
                            else if (zm.DebugInfo.Globals.Contains((byte)cf.ResultStorage))
                            {
                                Console.WriteLine("storing result to global {0} ({1})", cf.ResultStorage,
                                    zm.DebugInfo.Globals[(byte)cf.ResultStorage]);
                            }
                            else
                            {
                                Console.WriteLine("storing result to global {0}", cf.ResultStorage);
                            }
                        }
                        Console.WriteLine("==========");
                        break;

                    case "l":
                    case "locals":
                        frames = dbg.GetCallFrames();
                        int stackItems;
                        if (frames.Length == 0)
                        {
                            Console.WriteLine("No call frame.");
                            stackItems = dbg.StackDepth;
                        }
                        else
                        {
                            ICallFrame cf = frames[0];
                            if (cf.Locals.Length == 0)
                            {
                                Console.WriteLine("No local variables.");
                            }
                            else
                            {
                                Console.WriteLine("{0} local variable{1}:",
                                    cf.Locals.Length,
                                    cf.Locals.Length == 1 ? "" : "s");

                                rtn = zm.DebugInfo.FindRoutine(dbg.CurrentPC);
                                for (int i = 0; i < cf.Locals.Length; i++)
                                {
                                    Console.Write("    ");
                                    if (rtn != null && i < rtn.Locals.Length)
                                        Console.Write(rtn.Locals[i]);
                                    else
                                        Console.Write("local_{0}", i + 1);
                                    Console.WriteLine(" = {0} (${0:x4})", cf.Locals[i]);
                                }
                            }
                            stackItems = dbg.StackDepth - cf.PrevStackDepth;
                        }
                        if (stackItems == 0)
                        {
                            Console.WriteLine("No data on stack.");
                        }
                        else
                        {
                            Console.WriteLine("{0} word{1} on stack:",
                                stackItems,
                                stackItems == 1 ? "" : "s");
                            Stack<short> temp = new Stack<short>();
                            for (int i = 0; i < stackItems; i++)
                            {
                                short value = dbg.StackPop();
                                temp.Push(value);
                                Console.WriteLine("    ${0:x4} (${0})", value);
                            }
                            while (temp.Count > 0)
                                dbg.StackPush(temp.Pop());
                        }
                        break;

                    case "q":
                    case "quit":
                        Console.WriteLine("Goodbye.");
                        return;

                    default:
                        Console.WriteLine("Unrecognized debugger command.");

                        Console.WriteLine("Commands:");
                        Console.WriteLine("reset, (s)tep, (o)ver, stepline (sl), overline (ol), up, (r)un,");
                        Console.WriteLine("(b)reak, (c)lear, breakpoints (bps)");
                        Console.WriteLine("backtrace (bt), (l)ocals, (g)lobals, (q)uit");
                        break;
                }
            }
        }
Example #9
0
        private static string DumpCodeAddress(ZMachine zm, IDebugger dbg, int address)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("${0:x5}", address);

            if (zm.DebugInfo != null)
            {
                RoutineInfo rtn = zm.DebugInfo.FindRoutine(address);
                if (rtn != null)
                {
                    sb.AppendFormat(" ({0}+{1}", rtn.Name, address - rtn.CodeStart);

                    LineInfo? li = zm.DebugInfo.FindLine(address);
                    if (li != null)
                        sb.AppendFormat(", {0}:{1}", li.Value.File, li.Value.Line);

                    sb.Append(')');
                }
            }

            return sb.ToString();
        }
Example #10
0
        private static string RunAndCollectOutput(ZMachine zm, TestCaseIO io)
        {
            string output = null;

            try
            {
                zm.PredictableRandom = true;
                zm.Run();
                output = io.CollectOutput();
            }
            catch (Exception ex)
            {
                if (output == null)
                    output = io.CollectOutput();

                output += "\n\n*** Exception ***\n" + ex.ToString();
            }

            return output;
        }
Example #11
0
        private static bool? RunOneTest(TestCase test)
        {
            if (!File.Exists(test.InputFile) || !File.Exists(test.OutputFile))
            {
                Console.WriteLine("skipping (expected outcome not recorded).");
                return null;
            }
            else
            {
                try
                {
                    using (Stream zcode = test.GetZCode())
                    {
                        ReplayIO io = new ReplayIO(test.InputFile);
                        ZMachine zm = new ZMachine(zcode, io);

                        zm.PredictableRandom = true;
                        zm.ReadingCommandsFromFile = true;

                        string output = RunAndCollectOutput(zm, io);
                        string expectedOutput = File.ReadAllText(test.OutputFile);

                        if (OutputDiffers(expectedOutput, output))
                        {
                            Console.WriteLine("failed!");
                            File.WriteAllText(test.FailureFile, output);
                            return false;
                        }
                        else
                        {
                            Console.WriteLine("passed.");
                            return true;
                        }
                    }
                }
                finally
                {
                    test.CleanUp();
                }
            }
        }
Example #12
0
        private static void RecordExpectedOutcome()
        {
            TestCase selected = PromptForTestCase();

            if (selected != null)
            {
                try
                {
                    using (Stream zcode = selected.GetZCode())
                    {
                        RecordingIO io = new RecordingIO(selected.InputFile);
                        ZMachine zm = new ZMachine(zcode, io);
                        zm.PredictableRandom = true;
                        zm.WritingCommandsToFile = true;

                        string output = RunAndCollectOutput(zm, io);
                        File.WriteAllText(selected.OutputFile, output);
                    }
                }
                finally
                {
                    selected.CleanUp();
                }
            }
        }
Example #13
0
 public Debugger(ZMachine zm)
 {
     this.zm = zm;
 }
Example #14
0
        private static void RunAllTests()
        {
            List<string> names = new List<string>(testCases.Keys);
            names.Sort();

            if (names.Count == 0)
            {
                Console.WriteLine("No tests to run.");
            }
            else
            {
                int failures = 0;

                foreach (string name in names)
                {
                    TestCase test = testCases[name];

                    Console.Write("{0} - ", name);

                    if (!File.Exists(test.InputFile) || !File.Exists(test.OutputFile))
                    {
                        Console.WriteLine("skipping (expected outcome not recorded).");
                    }
                    else
                    {
                        try
                        {
                            using (Stream zcode = test.GetZCode())
                            {
                                ReplayIO io = new ReplayIO(test.InputFile);
                                ZMachine zm = new ZMachine(zcode, io);

                                zm.PredictableRandom = true;
                                zm.ReadingCommandsFromFile = true;

                                string output = RunAndCollectOutput(zm, io);
                                string expectedOutput = File.ReadAllText(test.OutputFile);

                                if (OutputDiffers(expectedOutput, output))
                                {
                                    Console.WriteLine("failed!");
                                    failures++;
                                    File.WriteAllText(test.FailureFile, output);
                                }
                                else
                                {
                                    Console.WriteLine("passed.");
                                }
                            }
                        }
                        finally
                        {
                            test.CleanUp();
                        }
                    }
                }

                if (failures > 0)
                {
                    Console.WriteLine();
                    Console.WriteLine("{0} test{1} failed. The actual output is saved with the suffix \".failed-output.txt\".",
                        failures,
                        failures == 1 ? "" : "s");
                }
            }
        }
Example #15
0
			public void Main()
			{
				try
				{	// will block on zm.Run() until the story file completes
					Stream gameStream = new FileStream(m_storyFile, FileMode.Open, FileAccess.Read);
					DumbIO io = new DumbIO(this);
					ZMachine zm = new ZMachine(gameStream, io);
					zm.Run(); 
				}
                catch (Exception ex) { EventSink.InvokeLogException(new LogExceptionEventArgs(ex)); }
				m_stopped = true;
				return;
			}
Example #16
0
 public Debugger(ZMachine zm)
 {
     this.zm = zm;
 }