View Single Post
Old Jul 19th, 2006, 6:51 PM   #26
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
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.
Arevos is offline   Reply With Quote