为什么有时在 Treetop 语法中似乎发出了空字符串而不是自定义节点?

Why an empty string seems emitted instead of a custom node, sometimes, in a Treetop grammar?

关于我使用 Treetop 时出现的反复出现的问题,我希望得到您的建议,我无法...不时解决。我可能遗漏了什么。

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

我通常像下面这样使用 Treetop :

  1. 我在 .tt 文件中定义我的语法
  2. 我修改它以发出自定义解析树对象 (即继承 Treetop::Runtime::SyntaxNode)。这些 类 是 在 "parsetree.rb" 文件中定义。
  3. 这些自定义对象有 to_ast 方法将它们递归地转换为 "pure" 树顶独立 类(构成我的最终 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

您的问题与可选表达式的行为有关。

acts:next_actions 是可选的。如果此可选元素在输入中不匹配,则您不会获得 NextActions 节点,而是获得一个 epsilon。你应该通过说这样的话来检测:

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

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

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