depager 0.2.3 → 0.3.0.b20160729

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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