我一直在使用python一段时间,并决定通过在python中编写自定义脚本处理程序来更好地理解编程语言。到目前为止,我已成功实现了一个基本的内存处理程序,并将一个内存地址坐标挂钩到打印到屏幕上。我的问题可以提出为:
如何在这里实现功能? goto声明太容易了,我想尝试更难的事情。 (编辑)最终我希望能够做到:
f0(x, y, z):=ax^by^cz
...在运行该模块的脚本的shell中(傻,嗯?)
# notes: separate addresses from data lest the loop of doom cometh
class Interpreter:
def __init__(self):
self.memory = { }
self.dictionary = {"mov" : self.mov,
"put" : self.put,
"add" : self.add,
"sub" : self.sub,
"clr" : self.clr,
"cpy" : self.cpy,
"ref" : self.ref }
self.hooks = {self.val("0") : self.out }
def interpret(self, line):
x = line.split(" ")
vals = tuple(self.val(y) for y in x[1:])
dereferenced = []
keys_only = tuple(key for key in self.memory)
for val in vals:
while val in self.memory: val = self.memory[val]
dereferenced.append(val)
vals = tuple(y for y in dereferenced)
self.dictionary[x[0]](vals)
def val(self, x):
return tuple(int(y) for y in str(x).split("."))
def mov(self, value):
self.ptr = value[0]
def put(self, value):
self.memory[self.ptr] = value[0]
def clr(self, value):
if self.ptr in self.hooks and self.ptr in self.memory:
x = self.hooks[self.ptr]
y = self.memory[self.ptr]
for z in y: x(z)
del self.memory[self.ptr]
def add(self, values):
self.put(self.mat(values, lambda x, y: x + y))
def sub(self, values):
self.put(self.mat(values, lambda x, y: x - y))
def mat(self, values, op):
a, b = self.memory[values[0]], self.memory[values[1]]
if len(a) > len(b): a, b = b, a
c = [op(a[x], b[x]) for x in xrange(len(b))] + [x for x in a[len(a):]]
return [tuple(x for x in c)]
def cpy(self, value):
self.put(value)
def out(self, x):
print chr(x),
def ref(self, x):
self.put(x)
interp = Interpreter()
for x in file(__file__.split('/')[-1].split(".")[-2] + ".why"):
interp.interpret(x.strip())
示例脚本:
mov 1
put 104.101.108.108.111.10
mov 0
ref 1
clr 0
(编辑)我决定用这个尝试作为灵感,并从头开始这个项目。 (希望我能找到一些实际的时间在课程开始之前坐下来编写代码。)我打算在几天内给出最佳答案。我希望这些信息无法阻止潜在的贡献者提交任何他们认为对这种编码问题有帮助的东西。
答案 0 :(得分:3)
我正在努力了解你在问什么。你的函数定义在哪里?在脚本处理程序或脚本中?
如果它在脚本处理程序中,显而易见的解决方案是使用lambda
表达式。使用问题f0(x, y, z):=x^2
中使用的示例将转换为:
>>> f0 = lambda x, y, z : x**2
>>> f0(2,3,4)
4
如果要将函数定义放在脚本本身中,您可以使用lambda
和eval
表达式的组合。这是一个简单的例子,我刚刚一起讨论这个想法。
class ScriptParser(object):
# See 'to_python' to check out what this does
mapping = {'^':'**', '!':' not ', '&':' and '}
def to_python(self, calc):
'''
Parse the calculation syntax from the script grammar to the python one.
This could be grown to a more complex parser, if needed. For now it will
simply assume any operator as defined in the grammar used for the script
has an equivalent in python.
'''
for k, v in self.mapping.items():
calc = calc.replace(k, v)
return calc
def feed(self, lfs):
'''
Parse a line of the script containing a function defintion
'''
signature, calc = lfs.split(':=')
funcname, variables = [s.strip() for s in signature.split('(')]
# as we stripped the strings, it's now safe to do...'
variables = variables[:-1]
setattr(self, funcname,
eval('lambda ' + variables + ' : ' + self.to_python(calc)))
def main():
lines = ['f0(x, y, z) := x^2',
'f1(x) := x**2 + x**3 + x*1000']
sp = ScriptParser()
for line in lines:
sp.feed(line)
print('Script definition : %s' % line)
for i in range(5):
res0 = sp.f0(i, None, None)
res1 = sp.f1(i)
print('f0(%d) = %d' % (i, res0))
print('f1(%d) = %d' % (i, res1))
print('--------')
if __name__ == '__main__':
main()
运行此程序输出:
Script definition : f0(x, y, z) := x^2
Script definition : f1(x) := x**2 + x**3 + x*1000
f0(0) = 0
f1(0) = 0
--------
f0(1) = 1
f1(1) = 1002
--------
f0(2) = 4
f1(2) = 2012
--------
f0(3) = 9
f1(3) = 3036
--------
f0(4) = 16
f1(4) = 4080
--------
请记住:
eval
具有您应该注意的安全隐患。HTH, Mac中。
答案 1 :(得分:2)
如果你去编译器手册,它会建议在调用方法时使用堆栈。这将允许您创建递归函数,调用其他函数的函数,并将变量保持在适当的范围内。
因此,您使用堆栈为每个函数调用堆叠变量,是的,使用goto
转到函数的地址。然后使用堆栈获取函数的返回地址,以及调用函数时变量的状态。就是这样。
答案 2 :(得分:2)
不确定我是否理解你,但如果你的目标是通过f0(x):=mov x
和其他复杂的语法来定义一个函数,那么它听起来就像你错过的重要组件是某种词法分析和语法分析器。一旦你摆脱了“线上的第一个符号定义线条的作用”的概念,那么line.split(" ")
的方法就不再足够了。这些是相当复杂的工具,每种比汇编更复杂的语言都需要这些工具(尽管它们可以手工构建,具体取决于语言和编译器/解释器)。
大多数人在两个主要步骤中解析他们的输入:
1)词法分析 - 此步骤采用“x + 1/5”并将其转换为有意义的符号,如“VARIABLE OPERATOR NUMBER OPERATOR NUMBER”。此步骤的输出用作语法分析器的输入
2)语法分析 - 这更复杂,并且有关于语法分析的最佳方法的大量理论。这将采用上述输入并将其解析为可以评估的树。像:
Operator+
| |
| ----Variable x
Operator/
| |
1 5
我对Python中的这些类型的工具都没有任何经验。在C ++中,我使用的唯一工具叫做flex和bison。我确定其他人在python之前已经使用过这样的工具,并且可以指向一些链接。看起来这个问题有一些:Efficient Context-Free Grammar parser, preferably Python-friendly
我尝试在概念上搜索关于你的一些教程,但是空白了。由于某些原因,今晚我的谷歌搜索技巧没有开启。
答案 3 :(得分:1)
考虑使用pyparsing来定义语法。其维基上有很多examples,例如interactive calculator。