diff options
author | tomsmeding <tom.smeding@gmail.com> | 2017-05-24 09:12:24 +0200 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2017-05-24 09:12:24 +0200 |
commit | 20b6ef15c03fb442eb6c96e1aaa301805be74c1e (patch) | |
tree | 39834d436733c1b1804ea32a633bb512b34c3d3c | |
parent | 36a8fffe4db7c5b01fd313563b120e0acc3bf834 (diff) |
Add python rip interpreter 'rippy'
-rwxr-xr-x | rippy/rippy.py | 158 |
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() |