为什么有时在 Treetop 语法中似乎发出了空字符串而不是自定义节点?
Why an empty string seems emitted instead of a custom node, sometimes, in a Treetop grammar?
关于我使用 Treetop 时出现的反复出现的问题,我希望得到您的建议,我无法...不时解决。我可能遗漏了什么。
我怀疑你们中的许多人都有正确的习语或习惯来解决这个问题。
我通常像下面这样使用 Treetop :
- 我在 .tt 文件中定义我的语法
- 我修改它以发出自定义解析树对象
(即继承 Treetop::Runtime::SyntaxNode)。这些 类 是
在 "parsetree.rb" 文件中定义。
- 这些自定义对象有
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 将失败。
简答:当你使用可选表达式时,你应该标记它并测试标记是否为空?在尝试使用内容之前。
关于我使用 Treetop 时出现的反复出现的问题,我希望得到您的建议,我无法...不时解决。我可能遗漏了什么。
我怀疑你们中的许多人都有正确的习语或习惯来解决这个问题。
我通常像下面这样使用 Treetop :
- 我在 .tt 文件中定义我的语法
- 我修改它以发出自定义解析树对象 (即继承 Treetop::Runtime::SyntaxNode)。这些 类 是 在 "parsetree.rb" 文件中定义。
- 这些自定义对象有 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 将失败。
简答:当你使用可选表达式时,你应该标记它并测试标记是否为空?在尝试使用内容之前。