Madbrain

From Esolang
Jump to navigation Jump to search

Madbrain is a stack-based "2D" esoteric programming language invented by User:Feuermonster in 2010.

If an opcode takes 2 arguments, the first argument is taken from the top of the stack, and the second from the bottom of the stack. Madbrain has a horizontal instruction pointer. The code is executed line by line. But only the opcode pointed to by the horizontal instruction pointer is executed.

012  <- 0 will be executed
ppp  <- p will be executed

If the horizontal instruction pointer is 1

012  <- 1 will be executed
ppp  <- p (the second) will be executed
4       <- 4 will be executed
i       <- i will be executed (horizontal  instruction pointer is now 4)
12345   <- 5 will be executed
    p   <- prints 5.
    4
    d   <- horizontal instruction pointer is now 0
12345   <- 1 will be executed
p       <- prints 1

Both instruction pointers are initially set to zero (lines are zero based).

Opcodes

0-9: Pushes the number onto the stack
j (1 Argument): Jumps to the line pointed to by the argument
g (2 Arguments): Jumps to the line pointed to by the first argument and increases the horizontal instruction pointer by the second argument
q (2 Arguments): Jumps to the line pointed to by the first argument and decreases the horizontal instruction pointer by the second argument
i (1 Argument): Increases the horizontal instruction pointer by the argument
d (1 Argument): Decreases the horizontal instruction pointer by the argument
x: Terminates the program
r: Reads a single digit from stdin and pushes it onto the stack as an integer
* (2 Arguments): Multiplies the arguments together
/ (2 Arguments): Divides the first argument by the second
+ (2 Arguments): Adds the arguments together
- (2 Arguments): Subtracts the second argument by the first
p (1 Argument): Prints the argument as a number
c (1 Argument): Prints the argument as a character. Only integers smaller than 256 are printed. Negative integers are undefined or implementation-dependent behavior.
> (2 Arguments): If the first argument is greater than the second, the horizontal instruction pointer is increased by one.
< (2 Arguments): If the first argument is less than the second, the horizontal instruction pointer is increased by one.
^ (2 Arguments): If the first argument is greater than the second, the horizontal instruction pointer is decreased by one.
v (2 Arguments): If the first argument is less than the second, the horizontal instruction pointer is decreased by one.
? (1 Argument): If the argument is greater than zero, the horizontal instruction pointer is increased by one.
! (1 Argument): If the argument is greater than zero, the horizontal instruction pointer is decreased by one.
: (1 Argument): If the argument is zero, the horizontal instruction pointer is increased by one.
; (1 Argument): If the argument is zero, the horizontal instruction pointer is decreased by one.
. (1 Argument): If the argument is less than zero, the horizontal instruction pointer is increased by one.
, (1 Argument): If the argument is less than zero, the horizontal instruction pointer is decreased by one.
= (2 Arguments): If the first argument is equal to the second, the horizontal instruction pointer is increased by one.
_ (2 Arguments): If the first argument is equal to the second, the horizontal instruction pointer is decreased by one.
# (2 Arguments): If the first argument is not equal to the second, the horizontal instruction pointer is increased by one.
@ (2 Arguments): If the first argument is not equal to the second, the horizontal instruction pointer is decreased by one.

Any character which is not an opcode is a nop.

Examples

Equality Check

rp
1x
r
=
01
00
gj

This program asks the user to input two numbers. If they are equal, madbrain will print 1, else 0.

Hello, world!

9 5 9 9 5 7 8 7 5 5 9 5 8
8 5 4 4 3 6 4 4 3 3 4 5 4
* * * * * * * * * * * * *
c 4 3 3 2 2 c 4 2 4 3 4 1
2 * * * * + 2 * * + * * +
0 1 c c 7 c 0 7 7 6 c c c
g + 2 2 + 2 g + + * 2 2 x
  c 0 0 3 0   c 3 c 0 0
  2 g g * g   2 * 2 g g
  0     c     0 c 0
  g     2     g 2 g
        0       0
        g       g

Spaces for readability.

Truth-machine

r
:
10
pp
2x
j

Computational class

Madbrain is Turing complete because it can implement tag systems with an alphabet of up to 8 characters, enough for Turing completeness. (A compiler to produce such implementations is available on the talk page.)

Implementation (Python 3)

#!/usr/bin/env python

import sys


def main():

    f = open(sys.argv[1], 'r')
    prg = f.read().splitlines()
    f.close()

    prgPos = 0
    ptr = 0
    stk = []

    cmds = {
            '*': 'mul', '/': 'div', '+': 'add', '-': 'sub',
            '>': 'ga', '<': 'la', '^': 'gs', 'v': 'ls',
            '?': 'gza', '!': 'gzs', ':': 'eza', ';': 'ezs', '.': 'lza', ',': 'lzs',
            '=': 'ea', '_': 'es', '#': 'nea', '@': 'nes'
           }

    def j():
        nonlocal prgPos
        prgPos = stk.pop() - 1

    def g():
        nonlocal ptr
        j()
        ptr += stk.pop(0)

    def q():
        nonlocal ptr
        j()
        ptr -= stk.pop(0)

    def i():
        nonlocal ptr
        ptr += stk.pop()

    def d():
        nonlocal ptr
        ptr -= stk.pop()

    def x():
        sys.exit(0)

    def mul():
        stk.append(stk.pop() * stk.pop(0))

    def div():
        stk.append(stk.pop() / stk.pop(0))

    def add():
        stk.append(stk.pop() + stk.pop(0))

    def sub():
        stk.append(stk.pop() - stk.pop(0))

    def r():
        inp = input('\nAwaiting input: ')[0]
        while not inp.isdigit():
            inp = input('Input must be a digit.\nAwaiting input: ')
        stk.append(int(inp))

    def p():
        print(stk.pop(), end='')

    def c():
        i = stk.pop()
        if 0 <= i <= 255:
            print(chr(i), end='')

    def ga():
        nonlocal ptr
        ptr += stk.pop() > stk.pop(0)

    def la():
        nonlocal ptr
        ptr += stk.pop() < stk.pop(0)

    def gs():
        nonlocal ptr
        ptr -= stk.pop() > stk.pop(0)

    def ls():
        nonlocal ptr
        ptr -= stk.pop() < stk.pop(0)

    def gza():
        nonlocal ptr
        ptr += stk.pop() > 0

    def gzs():
        nonlocal ptr
        ptr -= stk.pop() > 0

    def eza():
        nonlocal ptr
        ptr += stk.pop() == 0

    def ezs():
        nonlocal ptr
        ptr -= stk.pop() == 0

    def lza():
        nonlocal ptr
        ptr += stk.pop() < 0

    def lzs():
        nonlocal ptr
        ptr -= stk.pop() < 0

    def ea():
        nonlocal ptr
        ptr += stk.pop() == stk.pop(0)

    def es():
        nonlocal ptr
        ptr -= stk.pop() == stk.pop(0)

    def nea():
        nonlocal ptr
        ptr += stk.pop() != stk.pop(0)

    def nes():
        nonlocal ptr
        ptr -= stk.pop() != stk.pop(0)

    while prgPos < len(prg):
        cmd = prg[prgPos][ptr]

        if (cmd in 'jidpc?!:;.,' and len(stk) < 1) or (cmd in 'gq*/+-><^v=_#@' and len(stk) < 2):
            raise IndexError('at ' + cmd + ': insufficient items in stack')

        if cmd.isdigit():
            stk.append(int(cmd))
            prgPos += 1
            continue

        try:
            exec(cmds.get(cmd, cmd) + '()')
        except NameError:
            pass
        prgPos += 1


if __name__ == '__main__':
    main()