# File lib/racc/parserfilegenerator.rb, line 78
78: def generate_parser
79: string_io = StringIO.new
80:
81: init_line_conversion_system
82: @f = string_io
83: parser_file
84:
85: string_io.rewind
86: string_io.read
87: end
# File lib/racc/parserfilegenerator.rb, line 89
89: def generate_parser_file(destpath)
90: init_line_conversion_system
91: File.open(destpath, 'w') {|f|
92: @f = f
93: parser_file
94: }
95: File.chmod 0755, destpath if @params.make_executable?
96: end
State Transition Table Serialization
# File lib/racc/parserfilegenerator.rb, line 254
254: def put_state_transition_table(f)
255: @f = f
256: state_transition_table
257: end
# File lib/racc/parserfilegenerator.rb, line 405
405: def actions
406: @grammar.each do |rule|
407: unless rule.action.source?
408: raise "racc: fatal: cannot generate parser file when any action is a Proc"
409: end
410: end
411:
412: if @params.result_var?
413: decl = ', result'
414: retval = "\n result"
415: default_body = ''
416: else
417: decl = ''
418: retval = ''
419: default_body = 'val[0]'
420: end
421: @grammar.each do |rule|
422: line
423: if rule.action.empty? and @params.omit_action_call?
424: line "# reduce #{rule.ident} omitted"
425: else
426: src0 = rule.action.source || SourceText.new(default_body, __FILE__, 0)
427: if @params.convert_line?
428: src = remove_blank_lines(src0)
429: delim = make_delimiter(src.text)
430: @f.printf unindent_auto( module_eval(<<'%s', '%s', %d) def _reduce_%d(val, _values%s) %s%s end %s),
431: delim, src.filename, src.lineno - 1,
432: rule.ident, decl,
433: src.text, retval,
434: delim
435: else
436: src = remove_blank_lines(src0)
437: @f.printf unindent_auto( def _reduce_%d(val, _values%s) %s%s end),
438: rule.ident, decl,
439: src.text, retval
440: end
441: end
442: end
443: line
444: @f.printf unindent_auto( def _reduce_none(val, _values%s) val[0] end), decl
445: line
446: end
# File lib/racc/parserfilegenerator.rb, line 213
213: def cref_pop
214: @cref.pop
215: end
# File lib/racc/parserfilegenerator.rb, line 209
209: def cref_push(name)
210: @cref.push name
211: end
# File lib/racc/parserfilegenerator.rb, line 499
499: def detab(str, ts = 8)
500: add = 0
501: len = nil
502: str.gsub(/\t/) {
503: len = ts - ($`.size + add) % ts
504: add += len - 1
505: ' ' * len
506: }
507: end
# File lib/racc/parserfilegenerator.rb, line 136
136: def embed_library(src)
137: line %[###### #{src.filename} begin]
138: line %[unless $".index '#{src.filename}']
139: line %[$".push '#{src.filename}']
140: put src, @params.convert_line?
141: line %[end]
142: line %[###### #{src.filename} end]
143: end
# File lib/racc/parserfilegenerator.rb, line 167
167: def header
168: @params.header.each do |src|
169: line
170: put src, @params.convert_line_all?
171: end
172: end
# File lib/racc/parserfilegenerator.rb, line 375
375: def i_i_sym_list(name, table)
376: sep = ''
377: line "#{name} = ["
378: table.each_slice(3) do |len, target, mid|
379: @f.print sep; sep = ",\n"
380: @f.printf ' %d, %d, %s', len, target, mid.inspect
381: end
382: line " ]"
383: end
# File lib/racc/parserfilegenerator.rb, line 217
217: def indent
218: @f.print ' ' * @cref.size
219: end
# File lib/racc/parserfilegenerator.rb, line 495
495: def indent_re(n)
496: RE_CACHE[n] ||= /\A {#{n}}/
497: end
# File lib/racc/parserfilegenerator.rb, line 204
204: def init_line_conversion_system
205: @cref = []
206: @used_separator = {}
207: end
# File lib/racc/parserfilegenerator.rb, line 174
174: def inner
175: @params.inner.each do |src|
176: line
177: put src, @params.convert_line?
178: end
179: end
# File lib/racc/parserfilegenerator.rb, line 322
322: def integer_list(name, table)
323: if table.size > 2000
324: serialize_integer_list_compressed name, table
325: else
326: serialize_integer_list_std name, table
327: end
328: end
# File lib/racc/parserfilegenerator.rb, line 200
200: def line(str = '')
201: @f.puts str
202: end
# File lib/racc/parserfilegenerator.rb, line 471
471: def make_delimiter(body)
472: delim = '.,.,'
473: while body.index(delim)
474: delim *= 2
475: end
476: delim
477: end
# File lib/racc/parserfilegenerator.rb, line 233
233: def make_separator(src)
234: sep = unique_separator(src.filename)
235: sep *= 2 while src.text.index(sep)
236: sep
237: end
# File lib/racc/parserfilegenerator.rb, line 485
485: def minimum_indent(lines)
486: lines.map {|line| n_indent(line) }.min
487: end
# File lib/racc/parserfilegenerator.rb, line 489
489: def n_indent(line)
490: line.slice(/\A\s+/).size
491: end
# File lib/racc/parserfilegenerator.rb, line 124
124: def notice
125: line %[#]
126: line %[# DO NOT MODIFY!!!!]
127: line %[# This file is automatically generated by Racc #{Racc::Version}]
128: line %[# from Racc grammer file "#{@params.filename}".]
129: line %[#]
130: end
# File lib/racc/parserfilegenerator.rb, line 149
149: def parser_class(classname, superclass)
150: mods = classname.split('::')
151: classid = mods.pop
152: mods.each do |mod|
153: indent; line "module #{mod}"
154: cref_push mod
155: end
156: indent; line "class #{classid} < #{superclass}"
157: cref_push classid
158: yield
159: cref_pop
160: indent; line "end \# class #{classid}"
161: mods.reverse_each do |mod|
162: indent; line "end \# module #{mod}"
163: cref_pop
164: end
165: end
# File lib/racc/parserfilegenerator.rb, line 100
100: def parser_file
101: shebang @params.interpreter if @params.make_executable?
102: notice
103: line
104: if @params.embed_runtime?
105: embed_library runtime_source()
106: else
107: require 'racc/parser.rb'
108: end
109: header
110: parser_class(@params.classname, @params.superclass) {
111: inner
112: state_transition_table
113: }
114: footer
115: end
Low Level Routines
# File lib/racc/parserfilegenerator.rb, line 190
190: def put(src, convert_line = false)
191: if convert_line
192: replace_location(src) {
193: @f.puts src.text
194: }
195: else
196: @f.puts src.text
197: end
198: end
# File lib/racc/parserfilegenerator.rb, line 462
462: def remove_blank_lines(src)
463: body = src.text.dup
464: line = src.lineno
465: while m = body.slice!(/\A[ \t\f]*(?:\n|\r\n|\r)/)
466: line += 1
467: end
468: SourceText.new(body, src.filename, line)
469: end
# File lib/racc/parserfilegenerator.rb, line 225
225: def replace_location(src)
226: sep = make_separator(src)
227: @f.print 'self.class.' if toplevel?
228: @f.puts "module_eval(<<'#{sep}', '#{src.filename}', #{src.lineno})"
229: yield
230: @f.puts sep
231: end
# File lib/racc/parserfilegenerator.rb, line 145
145: def require(feature)
146: line "require '#{feature}'"
147: end
# File lib/racc/parserfilegenerator.rb, line 132
132: def runtime_source
133: SourceText.new(::Racc::PARSER_TEXT, 'racc/parser.rb', 1)
134: end
# File lib/racc/parserfilegenerator.rb, line 330
330: def serialize_integer_list_compressed(name, table)
331: sep = "\n"
332: nsep = ",\n"
333: buf = ''
334: com = ''
335: ncom = ','
336: co = com
337: @f.print 'clist = ['
338: table.each do |i|
339: buf << co << i.to_s; co = ncom
340: if buf.size > 66
341: @f.print sep; sep = nsep
342: @f.print "'", buf, "'"
343: buf = ''
344: co = com
345: end
346: end
347: unless buf.empty?
348: @f.print sep
349: @f.print "'", buf, "'"
350: end
351: line ' ]'
352:
353: @f.print( #{name} = arr = Array.new(#{table.size}, nil) idx = 0 clist.each do |str| str.split(',', -1).each do |i| arr[idx] = i.to_i unless i.empty? idx += 1 end end)
354: end
# File lib/racc/parserfilegenerator.rb, line 365
365: def serialize_integer_list_std(name, table)
366: sep = ''
367: line "#{name} = ["
368: table.each_slice(10) do |ns|
369: @f.print sep; sep = ",\n"
370: @f.print ns.map {|n| sprintf('%6s', n ? n.to_s : 'nil') }.join(',')
371: end
372: line ' ]'
373: end
# File lib/racc/parserfilegenerator.rb, line 120
120: def shebang(path)
121: line '#!' + (path == 'ruby' ? RUBY_PATH : path)
122: end
# File lib/racc/parserfilegenerator.rb, line 261
261: def state_transition_table
262: table = @states.state_transition_table
263: table.use_result_var = @params.result_var?
264: table.debug_parser = @params.debug_parser?
265:
266: line "##### State transition tables begin ###"
267: line
268: integer_list 'racc_action_table', table.action_table
269: line
270: integer_list 'racc_action_check', table.action_check
271: line
272: integer_list 'racc_action_pointer', table.action_pointer
273: line
274: integer_list 'racc_action_default', table.action_default
275: line
276: integer_list 'racc_goto_table', table.goto_table
277: line
278: integer_list 'racc_goto_check', table.goto_check
279: line
280: integer_list 'racc_goto_pointer', table.goto_pointer
281: line
282: integer_list 'racc_goto_default', table.goto_default
283: line
284: i_i_sym_list 'racc_reduce_table', table.reduce_table
285: line
286: line "racc_reduce_n = #{table.reduce_n}"
287: line
288: line "racc_shift_n = #{table.shift_n}"
289: line
290: sym_int_hash 'racc_token_table', table.token_table
291: line
292: line "racc_nt_base = #{table.nt_base}"
293: line
294: line "racc_use_result_var = #{table.use_result_var}"
295: line
296: @f.print(unindent_auto( Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ]))
297: line
298: string_list 'Racc_token_to_s_table', table.token_to_s_table
299: line
300: line "Racc_debug_parser = #{table.debug_parser}"
301: line
302: line '##### State transition tables end #####'
303: actions
304: end
# File lib/racc/parserfilegenerator.rb, line 395
395: def string_list(name, list)
396: sep = " "
397: line "#{name} = ["
398: list.each do |s|
399: @f.print sep; sep = ",\n "
400: @f.print s.dump
401: end
402: line ' ]'
403: end
# File lib/racc/parserfilegenerator.rb, line 385
385: def sym_int_hash(name, h)
386: sep = "\n"
387: @f.print "#{name} = {"
388: h.to_a.sort_by {|sym, i| i }.each do |sym, i|
389: @f.print sep; sep = ",\n"
390: @f.printf " %s => %d", sym.serialize, i
391: end
392: line " }"
393: end
# File lib/racc/parserfilegenerator.rb, line 221
221: def toplevel?
222: @cref.empty?
223: end
# File lib/racc/parserfilegenerator.rb, line 479
479: def unindent_auto(str)
480: lines = str.to_a
481: n = minimum_indent(lines)
482: lines.map {|line| detab(line).sub(indent_re(n), '').rstrip + "\n" }.join('')
483: end
# File lib/racc/parserfilegenerator.rb, line 239
239: def unique_separator(id)
240: sep = "...end #{id}/module_eval..."
241: while @used_separator.key?(sep)
242: sep.concat sprintf('%02x', rand(255))
243: end
244: @used_separator[sep] = true
245: sep
246: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.