用 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 时看到正在发生的事情。你可以例如使用调试器,或者您可以使用古老的调试打印方法(就像我在下面所做的那样)。
我已经用打印 acc
的 p
命令扩展了解释器,并使其接受任何整数,否则它是相同的。
您遇到的问题是您在将输入存储到 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 5
,push 2
,让 +
意思是 add top two items on stack and push the result
... 我会把它留作练习;- )
不,我的翻译问题还没有完成。对不起。
所以我为我在 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 时看到正在发生的事情。你可以例如使用调试器,或者您可以使用古老的调试打印方法(就像我在下面所做的那样)。
我已经用打印 acc
的 p
命令扩展了解释器,并使其接受任何整数,否则它是相同的。
您遇到的问题是您在将输入存储到 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 5
,push 2
,让 +
意思是 add top two items on stack and push the result
... 我会把它留作练习;- )