Pythonからの単純なインタプリタを構築します.09 :関数呼び出し、リターン
21975 ワード
このポストでは、関数、call、returnを実装しています.
その他の関連リンクPatreon
# This is required for returning without primitives
class Empty:
pass
class Interpreter:
# Updated constructor for holding our functions
def __init__(self):
self.scope= [{}]
self.loop_stack=[]
self.funcs = {}
#....(previous code)....
# Updated to check if we returned or not
def If(self,xs):
_,cond,trueblock,elseblock=xs
if self.eval(cond):
if isinstance(trueblock[0],list):
for x in trueblock:
self.eval(x)
# Return check
if "retval" in self.scope[-1]:
return
else:
self.eval(trueblock)
else:
if elseblock:
if isinstance(elseblock[0],list):
for x in elseblock:
self.eval(x)
# Return check
if "retval" in self.scope[-1]:
return
else:
self.eval(elseblock)
# Updated:
def While(self,xs):
self.loop_stack.append({"break":False,"continue":False})
_ , cond , block = xs
while self.eval(cond):
if isinstance(block[0],list):
for x in block:
self.eval(x)
# Return check
if "retval" in self.scope[-1]:
self.loop_stack.pop()
return
if self.loop_stack[-1]["break"]:
self.loop_stack.pop()
return
if self.loop_stack[-1]["continue"]:
self.loop_stack[-1]["continue"]=False
break
else:
self.eval(block)
self.loop_stack.pop()
# Updated:
def For(self,xs):
self.loop_stack.append({"break":False,"continue":False})
_, inits, cond, increments, block = xs
for x in inits:
self.eval(x)
while self.eval(cond):
if isinstance(block[0],list):
for x in block:
self.eval(x)
# Return check
if "retval" in self.scope[-1]:
self.loop_stack.pop()
return
if self.loop_stack[-1]["break"]:
self.loop_stack.pop()
return
if self.loop_stack[-1]["continue"]:
self.loop_stack[-1]["continue"]=False
break
else:
self.eval(block)
for x in increments:
self.eval(x)
self.loop_stack.pop()
#New: Define a function
def Function(self,xs):
_, name, params, block = xs
self.funcs[name]={"params":params,"block":block}
#New:
def Return(self,xs):
if len(self.scope)<2: # we are in global scope
print("error: 'return' must be in function")
exit(1)
# Return with value
if len(xs)>1:
self.scope[-1]["retval"]=self.eval(xs[1])
# Return without value
else:
self.scope[-1]["retval"]=Empty()
# New:
def Call(self,xs):
_, funcname, params = xs
# Before adding scope to scope list,
scope={}
func=self.funcs[funcname]
# we must evaluate function params in current scope,
for i,p in enumerate(func["params"]):
scope[p]=self.eval(params[i])
self.scope.append(scope)
# now we are in new scope,
for x in func["block"]:
self.eval(x)
if "retval" in self.scope[-1]:
break
retval=self.scope[-1]["retval"]
self.scope.pop()
return retval
code=[
["Function","fibonacci",["n"], [
["If",["Lte",["Get","n"],1],
["Return",["Get","n"]],[]
],
["Return",
["Add",
["Call","fibonacci",[["Sub",["Get","n"],1]]],
["Call","fibonacci",[["Sub",["Get","n"],2]]]
]
]
]],
["Print","fibonacci(15) = ", ["Call","fibonacci",[15]]],
["Return"]
]
interpreter=Interpreter()
interpreter.run(code)
出力:fibonacci(15) = 610
error: 'return' must be in function
コードを完了するLink.その他の関連リンクPatreon
Reference
この問題について(Pythonからの単純なインタプリタを構築します.09 :関数呼び出し、リターン), 我々は、より多くの情報をここで見つけました https://dev.to/smadev/lets-build-a-simple-interpreter-from-scratch-in-python-pt-08-function-call-return-1p55テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol