Skip to content

Instantly share code, notes, and snippets.

@koropicot
Created April 5, 2013 08:08
Show Gist options
  • Save koropicot/5317478 to your computer and use it in GitHub Desktop.
Save koropicot/5317478 to your computer and use it in GitHub Desktop.
謎インタプリタ
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