Divrac uses an unbounded number of memory slots, each of which can hold a signed integer. All slots are assigned a index, which is a nonnegative integer.
A program is made up of zero or more lines. Each line is of the form:
with optional (ignored) vertical whitespace. Lines are separated by newlines.
, , , , and must be either integers, representing integer values, or integers surrounded by any number of brackets. Each pair of brackets represents a level of indirection. For example,
1 represents the number 1,
 represents the value in the 1st memory space,
[] represents the value in the th memory space where is the value in the 1st memory slot, and so on.
Remove all vertical whitespace first.
program ::= lines | line | "" lines ::= line "\n" | lines lines line ::= val "," val "," val "," val "," val val ::= int | "[" val "]" int ::= digit | digit int
Each line, the numerator and denominator of the reduced improper form of are calculated. If is nonnegative, the numerator is stored in the th memory slot, and the denominator in the th.
If, however, is negative, then it prints the numerator to STDOUT if it is -2, and sets the instruction pointer to the numerator if it is -1 (any other value is undefined behaviour).
A negative value of , , , or represents a special value: represents the value of the instruction pointer, reads a positive integer from STDIN, and all other negative values of these four are undefined behaviour.
Division by zero at any point causes the program to exit. If the numerator of is 0, then the denominator is redefined to be a random integer from 1 to 1000.
Using the I/O extension:
0,1,1,1,0 1,1,1,1,1 [-2],1,1,1,2 ,1,1,1,-2 1,1,,1,3 4,1,1,1,-1
See #External resources.
It is not specified what should happen if . This implementation treats it as a nop. It also assumes that setting the IP to an invalid line number is a valid way to halt a program.
import sys from math import gcd from functools import partial from collections import defaultdict def process(ip,entry,special=False): global memory if isinstance(entry,list): if len(entry)!=1: print("Invalid entry on line %d: %s"%(ip,str(entry)));sys.exit(1) return memory[process(ip,entry,special=special)] elif type(entry) == int: if special: return entry else: if entry>=0: return entry elif entry==-1: return ip+1 elif entry==-2: return int(input()) else: print("Invalid entry on line %d: %d"%(ip,entry));sys.exit(1) else: print("Invalid entry on line %d: %s"%(ip,str(entry)));sys.exit(1) if len(sys.argv)<2: print("No filename to execute.") else: try: with open(sys.argv, "r") as f: prog = f.read().splitlines() except IOError: print("File '"+filename+"' not found."); sys.exit(1) for i in range(len(prog)): line = prog[i].strip() if not line: i-=1;continue try: prog[i] = list(map(eval,line.split(","))) except: print("Invalid instruction on line %d"%(i)); sys.exit(1) memory = defaultdict(int) ip = 0 while 0<=ip<len(prog): line = prog[ip] a,b,c,d = map(partial(process,ip),line[:4]) n=process(ip,line,special=True) numer = a*d denom = b*c if denom==0:sys.exit(1) div = gcd(numer,denom) numer//=div denom//=div if n>=0: memory[n]=numer memory[n+1]=denom elif n==-1: ip=numer-2 elif n==-2: print(numer) ip+=1
- Divrac.swift on GitHub