|
Programming Guru
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 
|
Here's my Befunge-93 interpreter. I originally aimed to program it in C, but I realised that by the time I got half way, I'd be bored and wouldn't complete it. So I constructed one in Python instead:
import sys
import string
import random
from operator import *
class State:
normal, string, skip, end = range(4)
class Interpreter:
def __init__(self, file):
self.code = [line.strip('\n') for line in file]
self.stack = []
self.delta = (1, 0)
self.pointer = (0, 0)
self.state = State.normal
up, down, left, right = (0, -1), (0, 1), (-1, 0), (1, 0)
pop, push, set_delta = self._pop, self._push, self._set_delta
set_state = self._set_state
self.instructions = {
'+' : lambda : push( add(*pop(2)) ),
'-' : lambda : push( sub(*reversed(pop(2))) ),
'*' : lambda : push( mul(*pop(2)) ),
'/' : lambda : push( div(*reversed(pop(2))) ),
'%' : lambda : push( mod(*reversed(pop(2))) ),
'!' : lambda : push( int(not_(*pop())) ),
'`' : lambda : push( int(gt(*reversed(pop(2)))) ),
'>' : lambda : set_delta( right ),
'<' : lambda : set_delta( left ),
'^' : lambda : set_delta( up ),
'v' : lambda : set_delta( down ),
'?' : lambda : set_delta( random.choice([up, down, left, right]) ),
'_' : lambda : pop() == 0 and set_delta(right) or set_delta(left),
'|' : lambda : pop() == 0 and set_delta(down) or set_delta(up),
'"' : lambda : set_state(State.string),
':' : lambda : push(*self.stack[-1:]),
'\\': lambda : push(*reversed(pop(2))),
'$' : pop,
'.' : lambda : sys.stdout.write( str(int(*pop())) ),
',' : lambda : sys.stdout.write( chr(*pop()) ),
'#' : lambda : set_state(State.skip),
'p' : lambda : self.set(reversed(pop(2)), pop()),
'g' : lambda : self.get(reversed(pop(2))),
'&' : lambda : push( int(raw_input()) ),
'~' : lambda : push( ord(raw_input()) ),
'@' : lambda : set_state(State.end)
}
def run(self):
while self.state != State.end:
self.evaluate(self.get(self.pointer))
self.next()
def evaluate(self, char):
if self.state == State.string:
if char != '"':
self._push(ord(char))
else:
self.state = State.normal
else:
if char in string.digits:
self._push(int(char))
elif char != ' ':
self.instructions[char]()
def next(self):
if self.state != State.end:
(x, y), (dx, dy) = self.pointer, self.delta
self.goto(((x + dx), (y + dy)))
if self.state == State.skip:
self.goto(((x + dx), (y + dy)))
def goto(self, (x, y)):
y = y % len(self.code)
x = x % len(self.code[y])
self.pointer = (x, y)
def _pop(self, amount = 1):
return [self.__pop_single() for i in range(amount)]
def __pop_single(self):
if not self.stack: return 0
return self.stack.pop()
def _push(self, *items):
self.stack.extend(items)
def _set_delta(self, delta):
self.delta = delta
return True
def set(self, (x, y), value):
self.code[y][x] = value
def get(self, (x, y)):
return self.code[y][x]
def _set_state(self, state):
self.state = state
if __name__ == '__main__':
Interpreter(sys.stdin).run() I could probably make it a little neater if I used decorators, functions and currying instead of lambdas, but there you go. As far as I know, this is a standard's compliant Befunge-93 interpreter, but it seems like most of the documentation for it is now for Funge-98, so it's difficult to be sure.
|