aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xrippy/rippy.py158
1 files changed, 158 insertions, 0 deletions
diff --git a/rippy/rippy.py b/rippy/rippy.py
new file mode 100755
index 0000000..d6158bb
--- /dev/null
+++ b/rippy/rippy.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+
+import sys
+
+rip_mode=False
+
+if len(sys.argv)!=2:
+ print("Usage: ./rippy.py <file.rip>",file=sys.stderr)
+ sys.exit(1)
+
+def error(msg):
+ if rip_mode:
+ msg="rip"
+ print(msg,file=sys.stderr)
+ sys.exit(1)
+
+def make_jumpmap(source):
+ jm={}
+ stk=[]
+ for i in range(len(source)):
+ if source[i]=="[":
+ stk.append(i)
+ elif source[i]=="]":
+ if len(stk)==0:
+ error("Too many ']' in source")
+ jm[stk[-1]]=i
+ jm[i]=stk[-1]
+ stk.pop()
+ if len(stk)!=0:
+ error("Too many '[' in source")
+ return jm
+
+def stack_check(stk,opname,nelems):
+ if len(stk)==0:
+ error(opname+" needs "+nelems+" element"+("s" if nelems!=1 else "")+" on the stack")
+
+def stack_pop(stk,opname,nelems):
+ stack_check(stk,opname,nelems)
+ e=stk[-1]
+ stk.pop()
+ return e
+
+
+def rip(source,jm):
+ ip=0
+ stk=[]
+ cstk=[]
+ lastif=None
+ while ip<len(source):
+ if source[ip] in " \t\n":
+ ip+=1
+ continue
+
+ if lastif!=None and source[ip]!="[":
+ error("'[' expected after '"+lastif+"'")
+
+ if source[ip] in "0123456789":
+ stk.append(int(source[ip]))
+ elif source[ip]=="P":
+ stack_pop(stk,"Pop",1)
+ elif source[ip]=="S":
+ stack_check(stk,"Swap",2)
+ stk[-2],stk[-1]=stk[-1],stk[-2]
+ elif source[ip]=="D":
+ stack_check(stk,"Duplicate",1)
+ stk.append(stk[-1])
+ elif source[ip]=="i":
+ stack_check(stk,"Increment",1)
+ stk[-1]+=1
+ elif source[ip]=="d":
+ stack_check(stk,"Decrement",1)
+ stk[-1]-=1
+ elif source[ip]=="r":
+ a=stack_pop(stk,"Roll",1)
+ if a<0:
+ error("Negative roll amount")
+ if a>1:
+ stack_check(stk,"Roll("+str(a)+")",a)
+ stk[-a],stk[-a+1:-1]=stk[-1],stk[-a:-2]
+ elif source[ip]=="R":
+ a=stack_pop(stk,"Reverse roll",1)
+ if a<0:
+ error("Negative reverse roll amount")
+ if a>1:
+ stack_check(stk,"Reverse roll("+str(a)+")",a)
+ stk[-a:-2],stk[-1]=stk[-a+1:-1],stk[-a]
+ elif source[ip]=="l":
+ stk.append(len(stk))
+ elif source[ip] in "asmqMpGLE":
+ names={
+ "a": "Add", "s": "Subtract", "m": "Multiply", "q": "Quotient",
+ "M": "Modulo", "p": "Power", "G": "Greater", "L": "Less", "E": "Equal"
+ }
+ funcs={
+ "a": lambda a,b: a+b, "s": lambda a,b: a-b, "m": lambda a,b: a*b,
+ "q": lambda a,b: a//b, "M": lambda a,b: a%b, "p": lambda a,b: a**b,
+ "G": lambda a,b: a>b, "L": lambda a,b: a<b, "E": lambda a,b: a==b,
+ }
+ b=stack_pop(stk,names[source[ip]],2)
+ a=stack_pop(stk,names[source[ip]],2)
+ stk.append(funcs[source[ip]](a,b))
+ elif source[ip]=="n":
+ stk.append(stack_pop(stk,"Not",1)!=0)
+ elif source[ip] in "IW":
+ if lastif!=None:
+ error("'"+source[lastif]+" without codeblock")
+ lastif=source[ip]
+ elif source[ip]=="[":
+ if lastif==None:
+ error("'[' without I or W")
+ if stack_pop(stk,"'[' for '"+lastif+"'",1)!=0:
+ cstk.append(lastif)
+ else:
+ ip=jm[ip]
+ lastif=None
+ elif source[ip]=="]":
+ if cstk[-1]=="W":
+ ip=jm[ip]-1
+ lastif=cstk[-1]
+ else:
+ cstk.pop()
+ elif source[ip]=="o":
+ n=stack_pop(stk,"Output character",1)
+ if n<0 or n>255:
+ error("Invalid output byte")
+ print(chr((n%256+256)%256),end="")
+ elif source[ip]=="O":
+ n=stack_pop(stk,"Output number",1)
+ print(n,end="")
+ elif source[ip]=="g":
+ c=sys.stdin.read(1)
+ if len(c)==0:
+ stk.append(-1)
+ else:
+ stk.append(ord(c))
+ elif source[ip]=="'":
+ if ip+1>=len(source):
+ error("Single-quote at end of file")
+ stk.append(ord(source[ip+1]))
+ ip+=1
+ else:
+ error("Unrecognised command '"+source[ip]+"'")
+
+ ip+=1
+
+
+def main():
+ sourcefname=sys.argv[1]
+ with open(sourcefname,"r") as f:
+ source=f.read()
+
+ jm=make_jumpmap(source)
+
+ rip(source,jm)
+
+
+if __name__=="__main__":
+ main()