From 1429c32976e5f26874aeed77e763a91448c3eb7a Mon Sep 17 00:00:00 2001 From: Wim Pomp Date: Sat, 26 Nov 2022 20:05:58 +0100 Subject: [PATCH] - Befunge 98 with concurrency and file io! --- README.md | 5 +- befunge/__init__.py | 718 +++++++++++++++++++++++++------------ examples/99.bf | 12 + examples/cat_v.bf | 4 + examples/concurrent.bf | 3 + examples/dna.bf | 9 + examples/ex1.bf | 0 examples/factorial.bf | 0 examples/factorial0.bf | 2 +- examples/factorial_eso.bf | 3 + examples/factorial_heap.bf | 1 + examples/fibonacci.bf | 2 + examples/guess.bf | 25 ++ examples/guess2.bf | 16 + examples/hello_b98.bf | 2 + examples/hello_world.bf | 0 examples/hello_world2.bf | 0 examples/mill.bf | 9 + examples/multiplier.bf | 0 examples/pi.bf | 4 + examples/quine1.bf | 2 + examples/random.bf | 0 examples/random_n.bf | 6 + examples/sieve.bf | 5 + examples/soup.bf | 23 ++ examples/test.bf | 2 + examples/v | 1 + 27 files changed, 621 insertions(+), 233 deletions(-) create mode 100755 examples/99.bf create mode 100755 examples/cat_v.bf create mode 100755 examples/concurrent.bf create mode 100755 examples/dna.bf mode change 100644 => 100755 examples/ex1.bf mode change 100644 => 100755 examples/factorial.bf mode change 100644 => 100755 examples/factorial0.bf create mode 100755 examples/factorial_eso.bf mode change 100644 => 100755 examples/factorial_heap.bf create mode 100755 examples/fibonacci.bf create mode 100755 examples/guess.bf create mode 100755 examples/guess2.bf create mode 100755 examples/hello_b98.bf mode change 100644 => 100755 examples/hello_world.bf mode change 100644 => 100755 examples/hello_world2.bf create mode 100755 examples/mill.bf mode change 100644 => 100755 examples/multiplier.bf create mode 100755 examples/pi.bf create mode 100755 examples/quine1.bf mode change 100644 => 100755 examples/random.bf create mode 100755 examples/random_n.bf create mode 100755 examples/sieve.bf create mode 100755 examples/soup.bf create mode 100755 examples/test.bf create mode 100755 examples/v diff --git a/README.md b/README.md index c7fe8e4..aa61d33 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Befunge -[Befunge](https://en.wikipedia.org/wiki/Befunge) interpreter and debugger for Befunge 93, -the first of the [Funges](https://web.archive.org/web/20041225010717/http://quadium.net/funge/spec98.html). +[Befunge](https://en.wikipedia.org/wiki/Befunge) interpreter and debugger for Befunge 93/98: [Funges](https://github.com/catseye/Funge-98/blob/master/doc/funge98.markdown#Whatis). ## Installation `pip install befunge@git+https://github.com/wimpomp/befunge.git` @@ -9,4 +8,4 @@ the first of the [Funges](https://web.archive.org/web/20041225010717/http://quad `befunge --help` ## Examples -`befunge examples/factorial0.bf -i 20 -d 0.05` \ No newline at end of file +`befunge examples/factorial0.bf 20 -d 0.05` \ No newline at end of file diff --git a/befunge/__init__.py b/befunge/__init__.py index 66861d2..7b02ca3 100644 --- a/befunge/__init__.py +++ b/befunge/__init__.py @@ -1,35 +1,19 @@ -from enum import Enum +import os +import sys +import re +import curses from random import randint from argparse import ArgumentParser from pathlib import Path from time import sleep from io import StringIO -from itertools import chain -from curses import wrapper +from itertools import chain, takewhile, dropwhile +from datetime import datetime +from ._version import __version__ -class OperatorException(Exception): - def __init__(self, op): - super().__init__(f'Could not parse operator {op}') - - -class Direction(Enum): - RIGHT = 0 - UP = 1 - LEFT = 2 - DOWN = 3 - - def __add__(self, other): - return Direction((self.value + other) % len(Direction)) - - def __radd__(self, other): - return self + other - - def __sub__(self, other): - return Direction((self.value - other) % len(Direction)) - - def __rsub__(self, other): - return self - other +class StopExecution(Exception): + pass class Input(list): @@ -37,49 +21,441 @@ class Input(list): return self.pop(0) -class Grid(dict): - def __init__(self, code=None, version=None): - self.version = version or 'b93' - self.cursor = True - if self.version == 'b93': - self.shape = 80, 25 +class Stack(list): + def copy(self): + return __class__(super().copy()) + + def pop(self, *args, **kwargs): + try: + return super().pop() + except IndexError: + return 0 + + def push(self, value): + self.append(value) + + +class StackStack(list): + def __repr__(self): + return '\n'.join(str(stack) for stack in self[::-1]) + + def copy(self): + return __class__(stack.copy() for stack in self) + + def push(self, value): + self.append(value) + + +class IP: + def __init__(self, funge, stackstack=None, position=(0, 0), delta=(1, 0), offset=(0, 0), version=982): + self.funge = funge + self.id = len([ip.id for ip in self.funge.ips]) if hasattr(self.funge, 'ip') else 0 + self.stackstack = stackstack or StackStack([Stack()]) + self.position = position + self.delta = delta + self.offset = offset + self.version = version + self.string = False + self.fingerprint_ops = {} + if self.op in (ord(' '), ord(';')): + self.advance() + + @property + def stack(self): + if not self.stackstack: + self.stackstack.append(Stack()) + return self.stackstack[-1] + + @stack.setter + def stack(self, stack): + if self.stackstack: + self.stackstack[-1] = stack else: - self.shape = None - self._ip = [0, 0] - self.direction = Direction.RIGHT + self.stackstack.append(stack) + + @property + def op(self): + return self.funge[self.position] + + def copy(self): + return __class__(self.funge, self.stackstack.copy(), self.position, self.delta) + + def reverse(self): + self.delta = -self.delta[0], -self.delta[1] + + def turn_right(self): + self.delta = -self.delta[1], self.delta[0] + + def turn_left(self): + self.delta = self.delta[1], -self.delta[0] + + def read_string(self): + string = '' + while True: + f = self.stack.pop() + if f == 0: + return string + else: + string += chr(f) + + def read_fingerprint(self): + n = self.stack.pop() + t = 0 + for _ in range(n): + t *= 256 + t += self.stack.pop() + return t + + def not_implemented(self): + print(f'operator {self.op} at {self.position} not implemented', file=self.funge.output) + self.reverse() + + def get_info(self, n): + time = datetime.now() + match n: + case 1: + yield 15 + case 2: + yield 2**1024 # as much as the memory can hold + case 3: + yield sum([256 ** i * ord(char) for i, char in enumerate('wpfunge')]) + case 4: + yield __version__.replace('.', '') + case 5: + yield 1 + case 6: + yield ord(os.path.sep) + case 7: + yield 2 + case 8: + yield self.id + case 9: + yield 0 + case 10: + yield from self.position + case 11: + yield from self.delta + case 12: + yield from self.offset + case 13: + yield from self.funge.extent[::2] + case 14: + yield from self.funge.extent[1::2] + case 15: + yield (time.year - 1900) * 256 * 256 + time.month * 256 + time.day + case 16: + yield time.hour * 256 * 256 + time.minute * 256 + time.second + case 17: + yield len(self.stackstack) + case 18: + yield from (len(stack) for stack in self.stackstack[::-1]) + case 19: + yield 0 + yield from [ord(char) for arg in sys.argv[2:] for char in f'{arg}\x00'][::-1] + yield 0 + yield from [ord(char) for char in Path(sys.argv[1]).name][::-1] + case 20: + yield 0 + yield from [ord(char) for key, value in os.environ.items() for char in f'{key}={value}\x00'][::-1] + case i: + i -= 20 + yield self.stack[-i] if len(self.stack) >= i else 0 + + def step(self, k=False): + if self.string: + match chr(self.op): + case '"': + self.string = False + case s: + self.stack.push(ord(s)) + elif self.op in self.fingerprint_ops: + try: + self.fingerprint_ops[self.op]() + except Exception: + self.reverse() + elif 0 <= self.op < 255: + match chr(self.op): + case '+': + self.stack.push(self.stack.pop() + self.stack.pop()) + case '-': + b, a = self.stack.pop(), self.stack.pop() + self.stack.push(a - b) + case '*': + self.stack.push(self.stack.pop() * self.stack.pop()) + case '/': + b, a = self.stack.pop(), self.stack.pop() + self.stack.push(a // b) + case '%': + b, a = self.stack.pop(), self.stack.pop() + self.stack.push(a % b) + case '!': + self.stack.push(int(not self.stack.pop())) + case '`': + self.stack.push(int(self.stack.pop() < self.stack.pop())) + case '>': + self.delta = 1, 0 + case '<': + self.delta = -1, 0 + case '^': + self.delta = 0, -1 + case 'v': + self.delta = 0, 1 + case '?': + self.delta = ((-1, 0), (1, 0), (0, -1), (0, 1))[randint(0, 3)] + case '_': + self.delta = ((1, 0), (-1, 0))[bool(self.stack.pop())] + case '|': + self.delta = ((0, 1), (0, -1))[bool(self.stack.pop())] + case '"': + self.string = True + case ':': + a = self.stack.pop() + self.stack.push(a) + self.stack.push(a) + case '\\': + b, a = self.stack.pop(), self.stack.pop() + self.stack.push(b) + self.stack.push(a) + case '$': + self.stack.pop() + case '.': + print(str(self.stack.pop()) + ' ', end='', file=self.funge.output) + case ',': + print(chr(self.stack.pop()), end='', file=self.funge.output) + case '#': + self.move() + case 'p': + y, x, a = self.stack.pop(), self.stack.pop(), self.stack.pop() + self.funge[x + self.offset[0], y + self.offset[1]] = a + case 'g': + y, x = self.stack.pop(), self.stack.pop() + self.stack.push(self.funge[x + self.offset[0], y + self.offset[1]]) + case '&': + try: + self.stack.push(int(''.join( + takewhile(lambda i: i.isdigit(), dropwhile(lambda i: not i.isdigit(), self.funge.input()))))) + except Exception: + self.delta = -self.delta[0], -self.delta[1] + case '~': + try: + self.stack.push(ord(self.funge.input())) + except Exception: + self.reverse() + case '@': + return + case ' ': + self.advance() + yield self.step() + return + # 98 from here + case '[': + self.turn_left() + case ']': + self.turn_right() + case '\'': + self.move() + self.stack.push(self.op) + case '{': + n = self.stack.pop() + cells = -n * [0] if n < 0 else self.stack[-n:][::-1] + for coordinate in self.offset: + self.stack.push(coordinate) + self.stackstack.push(Stack()) + for cell in cells: + self.stack.push(cell) + self.offset = self.next_pos + case '}': + n = self.stack.pop() + cells = -n * [0] if n < 0 else [self.stack.pop() for _ in range(n)][::-1] + self.stackstack.pop() + y, x = self.stack.pop(), self.stack.pop() + self.offset = x, y + for cell in cells: + self.stack.push(cell) + case '=': + self.stack.push(os.system(self.read_string())) + case '(': + # no fingerprints are implemented + self.read_fingerprint() + # self.fingerprint_ops[] = lambda i: i + self.reverse() + case ')': + self.read_fingerprint() + # self.fingerprint_ops.pop() + case 'i': + file = Path(self.read_string()) + flags, y0, x0 = self.stack.pop(), self.stack.pop(), self.stack.pop() + try: + text = file.read_text() + if flags % 2: + width, height = len(text), 1 + for x, char in enumerate(text, x0): + self.funge[x, y0] = char + else: + text = text.splitlines() + height = len(text) + width = max([len(line) for line in text]) + self.funge.insert_code([line + ' ' * (width - len(line)) for line in text], x0, y0) + except Exception: + width, height = 0, 0 + self.stack.push(x0) + self.stack.push(y0) + self.stack.push(width) + self.stack.push(height) + case 'j': + for _ in range(self.stack.pop()): + self.move() + case 'k': + self.advance() + ips = [self] + for n in range(self.stack.pop()): + ips = [i for ip in ips for i in ip.step(True)] + yield from ips + return + case 'n': + self.stack = Stack() + case 'o': + file = Path(self.read_string()) + flags, x0, y0, width, height = (self.stack.pop() for _ in range(5)) + try: + if flags % 2: + text = '\n'.join([''.join([chr(self.funge[x, y]) for x in range(x0, x0 + width)]).rstrip(' ') + for y in range(y0, y0 + height)]).rstrip('\n') + else: + text = '\n'.join([''.join([chr(self.funge[x, y]) for x in range(x0, x0 + width)]) + for y in range(y0, y0 + height)]) + file.write_text(text) + except Exception: + self.reverse() + case 'q': + raise StopExecution() + case 'r': + self.reverse() + case 's': + self.move() + self.funge[self.position] = self.stack.pop() + case 't': + new = self.copy() + new.reverse() + yield new.advance() + case 'u': + if len(self.stackstack) > 1: + n = self.stack.pop() + for _ in range(abs(n)): + toss = self.stackstack.pop() + toss.push(self.stack.pop()) + self.stackstack.push(toss) + else: + self.reverse() + case 'w': + b, a = self.stack.pop(), self.stack.pop() + if a < b: + self.turn_left() + elif a > b: + self.turn_right() + case 'x': + dy, dx = self.stack.pop(), self.stack.pop() + self.delta = dx, dy + case 'y': + n = self.stack.pop() + if n <= 0: + for j in range(1, 21): + for i in self.get_info(j): + self.stack.push(i) + else: + for i in self.get_info(n): + self.stack.push(i) + case 'z': + pass + case d: + if d in '1234567890': + self.stack.push(int(d)) + elif d in 'abcdef': + self.stack.push(ord(d) - 87) + else: + self.not_implemented() + else: + self.not_implemented() + if not k: + self.advance() + yield self + + @property + def next_pos(self): + pos = tuple(p + d for p, d in zip(self.position, self.delta)) + # TODO: analytic solution + if not all(a <= p < b for p, a, b in zip(pos, self.funge.extent[::2], self.funge.extent[1::2])): + while True: + pos = tuple(p - d for p, d in zip(pos, self.delta)) + if not all(a <= p < b for p, a, b in zip(pos, self.funge.extent[::2], self.funge.extent[1::2])): + break + pos = tuple(p + d for p, d in zip(pos, self.delta)) + return pos + + def move(self): + self.position = self.next_pos + + def advance(self): + """ move the ip to the next valid instruction """ + if self.string: + if self.op == ord(' ') and self.version // 10 > 93: + while self.op == ord(' '): + self.move() + else: + self.move() + else: + while True: + if self.op != ord(';'): + self.move() + if self.op == ord(';'): + self.move() + while self.op != ord(';'): + self.move() + self.move() + while self.op == ord(' '): + self.move() + if self.op != ord(';'): + break + return self + + +class Befunge(dict): + def __init__(self, code=None, inputs=None): super().__init__() - for y, line in enumerate(code.splitlines()): - for x, char in enumerate(line): - self[(x, y)] = char - - def wrap(self, value, dim): - if self.shape is None: - return value + self.extent = [0, 0, 0, 0] # xl, xr, yt, yb + if code.startswith(r'#!/usr/bin/env befunge') or code.startswith(r'#!/usr/bin/env -S befunge'): + code = '\n'.join(code.splitlines()[1:]) + self.insert_code(code) + self.output = None + if inputs is None: + self.input = input else: - return value % self.shape[dim] + self.input = Input(inputs) + self.string = False + self.steps = 0 + self.terminated = False + self.ips = [IP(self)] - @property - def x(self): - return self._ip[0] - - @x.setter - def x(self, value): - self._ip[0] = self.wrap(value, 0) - - @property - def y(self): - return self._ip[1] - - @y.setter - def y(self, value): - self._ip[1] = self.wrap(value, 1) + def insert_code(self, code, x0=0, y0=0): + if isinstance(code, str): + code = code.splitlines() + for y, line in enumerate(code, y0): + for x, char in enumerate(line, x0): + self[x, y] = char def __getitem__(self, key): return self.get(key, ord(' ')) def __setitem__(self, key, value): - super().__setitem__(tuple(self.wrap(k, i) for i, k in enumerate(key)), - ord(value) if isinstance(value, str) else value) + if key[0] < self.extent[0]: + self.extent[0] = key[0] + if key[0] >= self.extent[1]: + self.extent[1] = key[0] + 1 + if key[1] < self.extent[2]: + self.extent[2] = key[2] + if key[1] >= self.extent[3]: + self.extent[3] = key[1] + 1 + super().__setitem__(key, ord(value) if isinstance(value, str) else value) def __repr__(self): lines = [] @@ -89,70 +465,16 @@ class Grid(dict): while len(lines[y]) <= x: lines[y].append(' ') lines[y][x] = chr(value) if 32 <= value <= 126 or 161 <= value <= 255 else chr(164) - lines = [''.join(line) for line in lines] - if self.cursor: - return '\n'.join(lines[:self.y] + - [lines[self.y][:self.x] + - '\x1b[37m\x1b[40m' + lines[self.y][self.x] + '\033[0m' + - lines[self.y][self.x + 1:]] + - lines[self.y + 1:]) - else: - return '\n'.join(lines) - @property - def op(self): - return self[self.x, self.y] - - def advance(self): - match self.direction: - case Direction.RIGHT: - self.x += 1 - case Direction.UP: - self.y -= 1 - case Direction.LEFT: - self.x -= 1 - case Direction.DOWN: - self.y += 1 - - -class Stack(list): - def pop(self, index=-1): - try: - return super().pop(index) - except IndexError: - return 0 - - def push(self, value): - self.append(value) - - -class Befunge(Grid): - def __init__(self, code=None, version=None, inputs=None): - super().__init__(code, version) - self.output = None - if inputs is None: - self.input = input - else: - self.input = Input(inputs) - self.stack = Stack() - self.string = False - self.steps = 0 - self.terminated = False - self.operations = {'b93': '+-*/%!`><^v?_|":\\$.,#pg&~@ 1234567890'}[self.version] + for ip in self.ips: + lines[ip.position[1]][ip.position[0]] = f'\x1b[37m\x1b[40m{lines[ip.position[1]][ip.position[0]]}\033[0m' + return 'grid:\n' + '\n'.join([''.join(line) for line in lines]) + '\n\n' + \ + 'stacks:\n' + '\n-\n'.join(str(ip.stackstack) for ip in self.ips) @staticmethod - def from_file(file, version=None, inputs=None): + def from_file(file, inputs=None): file = Path(file) - if version is None: - match file.suffix: - case '.bf': - version = 'b93' - case suffix: - version = suffix.strip('.') - return Befunge(file.read_text(), version, inputs) - - def __repr__(self): - return f'grid:\n{super().__repr__()}\n\nstack:\n{self.stack}' + return Befunge(file.read_text(), inputs) def __iter__(self): return self @@ -166,146 +488,84 @@ class Befunge(Grid): for _ in self: pass - def debug(self, time_step): + def debug(self, time_step=None): def fun(stdscr): def scr_input(): height, width = stdscr.getmaxyx() stdscr.move(height - 1, 0) stdscr.clrtoeol() - stdscr.addstr(height - 1, 0, 'input?') - stdscr.move(self.y + 1, self.x) + stdscr.addstr(height - 1, 0, 'input?'[:width]) stdscr.refresh() return stdscr.getstr() + curses.curs_set(False) + curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) + pattern = re.compile(r'\x1b\[[\d;]+m') self.output = StringIO() - self.cursor = False if not isinstance(self.input, Input): self.input = scr_input stdscr.clear() stdscr.refresh() - for b in chain((self,), self): + for b in chain((self,), self, (self,)): height, width = stdscr.getmaxyx() stdscr.clear() - stdscr.addstr(f'{b}\n\noutput:\n{b.output.getvalue()}\n\nstep:\n{b.steps}') - if time_step > 0: - stdscr.move(b.y + 1, b.x) - stdscr.refresh() - sleep(time_step) - else: - stdscr.addstr(height - 1, 0, 'Press any key to continue.') - stdscr.move(b.y + 1, b.x) + b_str = re.sub(pattern, '', str(b)) + for y, line in enumerate(f'{b_str}\n\noutput:\n{b.output.getvalue()}\n\nstep:\n{b.steps}'.splitlines()): + if y >= height: + break + stdscr.addstr(y, 0, line[:width]) + + for ip in b.ips: + x, y = ip.position + if x < width and y < height: + stdscr.addstr(y + 1, x, b_str.splitlines()[y + 1][x], curses.color_pair(1)) + if b.terminated: + stdscr.addstr(height - 1, 0, 'Press any key to quit.'[:width]) stdscr.refresh() stdscr.getch() - - height, width = stdscr.getmaxyx() - stdscr.move(height - 1, 0) - stdscr.clrtoeol() - stdscr.addstr(height - 1, 0, 'Press any key to quit.') - stdscr.move(self.y + 1, self.x) - stdscr.getch() + elif time_step is None: + stdscr.addstr(height - 1, 0, 'Press any key to continue.'[:width]) + stdscr.refresh() + stdscr.getch() + else: + stdscr.refresh() + sleep(time_step) try: - wrapper(fun) + curses.wrapper(fun) except KeyboardInterrupt: pass def step(self, n=1): - m = 0 - while m < n: - if self.string: - if self.op == ord('"'): - self.string = False - else: - self.stack.push(self.op) - elif chr(self.op) in self.operations: - match chr(self.op): - case '+': - self.stack.push(self.stack.pop() + self.stack.pop()) - case '-': - self.stack.push(self.stack.pop(-2) - self.stack.pop()) - case '*': - self.stack.push(self.stack.pop() * self.stack.pop()) - case '/': - self.stack.push(self.stack.pop(-2) // self.stack.pop()) - case '%': - self.stack.push(self.stack.pop(-2) % self.stack.pop()) - case '!': - self.stack.push(int(not self.stack.pop())) - case '`': - self.stack.push(int(self.stack.pop() < self.stack.pop())) - case '>': - self.direction = Direction.RIGHT - case '<': - self.direction = Direction.LEFT - case '^': - self.direction = Direction.UP - case 'v': - self.direction = Direction.DOWN - case '?': - self.direction = Direction(randint(0, 3)) - case '_': - self.direction = Direction(2 * bool(self.stack.pop())) - case '|': - self.direction = Direction(3 - 2 * bool(self.stack.pop())) - case '[': - self.direction += 1 - case ']': - self.direction -= 1 - case '"': - self.string = True - case ':': - if len(self.stack): - self.stack.push(self.stack[-1]) - case '\\': - if len(self.stack) > 1: - self.stack.push(self.stack.pop(-2)) - case '$': - self.stack.pop() - case '.': - print(str(self.stack.pop()) + ' ', end='', file=self.output) - case ',': - print(chr(self.stack.pop()), end='', file=self.output) - case '#': - self.advance() - case 'p': - self[self.stack.pop(-2), self.stack.pop()] = self.stack.pop(-3) - case 'g': - self.stack.push(self[self.stack.pop(-2), self.stack.pop()]) - case '&': - self.stack.push(int(self.input())) - case '~': - self.stack.push(ord(self.input())) - case '@': - self.terminated = True - case ' ': - pass - case op: - self.stack.append(int(op)) - else: - raise OperatorException(self.op) - self.advance() - if not (not self.string and self.op == ord(' ')): - m += 1 - self.steps += 1 + for i in range(n): + self.steps += 1 + try: + self.ips = [i for ip in self.ips for i in ip.step()] + except StopExecution: + self.ips = [] + if not self.ips: + self.terminated = True + return self return self def main(): - parser = ArgumentParser(description='Display info and save as tif') - group = parser.add_mutually_exclusive_group() - group.add_argument('file', help='funge code file', nargs='?') - group.add_argument('-s', '--string', help='funge code string', default=None) - parser.add_argument('-v', '--version', help='funge version: b93, b98', type=str, default=None) - parser.add_argument('-d', '--debug', help='debug, steps / second, 0: continue on key press', type=float, default=-1) - parser.add_argument('-i', '--inputs', help='inputs for when befunge asks for it', nargs='*') + parser = ArgumentParser(description='Funge interpreter and debugger') + parser.add_argument('input', help='funge code file or string') + parser.add_argument('args', help='arguments to the funge (& or ~)', nargs='*') + parser.add_argument('-v', '--version', help='show interpreter\'s version number and exit', + action='version', version=__version__) + parser.add_argument('-d', '--debug', help='debug, step on key press or steps / second', + type=float, default=False, nargs='?') args = parser.parse_args() - if args.file: - befunge = Befunge.from_file(args.file, args.version, args.inputs) - else: - befunge = Befunge(args.string, args.version, args.inputs) - if args.debug < 0: + if Path(args.input).exists(): + befunge = Befunge.from_file(args.input, args.args or None) + else: + befunge = Befunge(args.input, args.args or None) + + if args.debug is False: befunge.run() else: befunge.debug(args.debug) diff --git a/examples/99.bf b/examples/99.bf new file mode 100755 index 0000000..153f7c7 --- /dev/null +++ b/examples/99.bf @@ -0,0 +1,12 @@ +#!/usr/bin/env befunge +992+*: v: < +v" ".:<_091+".reeb fo selttob erom on ,llaw eht no reeb fo selttob erom oN">:v +,v"Go to the store and buy some more, 99 bottles of beer on the wall."+910<^,_v + >:#,_@>:101-*+v >$0" ,llaw eht no reeb fo ">:#,_$:.1v ^ $< +>0\ >> ^ v_0"elttob">:#,_$\:!| >091+".reeb fo ">:#,_$ v + >0"selttob"^ >1-!| >" ",\v +>$2\ ^\2<," ".< >091+:".llaw eht no reeb fo "v +^_v > ^ |:< v!:<"Take one down and pass it around, "0< v!:< + !,v ^ ^:-1$_, ^ v$_>,^ +>^ ^ < +^:<"no more "0< > ^ \ No newline at end of file diff --git a/examples/cat_v.bf b/examples/cat_v.bf new file mode 100755 index 0000000..fb2c8da --- /dev/null +++ b/examples/cat_v.bf @@ -0,0 +1,4 @@ +#!/usr/bin/env befunge + w4110'vin10 +">#,:#<_@ \ No newline at end of file diff --git a/examples/concurrent.bf b/examples/concurrent.bf new file mode 100755 index 0000000..c2b5959 --- /dev/null +++ b/examples/concurrent.bf @@ -0,0 +1,3 @@ +#!/usr/bin/env befunge + v +@000_1t111@ \ No newline at end of file diff --git a/examples/dna.bf b/examples/dna.bf new file mode 100755 index 0000000..60d2cca --- /dev/null +++ b/examples/dna.bf @@ -0,0 +1,9 @@ +#!/usr/bin/env befunge +7^DN>vA +v_#v? v +7^<"""" +3 ACGT +90!"""" +4*:>>>v ++8^-1,< +> ,+,@) \ No newline at end of file diff --git a/examples/ex1.bf b/examples/ex1.bf old mode 100644 new mode 100755 diff --git a/examples/factorial.bf b/examples/factorial.bf old mode 100644 new mode 100755 diff --git a/examples/factorial0.bf b/examples/factorial0.bf old mode 100644 new mode 100755 index e2ea4a9..c5d1b17 --- a/examples/factorial0.bf +++ b/examples/factorial0.bf @@ -1,5 +1,5 @@ +#!/usr/bin/env befunge v -0 & >>:1v |:-< diff --git a/examples/factorial_eso.bf b/examples/factorial_eso.bf new file mode 100755 index 0000000..35c4c04 --- /dev/null +++ b/examples/factorial_eso.bf @@ -0,0 +1,3 @@ +#!/usr/bin/env befunge +&>:1-:v v *_$.@ + ^ _$>\:^ \ No newline at end of file diff --git a/examples/factorial_heap.bf b/examples/factorial_heap.bf old mode 100644 new mode 100755 index a9136fd..c85b5d4 --- a/examples/factorial_heap.bf +++ b/examples/factorial_heap.bf @@ -1,2 +1,3 @@ +#!/usr/bin/env befunge &:>00p1-::v ^ *g00 _g.25*,@ diff --git a/examples/fibonacci.bf b/examples/fibonacci.bf new file mode 100755 index 0000000..6ddfb0d --- /dev/null +++ b/examples/fibonacci.bf @@ -0,0 +1,2 @@ +#!/usr/bin/env befunge +j1\:b0p+:.' 1 \ No newline at end of file diff --git a/examples/guess.bf b/examples/guess.bf new file mode 100755 index 0000000..9cd5771 --- /dev/null +++ b/examples/guess.bf @@ -0,0 +1,25 @@ +#!/usr/bin/env befunge +vv < < + 2 + ^ v< + v13v4 + ^ ^ +> >?> ?>5^ + v v + v97v6 + v v< + 8 + > > ^ + vv < < + 2 + ^ v< + v13v4 + ^ ^ + > >?> ?>5^ + v v v ,*25 << + v97v6 ,, + v v< "" + 8 >< + > > ^ ""v + >*: >0"!rebmun tupnI">:#,_$25*,:&:99p`|^< _0"!niw uoY">:#,_$25*,@ + ^ < >:99g01-*+^ \ No newline at end of file diff --git a/examples/guess2.bf b/examples/guess2.bf new file mode 100755 index 0000000..9f138a2 --- /dev/null +++ b/examples/guess2.bf @@ -0,0 +1,16 @@ +#!/usr/bin/env befunge +v>>> > v>>> > v + 012 3 012 3 + ^?^ ^?^ +>>?#v?4>>?#v?4v + v?v v?v + 98765 98765 + >>>>> ^>>>>> v +v 0 + * + : 5 < +>"!sseuG">:#,_v +0v_v#:-&:,+:5$< +, v>0"!niw uoY" ++0>:#,_$5:+,@ +:>`0\"!"\v + v"small"_"gib" +^>" ooT">:#,_$5 \ No newline at end of file diff --git a/examples/hello_b98.bf b/examples/hello_b98.bf new file mode 100755 index 0000000..621d2ab --- /dev/null +++ b/examples/hello_b98.bf @@ -0,0 +1,2 @@ +#!/usr/bin/env befunge +<>:#,_# @#"Hello, World!" \ No newline at end of file diff --git a/examples/hello_world.bf b/examples/hello_world.bf old mode 100644 new mode 100755 diff --git a/examples/hello_world2.bf b/examples/hello_world2.bf old mode 100644 new mode 100755 diff --git a/examples/mill.bf b/examples/mill.bf new file mode 100755 index 0000000..d7d9b4a --- /dev/null +++ b/examples/mill.bf @@ -0,0 +1,9 @@ +#!/usr/bin/env befunge + ] v + >v +v?t1? + 1 t + t 1 + ?1t?v +v< < +>29*y.@ \ No newline at end of file diff --git a/examples/multiplier.bf b/examples/multiplier.bf old mode 100644 new mode 100755 diff --git a/examples/pi.bf b/examples/pi.bf new file mode 100755 index 0000000..f7c90ba --- /dev/null +++ b/examples/pi.bf @@ -0,0 +1,4 @@ +#!/usr/bin/env befunge +"^a&EPm=kY}t/qYC+i9wHye$m N@~x+"v +"|DsY<"-"z6n<[Yo2x|UP5VD:">:#v_@> +-:19+/"0"+,19+%"0"+, ^ >39* \ No newline at end of file diff --git a/examples/quine1.bf b/examples/quine1.bf new file mode 100755 index 0000000..724c8b1 --- /dev/null +++ b/examples/quine1.bf @@ -0,0 +1,2 @@ +#!/usr/bin/env befunge +01->1# +# :# 0# g# ,# :# 5# 8# *# 4# +# -# _@ \ No newline at end of file diff --git a/examples/random.bf b/examples/random.bf old mode 100644 new mode 100755 diff --git a/examples/random_n.bf b/examples/random_n.bf new file mode 100755 index 0000000..bab7643 --- /dev/null +++ b/examples/random_n.bf @@ -0,0 +1,6 @@ +#!/usr/bin/env befunge +& :v>00g2/.@ +v00_^#!`/2g00:< +>0p:1>>:10p` !| +>+00p^?<*2g01:< +^ g00:< \ No newline at end of file diff --git a/examples/sieve.bf b/examples/sieve.bf new file mode 100755 index 0000000..30d8810 --- /dev/null +++ b/examples/sieve.bf @@ -0,0 +1,5 @@ +#!/usr/bin/env befunge +2>:3g" "-!v\ g30 < + |!`"O":+1_:.:03p>03g+:"O"`| + @ ^ p3\" ":< +2 234567890123456789012345678901234567890123456789012345678901234567890123456789 \ No newline at end of file diff --git a/examples/soup.bf b/examples/soup.bf new file mode 100755 index 0000000..abfe598 --- /dev/null +++ b/examples/soup.bf @@ -0,0 +1,23 @@ +#!/usr/bin/env befunge + 060p070 p'O80v + pb2*90p4$4> $4$>v> + v4$>4$>4$>4$># ARGH>! + <{[BEFUNGE_97]}> FUNGE! + ##:-:## #####* 4$*>4$ >060p> 60g80g -!#v_ 60g1+ 60p60v + #vOOGAH **>4$>^!!eg nufeB^ $4$4$4 $470g>90g-! #@_^Befunge!! 123456 123456 VvVv!#!>Weird! >0ggv* + ^$4$4p07+1g07 ,a<$4< <$4$4< <$4$4< <$4$4< <<#<*-=-=-=-=-* -=-=v* + ::48*-#v_>,4$> 4$4$4 $4$4$ 4$4$4$ 4$4$4$ 4$^*!* XXXXXX XXX> + BOINK>$60g1-7 0g+d2* %'A+,1 $1$1$1 $1$1$1 $>^<$ HAR!!! 8888 + Befunge_is such_a pretty langua ge,_is n't_i t?_It_ 8888 + looks_so much_l ike_li ne_noi se_and it's_ STILL_ ā€˜88’ +Turing- Complet e!_Cam ouflag e_your code!! Confu se_the +hell_out of_every one_re ading_ your_co de._Oh, AND_y ou.:-) ,o88o. + Once_this_thing_i s_code d,_rea ding_it_back_ver ges_on the_imp 888888 + ossible._Obfusc ate_the_obfus cated!_Befunge_ debuggers_are__ 888888 + your_friends! By:_Alexios Chouchou las... X-X-X-X-X-X-X! 888888 + -=*##*=- \*****/ 9797* -=97=- !@-*= ***** ā€˜"88P’ + *!@-* + =*!@- + -=*!@ + @-=*! \ No newline at end of file diff --git a/examples/test.bf b/examples/test.bf new file mode 100755 index 0000000..5c61223 --- /dev/null +++ b/examples/test.bf @@ -0,0 +1,2 @@ +#!/usr/bin/env befunge +45*1-y>>#,:#<_$:w@ \ No newline at end of file diff --git a/examples/v b/examples/v new file mode 100755 index 0000000..6769dd6 --- /dev/null +++ b/examples/v @@ -0,0 +1 @@ +Hello world! \ No newline at end of file