用 Python 编写的解释器无法正常工作

Interpreter written in Python not working properly

不,我的翻译问题还没有完成。对不起。

所以我为我在 Python 中编写的编程语言编写了另一个解释器。编程语言有一个有趣的概念:你只能得到一些基本命令。要"get"更复杂的命令,你必须编写函数并结合给你的简单命令。

无论如何,我已经为该语言编写了一个简单的解释器。

问题是:简单命令有效,但定义函数无效。

这是解释器(我删除了对解决问题没有用的代码)。

class Interpreter:
    acc = 0
    defined = {}

    def read(self, cmd):
        tokens = cmd.replace("\n", ";").split(";")
        for token in tokens:
            self.parse(token)

    def parse(self, cmd):
        if cmd.startswith("def(") and cmd.endswith(")"):
            cmd = cmd[2:]
            cmd = cmd[:-1]
            cmd = cmd.split("|")
            self.defined[cmd[0]] = cmd[1]

        elif cmd in self.defined:
            self.read(self.defined[cmd])

        elif cmd == "1":
            self.acc += 1

        elif cmd == "2":
            print(self.acc)

        elif cmd == "i":
            self.acc = int(input(">> "))

i = Interpreter()
while 1:
    i.read(input("> "))

您可以使用语法 def(name|code) 定义函数。例如,def(cat|i;2).

现在,谈谈我遇到的问题。定义函数是不可能的。他们只是不工作。它不会抛出错误或任何东西。它什么都不做。

这是我尝试使用的代码:

def(c|i;2)
c

它应该获取输入并显示它,但它什么也没做。

虽然这有效:

i;2

在我看来,问题出在 if cmd.startswith("def(") if 语句中的某处,因为除了函数之外的所有内容都有效。

在解决这类问题时,必须能够在程序 运行ning 时看到正在发生的事情。你可以例如使用调试器,或者您可以使用古老的调试打印方法(就像我在下面所做的那样)。

我已经用打印 accp 命令扩展了解释器,并使其接受任何整数,否则它是相同的。

您遇到的问题是您在将输入存储到 defined 之前销毁了输入。我通过仅使用 \n 拆分外部命令和 ; 拆分 def.

内的命令来解决它
import textwrap

class Interpreter:
    acc = 0
    defined = {}

    def read(self, cmd):
        cmd = textwrap.dedent(cmd).strip()
        lines = cmd.split("\n")
        for line in lines:
            print '==> parsing:', line
            self.parse(line)

    def parse(self, cmd):
        if cmd.startswith("def(") and cmd.endswith(")"):
            print '::found def',
            name, code = cmd[4:-1].split('|')  # def( is 4 characters..
            self.defined[name] = code.replace(';', '\n')  # read() expects commands divided by \n, so replace ; before storing in self.defined
            print self.defined

        elif cmd in self.defined:
            print '::found defined name', cmd, '=>', `self.defined[cmd]`
            self.read(self.defined[cmd])

        elif cmd == "i":
            self.acc = int(input(">> "))

        elif cmd == "p":
            print(self.acc)

        else:
            self.acc += int(cmd)


intp = Interpreter()
intp.read("""
    def(c|i;2)
    c
    p
""")

运行 的输出:

(dev) go|c:\srv\tmp> python pars.py
==> parsing: def(c|i;2)
::found def {'c': 'i\n2'}
==> parsing: c
::found defined name c => 'i\n2'
==> parsing: i
>> 5
==> parsing: 2
==> parsing: p
7

编写以这种方式递归调用自身的解释器有一些主要限制,因为编译语言中的每个函数调用都需要宿主语言中的函数调用 (Python)。更好的方法是将程序转化为命令栈,然后从栈中弹出一条命令并执行。当堆栈为空时,你就完成了。函数调用将只涉及将定义符号的值压入堆栈。我已经扩展了您的解释器以在下面执行此操作。我已经添加了一个命令 x0 如果 acc 为零,它将退出函数调用(并且我在调用函数之前将 $marker 压入堆栈所以我知道函数调用从哪里开始):

def debug(*args):
    pass
    # print '[dbg]', ' '.join(str(a) for a in args)

class Interpreter:
    acc = 0
    defined = {}
    commands = []  # the stack

    def compile(self, program):
        program = textwrap.dedent(program).strip()
        lines = program.split("\n")
        lines.reverse()
        self.commands += lines

        while self.commands:
            command = self.commands.pop()
            debug('==> running:', command, 'stack:', self.commands)
            self.run_command(command)

    def run_command(self, cmd):
        if cmd.startswith("def(") and cmd.endswith(")"):
            name, code = cmd[4:-1].split('|')
            self.defined[name] = code.split(';')
            debug('::found def', self.defined)

        elif cmd in self.defined:
            debug('::found defined name', cmd, '=>', `self.defined[cmd]`)
            # mark command stack before executing function
            self.commands += ['$marker']  
            self.commands += list(reversed(self.defined[cmd]))

        elif cmd == '$marker':
            pass  # do nothing (we get here if a def doesn't have an x0 when the acc is zero)

        elif cmd == 'x0':
            # exit function call if acc is zero
            if self.acc == 0:
                while self.commands:  # pop the stack until we get to the $marker
                    tmp = self.commands.pop()
                    if tmp == '$marker':
                        break

        elif cmd == "i":
            self.acc = int(input(">> "))

        elif cmd == "p":
            print(self.acc)

        else:
            self.acc += int(cmd)

我们现在可以编写递归函数了:

intp = Interpreter()
intp.compile("""
    4
    def(c|-1;x0;p;c)
    c
    p
""")

输出:

(dev) go|c:\srv\tmp> python pars.py  
3                                    
2                                    
1                                    
0                                    

而不是累加器(acc),将堆栈用于值可能更具表现力,例如5;p 会将 5 压入堆栈,然后 p 会打印堆栈顶部的元素。然后你可以实现像 5;2;+ 这样的加法,意思是 push 5push 2,让 + 意思是 add top two items on stack and push the result... 我会把它留作练习;- )