0

关于我使用 Treetop 的一个反复出现的问题,我希望得到您的建议,我无法解决……有时。我可能错过了一些东西。

我怀疑你们中的许多人都有正确的习语或习惯来解决这个问题。

我通常使用 Treetop,如下所示:

  1. 我在 .tt 文件中定义我的语法
  2. 我修改它以发出自定义解析树对象(继承 Treetop::Runtime::SyntaxNode)。这些类在“parsetree.rb”文件中定义。
  3. 这些自定义对象有一个 to_ast方法,可以将它们递归地转换为“纯”树顶独立类(构成我的最终 AST)。为此,我有两个单独的模块(ParseTree 和 AST)。

但是,我遇到了一条经典的错误消息,我通常无法修复:

parsetree.rb:380:in `to_ast': undefined method `to_ast' for SyntaxNode
offset=149, "":Treetop::Runtime::SyntaxNode (NoMethodError)

我在这里感到困惑,因为似乎发出了一个空字符串“”而不是我的自定义节点之一。

在这个例子中,在这行 380 我有以下代码(它是关于一个有限状态机)

# in parsetree.rb
class Next < Tree
      def to_ast
        ret=Ldl::Ast::Next.new
        ret.name=ns.to_ast
        if cond
          ret.condition=cond.c.to_ast
        end
        ret.actions=acts.to_ast # <==== line 380
        ret
      end
    end

 class NextActions < Tree
      def to_ast
        eqs.elements.collect{|eq| eq.to_ast}
      end
    end

我与错误有关的语法是:

rule nextstate
    space? 'next' space ns:identifier space? cond:('?' space? c:expression)? space
    acts:next_actions? <Ldl::ParseTree::Next>
end  

rule next_actions
    space? eqs:equation+ space 'end' space <Ldl::ParseTree::NextActions>
end
4

1 回答 1

1

您的问题在于可选表达式的行为。

act:next_actions 是可选的。如果此可选元素在输入中不匹配,则您不会获得 NextActions 节点,而是一个 epsilon。您应该通过以下方式检测到这一点:

ret.actions = acts.empty? ? [] : acts.to_ast

可能会出现同样的问题,因为标签 cond: 命名的序列是可选的。如果输入中不存在此序列,则它没有内容“c”。在这种情况下,“cond”仍将被定义,并且您的“if”语句将为真,但 cond.c.to_ast 将失败。

简短回答:当您使用可选表达式时,您应该标记它并测试标记是否为空?在尝试使用内容之前。

于 2015-05-07T10:47:21.190 回答