0

我正在尝试创建一个映射其所有非终端节点的自定义语法节点类。问题是其中一个节点不一定必须存在,这在自定义语法节点类中使用 elements.map 时会产生问题,因为语法节点树会为其创建 SyntaxNode: "" 代替,我有没有创建一个类。

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

例如,如果我尝试解析:“开始文档\n\nend 文档”。然后我希望这是一个输出:[“begin document”,“\n\n”,“end document”],但我收到错误消息:block in to_array': undefined methodto_array' for SyntaxNode offset=16, "":Treetop::运行时::SyntaxNode (NoMethodError)。

所以我做了一些进一步的调查,发现语法节点树确实在 offset=16 处包含一个 SyntaxNode "",我认为这是由于 (block twoOrMoreNewLines)* 不存在。

我该如何处理这个问题?有没有办法避免 SyntaxNode "" 被创建?

4

1 回答 1

0

偏移量 16 处的 SyntaxNode 包含一个空的子数组,用于迭代的子规则。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

或类似的东西。

于 2019-07-23T22:40:16.937 回答