depager 0.2.3 → 0.3.0.b20160729

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/README.en +4 -19
  3. data/README.ja +42 -79
  4. data/bin/depager +42 -45
  5. data/examples/action_pl0d/pl0d.action.dr +421 -0
  6. data/examples/action_pl0d/test.pl0ds +49 -0
  7. data/examples/c89/c89.dr +493 -496
  8. data/examples/c89/test.c89 +10 -10
  9. data/examples/extension/astdf.rb +10 -0
  10. data/examples/extension/atree.dr +55 -0
  11. data/examples/{sample_calc → extension}/calc.atree.dr +42 -43
  12. data/examples/extension/calc.simple_action.dr +33 -0
  13. data/examples/extension/paction.dr +16 -15
  14. data/examples/extension/pactiontest.dr +14 -14
  15. data/examples/extension/simple_action.rb +44 -0
  16. data/examples/pl0d/pl0ds.dr +337 -334
  17. data/examples/pl0d/test.pl0ds +33 -33
  18. data/examples/rie_calc/calc.rie.dr +57 -0
  19. data/examples/rie_calc/test.calc +4 -0
  20. data/examples/rie_dcuse/dcuse.rie.dr +71 -0
  21. data/examples/rie_dcuse/test.dcuse +1 -0
  22. data/examples/rie_pl0/orig_ex/exerrdg.pl0 +44 -0
  23. data/examples/rie_pl0/orig_ex/exerrm.pl0 +19 -0
  24. data/examples/rie_pl0/orig_ex/exerrmre.pl0 +20 -0
  25. data/examples/rie_pl0/orig_ex/exerrtok.pl0 +18 -0
  26. data/examples/rie_pl0/orig_ex/exmdg.pl0 +40 -0
  27. data/examples/rie_pl0/orig_ex/exmdgwwl.pl0 +43 -0
  28. data/examples/rie_pl0/orig_ex/exmrw.pl0 +22 -0
  29. data/examples/rie_pl0/orig_ex/exmwwl.pl0 +18 -0
  30. data/examples/rie_pl0/orig_ex/exnorw.pl0 +17 -0
  31. data/examples/rie_pl0/pl0.rie.dr +450 -0
  32. data/examples/rie_pl0/test.pl0 +10 -0
  33. data/examples/sample_calc/calc.action.dr +33 -33
  34. data/examples/sample_calc/calc.ast.action.dr +65 -66
  35. data/examples/sample_calc/calc.ast.dr +55 -55
  36. data/examples/sample_calc/calc.cst.dr +45 -45
  37. data/examples/sample_calc/calc.dr +43 -43
  38. data/examples/sample_calc/calc.lex.dr +29 -29
  39. data/examples/sample_calc/{calc_prec.nvaction.dr → calc_prec.action.dr} +31 -31
  40. data/examples/slex_test/divreg.slex.dr +29 -29
  41. data/examples/slex_test/ljoin.slex.dr +36 -36
  42. data/examples/slex_test/test.divreg +1 -1
  43. data/examples/slex_test/test.ljoin +3 -3
  44. data/lib/depager.rb +582 -670
  45. data/lib/depager/grammar.rb +256 -291
  46. data/lib/depager/lr.rb +574 -579
  47. data/lib/depager/parser.rb +282 -277
  48. data/lib/depager/ruby/plugins/_rie_debug.rb +35 -0
  49. data/lib/depager/ruby/plugins/action.rb +53 -43
  50. data/lib/depager/ruby/plugins/ast.dr +364 -269
  51. data/lib/depager/ruby/plugins/ast.rb +1367 -1308
  52. data/lib/depager/ruby/plugins/cst.dr +172 -180
  53. data/lib/depager/ruby/plugins/cst.rb +587 -626
  54. data/lib/depager/ruby/plugins/lex.dr +85 -89
  55. data/lib/depager/ruby/plugins/lex.rb +310 -336
  56. data/lib/depager/ruby/plugins/rie.dr +723 -0
  57. data/lib/depager/ruby/plugins/rie.rb +1653 -0
  58. data/lib/depager/ruby/plugins/slex.dr +202 -200
  59. data/lib/depager/ruby/plugins/slex.rb +780 -817
  60. data/lib/depager/ruby/plugins/srp.rb +56 -51
  61. data/lib/depager/ruby/templates/extension_lalr_master.erb +46 -51
  62. data/lib/depager/ruby/templates/extension_lalr_slave.erb +99 -107
  63. data/lib/depager/ruby/templates/single_lalr_parser.erb +115 -117
  64. data/lib/depager/utils.rb +148 -318
  65. data/lib/depager/version.rb +4 -3
  66. metadata +52 -60
  67. data/ChangeLog +0 -16
  68. data/data/depager/pre-setup.rb +0 -3
  69. data/examples/c89/c89.tab.rb +0 -7127
  70. data/examples/pl0d/pl0ds.tab.rb +0 -2698
  71. data/examples/sample_calc/calc.action.tab.rb +0 -457
  72. data/examples/sample_calc/calc.ast.action.tab.rb +0 -749
  73. data/examples/sample_calc/calc.ast.tab.rb +0 -665
  74. data/examples/sample_calc/calc.astdf.dr +0 -54
  75. data/examples/sample_calc/calc.astdf.tab.rb +0 -672
  76. data/examples/sample_calc/calc.atree.tab.rb +0 -451
  77. data/examples/sample_calc/calc.cst.tab.rb +0 -644
  78. data/examples/sample_calc/calc.lex.tab.rb +0 -374
  79. data/examples/sample_calc/calc.nvaction.dr +0 -33
  80. data/examples/sample_calc/calc.nvaction.tab.rb +0 -465
  81. data/examples/sample_calc/calc.tab.rb +0 -365
  82. data/examples/sample_calc/calc_prec.nvaction.tab.rb +0 -431
  83. data/examples/slex_test/divreg.slex.tab.rb +0 -303
  84. data/examples/slex_test/ljoin.slex.tab.rb +0 -370
  85. data/lib/depager/ruby/plugins/_ast_tmpl.rb +0 -73
  86. data/lib/depager/ruby/plugins/astdf.rb +0 -6
  87. data/lib/depager/ruby/plugins/atree.dr +0 -55
  88. data/lib/depager/ruby/plugins/atree.rb +0 -347
  89. data/lib/depager/ruby/plugins/nvaction.rb +0 -19
  90. data/lib/depager/ruby/templates/simple.erb +0 -23
  91. data/setup.rb +0 -1585
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'pp'
3
+ class Depager::RieExtension
4
+ module Nodes
5
+ def self.defnode name, *args
6
+ code = ''; args.each_with_index{|a, x|
7
+ code << "def #{a};@_values[#{x}];end; def #{a}=(v);@_values[#{x}]=v;end;"
8
+ }; module_eval %{
9
+ class #{name}; attr_accessor :lineno, :_values; #{code}
10
+ def self.[] *args ; self.new *args ; end
11
+ def initialize n, *as; @lineno, @_values = n, as; end
12
+ def inspect ; "<#{name}:\#{@_values.inspect}>"; end
13
+ def pretty_print q ; q.group(1, "<#{name}:", ">"){ q.pp @_values }; end
14
+ end
15
+ } # end of eval
16
+ end
17
+ defnode :N_THREAD, :targets, :excepts
18
+ defnode :N_TRANSFER, :targets, :excepts
19
+ defnode :N_EXCEPT, :let_or_ids
20
+ defnode :N_LET, :atoc, :expr, :state
21
+ defnode :N_ACTION, :expr
22
+ defnode :N_ATOC, :sym_name, :attr_name, :rx
23
+
24
+ class N_ATOC
25
+ def inspect
26
+ name = sym_name == '$' ? '$'+$grammar.symname($grammar[rx].lhs) : sym_name
27
+ "<N_ATOC:#{[name, attr_name, rx].inspect}>"
28
+ end
29
+ def pretty_print q
30
+ name = sym_name == '$' ? '$'+$grammar.symname($grammar[rx].lhs) : sym_name rescue nil
31
+ q.group(1, "<N_ATOC:", ">"){ q.pp [name, attr_name, rx] }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,43 +1,53 @@
1
- require 'depager/parser.rb'
2
-
3
- class ActionExtension #:nodoc:all
4
- include Depager::ExtensionUtils
5
- def initialize
6
- @line0 = @line = @oldline = ''
7
- @optouter = []
8
- @on_reduce = []
9
- end
10
-
11
- def modify_action_code code
12
- return code, 0
13
- end
14
-
15
- def pre_rule_list
16
- if g_parser.line0 =~ /^%ACTION\{\s*$/
17
- while line = getline
18
- break if line =~ /^%\}\s*$/
19
- @optouter.push line
20
- end
21
- g_parser.update_context ''
22
- end
23
- end
24
-
25
- def post_rhs
26
- if g_parser.line =~ /\s*\{/
27
- @line0, @line = g_parser.line0, g_parser.line
28
- lineno = g_parser.lineno
29
- code, d = modify_action_code(parse_action)
30
- @optouter <<
31
- gen_defm_code("_act_#{nrules} val", code, lineno, d)
32
- g_parser.update_context @line
33
- @on_reduce[nrules] = ":_act_#{nrules}"
34
- end
35
- end
36
-
37
- def post_rule_list
38
- g_parser.optouter <<
39
- gen_action_decorator_code(
40
- target_name, paramkey,
41
- @on_reduce, @optouter, g_parser.mixin)
42
- end
43
- end
1
+ # -*- coding: utf-8 -*-
2
+ require 'plugins/action.rb'
3
+
4
+ class Depager::ActionExtension < Depager::Extension
5
+ def init_extension
6
+ @action_code = ''
7
+ @on_reduce = []
8
+ end
9
+
10
+ def term_extension
11
+ g_parser.outer_code <<
12
+ generate_action_decorator_code(@on_reduce, @action_code)
13
+ end
14
+
15
+ def pre_rule_list
16
+ if g_parser.original_line =~ /^%ACTION\{\s*$/
17
+ while line = file.gets
18
+ break if line =~ /^%\}\s*$/
19
+ @action_code << line
20
+ end
21
+ g_parser.update_context ''
22
+ end
23
+ end
24
+
25
+ def post_rhs
26
+ if g_parser.line =~ /\s*\{/
27
+ @original_line, @line = g_parser.original_line, g_parser.line
28
+ lineno = g_parser.file.lineno
29
+ code, d = modify_action_code(parse_block)
30
+ n = g_parser.rules.size - 1
31
+ @action_code <<
32
+ expand_inline_code(code, lineno, :wrap => "def _act_#{n} val", :delta => d)
33
+ g_parser.update_context @line
34
+ @on_reduce[n] = ":_act_#{n}"
35
+ end
36
+ end
37
+
38
+ def modify_action_code code
39
+ let_code = ""
40
+ if g_parser.rhs_names.size > 0
41
+ let_code = g_parser.rhs_names.map do |name|
42
+ if name =~ /[a-zA-Z][a-zA-Z0-9_]*/
43
+ "_#{name}"
44
+ else
45
+ '_'
46
+ end
47
+ end
48
+ let_code = " #{let_code.join(', ')}, = *val \n"
49
+ end
50
+ return let_code << code, 1
51
+ end
52
+ end
53
+
@@ -1,269 +1,364 @@
1
- %defext ASTBuilderExtension
2
- %extend Lexer ('plugins/lex.rb')
3
- %extend NVAction ('plugins/nvaction.rb')
4
- %decorate @NVAction
5
- #%decorate ShiftReducePrinter ('plugins/srp.rb')
6
- %inner{
7
- require 'plugins/_ast_tmpl'
8
- attr_accessor :optouter, :on_reduce, :visitor
9
- def init_parser
10
- super
11
- @visitor = Hash.new{|hash, key| hash[key] = []}
12
- @optouter = []
13
- @on_reduce = []
14
- @output_file_name = nil
15
- end
16
- def post_rule_list
17
- g_parser.optouter <<
18
- gen_action_decorator_code(target_name, paramkey,
19
- @on_reduce, @optouter)
20
- end
21
-
22
- def modify_action_code code, nodes=[]
23
- code = code.gsub(/\$\.([a-z_])/, 'node.\1')
24
- code << %{
25
- rescue
26
- warn "raise at src:\#{node.lineno}/\#{node.class.name}"
27
- raise
28
- }
29
- end
30
- def gen_accept_code sym
31
- return ''
32
- end
33
-
34
- attr_reader :output_file_name
35
- def output_file_name= ofname
36
- ofname = ofname.match(/'(.+)'/) ? $1 : ofname
37
- @output_file_name = ofname
38
- end
39
- %}
40
- %hook pre_rule_list /%AST\{\s*\Z/ skip
41
- %banner '%AST{ ... }'
42
- %%
43
-
44
- %LEX{
45
- /\s+/, /#.*/ { }
46
- /%\}\s*\Z/ { @line = $'; yield nil,nil }
47
- 'Node' { yield token(:NODE, $&) }
48
- 'Visitor' { yield token(:VISITOR, $&) }
49
- /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(:ID, $&) }
50
- '{' ! { ln = lineno; yield token(:ACTION, parse_action, ln) }
51
- /./ { yield token($&, $&) }
52
- %}
53
-
54
- #begin-rule
55
- start:
56
- opt_defnode opt_defvis defnode_list
57
- {
58
- code = _opt_defnode
59
- code << val[2] << %{
60
- class Visitor
61
- def visit node
62
- node.accept(self)
63
- end
64
- #{master.visitor[nil].join}
65
- end
66
- };#code
67
- master.visitor.each do |k, v|
68
- next unless k
69
- code << %{
70
- class Visitor_#{k}
71
- #{v.join}
72
- end
73
- };#code
74
- end
75
- if master.output_file_name
76
- File.open(master.output_file_name, 'w') do |f|
77
- f.write code
78
- end
79
- g_parser.optouter << %!require '#{master.output_file_name}'\n!
80
- else
81
- g_parser.optouter << code
82
- end
83
- }
84
- ;
85
- opt_defnode:
86
- { "" }
87
- | NODE opt_attr ACTION
88
- {
89
- ini = %{
90
- def initialize
91
- #{_ACTION.value}
92
- end
93
- };#code
94
- ERB.new(master.class::TMPL_NODE_BASE).result(binding)
95
- }
96
- ;
97
- opt_defvis:
98
- { [] }
99
- | VISITOR opt_action
100
- {
101
- _opt_action[nil] ||= Token['', 0]
102
- _opt_action.each do |pass, act|
103
- master.visitor[pass].unshift(
104
- master.gen_meval_code(act.lineno, 0, act.value.to_s))
105
- end
106
- }
107
- ;
108
- defnode_list:
109
- defnode { _defnode }
110
- | defnode_list defnode { _defnode_list << _defnode}
111
- ;
112
- defnode:
113
- defnode_header opt_attr opt_action
114
- {
115
- name, args = _defnode_header
116
- nodes, accept, attrs = [], '', _opt_attr
117
- args.each do |i|
118
- if i =~ /\-(.*)/
119
- nodes.push $1
120
- attrs.push $1
121
- else
122
- nodes.push i
123
- accept << master.gen_accept_code(i)
124
- end
125
- end
126
- _opt_action[nil] = Token['', 0] unless _opt_action[nil]
127
- _opt_action.each do |pass, act|
128
- vis_code = master.modify_action_code(act.value, nodes - attrs)
129
- master.visitor[pass] <<
130
- master.gen_defm_code("visit_Node_#{name} node",
131
- vis_code, act.lineno)
132
- end
133
- ERB.new(master.class::TMPL_NODE).result(binding)
134
- }
135
- ;
136
- defnode_header:
137
- ID '(' ')' { [_ID.value, []]}
138
- | ID '(' fact_list ')' { [_ID.value, _fact_list] }
139
- ;
140
- opt_attr:
141
- { [] }
142
- | '[' ']' { [] }
143
- | '[' id_list ']' { _id_list }
144
- ;
145
- fact_list:
146
- fact { [_fact] }
147
- | fact_list ',' fact { _fact_list.push _fact }
148
- ;
149
- fact:
150
- ID { _ID.value }
151
- | '-' ID { '-' + _ID.value }
152
- ;
153
- id_list:
154
- ID { [ _ID.value ] }
155
- | id_list ',' ID { _id_list.push _ID.value }
156
- ;
157
- opt_action:
158
- { {nil => Token['', 0]} }
159
- | ACTION { {nil => _ACTION} }
160
- | pass_action_list
161
- {
162
- Hash[ *_pass_action_list.flatten ].merge({nil => Token['', 0]})
163
- }
164
- ;
165
- pass_action_list:
166
- pass_action { [ _pass_action ] }
167
- | pass_action_list pass_action { _pass_action_list << _pass_action }
168
- ;
169
-
170
- pass_action:
171
- '<' ID '>' ACTION { [_ID.value, _ACTION]}
172
- ;
173
- #end-rule
174
- %%
175
- %hook post_rhs /=>/ skip
176
- %banner '=>...'
177
- %prec{
178
- left LL '@'
179
- %}
180
- %inner{
181
- def do_default
182
- n = master.nrules
183
- master.optouter <<
184
- master.gen_defm_code("_ast_#{n} val", "NilNode.new(basis.file.lineno)", lineno)
185
- master.on_reduce[n] = ":_ast_#{n}"
186
- end
187
- %}
188
- %%
189
-
190
- %LEX{
191
- /[ \t]+/ { }
192
- /\r?\n/ { yield nil, nil }
193
- /<</ { yield token(:LL, $&) }
194
- /%([a-zA-Z0-9_]+)((::[a-zA-Z0-9_]+)*)/
195
- { yield token(:CONST, $1+$2) }
196
- /%\((.+)\)%/ { yield token(:EMBED, $1) }
197
- 'nil' { yield token(:NIL, $&) }
198
- 'NilNode' { yield token(:NILNODE, $&) }
199
- /[0-9]+/ { yield token(:NUMBER, $&.to_i) }
200
- /:[a-zA-Z0-9_]+/ { yield token(:SYMBOL, $&) }
201
- /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(:ID, $&) }
202
- /'(.+)'/ { yield token(:STR, $1) }
203
- /./ { yield token($&, $&) }
204
- %}
205
- #begin-rule
206
- start:
207
- fnl
208
- {
209
- n = master.nrules
210
- master.optouter <<
211
- master.gen_defm_code("_ast_#{n} val", _fnl, basis.file.lineno)
212
- master.on_reduce[n] = ":_ast_#{n}"
213
- }
214
- ;
215
- node:
216
- ID '(' ')' { "Node_#{_ID.value}.new(basis.file.lineno)" }
217
- | ID '(' fnlpair ')'
218
- {
219
- if g_parser.rhs.size > 0
220
- "Node_#{_ID.value}.new(val[0].lineno, #{_fnlpair.join(', ')})"
221
- else
222
- "Node_#{_ID.value}.new(basis.file.lineno, #{_fnlpair.join(', ')})"
223
- end
224
- }
225
- ;
226
- fnlpair:
227
- fnl { [_fnl] }
228
- | fnlpair ',' fnl { _fnlpair << _fnl }
229
- ;
230
- fnl:
231
- fact { _fact }
232
- | node { _node }
233
- | list { _list }
234
- ;
235
- fact:
236
- ID opt_embed
237
- {
238
- unless i = g_parser.name_to_rhs_index(_ID.value)
239
- warn "#{g_parser.lineno}: ?#{_ID.value}"
240
- raise
241
- end
242
- "val[#{i}]#{val[1]}"
243
- }
244
- | CONST { "Depager::Token[#{_CONST.value}]" }
245
- | SYMBOL { "Depager::Token[#{_SYMBOL.value}]" }
246
- | STR { "Depager::Token['#{_STR.value}']" }
247
- | NILNODE { "NilNode.new(basis.file.lineno)" }
248
- | NUMBER { "Depager::Token[#{_NUMBER.value}]" }
249
- | NIL { "nil" }
250
- ;
251
- opt_embed:
252
- { '' }
253
- | EMBED { _EMBED.value }
254
- ;
255
- list:
256
- '['']' { "NodeList.new(basis.file.lineno, [])" }
257
- | '['fnlpair']'
258
- {
259
- if g_parser.rhs.size > 0
260
- "NodeList.new(val[0].lineno, [#{_fnlpair.join(', ')}])"
261
- else
262
- "NodeList.new(basis.file.lineno, #{_fnlpair.join(', ')})"
263
- end
264
- }
265
- | fnl-l LL fnl-r { "#{_l}.push(#{_r})" }
266
- | fnl-l '@' fnl-r { "#{_l}.concat(#{_r})" }
267
- ;
268
- #end-rule
269
- %%
1
+ %defext Depager::ASTBuilderExtension
2
+ %extend Depager::Lexer ('plugins/lex.rb')
3
+ %extend Depager::Action ('plugins/action.rb')
4
+ %decorate @Action
5
+ #%decorate Depager::LALR::ShiftReducePrinter ('plugins/srp.rb')
6
+ %expanded_code_delimiter DEPAGER_EXPANDED_CODE
7
+ %inner{
8
+ attr_accessor :action_code, :on_reduce, :visitors
9
+ def init_extension
10
+ @visitors = Hash.new{|hash, key| hash[key] = []}
11
+ @action_code = ''
12
+ @on_reduce = []
13
+ @output_file_name = nil
14
+ end
15
+ def term_extension
16
+ g_parser.outer_code <<
17
+ generate_action_decorator_code(@on_reduce, @action_code)
18
+ end
19
+
20
+ def modify_action_code code, nodes=[]
21
+ code = code.gsub(/\$\.([a-z_])/, 'node.\1')
22
+ code << %{
23
+ rescue
24
+ warn "raise at src:\#{node.lineno}/\#{node.class.name}"
25
+ raise
26
+ }
27
+ end
28
+
29
+ def gen_accept_code sym
30
+ return ''
31
+ end
32
+
33
+ def node_name name
34
+ name = name == '@List' ? "NodeList" : "Node_#{name}"
35
+ "#{target_namespace}::#{name}"
36
+ end
37
+
38
+ attr_reader :output_file_name
39
+ def output_file_name= name
40
+ name = name.match(/'(.+)'/) ? $1 : name
41
+ @output_file_name = name
42
+ end
43
+ %}
44
+ %hook pre_rule_list /%AST\{\s*\Z/ skip
45
+ %banner '%AST{ ... }'
46
+ %%
47
+
48
+ %LEX{
49
+ /\s+/, /#.*/ { }
50
+ /%\}\s*\Z/ { @line = $'; yield nil,nil }
51
+ 'Node' { yield token(:NODE, $&) }
52
+ 'Visitor' { yield token(:VISITOR, $&) }
53
+ /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(:ID, $&) }
54
+ '{' ! { lineno = file.lineno; yield token(:ACTION, parse_block, lineno) }
55
+ /./ { yield token($&, $&) }
56
+ %}
57
+
58
+ #begin-rule
59
+ start:
60
+ opt_defnode opt_defvis defnode_list
61
+ {
62
+ code = "module #{target_namespace}\n"
63
+ code << _opt_defnode
64
+ code << val[2]
65
+ master.visitors.each do |name, body|
66
+ code << ERB.new(master.class::VISITOR_TEMPLATE, nil, '-').result(binding)
67
+ end
68
+ code << "end\n"
69
+ if master.output_file_name
70
+ File.open(master.output_file_name, 'w') do |f|
71
+ f.write code
72
+ end
73
+ g_parser.outer_code << %!require '#{master.output_file_name}'\n!
74
+ else
75
+ g_parser.outer_code << code
76
+ end
77
+ }
78
+ ;
79
+ opt_defnode:
80
+ { "" }
81
+ | NODE opt_attr ACTION
82
+ {
83
+ ini = %{
84
+ def initialize
85
+ #{_ACTION.value}
86
+ end
87
+ };#code
88
+ ERB.new(master.class::BASE_NODE_TEMPLATE, nil, '-').result(binding)
89
+ }
90
+ ;
91
+ opt_defvis:
92
+ { [] }
93
+ | VISITOR opt_action
94
+ {
95
+ _opt_action[nil] ||= Token.new('', 0)
96
+ _opt_action.each do |pass, act|
97
+ master.visitors[pass].unshift(
98
+ master.expand_inline_code(act.value.to_s, act.lineno))
99
+ end
100
+ }
101
+ ;
102
+ defnode_list:
103
+ defnode { _defnode }
104
+ | defnode_list defnode { _defnode_list << _defnode}
105
+ ;
106
+ defnode:
107
+ defnode_header opt_attr opt_action
108
+ {
109
+ name, args = _defnode_header
110
+ nodes, accept, attrs = [], '', _opt_attr
111
+ args.each do |i|
112
+ if i =~ /\-(.*)/
113
+ nodes.push $1
114
+ attrs.push $1
115
+ else
116
+ nodes.push i
117
+ accept << master.gen_accept_code(i)
118
+ end
119
+ end
120
+ _opt_action[nil] = Token.new('', 0) unless _opt_action[nil]
121
+ _opt_action.each do |pass, act|
122
+ vis_code = master.modify_action_code(act.value, nodes - attrs)
123
+ master.visitors[pass] <<
124
+ master.expand_inline_code(vis_code, act.lineno, :wrap => "def visit_Node_#{name} node")
125
+ end
126
+ ERB.new(master.class::NODE_TEMPLATE, nil, '-').result(binding)
127
+ }
128
+ ;
129
+ defnode_header:
130
+ ID '(' ')' { [_ID.value, []]}
131
+ | ID '(' fact_list ')' { [_ID.value, _fact_list] }
132
+ ;
133
+ opt_attr:
134
+ { [] }
135
+ | '[' ']' { [] }
136
+ | '[' id_list ']' { _id_list }
137
+ ;
138
+ fact_list:
139
+ fact { [_fact] }
140
+ | fact_list ',' fact { _fact_list.push _fact }
141
+ ;
142
+ fact:
143
+ ID { _ID.value }
144
+ | '-' ID { '-' + _ID.value }
145
+ ;
146
+ id_list:
147
+ ID { [ _ID.value ] }
148
+ | id_list ',' ID { _id_list.push _ID.value }
149
+ ;
150
+ opt_action:
151
+ { {nil => Token.new('', 0)} }
152
+ | ACTION { {nil => _ACTION} }
153
+ | pass_action_list
154
+ {
155
+ Hash[ *_pass_action_list.flatten ].merge({nil => Token.new('', 0)})
156
+ }
157
+ ;
158
+ pass_action_list:
159
+ pass_action { [ _pass_action ] }
160
+ | pass_action_list pass_action { _pass_action_list << _pass_action }
161
+ ;
162
+
163
+ pass_action:
164
+ '<' ID '>' ACTION { [_ID.value, _ACTION]}
165
+ ;
166
+ #end-rule
167
+ %%
168
+ %hook post_rhs /=>/ skip
169
+ %banner '=>...'
170
+ %prec{
171
+ left LL '@'
172
+ %}
173
+ %inner{
174
+ def do_default
175
+ n = g_parser.rules.size-1
176
+ master.action_code << %{
177
+ def _ast_#{n} val
178
+ NilNode.new(basis.file.lineno)
179
+ end
180
+ }.unindent #code
181
+ master.on_reduce[n] = ":_ast_#{n}"
182
+ end
183
+ %}
184
+ %%
185
+
186
+ %LEX{
187
+ /[ \t]+/ { }
188
+ /\r?\n/ { yield nil, nil }
189
+ /<</ { yield token(:LL, $&) }
190
+ /%([a-zA-Z0-9_]+)((::[a-zA-Z0-9_]+)*)/
191
+ { yield token(:CONST, $1+$2) }
192
+ /%\((.+)\)%/ { yield token(:EMBED, $1) }
193
+ 'nil' { yield token(:NIL, $&) }
194
+ 'NilNode' { yield token(:NILNODE, $&) }
195
+ /[0-9]+/ { yield token(:NUMBER, $&.to_i) }
196
+ /:[a-zA-Z0-9_]+/ { yield token(:SYMBOL, $&) }
197
+ /[a-zA-Z][a-zA-Z0-9_]*/ { yield token(:ID, $&) }
198
+ /'(.+)'/ { yield token(:STR, $1) }
199
+ /./ { yield token($&, $&) }
200
+ %}
201
+ #begin-rule
202
+ start:
203
+ fnl
204
+ {
205
+ n = g_parser.rules.size-1
206
+ master.action_code <<
207
+ master.expand_inline_code(_fnl, basis.file.lineno, :wrap => "def _ast_#{n} val")
208
+ master.on_reduce[n] = ":_ast_#{n}"
209
+ }
210
+ ;
211
+ node:
212
+ ID '(' ')' { "#{master.node_name _ID.value}.new(basis.file.lineno)" }
213
+ | ID '(' fnlpair ')'
214
+ {
215
+ if g_parser.rhs.size > 0
216
+ "#{master.node_name _ID.value}.new(val[0].lineno, #{_fnlpair.join(', ')})"
217
+ else
218
+ "#{master.node_name _ID.value}.new(basis.file.lineno, #{_fnlpair.join(', ')})"
219
+ end
220
+ }
221
+ ;
222
+ fnlpair:
223
+ fnl { [_fnl] }
224
+ | fnlpair ',' fnl { _fnlpair << _fnl }
225
+ ;
226
+ fnl:
227
+ fact { _fact }
228
+ | node { _node }
229
+ | list { _list }
230
+ ;
231
+ fact:
232
+ ID opt_embed
233
+ {
234
+ unless i = g_parser.name_to_rhs_index(_ID.value)
235
+ warn "#{g_parser.lineno}: ?#{_ID.value}"
236
+ raise
237
+ end
238
+ "val[#{i}]#{val[1]}"
239
+ }
240
+ | CONST { "Depager::Token.new(#{_CONST.value})" }
241
+ | SYMBOL { "Depager::Token.new(#{_SYMBOL.value})" }
242
+ | STR { "Depager::Token.new('#{_STR.value}')" }
243
+ | NILNODE { "NilNode.new(basis.file.lineno)" }
244
+ | NUMBER { "Depager::Token.new(#{_NUMBER.value})" }
245
+ | NIL { "nil" }
246
+ ;
247
+ opt_embed:
248
+ { '' }
249
+ | EMBED { _EMBED.value }
250
+ ;
251
+ list:
252
+ '['']' { "#{master.node_name '@List'}.new(basis.file.lineno, [])" }
253
+ | '['fnlpair']'
254
+ {
255
+ if g_parser.rhs.size > 0
256
+ "#{master.node_name '@List'}.new(val[0].lineno, [#{_fnlpair.join(', ')}])"
257
+ else
258
+ "#{master.node_name '@List'}.new(basis.file.lineno, #{_fnlpair.join(', ')})"
259
+ end
260
+ }
261
+ | fnl-l LL fnl-r { "#{_l}.push(#{_r})" }
262
+ | fnl-l '@' fnl-r { "#{_l}.concat(#{_r})" }
263
+ ;
264
+ #end-rule
265
+ %%
266
+ %%
267
+
268
+ class Depager::ASTBuilderExtension
269
+ BASE_NODE_TEMPLATE = <<-'EOS'
270
+ class Node
271
+ attr_accessor :lineno
272
+ attr_accessor <%= _opt_attr.map{|i| ":#{i}" }.join(', ') %>
273
+ <%= ini %>
274
+
275
+ def self.[] lineno, *args
276
+ self.new lineno, *args
277
+ end
278
+
279
+ def accept v
280
+ end
281
+ end
282
+
283
+ class NodeList < Node
284
+ attr_accessor :lineno
285
+ def initialize(lineno, lst=[])
286
+ @lineno = lineno
287
+ @lst = lst.to_a.select{|i| ! i.is_a?(NilNode)}
288
+ end
289
+
290
+ <%- _opt_attr.each do |i| -%>
291
+ def all_<%= i %>
292
+ @lst.map{|i| i.<%= i %>}
293
+ end
294
+ <%- end -%>
295
+
296
+ def size
297
+ @lst.size
298
+ end
299
+ alias length size
300
+
301
+ def push(i)
302
+ @lst.push i unless i.is_a? NilNode
303
+ self
304
+ end
305
+
306
+ def concat(i)
307
+ @lst.concat i
308
+ self
309
+ end
310
+
311
+ def to_ary()
312
+ @lst
313
+ end
314
+
315
+ alias to_a to_ary
316
+ alias list to_ary
317
+
318
+ def accept(v)
319
+ @lst.each{|i| i.accept(v) }
320
+ end
321
+ end
322
+
323
+ class NilNode
324
+ attr_accessor :lineno
325
+ attr_accessor <%= _opt_attr.map{|i| ":#{i}" }.join(', ') %>
326
+
327
+ def initialize(lineno, *args)
328
+ @lineno = lineno
329
+ end
330
+
331
+ def accept v
332
+ end
333
+ end
334
+ EOS
335
+
336
+ NODE_TEMPLATE = <<-'EOS'
337
+ class Node_<%= name %> < Node
338
+ attr_accessor <%= nodes.map{|i| ":#{i}" }.join(', ') %>
339
+ attr_accessor <%= attrs.map{|i| ":#{i}" }.join(', ') %>
340
+
341
+ def initialize <%= nodes.unshift('lineno').join(', ') %>
342
+ super()
343
+ @lineno = lineno
344
+ <%= nodes.inject(''){|r,i| r << " @#{i} = #{i}\n"} %>
345
+ end
346
+
347
+ def accept v
348
+ warn @lineno.to_s+':'+self.class.to_s if $DEBUG
349
+ <%= accept %>
350
+ v.visit_Node_<%= name %>(self)
351
+ self
352
+ end
353
+ end
354
+ EOS
355
+
356
+ VISITOR_TEMPLATE = <<-'EOS'
357
+ class Visitor<%= name ? '_' + name : '' %>
358
+ def visit node
359
+ node.accept(self)
360
+ end
361
+ <%= body.join %>
362
+ end # Visitor<%= name ? '_' + name : '' %>
363
+ EOS
364
+ end