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.
a, b, c, d, and 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 mth memory space where 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 \frac{a}{b}\div\frac{c}{d} are calculated. If n is nonnegative, the numerator is stored in the nth memory slot, and the denominator in the n+1th.
If, however, 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 a, b, c, or d represents a special value: -1 represents the value of the instruction pointer, -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 \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==
===Swift===
See #External resources.
===Python 3===
It is not specified what should happen if 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:
 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[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
==External resources==
* Divrac.swift on GitHub
Category:Languages Category:Implemented Category:2021 Category:OISC