如何在 Ruby 树顶树的子节点中触发函数。 (是:如何防止 ruby Treetop 进行 AST 压缩)
How to trigger functions in subnodes in Ruby Treetop tree. (was:How to prevent ruby Treetop doing AST squashing)
我使用 treetop 有一段时间了。我按照
编写了规则
http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html
我可以解析我的整个输入字符串,但是我 none 的另一个 to_array
函数被触发,而不是初始的。
然后我发现 https://whitequark.org/blog/2011/09/08/treetop-typical-errors/ 谈论 AST squashing
我发现我的规则也是如此。
我的第一条规则是
rule bodies
blankLine* interesting:(body+) blankLine* <Bodies>
end
一切都被body
吞噬了。
有人可以建议我如何解决这个问题吗?
编辑
添加代码片段:
grammar Sexp
rule bodies
blankLine* interesting:(body+) blankLine* <Bodies>
end
rule body
commentPortString (ifdef_blocks / interface)+ (blankLine / end_of_file) <Body>
end
rule interface
space? (intf / intfWithSize) space? newLine <Interface>
end
rule commentPortString
space? '//' space portString space? <CommentPortString>
end
rule portString
'Port' space? '.' newLine <PortString>
end
rule expression
space? '(' body ')' space? <Expression>
end
rule intf
(input / output) space wire:wireName space? ';' <Intf>
end
rule intfWithSize
(input / output) space? width:ifWidth space? wire:wireName space? ';' <IntfWithSize>
end
rule input
'input' <InputDir>
end
rule output
'output' <OutputDir>
end
rule ifdef_blocks
ifdef_line (interface / ifdef_block)* endif_line <IfdefBlocks>
end
rule ifdef_block
ifdef_line interface* endif_line <IfdefBlocks>
end
rule ifdef_line
space? (ifdef / ifndef) space+ allCaps space? newLine <IfdefLine>
end
rule endif_line
space? (endif) space? newLine <EndifLine>
end
rule ifdef
'`ifdef' <Ifdef>
end
rule ifndef
'`ifndef' <Ifndef>
end
rule endif
'`endif' <Endif>
end
rule ifWidth
'[' space? msb:digits space? ':' space? lsb:digits ']' <IfWidth>
end
rule digits
[0-9]+ <Digits>
end
rule integer
('+' / '-')? [0-9]+ <IntegerLiteral>
end
rule float
('+' / '-')? [0-9]+ (('.' [0-9]+) / ('e' [0-9]+)) <FloatLiteral>
end
rule string
'"' ('\"' / !'"' .)* '"' <StringLiteral>
end
rule identifier
[a-zA-Z\=\*] [a-zA-Z0-9_\=\*]* <Identifier>
end
rule allCaps
[A-Z] [A-Z0-9_]*
end
rule wireName
[a-zA-Z] [a-zA-Z0-9_]* <WireName>
end
rule non_space
!space .
end
rule space
[^\S\n]+
end
rule non_space
!space .
end
rule blankLine
space* newLine
end
rule not_newLine
!newLine .
end
rule newLine
[\n\r]
end
rule end_of_file
!.
end
end
测试字符串
// Port.
input CLK;
// Port.
input REFCLK;
// Port.
input [ 41:0] mem_power_ctrl;
output data;
编辑:添加更多详细信息
测试代码签入:
https://github.com/justrajdeep/treetop_ruby_issue.
正如您在我的 node_extensions.rb
中看到的那样,除 Bodies
之外的所有节点都在方法 to_array
中引发异常。但是 none 的异常触发。
尝试将 (body+)
打破成这样的新规则:
rule bodies
blankLine* interesting:interesting blankLine* <Bodies>
end
rule interesting
body+ <Interesting>
end
否则,查看 SyntaxNode 会有所帮助 类。
您在 tree
上调用 to_array
,这是一个 Bodies
。这是您唯一调用 to_array
的方法,因此不会调用其他 to_array
方法。
如果要在 Bodies
节点的子节点上调用 to_array
,则 Bodies#to_array
需要在这些子节点上调用 to_array
。因此,如果您想在标记为 interesting
的 Body
节点上调用它,您应该遍历 interesting
并在每个元素上调用 .to_array
。
我使用 treetop 有一段时间了。我按照
编写了规则http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html
我可以解析我的整个输入字符串,但是我 none 的另一个 to_array
函数被触发,而不是初始的。
然后我发现 https://whitequark.org/blog/2011/09/08/treetop-typical-errors/ 谈论 AST squashing
我发现我的规则也是如此。
我的第一条规则是
rule bodies
blankLine* interesting:(body+) blankLine* <Bodies>
end
一切都被body
吞噬了。
有人可以建议我如何解决这个问题吗?
编辑 添加代码片段:
grammar Sexp
rule bodies
blankLine* interesting:(body+) blankLine* <Bodies>
end
rule body
commentPortString (ifdef_blocks / interface)+ (blankLine / end_of_file) <Body>
end
rule interface
space? (intf / intfWithSize) space? newLine <Interface>
end
rule commentPortString
space? '//' space portString space? <CommentPortString>
end
rule portString
'Port' space? '.' newLine <PortString>
end
rule expression
space? '(' body ')' space? <Expression>
end
rule intf
(input / output) space wire:wireName space? ';' <Intf>
end
rule intfWithSize
(input / output) space? width:ifWidth space? wire:wireName space? ';' <IntfWithSize>
end
rule input
'input' <InputDir>
end
rule output
'output' <OutputDir>
end
rule ifdef_blocks
ifdef_line (interface / ifdef_block)* endif_line <IfdefBlocks>
end
rule ifdef_block
ifdef_line interface* endif_line <IfdefBlocks>
end
rule ifdef_line
space? (ifdef / ifndef) space+ allCaps space? newLine <IfdefLine>
end
rule endif_line
space? (endif) space? newLine <EndifLine>
end
rule ifdef
'`ifdef' <Ifdef>
end
rule ifndef
'`ifndef' <Ifndef>
end
rule endif
'`endif' <Endif>
end
rule ifWidth
'[' space? msb:digits space? ':' space? lsb:digits ']' <IfWidth>
end
rule digits
[0-9]+ <Digits>
end
rule integer
('+' / '-')? [0-9]+ <IntegerLiteral>
end
rule float
('+' / '-')? [0-9]+ (('.' [0-9]+) / ('e' [0-9]+)) <FloatLiteral>
end
rule string
'"' ('\"' / !'"' .)* '"' <StringLiteral>
end
rule identifier
[a-zA-Z\=\*] [a-zA-Z0-9_\=\*]* <Identifier>
end
rule allCaps
[A-Z] [A-Z0-9_]*
end
rule wireName
[a-zA-Z] [a-zA-Z0-9_]* <WireName>
end
rule non_space
!space .
end
rule space
[^\S\n]+
end
rule non_space
!space .
end
rule blankLine
space* newLine
end
rule not_newLine
!newLine .
end
rule newLine
[\n\r]
end
rule end_of_file
!.
end
end
测试字符串
// Port.
input CLK;
// Port.
input REFCLK;
// Port.
input [ 41:0] mem_power_ctrl;
output data;
编辑:添加更多详细信息
测试代码签入: https://github.com/justrajdeep/treetop_ruby_issue.
正如您在我的 node_extensions.rb
中看到的那样,除 Bodies
之外的所有节点都在方法 to_array
中引发异常。但是 none 的异常触发。
尝试将 (body+)
打破成这样的新规则:
rule bodies
blankLine* interesting:interesting blankLine* <Bodies>
end
rule interesting
body+ <Interesting>
end
否则,查看 SyntaxNode 会有所帮助 类。
您在 tree
上调用 to_array
,这是一个 Bodies
。这是您唯一调用 to_array
的方法,因此不会调用其他 to_array
方法。
如果要在 Bodies
节点的子节点上调用 to_array
,则 Bodies#to_array
需要在这些子节点上调用 to_array
。因此,如果您想在标记为 interesting
的 Body
节点上调用它,您应该遍历 interesting
并在每个元素上调用 .to_array
。