Volatile

From Esolang
Jump to navigation Jump to search

Volatile is an esoteric programming language that can only push random numbers onto an unbounded stack that can push unbounded numbers. It is inspired by Keg; 7 of the 8 instructions are borrowed from Keg.

Syntax

~: Push a random number in any range of numbers. The range is determined by what the implementors like.
+: Pop 2 values and push the sum of the 2 values
-: Like +, but subtracts
*: Multiply
/: Divide. 0-division will result in an error.
:: Duplicate the top of the stack
.: Output the top of the stack without popping it
(...): Execute ... inside a while loop when the top of the stack is not 0

It is quite obvious that it does not have a discard operation.

Examples

These examples may randomly fail due to Volatile being non-deterministic.

Discard the top element of the stack

:-+

Increment top of stack

~:/+

Decrement top of stack

~:/-

Create an error

You can definitely be sure on this one.

~:-:/

Square top of the stack

:*

NOT the top of the stack

~:-~:/-*~:/+

Display the word "Hi"

~:/:+:*:*~:/:::+++*~:/:::+++:++.~:/::::++++~:/:::+++*::::++++~:/::::+++++.

Note: It only prints the ASCII values of the letters H and i (72 and 105 respectively)

Hello, world! program

This program is created mechanically, see the code.

~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++.~:/::::::::::++++++++++.

Infinite loop

~()

Looping counter

~:-.~:/+.(~:/+.)

Number tricks

You obviously cannot wish that the random operation("~") will push the number that you want. (You have to be very lucky.)

So, you need a technique that reverses this probability. (Getting a number that you don't want is highly unlikely.)

You can use these code snippets to push 0 or 1 onto the stack.

To push 0(it definitely will not cause an error): ~:-

To push 1(not 100% deterministic; 0-division exception): ~:/

Another way to push 1(crashes in a different manner(array index out of bounds exception in Java interpreter, no-op in Python interpreter)): ~(:/~:-)+

Also, to represent larger integers(like 4), you only have to add by 1's. (Split 4 into 1+1+1+1, and do the push-1 operations.)

Almost every Volatile program relies on duplicating the top of the stack and pushing random numbers.

How to discard the top of the stack

It seems impossible to discard the top of the stack using only numeric operations. However, what we need is just a way to ignore the top of the stack.

The way to achieve this is to multiply the top of the stack by 0(recycling the top-stack number) and add. (This deletes the top-of stack 0 and preserves the bottom-of stack value.)

Computational Class

Volatile is Turing-complete. See the talk page for details.

Python Interpreter

#Volatile Interpreter
#https://esolangs.org/wiki/Volatile

import random, sys

source = input()
stack = []

push = stack.append

ip = 0
loop_mode = False
loops = []

while ip < len(source):
    char = source[ip]

    if loop_mode:
        if char == "(":
            loop_mode = False
        else:
            ip += 1; continue

    if char == "~": push(random.randint(-sys.maxsize, sys.maxsize))
    elif char in "+-/*":
        a, b = stack.pop(), stack.pop()
        push(eval(f"{b}{char}{a}"))
    elif char == ":": push(stack[-1])
    elif char == ".": print(*[chr(stack[-1]) if 10 <= stack[-1] <= 256 else stack[-1]])
    elif char == "(": loop_mode = stack[-1] == 0; loops.append(ip)
    elif char == ")":
        if stack[-1] != 0:
            ip = loops[-1] + 1
            continue
        else:
            loops.pop()
    else: continue

    ip += 1

(Another) Python 3 interpreter

Implements the spec fully with support for unbounded numbers and nested loops.

# Python interpreter for Volatile
# https://esolangs.org/wiki/Volatile
# No rights reserved

import random
import sys

rand = lambda: random.randint(-(2**31), (2**31)-1)

def pop(stack, k=0):
	if not stack:
		raise IndexError("stack empty")
	if k:
		return stack[-1]
	return stack.pop()

def _op(stack, f, d):
	b = pop(stack)
	a = pop(stack)
	if d and not b:
		raise ArithmeticError("division by zero")
	stack.append(f(a, b))

def op(f, d=0):
	return lambda stack: _op(stack, f, d)

cmd = {
	"~": lambda stack: stack.append(rand()),
	"+": op(lambda a, b: a + b),
	"-": op(lambda a, b: a - b),
	"*": op(lambda a, b: a * b),
	"/": op(lambda a, b: a // b, 1),
	":": lambda stack: stack.append(pop(stack, 1)),
	".": lambda stack: print(pop(stack, 1)),
}

def volatile_eval(ast, stack=[]):
	for x in ast:
		if isinstance(x, list):
			while pop(stack, 1):
				volatile_eval(x, stack)
		else:
			cmd[x](stack)
	return stack

def parse(s):
	st = [[]]
	for c in s:
		if c == "(":
			st.append([])
		elif c == ")":
			x = st.pop()
			if not st:
				raise SyntaxError("unbalanced parentheses")
			st[-1].append(x)
		elif c in "~+-*/:.":
			st[-1].append(c)
	if len(st) > 1:
		raise SyntaxError("unbalanced parentheses")
	return st.pop()

if __name__ == "__main__":
	if len(sys.argv) < 2 or \
	   (sys.argv[1] == "-f" and len(sys.argv) != 3) or \
	   (sys.argv[1] != "-f" and len(sys.argv) != 2):
		print("usage: %s {CODE | -f FILE}" % sys.argv[0])
		exit(1)
	if sys.argv[1] == "-f":
		with open(sys.argv[2]) as f:
			code = f.read()
	else:
		code = sys.argv[1]
	try:
		ast = parse(code)
		stack = volatile_eval(ast)
		if stack:
			print("stack:", end=" ")
			for x in stack[:-1]:
				print(x, end=" ")
			print("|%d|" % stack[-1], end="")
		print()
	except Exception as ex:
		print(ex)

Volatile instruction minimalization

It seems that 8 instructions(excluding I/O instructions) is extra for a Turing-complete language. Therefore, the instruction set might be capable of being minimalized. It is unknown whether that is feasible, though.