public override bool Equals(object o) { if (o.GetType() != GetType()) { return(false); } ExtendedChar other = (ExtendedChar)o; return((Number != null && other.Number != null) ? Number == other.Number : Value == other.Value); }
static void Main(string[] args) { bool asciiMode = false, strictMode = false, breakMode = false, fileMode = false, commentMode = false; string command; if (args.Contains("--help") || args.Contains("-h")) { Console.WriteLine("\nInterprets a Defunc program.\n\n --help -h Displays this help message.\n --ascii -a Converts ASCII input to integers and outputs as ASCII characters.\n --strict -s Makes minor errors halt execution.\n --break -b Gives option to break during a long execution cycle.\n --file -f Use F\"Filename\" to run a premade file.\n --comment -c Allows | to be used to toggle between comments and code. (Always on for loaded files.)\n\nPress any key to exit."); Console.ReadKey(); return; } if (args.Contains("--ascii") || args.Contains("-a")) { asciiMode = true; } if (args.Contains("--strict") || args.Contains("-s")) { strictMode = true; } if (args.Contains("--break") || args.Contains("-b")) { breakMode = true; } if (args.Contains("--file") || args.Contains("-f")) { fileMode = true; } if (args.Contains("--comment") || args.Contains("-c")) { commentMode = true; } List <OpInfo> Functions = OpInfo.GetDefault(asciiMode); if (fileMode) { Functions.Add(new OpInfo('F')); } if (commentMode) { Functions.Add(new OpInfo('|')); } List <string> commands = new List <string>(); while (true) { if (commands.Count == 0) { commands.AddRange(Console.ReadLine().Split(new char[] { '\n' })); if (commands[0] == "") { break; } } command = commands[0]; #region Read From File Regex regex = new Regex("^F\".*\"$"); if (fileMode && regex.IsMatch(command)) { string path = command.Substring(2, command.Length - 3); string[] lines = new string[0]; try { lines = File.ReadAllLines(path); } catch (Exception e) { Console.WriteLine("Error reading file: " + e.ToString()); } //Strip comments. string[] strippedLines = new string[lines.Length]; foreach (string line in lines) { string strippedLine = ""; string tempLine = line; while (tempLine.Length > 0) { if (tempLine[0] == '|') { tempLine = tempLine.Substring(1); while (tempLine[0] != '|' && tempLine.Length > 0) { tempLine = tempLine.Substring(1); } tempLine = tempLine.Substring(1); continue; } strippedLine += tempLine[0]; tempLine = tempLine.Substring(1); } strippedLines[Array.IndexOf(lines, line)] = strippedLine; } commands.AddRange(strippedLines); commands = commands.Skip(1).ToList(); continue; } #endregion #region Strip Comments string strippedCommand = ""; string tempCommand = command; while (tempCommand.Length > 0) { if (tempCommand[0] == '|') { tempCommand = tempCommand.Substring(1); while (tempCommand[0] != '|' && tempCommand.Length > 0) { tempCommand = tempCommand.Substring(1); } tempCommand = tempCommand.Substring(1); continue; } strippedCommand += tempCommand[0]; tempCommand = tempCommand.Substring(1); } if (commentMode) { command = strippedCommand; } #endregion #region New Function Definition if (!Functions.Select(x => x.Name).Contains(command[0])) { // Scan for the function name, and any local variables. char name = command[0]; command = command.Substring(1); Dictionary <char, int> locals = new Dictionary <char, int>(); while (!Functions.Select(x => x.Name).Contains(command[0]) && !locals.Select(x => x.Key).Contains(command[0])) { locals.Add(command[0], locals.Count); command = command.Substring(1); } //Create the function itself. char[] innerCommand = command.ToCharArray(); Functions.Add(new OpInfo(name, locals.Count, x => { x.Stack.Push(y => y.MoveNext()); x.Stack.Push(y => { List <ReturnValue> returned = y.ReturnValues.Pop(); ExtendedChar[] modCommand = new ExtendedChar[innerCommand.Length]; innerCommand.Select(z => (ExtendedChar)z).ToArray().CopyTo(modCommand, 0); //Substitute in passed values. foreach (KeyValuePair <char, int> kvp in locals) { modCommand = modCommand.Select(z => z.Equals((ExtendedChar)kvp.Key) ? new ExtendedChar(returned[kvp.Value].Value) : z).ToArray(); } List <ExtendedChar> trimmed = new List <ExtendedChar>(); //Trim any excess commands. int count = 1; while (count > 0) { if (modCommand[0].Number == null) { count += y.Funcs.Where(z => z.Name == modCommand[0].Value).GetFunction().ParamCount; } count--; trimmed.AddRange(modCommand.Take(1)); modCommand = modCommand.Skip(1).ToArray(); } if (strictMode && modCommand.Length > 0) { throw new ArgumentCountException(); } //Add to unanalyzed program. y.Program = trimmed.Concat(y.Program).ToArray(); return(y); }); x.Await(locals.Count); return(x); })); commands = commands.Skip(1).ToList(); continue; } #endregion #region Execute Function //Initialize the program's state. State CurrentState = new State(); CurrentState.Funcs = Functions; CurrentState.ReturnValues = new Stack <List <ReturnValue> >(); CurrentState.Stack = new Stack <Func <State, State> >(new Func <State, State>[] { new Func <State, State>(x => x.MoveNext()) }); CurrentState.Program = command.ToCharArray().Select(x => (ExtendedChar)x).ToArray(); ulong cycles = 0ul; ulong max = 100_000_000ul; while (CurrentState.Stack.Count > 0) { try { //Runs the current command. CurrentState = CurrentState.Stack.Pop()(CurrentState); } catch (Exception e) { Console.WriteLine("There was an error: " + e.ToString()); break; } if (breakMode && cycles++ >= max) { Console.Write("\nContinue execution? Y/N : "); string response = Console.ReadLine(); if (response.Length == 0 || (response[0] != 'y' && response[0] != 'Y')) { break; } max *= 10; } } Console.WriteLine(); if (CurrentState.Program.Count() > 0 && strictMode) { throw new ArgumentCountException(); } commands = commands.Skip(1).ToList(); #endregion } }