关于解析:如何在Ruby Treetop树的子节点中触发函数。 (是:如何防止rubyTreetop进行AST压榨)

How to trigger functions in subnodes in Ruby Treetop tree. (was:How to prevent ruby Treetop doing AST squashing)

我使用树梢已有一段时间了。我在

之后写了规则

http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html

我可以解析我的整个输入字符串,但是除了初始的一个之外,没有其他to_array函数被触发。

然后我发现https://whitequark.org/blog/2011/09/08/treetop-typical-errors/谈论了AST squashing,我发现我的规则也在做同样的事情。

我的第一个规则是

1
2
3
  rule bodies
    blankLine* interesting:(body+) blankLine* <Bodies>
  end

body吞噬了一切。

有人可以建议我如何解决此问题吗?

编辑
添加代码段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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\
]+
  end

  rule non_space
    !space .
  end

  rule blankLine
    space* newLine
  end

  rule not_newLine
    !newLine .
  end

  rule newLine
    [\
\
]
  end

  rule end_of_file
    !.
  end

end

测试字符串

1
2
3
4
5
6
7
8
9
// 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中引发异常。但是没有异常触发。


您在tree上调用to_array,这是Bodies。那是您曾经调用过to_array的唯一方法,因此不会调用其他任何to_array方法。

如果要在Bodies节点的子节点上调用to_arrayBodies#to_array需要在那些子节点上调用to_array。因此,如果要在标记为interestingBody节点上调用它,则应遍历interesting并在每个元素上调用.to_array


尝试将(body+)分解为新规则,如下所示:

1
2
3
4
5
6
7
rule bodies
   blankLine* interesting:interesting blankLine* <Bodies>
end

rule interesting
   body+ <Interesting>
end

否则,查看SyntaxNode类将很有帮助。