static void Main(string[] args) { try { string arg = args[0]; if (arg.EndsWith("!")) { bool debug = arg.StartsWith("?"); if (debug) { arg = arg.Remove(0, 1); } var breakpoints = new List <int>(); bool running = !debug; string data = DataStream.Read(arg, "0"); Environment.CurrentDirectory = Directory.GetParent(arg).FullName; List <string> stack = args.ToList(); stack.RemoveAt(0); var instructions = data.Split(new char[] { ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int statementIndex = 0; statementIndex < instructions.Length && statementIndex >= 0; ++statementIndex) { var e = instructions[statementIndex]; if (debug) { if (!running || breakpoints.Contains(statementIndex)) { running = false; Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine($"\n [{statementIndex + 1}] >> {e}"); Console.ForegroundColor = ConsoleColor.DarkGray; Console.WriteLine("\nVariables:"); PrintVars(arg, stack); Console.ForegroundColor = ConsoleColor.Yellow; debug_io: Console.Write("\n > "); var s = Console.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (s.Length >= 1) { try { switch (s[0]) { case "EXEC": statementIndex--; string a = ""; for (int i = 1; i < s.Length; i++) { a += s[i] + " "; } e = a; break; case "RUN": running = true; break; case "CODE": for (int i = statementIndex; i < Math.Min(statementIndex + 10, instructions.Length); i++) { Console.WriteLine($" [{i + 1}] {instructions[i]}"); } goto debug_io; case "CODEAT": for (int i = int.Parse(s[1]) - 1; i < Math.Min(int.Parse(s[1]) + 10, instructions.Length); i++) { Console.WriteLine($" [{i + 1}] {instructions[i]}"); } goto debug_io; case "ADDB": for (int i = 1; i < s.Length; i++) { breakpoints.Add(int.Parse(s[i]) - 1); } goto debug_io; case "PUTB": foreach (var b in breakpoints) { Console.WriteLine($" Breakpoint set at {b + 1}."); } goto debug_io; case "RMB": for (int i = breakpoints.Count - 1; i >= 0; i--) { if (breakpoints[i] == int.Parse(s[1]) - 1) { breakpoints.RemoveAt(i); } } goto debug_io; case "CLRB": breakpoints.Clear(); goto debug_io; default: Console.WriteLine("Invalid Parameter.\n\n Valid Parameters:\n\n Press enter to continue to next statement.\n\n EXEC <STATEMENT>\n\tMove the Instruction Pointer to the previous instruction and execute the given instruction <STATEMENT>.\n\n RUN\n\tContinue Execution.\n\n CODE\n\tShow the next few lines of code.\n\n CODEAT <INSTRUCTION_INDEX>\n\tShow the next few lines of code starting at <INSTRUCTION_INDEX>.\n\n ADDB <INSTRUCTION_INDEX ...>\n\tAdd breakpoints at all specified instruction indices.\n\n PUTB\n\tShow all breakpoints.\n\n RMB <INSTRUCTION_INDEX>\n\tRemove the breakpoint at <INSTRUCTION_INDEX>.\n\n CLRB\n\tRemove All Breakpoints."); goto debug_io; } } catch (Exception ex) { Console.WriteLine($"Error in debugger: {(ex != null ? ex.ToString() : " < NULL > ")}"); } } Console.ResetColor(); } } try { var s = e.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (s.Length == 1) { switch (s[0]) { case "FLUSH": stack.Clear(); break; case "CR": Console.WriteLine(); break; case "EXIT": goto exit; } } else if (s.Length == 2) { switch (s[0]) { case "CLR": DataStream.Delete(arg, s[1]); break; case "PUTS": Console.Write(DataStream.Read(arg, s[1])); break; case "PUSH": stack.Add(DataStream.Read(arg, s[1])); break; case "PUSHF": stack.Insert(0, DataStream.Read(arg, s[1])); break; case "NOT": stack.Add(_true == DataStream.Read(arg, s[1]) ? _false : _true); break; case "POP": DataStream.Write(arg, s[1], stack.Count() > 0 ? stack.Last() : ""); if (stack.Count() > 0) { stack.RemoveAt(stack.Count() - 1); } break; case "POPF": DataStream.Write(arg, s[1], stack.Count() > 0 ? stack.First() : ""); if (stack.Count() > 0) { stack.RemoveAt(stack.Count() - 1); } break; case "CALL": CallFunc(s[1], ref stack); break; case "SETSP": DataStream.Write(arg, s[1], " "); break; case "JMP": statementIndex = int.Parse(s[1]) - 2; break; case "DJMP": statementIndex = int.Parse(DataStream.Read(arg, s[1])) - 2; break; case "SETIP": DataStream.Write(arg, s[1], (statementIndex - 1).ToString()); break; } } else if (s.Length == 3) { switch (s[0]) { case "SAT": var v = DataStream.Read(arg, s[1]); int x = int.Parse(DataStream.Read(arg, s[2])); if (v.Length > x && x >= 0) { stack.Add(v[x].ToString()); } else { stack.Add(""); } break; case "SET": DataStream.Write(arg, s[1], s[2]); break; case "MOV": DataStream.Write(arg, s[1], DataStream.Read(arg, s[2])); break; case "IADD": stack.Add((int.Parse(DataStream.Read(arg, s[1])) + int.Parse(DataStream.Read(arg, s[2]))).ToString()); break; case "ISUB": stack.Add((int.Parse(DataStream.Read(arg, s[1])) - int.Parse(DataStream.Read(arg, s[2]))).ToString()); break; case "IMUL": stack.Add((int.Parse(DataStream.Read(arg, s[1])) * int.Parse(DataStream.Read(arg, s[2]))).ToString()); break; case "IDIV": stack.Add((int.Parse(DataStream.Read(arg, s[1])) / int.Parse(DataStream.Read(arg, s[2]))).ToString()); break; case "SCAT": stack.Add(DataStream.Read(arg, s[1]) + DataStream.Read(arg, s[2])); break; case "EQ": stack.Add((DataStream.Read(arg, s[1]) == DataStream.Read(arg, s[2])) ? _true : _false); break; case "NE": stack.Add((DataStream.Read(arg, s[1]) != DataStream.Read(arg, s[2])) ? _true : _false); break; case "IGCMP": stack.Add((int.Parse(DataStream.Read(arg, s[1])) > int.Parse(DataStream.Read(arg, s[2]))) ? _true : _false); break; case "IFCALL": if (DataStream.Read(arg, s[1]) == _true) { CallFunc(s[2], ref stack); } break; case "IFJMP": if (DataStream.Read(arg, s[1]) == _true) { statementIndex = int.Parse(s[2]) - 2; } break; case "IFDJMP": if (DataStream.Read(arg, s[1]) == _true) { statementIndex = int.Parse(DataStream.Read(arg, s[2])) - 2; } break; } } if (s.Length > 1) { switch (s[0]) { case "SETS": string a = ""; for (int i = 2; i < s.Length; i++) { a += s[i]; if (i + 1 < s.Length) { a += " "; } } DataStream.Write(arg, s[1], a); break; } } } catch (Exception ex) { if (debug) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"\n\nFailed in Statement {statementIndex} ('{e}').\n{(ex != null ? ex.ToString() : "<NULL>\n\nVariables:\n")}"); PrintVars(arg, stack); Console.ResetColor(); running = false; statementIndex--; } else { Console.WriteLine($"\n\nFailed in Statement {statementIndex} ('{e}')."); break; } } } exit: Clipboard.SetText(stack.Any() ? stack.Last() : "-1"); } else { try { var file = File.ReadAllText(arg); var dict = new Dictionary <string, string>(); var labels = new Dictionary <string, int>(); string a = ""; int statementIndex = 0; foreach (var e in file.Split(new char[] { ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) { try { if (e.StartsWith("#")) { if (!e.StartsWith("##")) { var s = e.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (s.Length == 2) { switch (s[0]) { case "#LABEL": labels.Add(s[1], statementIndex + 1); break; default: Console.WriteLine($"Warning: Invalid Preprocessor Token '{e}'."); break; } } else if (s.Length == 3) { switch (s[0]) { case "#SET": dict.Add(s[1], s[2]); break; case "#SETX": dict.Add(s[1], s[2].Replace('_', ' ')); break; case "#AP": dict.Add(s[1], dict[s[1]] + s[2]); break; case "#APX": dict.Add(s[1], dict[s[1]] + s[2].Replace('_', ' ')); break; default: Console.WriteLine($"Warning: Invalid Preprocessor Token '{e}'."); break; } } else { Console.WriteLine($"Warning: Invalid Preprocessor Token '{e}'."); } } } else { ++statementIndex; a += e + "\n"; } } catch (Exception ex) { Console.WriteLine($"Failed to compile statement '{e}'.\n{(ex != null ? ex.ToString() : "<NULL>")}"); } } try { foreach (var l in labels) { a = a.Replace($"${l.Key}", l.Value.ToString()); } DataStream.Write(arg + "!", "0", a); foreach (var v in dict) { DataStream.Write(arg + "!", v.Key, v.Value); } } catch (Exception) { throw new IOException(); } } catch (Exception e) { Console.WriteLine($"Failed to compile object '{arg}'.\n{(e != null ? e.ToString() : "<NULL>")}"); } } } catch (Exception e) { Console.WriteLine($"Invalid Parameter.\n{(e != null ? e.ToString() : "<NULL>")}"); } }