Madbrain

From Esolang
Jump to: navigation, 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 5 5 5 6 8 5 5 5 5 5 8
8 2 2 2 2 7 4 2 2 2 2 2 4
* * * * * * * * * * * * *
c 5 5 5 5 2 c 1 5 5 5 5 1
2 * * * * + 2 + * * * * +
0 2 2 2 2 c 0 1 2 2 2 2 c
g * * * * 2 g 8 * * * * x
  1 8 8 9 0   * 9 9 8 c
  + + + + g   - + + + 2
  c c c 2     c 2 5 c 0
  2 2 2 +     2 + + 2 g
  0 0 0 c     0 c c 0
  g g g 2     g 2 2 g
        0       0 0
        g       g g

Multiple columns for readability.

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)

#!usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def main():

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

    prgPos = 0
    ptr = 0

    stk = []

    errEq0 = ': stack is empty'
    errLt2 = ': stack contains less than 2 items'

    while prgPos < len(prg):

        if prg[prgPos][ptr].isdigit():
            stk.append(prg[prgPos][ptr])

        elif prg[prgPos][ptr] == 'j':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            prgPos = stk.pop() - 1

        elif prg[prgPos][ptr] == 'g':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            prgPos = stk.pop() - 1
            ptr += stk.pop(0)

        elif prg[prgPos][ptr] == 'q':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            prgPos = stk.pop() - 1
            ptr -= stk.pop(0)
            

        elif prg[prgPos][ptr] == 'i':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            ptr += stk.pop()

        elif prg[prgPos][ptr] == 'd':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            ptr -= stk.pop()

        elif prg[prgPos][ptr] == 'x':
            sys.exit(0)

        elif prg[prgPos][ptr] == 'r':
            inp = input(' Awaiting input: ')[0]
            while not inp.isdigit():
                inp = input(' Input must be a digit.\n Awaiting input: ')
            stk.append(int(inp))

        elif prg[prgPos][ptr] == '*':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            res = stk.pop() * stk.pop(0)
            stk.append(res)

        elif prg[prgPos][ptr] == '/':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            res = stk.pop() / stk.pop(0)
            stk.append(res)

        elif prg[prgPos][ptr] == '+':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            res = stk.pop() + stk.pop(0)
            stk.append(res)

        elif prg[prgPos][ptr] == '-':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            res = stk.pop() - stk.pop(0)
            stk.append(res)

        elif prg[prgPos][ptr] == 'p':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            print(stk.pop(), end='')

        elif prg[prgPos][ptr] == 'c':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() < 256 and stk.pop() > 0:
                print(chr(stk.pop()), end='')

        elif prg[prgPos][ptr] == '>':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() > stk.pop(0):
                ptr += 1

        elif prg[prgPos][ptr] == '<':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() < stk.pop(0):
                ptr += 1

        elif prg[prgPos][ptr] == '^':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() > stk.pop(0):
                ptr -= 1

        elif prg[prgPos][ptr] == 'v':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() < stk.pop(0):
                ptr -= 1

        elif prg[prgPos][ptr] == '?':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() > 0:
                ptr += 1

        elif prg[prgPos][ptr] == '!':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() > 0:
                ptr -= 1

        elif prg[prgPos][ptr] == ':':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() == 0:
                ptr += 1

        elif prg[prgPos][ptr] == ';':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() == 0:
                ptr -= 1

        elif prg[prgPos][ptr] == '.':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() < 0:
                ptr += 1

        elif prg[prgPos][ptr] == ',':
            if len(stk) == 0:
                raise IndexError('error at ' + prg[prgPos][ptr] + errEq0)
            if stk.pop() < 0:
                ptr -= 1

        elif prg[prgPos][ptr] == '=':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() == stk.pop(0):
                ptr += 1

        elif prg[prgPos][ptr] == '_':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() == stk.pop(0):
                ptr -= 1

        elif prg[prgPos][ptr] == '#':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() != stk.pop(0):
                ptr += 1

        elif prg[prgPos][ptr] == '@':
            if len(stk) < 2:
                raise IndexError('error at ' + prg[prgPos][ptr] + errLt2)
            if stk.pop() != stk.pop(0):
                ptr -= 1

        prgPos += 1

if __name__ == '__main__':
    main()