Created
April 5, 2013 08:08
-
-
Save koropicot/5317478 to your computer and use it in GitHub Desktop.
謎インタプリタ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.IO; | |
namespace Brainfuck_i | |
{ | |
struct Command | |
{ | |
public int pointerDiff; | |
public byte memoryDiff; | |
public bool isAdd; | |
} | |
struct SimpleCommand | |
{ | |
public Operator ope; | |
public int matchBracket; | |
} | |
enum Operator :byte | |
{ | |
INC, | |
DEC, | |
RIGHT, | |
LEFT, | |
WHILE, | |
END, | |
OUT, | |
IN, | |
KEY, | |
NONE | |
} | |
static class Program | |
{ | |
static void Main(string[] args) | |
{ | |
if (args.Length == 1) | |
{ | |
if (Executor.Compile(File.ReadAllText(args[0]).ToCharArray())) | |
{ | |
var stopWatch = new System.Diagnostics.Stopwatch(); | |
stopWatch.Start(); | |
try | |
{ | |
Executor.topSequence.Run(0); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine("Runtime Error:"); | |
Console.WriteLine(e.Message); | |
} | |
stopWatch.Stop(); | |
Console.WriteLine("\nRunning time:" + stopWatch.Elapsed.ToString()); | |
} | |
else | |
{ | |
Console.WriteLine("Compile Error:"); | |
Console.WriteLine(Executor.ErrorMessage); | |
} | |
} | |
else | |
Console.WriteLine("Wrong number of argument"); | |
Console.ReadKey(); | |
} | |
} | |
static class Executor | |
{ | |
const int MemSize = 1000; | |
static byte[] memory= new byte[MemSize]; | |
private static bool error = false; | |
public static TopSequence topSequence = null; | |
public static string ErrorMessage = ""; | |
public static bool Compile(IEnumerable<char> source) | |
{ | |
SimpleCommand[] commands = ToSimpleCommamds(source); | |
if (commands == null) | |
{ | |
error = true; | |
ErrorMessage = "[] : NOT matching"; | |
return !error; | |
} | |
topSequence = ToSequence(commands); | |
memory = memory.Select(m => (byte)0).ToArray(); | |
if (error) | |
ErrorMessage = "ToSequence failed"; | |
return !error; | |
} | |
private static TopSequence ToSequence(SimpleCommand[] commands) | |
{ | |
List<Command> cmdList; | |
List<Sequence> sqsList; | |
int pointer; | |
CreatCmdAmdSqsList(commands, out cmdList, out sqsList, out pointer); | |
var ret = new TopSequence(); | |
ret.commands = cmdList.ToArray(); | |
ret.sequences = sqsList.ToArray(); | |
ret.constantDiff = pointer; | |
return ret; | |
} | |
private static LoopSequence GetLoopSequence(SimpleCommand[] commands) | |
{ | |
List<Command> cmdList; | |
List<Sequence> sqsList; | |
int pointer; | |
CreatCmdAmdSqsList(commands, out cmdList, out sqsList,out pointer); | |
var ret = new LoopSequence(); | |
ret.commands = cmdList.ToArray(); | |
ret.sequences = sqsList.ToArray(); | |
ret.constantDiff = pointer; | |
return ret; | |
} | |
private static void CreatCmdAmdSqsList(SimpleCommand[] commands,out List<Command> cmdList,out List<Sequence> sqsList,out int pointer) | |
{ | |
int com = 0; | |
pointer = MemSize / 2; | |
cmdList = new List<Command>(); | |
sqsList = new List<Sequence>(); | |
memory = memory.Select(m => (byte)0).ToArray(); | |
var NONE = new SimpleCommand(); | |
NONE.ope = Operator.NONE; | |
var list = commands.ToList(); | |
list.Add(NONE); | |
commands = list.ToArray(); | |
BracketMatch(ref commands); | |
while (!error && com < commands.Length) | |
{ | |
switch (commands[com].ope) | |
{ | |
case Operator.INC: | |
memory[pointer]++; | |
break; | |
case Operator.DEC: | |
memory[pointer]--; | |
break; | |
case Operator.RIGHT: | |
pointer++; | |
if (pointer >= MemSize) | |
error = true; | |
break; | |
case Operator.LEFT: | |
pointer--; | |
if (pointer < 0) | |
error = true; | |
break; | |
default: | |
cmdList.AddRange(memory.Select((m, i) => | |
{ | |
var c = new Command(); | |
c.isAdd = true;//要改良 | |
c.memoryDiff = m;//要改良 | |
c.pointerDiff = i - (MemSize / 2); | |
return c; | |
}).Where(c => c.memoryDiff != 0)); | |
bool sqs = true; | |
switch (commands[com].ope) | |
{ | |
case Operator.WHILE: | |
sqsList.Add(GetLoopSequence(commands.Skip(com + 1).Take((commands[com].matchBracket - com) - 1).ToArray())); | |
com = commands[com].matchBracket ; | |
break; | |
case Operator.OUT: | |
sqsList.Add(new Output()); | |
break; | |
case Operator.IN: | |
sqsList.Add(new Input()); | |
break; | |
case Operator.NONE: | |
sqs = false; | |
break; | |
default: | |
error = true; | |
break; | |
} | |
if (sqs) | |
{ | |
var sqsCmd = new Command(); | |
sqsCmd.memoryDiff = 0; | |
sqsCmd.pointerDiff = pointer - (MemSize / 2); | |
cmdList.Add(sqsCmd); | |
} | |
memory = memory.Select(m => (byte)0).ToArray(); | |
break; | |
} | |
com++; | |
} | |
pointer -= (MemSize / 2); | |
} | |
private static SimpleCommand[] ToSimpleCommamds(IEnumerable<char> source) | |
{ | |
var comList = new List<SimpleCommand>(); | |
foreach (char c in source) | |
{ | |
var ret = new SimpleCommand(); | |
bool isCommand = true; | |
switch (c) | |
{ | |
case '+': | |
ret.ope = Operator.INC; | |
break; | |
case '-': | |
ret.ope = Operator.DEC; | |
break; | |
case '>': | |
ret.ope = Operator.RIGHT; | |
break; | |
case '<': | |
ret.ope = Operator.LEFT; | |
break; | |
case '[': | |
ret.ope = Operator.WHILE; | |
break; | |
case ']': | |
ret.ope = Operator.END; | |
break; | |
case '.': | |
ret.ope = Operator.OUT; | |
break; | |
case ',': | |
ret.ope = Operator.IN; | |
break; | |
default: | |
isCommand = false; | |
break; | |
} | |
if (isCommand) | |
comList.Add(ret); | |
} | |
var commands = comList.ToArray(); | |
if (!BracketMatch(ref commands))//############## | |
return null; | |
return commands; | |
} | |
static bool BracketMatch(ref SimpleCommand[] commands)// | |
{ | |
var stack = new Stack<int>(); | |
for (int i = 0; i < commands.Length; i++) | |
{ | |
if (commands[i].ope == Operator.WHILE) | |
stack.Push(i); | |
if (commands[i].ope == Operator.END) | |
{ | |
if (stack.Count != 0) | |
{ | |
commands[i].matchBracket = stack.Pop(); | |
commands[commands[i].matchBracket].matchBracket = i; | |
} | |
else | |
return false; | |
} | |
} | |
return true; | |
} | |
public abstract class Sequence | |
{ | |
public Sequence[] sequences = null; | |
public Command[] commands = null; | |
public int constantDiff = 0; | |
protected int currentPointer = 0; | |
public abstract int Run(int pointer); | |
} | |
public class TopSequence : Sequence | |
{ | |
public override int Run(int pointer) | |
{ | |
currentPointer = pointer; | |
uint i = 0; | |
try | |
{ | |
foreach (Command cmd in commands) | |
{ | |
if (cmd.memoryDiff != 0) | |
{ | |
if (currentPointer + cmd.pointerDiff < 0 || currentPointer + cmd.pointerDiff >= MemSize) | |
throw new Exception("Out of Memory"); | |
if (cmd.isAdd) | |
memory[currentPointer + cmd.pointerDiff] += cmd.memoryDiff; | |
else | |
memory[currentPointer + cmd.pointerDiff] -= cmd.memoryDiff; | |
} | |
else | |
currentPointer = sequences[i++].Run(currentPointer + cmd.pointerDiff) - cmd.pointerDiff; | |
} | |
} | |
catch (Exception e) | |
{ | |
throw e; | |
} | |
currentPointer += constantDiff; | |
return currentPointer; | |
} | |
} | |
class LoopSequence : Sequence | |
{ | |
public override int Run(int pointer) | |
{ | |
currentPointer = pointer; | |
while (memory[currentPointer] != 0) | |
{ | |
uint i = 0; | |
try | |
{ | |
foreach (Command cmd in commands) | |
{ | |
if (cmd.memoryDiff != 0) | |
{ | |
if (currentPointer + cmd.pointerDiff < 0 || currentPointer + cmd.pointerDiff >= MemSize) | |
throw new Exception("Out of Memory"); | |
if (cmd.isAdd) | |
memory[currentPointer + cmd.pointerDiff] += cmd.memoryDiff; | |
else | |
memory[currentPointer + cmd.pointerDiff] -= cmd.memoryDiff; | |
} | |
else | |
currentPointer = sequences[i++].Run(currentPointer + cmd.pointerDiff) - cmd.pointerDiff; | |
} | |
} | |
catch (Exception e) | |
{ | |
throw e; | |
} | |
currentPointer += constantDiff; | |
} | |
return currentPointer; | |
} | |
} | |
class Input : Sequence | |
{ | |
public override int Run(int pointer) | |
{ | |
int charCode = Console.In.Read(); | |
if (charCode < 0 || charCode > byte.MaxValue) | |
memory[pointer] = byte.MaxValue; | |
else | |
memory[pointer] = (byte)charCode; | |
return pointer; | |
} | |
} | |
class Output : Sequence | |
{ | |
public override int Run(int pointer) | |
{ | |
Console.Write((char)memory[pointer]); | |
return pointer; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment