# Divrac

Divrac is an OISC by User:PythonshellDebugwindow.

## Memory

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.

## Syntax

A program is made up of zero or more lines. Each line is of the form:

a,b,c,d,n

with optional (ignored) vertical whitespace. Lines are separated by newlines.

${\displaystyle a}$, ${\displaystyle b}$, ${\displaystyle c}$, ${\displaystyle d}$, and ${\displaystyle n}$ 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, [1] represents the value in the 1st memory space, [[1]] represents the value in the ${\displaystyle m}$th memory space where ${\displaystyle m}$ is the value in the 1st memory slot, and so on.

### BNF

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

## Semantics

Each line, the numerator and denominator of the reduced improper form of ${\displaystyle {\frac {a}{b}}\div {\frac {c}{d}}}$ are calculated. If ${\displaystyle n}$ is nonnegative, the numerator is stored in the ${\displaystyle n}$th memory slot, and the denominator in the ${\displaystyle n+1}$th.

If, however, ${\displaystyle n}$ 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 ${\displaystyle a}$, ${\displaystyle b}$, ${\displaystyle c}$, or ${\displaystyle d}$ represents a special value: ${\displaystyle -1}$ represents the value of the instruction pointer, ${\displaystyle -2}$ 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 ${\displaystyle {\frac {a}{b}}\div {\frac {c}{d}}}$ is 0, then the denominator is redefined to be a random integer from 1 to 1000.

## Examples

### Truth-machine

Using the I/O extension:

0,1,1,1,0
1,1,1,1,1
[-2],1,1,1,2
[2],1,1,1,-2
1,1,[2],1,3
4,1,1,1,-1

## Implementations

### Python 3

It is not specified what should happen if ${\displaystyle n<-2}$. 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[0],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[1], "r") as f:
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[4],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