在 Ruby Treetop 中使用 elements.map 时,如何处理 0 或多个语句中没有非终端节点?
How do you handle no nonterminal node in a 0 or more statement when using elements.map in Ruby Treetop?
我正在尝试创建一个映射其所有非终端节点的自定义语法节点 class。问题是其中一个节点不一定必须存在,这在自定义语法节点 class 中使用 elements.map 时会产生问题,因为语法节点树会创建 SyntaxNode: "" for相反,我还没有为它创建 class。
grammar Foo
rule textStructure
beginDoc twoOrMoreNewLines (block twoOrMoreNewLines)* endDoc <Structure>
end
rule beginDoc
'begin document' <BeginLine>
end
rule twoOrMoreNewLines
"\n" 2.. <NewLine>
end
rule block
!beginDoc information:((!"\n" .)+) <BlockLine>
end
rule endDoc
'end document' <EndLine>
end
end
# On a different file
module Foo
class Structure < Treetop::Runtime::SyntaxNode
def to_array
return self.elements.map {|x| x.to_array}
end
end
class BeginLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
class NewLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
class BlockLine < Treetop::Runtime::SyntaxNode
def to_array
return self.information.text_value
end
end
class EndLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
end
例如,如果我尝试解析:"begin document\n\nend document"。然后我希望这是一个输出:["begin document"、“\n\n”、"end document"],但我收到错误消息:block in to_array': undefined method
to_array'对于 SyntaxNode offset=16, "":Treetop::Runtime::SyntaxNode (NoMethodError).
所以我做了一些进一步的调查,发现语法节点树确实在 offset=16 处包含一个 SyntaxNode "",我认为这是由于 (block twoOrMoreNewLines)* 不存在。
我该如何处理这个问题?有没有办法避免创建 SyntaxNode ""?
偏移量 16 处的 SyntaxNode 包含一个空子数组,用于迭代 sub-rule。 Packrat 解析算法需要它才能工作。您不应该只在任意 SyntaxNode 上调用 to_array,而应该对其进行特殊处理。最好的方法是给它打上标签,然后在迭代它的元素之前询问标签是否为空:
rule textStructure
beginDoc twoOrMoreNewLines nested:(block twoOrMoreNewLines)* endDoc <Structure>
end
...
class Structure < Treetop::Runtime::SyntaxNode
def to_array
return nested.empty? ? [] : nested.elements.map {|x| x.to_array}
end
end
或类似的东西。
我正在尝试创建一个映射其所有非终端节点的自定义语法节点 class。问题是其中一个节点不一定必须存在,这在自定义语法节点 class 中使用 elements.map 时会产生问题,因为语法节点树会创建 SyntaxNode: "" for相反,我还没有为它创建 class。
grammar Foo
rule textStructure
beginDoc twoOrMoreNewLines (block twoOrMoreNewLines)* endDoc <Structure>
end
rule beginDoc
'begin document' <BeginLine>
end
rule twoOrMoreNewLines
"\n" 2.. <NewLine>
end
rule block
!beginDoc information:((!"\n" .)+) <BlockLine>
end
rule endDoc
'end document' <EndLine>
end
end
# On a different file
module Foo
class Structure < Treetop::Runtime::SyntaxNode
def to_array
return self.elements.map {|x| x.to_array}
end
end
class BeginLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
class NewLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
class BlockLine < Treetop::Runtime::SyntaxNode
def to_array
return self.information.text_value
end
end
class EndLine < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value
end
end
end
例如,如果我尝试解析:"begin document\n\nend document"。然后我希望这是一个输出:["begin document"、“\n\n”、"end document"],但我收到错误消息:block in to_array': undefined method
to_array'对于 SyntaxNode offset=16, "":Treetop::Runtime::SyntaxNode (NoMethodError).
所以我做了一些进一步的调查,发现语法节点树确实在 offset=16 处包含一个 SyntaxNode "",我认为这是由于 (block twoOrMoreNewLines)* 不存在。
我该如何处理这个问题?有没有办法避免创建 SyntaxNode ""?
偏移量 16 处的 SyntaxNode 包含一个空子数组,用于迭代 sub-rule。 Packrat 解析算法需要它才能工作。您不应该只在任意 SyntaxNode 上调用 to_array,而应该对其进行特殊处理。最好的方法是给它打上标签,然后在迭代它的元素之前询问标签是否为空:
rule textStructure
beginDoc twoOrMoreNewLines nested:(block twoOrMoreNewLines)* endDoc <Structure>
end
...
class Structure < Treetop::Runtime::SyntaxNode
def to_array
return nested.empty? ? [] : nested.elements.map {|x| x.to_array}
end
end
或类似的东西。