Volatile
Volatile is an esoteric programming language invented by User:A that can only push random numbers onto an unbounded stack that can push unbounded numbers. It is inspired by Keg; 7 of the 7 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 (...): Execute ... inside a while loop when the top of the stack is not 0
Debugging features (not part of the language)
This instruction is frequently used in these examples below. However, they are examples and are expected to be understood by the readers.
.: Output the top of the stack, without popping
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)
More Interpreters
CGCC User Lyxal asked a question on codegolf.stackexchange.com to create Volatile interpreters. Here's the question: https://codegolf.stackexchange.com/questions/191573/interpret-volatile?r=SearchResults.