Skip to content

Commit

Permalink
First commit, reall
Browse files Browse the repository at this point in the history
  • Loading branch information
TinnedTuna committed Sep 27, 2009
1 parent 7f591a9 commit f6746ff
Show file tree
Hide file tree
Showing 4 changed files with 353 additions and 0 deletions.
153 changes: 153 additions & 0 deletions bfinterpreter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import sys

import stack
import tape
"""
Brainfuck interpreter
Uses a bre-built map of where to jump as an optimization. Code must be
preprocessed, this is not a repl.
"""


class BFInterpreter():
def __init__(self):
self.tape = tape.Tape()
#self.stack = stack.Stack() # Stack for loops
self.instruction_pointer = 0 # Current instruction
self.program = [] # The program
self.instructions = { ">":self.tape.move_forwards, \
"<":self.tape.move_backwards, \
"+":self.tape.increment, \
"-":self.tape.decrement, \
"[":self.enter_loop, \
"]":self.end_loop, \
".":self.output, \
",":self.input, \
"#":self.debug \
}
self.jump_map = {} # A place to look for corresponding braces

def preprocess_program(self, input_code=None):
"""
Preprocess the brainfuck
Remove comments, split each individual instruction into the
program tape. Clear the memory tape for the next execution.
"""
if (input_code == None):
return;
map(self.program.append, filter((lambda (char): char in self.instructions), input_code))
#self.program.append(False) # Causes interpretation to stop after the program has finished.
self.build_jump_map(self.program)

def build_jump_map(self, input_program):
"""
Build a map of where each "]" has an opening "[".
input_program must be a list of bf commands.
"""
open_bracket_stack = stack.Stack()
for inst, command in enumerate(input_program):
if command in (">","<","+","-",".",",","#",):
# Ignore all normal brainfuck characters.
pass
elif (command=="["):
# We've found one, push it's location onto the stack.
open_bracket_stack.push(inst)
elif (command=="]"):
# We've found a closing one. Map this location to the location
# on the top of the stack
try:
previous_bracket = open_bracket_stack.pop()
self.jump_map[previous_bracket]=inst
self.jump_map[inst] = previous_bracket
except:
print "Missing open bracket."
#print self.jump_map

def output(self):
"""
Outputs the value of the current cell.
"""
try:
sys.stdout.write(chr(self.tape.current_cell()%256)) # Wrapping fits it into ascii codes
except:
print "Error -001"

def input(self):
"""
Set the current cell to a new value
"""
try:
temp = ord(raw_input())
self.tape.replace(temp)
except:
print "Error -002"

def enter_loop(self):
"""
Do the code goodness for entering a loop.
"""
if (self.tape.current_cell()==0):
# Jump past the end.
self.instruction_pointer = (self.jump_map[self.instruction_pointer])
else:
pass


def end_loop(self):
"""
Jump to the start of the loop if the current cell is not 0.
"""
# if (not self.tape.current_cell()):
# Jump to the start of the loop
self.instruction_pointer = (self.jump_map[self.instruction_pointer]-1)
#else:
# pass


def execute(self):
"""
Execute the cleaned brainfuck program
Will only correctly run after preprocess_program() has been run.
"""
while len(self.program)>(self.instruction_pointer):
self.step()
#self.tape = tape.Tape() # Clear for next time.

def step(self):
"""
Do a single step in a brainfuck program
"""
try:
self.instructions[self.program[self.instruction_pointer]]()
self.instruction_pointer+=1
except tape.TapeError:
print "Tape underflow, instruction number: "+str(self.instruction_pointer)
raise

def debug(self):
"""
Print debugging information.
"""
print "Tape: "+str(self.tape.tape[:10])+" Current Pointer: "+str(self.tape.pointer)+" Instruction Pointer: "+str(self.instruction_pointer)

def clear_tape(self):
"""
Clear the tape for next round.
"""
self.tape = tape.Tape()

def __str__(self):
"""
A string representation of the interpreter
"""
return str((self.instruction_pointer, self.program,))

def __len__(self):
"""
The length of this brainfuck interpreter
"""
return len(self.tape)
45 changes: 45 additions & 0 deletions sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import bfinterpreter
import time

class Sandbox(object):
"""
This is a sandbox for running limited brainfuck programs
"""
def __init__(self, max_time=None, max_mem=None):
"""
Setup the sandbox.
This can accept a maximum time for running, a maximum memory
allocation allowed.
"""
if (max_time==None):
self.max_time=10000
else:
self.max_time = max_time
if (max_mem==None):
self.max_mem=10000
else:
self.max_mem = max_mem
self.start_time = None

def run(self, code=None):
"""
Run some code in this sandbox
"""
if (code==None):
return False
self.bfi = bfinterpreter.BFInterpreter()
self.bfi. preprocess_program(code)
self.start_time = int(time.time())
while len(self.bfi.program)>(self.bfi.instruction_pointer):
if (not self.exceeded()):
self.bfi.step()
else:
return False
return True

def exceeded(self):
"""
Return true if this code has exceeded it's memory or time allowance
"""
return (self.max_mem < len(self.bfi.tape)) or (self.max_time < (int(time.time()) - self.start_time))
41 changes: 41 additions & 0 deletions stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
A nice little wrapper for a stack class
"""

class Stack():
def __init__(self):
"""
Initialize an empty stack
"""
self.stack=[]

def pop(self):
"""
Get an element of the top of the stack
"""
try:
return self.stack.pop()
except:
raise Exception("Stack underflow.")

def push(self, val=None):
"""
Push an element onto the top of the stack
"""
if (val == None):
raise ValueError("Must put a none-None value on the stack")
else:
self.stack.append(val)
return True

def __len__(self):
"""
Find the size of this stack
"""
return len(self.stack)

def __str__(self):
"""
Show a str representation of this object
"""
return str(self.stack[:5]) # First 5 elements
114 changes: 114 additions & 0 deletions tape.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""
A Tape
Represents a tape, initialized to 0s with a few functions predefined on it.
"""

class TapeError( Exception ):
pass

class Tape(object):
"""
A Tape Object
This tape object will automatically expand to the right should an
overflow be detected. Default size is 30,000.
"""
def __init__(self):
"""
Initalize the tape
This tape initially has 30,000 cells and all are 0
"""
self.tape = [0 for x in range(1,30001,1)]
self.pointer = 0

def increment(self):
"""
Increment the value under the pointer
"""
try:
self.tape[self.pointer]+=1
except:
self.expand()
self.tape[self.pointer]+=1

def decrement(self):
"""
Decrement the value under the pointer
"""
try:
self.tape[self.pointer]-=1
except:
self.expand()
self.tape[self.pointer]-=1

def move_forwards(self):
"""
Move the tape forwards
This actually just increments the internal pointer. Also deals with if the tape is
all used, declares more tape. Doubles the length of the tape when more is needed.
"""
if ((self.pointer) == len(self.tape)):
self.expand()
self.pointer+=1

def move_backwards(self):
"""
Move the tape backwards.
As in the move_forwards, just decrements an internal pointer.
"""
if (self.pointer == 0):
raise TapeError
self.pointer-=1

def replace(self, value=None):
"""
Replace the value of the current cell
The current cell will be replaced the value given. This raises an
error on value not being specified
"""
if (value == None):
raise TapeError
else:
self.tape[self.pointer] = value # No value wrapping to make large
# value calculations easier.

def current_cell(self):
"""
Get the value of the current cell
"""
return self.tape[self.pointer]

def __getitem__(self, i=None):
"""
Get the i-th element of this tape
"""
if (i!=None):
return self.tape[i]

def __eq__(self, other_tape):
"""
Test that this tape is equal to another.
"""
return (self.tape == other_tape.tape)

def __ne__(self, other_tape):
"""
Test if this tape is not equal to another.
"""
return (self.tape != other_tape.tape)

def __len__(self):
"""
Return the length of this tape.
"""
return len(self.tape)
def expand(self):
"""
Double the length of this tape with fresh 0s
"""
self.tape += [0 for x in range(len(self.tape))]

0 comments on commit f6746ff

Please sign in to comment.