ed-precompiled_racc 1.8.1

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.
@@ -0,0 +1,473 @@
1
+ #--
2
+ #
3
+ #
4
+ #
5
+ # Copyright (c) 1999-2006 Minero Aoki
6
+ #
7
+ # This program is free software.
8
+ # You can distribute/modify this program under the same terms of ruby.
9
+ # see the file "COPYING".
10
+ #
11
+ #++
12
+
13
+ require_relative 'compat'
14
+ require_relative 'sourcetext'
15
+ require_relative 'parser-text'
16
+ require 'rbconfig'
17
+
18
+ module Racc
19
+
20
+ class ParserFileGenerator
21
+
22
+ class Params
23
+ def self.bool_attr(name)
24
+ module_eval(<<-End)
25
+ def #{name}?
26
+ @#{name}
27
+ end
28
+
29
+ def #{name}=(b)
30
+ @#{name} = b
31
+ end
32
+ End
33
+ end
34
+
35
+ attr_accessor :filename
36
+ attr_accessor :classname
37
+ attr_accessor :superclass
38
+ bool_attr :omit_action_call
39
+ bool_attr :result_var
40
+ attr_accessor :header
41
+ attr_accessor :inner
42
+ attr_accessor :footer
43
+
44
+ bool_attr :debug_parser
45
+ bool_attr :convert_line
46
+ bool_attr :convert_line_all
47
+ bool_attr :embed_runtime
48
+ bool_attr :frozen_strings
49
+ bool_attr :make_executable
50
+ attr_accessor :interpreter
51
+
52
+ def initialize
53
+ # Parameters derived from parser
54
+ self.filename = nil
55
+ self.classname = nil
56
+ self.superclass = 'Racc::Parser'
57
+ self.omit_action_call = true
58
+ self.result_var = true
59
+ self.header = []
60
+ self.inner = []
61
+ self.footer = []
62
+
63
+ # Parameters derived from command line options
64
+ self.debug_parser = false
65
+ self.convert_line = true
66
+ self.convert_line_all = false
67
+ self.embed_runtime = false
68
+ self.frozen_strings = false
69
+ self.make_executable = false
70
+ self.interpreter = nil
71
+ end
72
+ end
73
+
74
+ def initialize(states, params)
75
+ @states = states
76
+ @grammar = states.grammar
77
+ @params = params
78
+ end
79
+
80
+ def generate_parser
81
+ string_io = StringIO.new
82
+
83
+ init_line_conversion_system
84
+ @f = string_io
85
+ parser_file
86
+
87
+ string_io.rewind
88
+ string_io.read
89
+ end
90
+
91
+ def generate_parser_file(destpath)
92
+ init_line_conversion_system
93
+ File.open(destpath, 'w') {|f|
94
+ @f = f
95
+ parser_file
96
+ }
97
+ File.chmod 0755, destpath if @params.make_executable?
98
+ end
99
+
100
+ private
101
+
102
+ def parser_file
103
+ shebang @params.interpreter if @params.make_executable?
104
+ notice
105
+ line
106
+ if @params.embed_runtime?
107
+ embed_library runtime_source()
108
+ else
109
+ require 'racc/parser.rb'
110
+ end
111
+ header
112
+ parser_class(@params.classname, @params.superclass) {
113
+ inner
114
+ state_transition_table
115
+ }
116
+ footer
117
+ end
118
+
119
+ c = ::RbConfig::CONFIG
120
+ RUBY_PATH = "#{c['bindir']}/#{c['ruby_install_name']}#{c['EXEEXT']}"
121
+
122
+ def shebang(path)
123
+ line '#!' + (path == 'ruby' ? RUBY_PATH : path)
124
+ end
125
+
126
+ def notice
127
+ line %q[# frozen_string_literal: true] if @params.frozen_strings?
128
+ line %q[#]
129
+ line %q[# DO NOT MODIFY!!!!]
130
+ line %Q[# This file is automatically generated by Racc #{Racc::Version}]
131
+ line %Q[# from Racc grammar file "#{@params.filename}".]
132
+ line %q[#]
133
+ end
134
+
135
+ def runtime_source
136
+ SourceText.new(::Racc::PARSER_TEXT, 'racc/parser.rb', 1)
137
+ end
138
+
139
+ def embed_library(src)
140
+ line %[###### #{src.filename} begin]
141
+ line %[unless $".find {|p| p.end_with?('/#{src.filename}')}]
142
+ line %[$".push "\#{__dir__}/#{src.filename}"]
143
+ put src, @params.convert_line?
144
+ line %[end]
145
+ line %[###### #{src.filename} end]
146
+ end
147
+
148
+ def require(feature)
149
+ line "require '#{feature}'"
150
+ end
151
+
152
+ def parser_class(classname, superclass)
153
+ mods = classname.split('::')
154
+ classid = mods.pop
155
+ mods.each do |mod|
156
+ indent; line "module #{mod}"
157
+ cref_push mod
158
+ end
159
+ indent; line "class #{classid} < #{superclass}"
160
+ cref_push classid
161
+ yield
162
+ cref_pop
163
+ indent; line "end \# class #{classid}"
164
+ mods.reverse_each do |mod|
165
+ cref_pop
166
+ indent; line "end \# module #{mod}"
167
+ end
168
+ end
169
+
170
+ def header
171
+ @params.header.each do |src|
172
+ line
173
+ put src, @params.convert_line_all?
174
+ end
175
+ end
176
+
177
+ def inner
178
+ @params.inner.each do |src|
179
+ line
180
+ put src, @params.convert_line?
181
+ end
182
+ end
183
+
184
+ def footer
185
+ @params.footer.each do |src|
186
+ line
187
+ put src, @params.convert_line_all?
188
+ end
189
+ end
190
+
191
+ # Low Level Routines
192
+
193
+ def put(src, convert_line = false)
194
+ if convert_line
195
+ replace_location(src) {
196
+ @f.puts src.text
197
+ }
198
+ else
199
+ @f.puts src.text
200
+ end
201
+ end
202
+
203
+ def line(str = '')
204
+ @f.puts str
205
+ end
206
+
207
+ def init_line_conversion_system
208
+ @cref = []
209
+ @used_separator = {}
210
+ end
211
+
212
+ def cref_push(name)
213
+ @cref.push name
214
+ end
215
+
216
+ def cref_pop
217
+ @cref.pop
218
+ end
219
+
220
+ def indent
221
+ @f.print ' ' * @cref.size
222
+ end
223
+
224
+ def toplevel?
225
+ @cref.empty?
226
+ end
227
+
228
+ def replace_location(src)
229
+ sep = make_separator(src)
230
+ @f.print 'self.class.' if toplevel?
231
+ @f.puts "module_eval(<<'#{sep}', '#{src.filename}', #{src.lineno})"
232
+ yield
233
+ @f.puts sep
234
+ end
235
+
236
+ def make_separator(src)
237
+ sep = unique_separator(src.filename)
238
+ sep *= 2 while src.text.index(sep)
239
+ sep
240
+ end
241
+
242
+ def unique_separator(id)
243
+ sep = String.new "...end #{id}/module_eval..."
244
+ while @used_separator.key?(sep)
245
+ sep.concat sprintf('%02x', rand(255))
246
+ end
247
+ @used_separator[sep] = true
248
+ sep
249
+ end
250
+
251
+ #
252
+ # State Transition Table Serialization
253
+ #
254
+
255
+ public
256
+
257
+ def put_state_transition_table(f)
258
+ @f = f
259
+ state_transition_table
260
+ end
261
+
262
+ private
263
+
264
+ def state_transition_table
265
+ table = @states.state_transition_table
266
+ table.use_result_var = @params.result_var?
267
+ table.debug_parser = @params.debug_parser?
268
+
269
+ line "##### State transition tables begin ###"
270
+ line
271
+ integer_list 'racc_action_table', table.action_table
272
+ line
273
+ integer_list 'racc_action_check', table.action_check
274
+ line
275
+ integer_list 'racc_action_pointer', table.action_pointer
276
+ line
277
+ integer_list 'racc_action_default', table.action_default
278
+ line
279
+ integer_list 'racc_goto_table', table.goto_table
280
+ line
281
+ integer_list 'racc_goto_check', table.goto_check
282
+ line
283
+ integer_list 'racc_goto_pointer', table.goto_pointer
284
+ line
285
+ integer_list 'racc_goto_default', table.goto_default
286
+ line
287
+ i_i_sym_list 'racc_reduce_table', table.reduce_table
288
+ line
289
+ line "racc_reduce_n = #{table.reduce_n}"
290
+ line
291
+ line "racc_shift_n = #{table.shift_n}"
292
+ line
293
+ sym_int_hash 'racc_token_table', table.token_table
294
+ line
295
+ line "racc_nt_base = #{table.nt_base}"
296
+ line
297
+ line "racc_use_result_var = #{table.use_result_var}"
298
+ line
299
+ @f.print(unindent_auto(<<-End))
300
+ Racc_arg = [
301
+ racc_action_table,
302
+ racc_action_check,
303
+ racc_action_default,
304
+ racc_action_pointer,
305
+ racc_goto_table,
306
+ racc_goto_check,
307
+ racc_goto_default,
308
+ racc_goto_pointer,
309
+ racc_nt_base,
310
+ racc_reduce_table,
311
+ racc_token_table,
312
+ racc_shift_n,
313
+ racc_reduce_n,
314
+ racc_use_result_var ]
315
+ End
316
+ line "Ractor.make_shareable(Racc_arg) if defined?(Ractor)"
317
+ line
318
+ string_list 'Racc_token_to_s_table', table.token_to_s_table
319
+ line "Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)"
320
+ line
321
+ line "Racc_debug_parser = #{table.debug_parser}"
322
+ line
323
+ line '##### State transition tables end #####'
324
+ actions
325
+ end
326
+
327
+ def integer_list(name, table)
328
+ sep = ''
329
+ line "#{name} = ["
330
+ table.each_slice(10) do |ns|
331
+ @f.print sep; sep = ",\n"
332
+ @f.print ns.map {|n| sprintf('%6s', n ? n.to_s : 'nil') }.join(',')
333
+ end
334
+ line ' ]'
335
+ end
336
+
337
+ def i_i_sym_list(name, table)
338
+ sep = ''
339
+ line "#{name} = ["
340
+ table.each_slice(3) do |len, target, mid|
341
+ @f.print sep; sep = ",\n"
342
+ @f.printf ' %d, %d, %s', len, target, mid.inspect
343
+ end
344
+ line " ]"
345
+ end
346
+
347
+ def sym_int_hash(name, h)
348
+ sep = "\n"
349
+ @f.print "#{name} = {"
350
+ h.to_a.sort_by {|sym, i| i }.each do |sym, i|
351
+ @f.print sep; sep = ",\n"
352
+ @f.printf " %s => %d", sym.serialize, i
353
+ end
354
+ line " }"
355
+ end
356
+
357
+ def string_list(name, list)
358
+ sep = " "
359
+ line "#{name} = ["
360
+ list.each do |s|
361
+ @f.print sep; sep = ",\n "
362
+ @f.print s.dump
363
+ end
364
+ line ' ]'
365
+ end
366
+
367
+ def actions
368
+ @grammar.each do |rule|
369
+ unless rule.action.source?
370
+ raise "racc: fatal: cannot generate parser file when any action is a Proc"
371
+ end
372
+ end
373
+
374
+ if @params.result_var?
375
+ decl = ', result'
376
+ retval = "\n result"
377
+ default_body = ''
378
+ else
379
+ decl = ''
380
+ retval = ''
381
+ default_body = 'val[0]'
382
+ end
383
+ @grammar.each do |rule|
384
+ line
385
+ if rule.action.empty? and @params.omit_action_call?
386
+ line "# reduce #{rule.ident} omitted"
387
+ else
388
+ src0 = rule.action.source || SourceText.new(default_body, __FILE__, 0)
389
+ if @params.convert_line?
390
+ src = remove_blank_lines(src0)
391
+ delim = make_delimiter(src.text)
392
+ @f.printf unindent_auto(<<-End),
393
+ module_eval(<<'%s', '%s', %d)
394
+ def _reduce_%d(val, _values%s)
395
+ %s%s
396
+ end
397
+ %s
398
+ End
399
+ delim, src.filename, src.lineno - 1,
400
+ rule.ident, decl,
401
+ src.text, retval,
402
+ delim
403
+ else
404
+ src = remove_blank_lines(src0)
405
+ @f.printf unindent_auto(<<-End),
406
+ def _reduce_%d(val, _values%s)
407
+ %s%s
408
+ end
409
+ End
410
+ rule.ident, decl,
411
+ src.text, retval
412
+ end
413
+ end
414
+ end
415
+ line
416
+ @f.printf unindent_auto(<<-'End'), decl
417
+ def _reduce_none(val, _values%s)
418
+ val[0]
419
+ end
420
+ End
421
+ line
422
+ end
423
+
424
+ def remove_blank_lines(src)
425
+ body = src.text.dup
426
+ line = src.lineno
427
+ while body.slice!(/\A[ \t\f]*(?:\n|\r\n|\r)/)
428
+ line += 1
429
+ end
430
+ SourceText.new(body, src.filename, line)
431
+ end
432
+
433
+ def make_delimiter(body)
434
+ delim = '.,.,'
435
+ while body.index(delim)
436
+ delim *= 2
437
+ end
438
+ delim
439
+ end
440
+
441
+ def unindent_auto(str)
442
+ lines = str.lines.to_a
443
+ n = minimum_indent(lines)
444
+ lines.map {|line| detab(line).sub(indent_re(n), '').rstrip + "\n" }.join('')
445
+ end
446
+
447
+ def minimum_indent(lines)
448
+ lines.map {|line| n_indent(line) }.min
449
+ end
450
+
451
+ def n_indent(line)
452
+ line.slice(/\A\s+/).size
453
+ end
454
+
455
+ RE_CACHE = {}
456
+
457
+ def indent_re(n)
458
+ RE_CACHE[n] ||= /\A {#{n}}/
459
+ end
460
+
461
+ def detab(str, ts = 8)
462
+ add = 0
463
+ len = nil
464
+ str.gsub(/\t/) {
465
+ len = ts - ($`.size + add) % ts
466
+ add += len - 1
467
+ ' ' * len
468
+ }
469
+ end
470
+
471
+ end
472
+
473
+ end
@@ -0,0 +1,35 @@
1
+ #--
2
+ #
3
+ #
4
+ #
5
+ # Copyright (c) 1999-2006 Minero Aoki
6
+ #
7
+ # This program is free software.
8
+ # You can distribute/modify this program under the same terms of ruby.
9
+ # see the file "COPYING".
10
+ #
11
+ #++
12
+
13
+ module Racc
14
+
15
+ class SourceText
16
+ def initialize(text, filename, lineno)
17
+ @text = text
18
+ @filename = filename
19
+ @lineno = lineno
20
+ end
21
+
22
+ attr_reader :text
23
+ attr_reader :filename
24
+ attr_reader :lineno
25
+
26
+ def to_s
27
+ "#<SourceText #{location()}>"
28
+ end
29
+
30
+ def location
31
+ "#{@filename}:#{@lineno}"
32
+ end
33
+ end
34
+
35
+ end