ZeptoBasic

From Esolang
Jump to navigation Jump to search

ZeptoBasic is a minimal BASIC clone, built on top of Python, designed by User:nooodl in December 2012.

Language overview

ZeptoBasic programs are a sequence of commands, separated by newlines. There are two datatypes in ZeptoBasic: numbers and strings.

ZeptoBasic commands are tokenized into:

  • String values, surrounded by double quotes.
  • Numbers, non-string tokens matching -?[0-9]*.
  • Identifiers, any other series of non-whitespace characters. (These are valid variable names.)

Instructions

Command Description
label name Mark a label, name, on this line.
goto name Jump to the label name.
set var value Set var to value, which is either a string or a number.
print var Prints var, followed by a newline.
input var prompt Ask for a value to be placed in var, prompting with prompt, a string.
if v1 cmp v2 label Evaluates v1 and v2, and compares them using cmp, which is one of lt, le, eq, ne, gt, ge.
get var a vind Evaluates the value vind, then sets var to the variable a.(x), where (x) is replaced by the value of vind.
put a vind vnew Stores the value of vnew into the variable a.(x), where (x) is replaced by the value of vind.
op var v Sets var to the value of applying op to var and v, where op is one of add (addition), sub (subtraction), mul (multiplication), div (division), mod (modulo), pow (power).

Adding two strings concatenates them; multiplying a string by a number repeats it.

Examples

Hello World

print "Hello, world!"

Factorial

input n "Number to calculate n! of: "
set acc 1
label loop
mul acc n
sub n 1
if n gt 0 loop
print acc

Arrays

put a 0 65
put a 1 34
put a 2 86
put a 3 15
put a 4 91
set i 0
label loop
get j a i
mul j j
print j
add i 1
if i lt 5 loop

Implementation

The original implementation by User:nooodl, in Python:

import re, operator, sys

ops = operator.__dict__
code = map(re.compile(r'"[^"]*"|\S+').findall,
           sys.stdin.read().split('\n'))
labels, vs, pc = {}, {}, 0

def v(s):
    if s[0] == '"':
        return s[1:-1]
    elif s[0] in '-0123456789':
        return int(s)
    return vs[s]

while pc < len(code):
    l = code[pc]
    if l == [] or l[0] == 'label':
        pass
    elif l[0] == 'goto':
        pc = [x == ['label', l[1]] for x in code].index(True)
    elif l[0] == 'set':
        vs[l[1]] = v(l[2])
    elif l[0] == 'print':
        print v(l[1])
    elif l[0] == 'input':
        vs[l[1]] = v(raw_input(v(l[2])))
    elif l[0] == 'if':
        if ops[l[2]](v(l[1]), v(l[3])):
            pc = [x == ['label', l[4]] for x in code].index(True)
    elif l[0] == 'get':
        vs[l[1]] = vs[l[2] + '.' + str(v(l[3]))]
    elif l[0] == 'put':
        vs[l[1] + '.' + str(v(l[2]))] = v(l[3])
    else:
        vs[l[1]] = ops[l[0]](vs[l[1]], v(l[2]))
    pc += 1

Computation class

ZeptoBasic is Turing-complete; the following Python program converts a brainfuck program to ZeptoBasic:

import sys
code = sys.stdin.read()

# The tape size can be adjusted here; by default, it's 300.
print '''\
set p 0
set i 299
label setup
put tape i 0
sub i 1
if i ge 0 setup
'''

li = 0
lstack = []

for i in code:
    if i == '+':
        print 'get a tape p'
        print 'add a 1'
        print 'mod a 256'
        print 'put tape p a'
    if i == '-':
        print 'get a tape p'
        print 'sub a 1'
        print 'mod a 256'
        print 'put tape p a'
    if i == '>':
        print 'add p 1'
        print 'mod p 256'
    if i == '<':
        print 'sub p 1'
        print 'mod p 256'
    if i == '[':
        print 'label start{0}'.format(li)
        print 'get a tape p'
        print 'if a eq 0 end{0}'.format(li)
        lstack.append(li)
        li += 1
    if i == ']':
        lp = lstack.pop()
        print 'get a tape p'
        print 'if a ne 0 start{0}'.format(lp)
        print 'label end{0}'.format(lp)
    if i == ',':
        print 'input a ""'
        print 'mod a 256'
        print 'put tape p a'
    if i == '.':
        print 'get a tape p'
        print 'print a'