我问treetop将您的语言编译成.rb文件。这给了我的东西钻进去:
$ tt -o /tmp/rip.rb /tmp/rip.treetop
然后我用这个小存根重新循环:
require 'treetop'
load '/tmp/rip.rb'
RipParser.new.parse('')
此挂起。现在,没有那么有趣!一个空字符串就像你问题中的十几行例子一样重现行为。
要找出悬挂的位置,我使用Emacs键盘宏编辑rip.rb,并在每个方法的条目中添加一条调试语句。例如:
def _nt_root
p [__LINE__, '_nt_root'] #DEBUG
start_index = index
现在我们可以看到循环的范围:
[16, "root"]
[21, "_nt_root"]
[57, "_nt_statement"]
...
[3293, "_nt_eol"]
[3335, "_nt_semicolon"]
[3204, "_nt_comment"]
[57, "_nt_statement"]
[57, "_nt_statement"]
[57, "_nt_statement"]
...
进一步调试从那里揭示了一个整数允许为空字符串:
rule integer
digit*
end
这间接地允许语句是一个空字符串,并且顶级规则永远消耗空语句。更改*
到+
修复的循环,但揭示了另外一个问题:
/tmp/rip.rb:777:in `_nt_object': stack level too deep (SystemStackError)
from /tmp/rip.rb:757:in `_nt_compound_object'
from /tmp/rip.rb:1726:in `_nt_range'
from /tmp/rip.rb:1671:in `_nt_special_literals'
from /tmp/rip.rb:825:in `_nt_literal_object'
from /tmp/rip.rb:787:in `_nt_object'
from /tmp/rip.rb:757:in `_nt_compound_object'
from /tmp/rip.rb:1726:in `_nt_range'
from /tmp/rip.rb:1671:in `_nt_special_literals'
... 3283 levels...
范围是左递归,间接地通过special_literals,literal_object,对象和compound_object。 Treetop在面临左递归时会一直吃下去,直到它呕吐。我没有解决这个问题的快速解决方案,但至少你已经有了一个从现在开始的堆栈跟踪。
此外,这不是你的直接问题,但digit
的定义很奇怪:它可以是一个数字,也可以是多个。这导致digit*
或digit+
允许(推测)非法整数1________2
。
我看了第一个五六个教程视频,但到目前为止,我还没有能够得到一个工作安装程序。你是正确的,他没有开始太快。我会再给ANTLR一次尝试。 – ravinggenius 2011-05-24 15:16:31
@好吧,我喜欢你的'treetop'语法的外观,如果你想用Ruby编程,那么切换到ANTLR将无济于事。 :)我只是觉得他的书在讨论如何构建优秀的解析器方面表现出色,ANTLR是他选择使用的工具。 – sarnold 2011-05-24 20:44:37