Divrac

From Esolang
Jump to navigation Jump to search

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.

, , , , 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, [1] represents the value in the 1st memory space, [[1]] represents the value in the th memory space where 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 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.

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 . 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