class Racc::ParserFileGenerator
Constants
- RE_CACHE
- RUBY_PATH
Public Class Methods
new(states, params)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 72 def initialize(states, params) @states = states @grammar = states.grammar @params = params end
Public Instance Methods
generate_parser()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 78 def generate_parser string_io = StringIO.new init_line_conversion_system @f = string_io parser_file string_io.rewind string_io.read end
generate_parser_file(destpath)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 89 def generate_parser_file(destpath) init_line_conversion_system File.open(destpath, 'w') {|f| @f = f parser_file } File.chmod 0755, destpath if @params.make_executable? end
put_state_transition_table(f)
click to toggle source
State
Transition Table Serialization
# File lib/racc/parserfilegenerator.rb, line 254 def put_state_transition_table(f) @f = f state_transition_table end
Private Instance Methods
actions()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 406 def actions @grammar.each do |rule| unless rule.action.source? raise "racc: fatal: cannot generate parser file when any action is a Proc" end end if @params.result_var? decl = ', result' retval = "\n result" default_body = '' else decl = '' retval = '' default_body = 'val[0]' end @grammar.each do |rule| line if rule.action.empty? and @params.omit_action_call? line "# reduce #{rule.ident} omitted" else src0 = rule.action.source || SourceText.new(default_body, __FILE__, 0) if @params.convert_line? src = remove_blank_lines(src0) delim = make_delimiter(src.text) @f.printf unindent_auto(<<-End), module_eval(<<'%s', '%s', %d) def _reduce_%d(val, _values%s) %s%s end %s End delim, src.filename, src.lineno - 1, rule.ident, decl, src.text, retval, delim else src = remove_blank_lines(src0) @f.printf unindent_auto(<<-End), def _reduce_%d(val, _values%s) %s%s end End rule.ident, decl, src.text, retval end end end line @f.printf unindent_auto(<<-'End'), decl def _reduce_none(val, _values%s) val[0] end End line end
cref_pop()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 213 def cref_pop @cref.pop end
cref_push(name)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 209 def cref_push(name) @cref.push name end
detab(str, ts = 8)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 500 def detab(str, ts = 8) add = 0 len = nil str.gsub(/\t/) { len = ts - ($`.size + add) % ts add += len - 1 ' ' * len } end
embed_library(src)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 136 def embed_library(src) line %[###### #{src.filename} begin] line %[unless $".index '#{src.filename}'] line %[$".push '#{src.filename}'] put src, @params.convert_line? line %[end] line %[###### #{src.filename} end] end
header()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 167 def header @params.header.each do |src| line put src, @params.convert_line_all? end end
i_i_sym_list(name, table)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 376 def i_i_sym_list(name, table) sep = '' line "#{name} = [" table.each_slice(3) do |len, target, mid| @f.print sep; sep = ",\n" @f.printf ' %d, %d, %s', len, target, mid.inspect end line " ]" end
indent()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 217 def indent @f.print ' ' * @cref.size end
indent_re(n)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 496 def indent_re(n) RE_CACHE[n] ||= /\A {#{n}}/ end
init_line_conversion_system()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 204 def init_line_conversion_system @cref = [] @used_separator = {} end
inner()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 174 def inner @params.inner.each do |src| line put src, @params.convert_line? end end
integer_list(name, table)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 322 def integer_list(name, table) if table.size > 2000 serialize_integer_list_compressed name, table else serialize_integer_list_std name, table end end
line(str = '')
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 200 def line(str = '') @f.puts str end
make_delimiter(body)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 472 def make_delimiter(body) delim = '.,.,' while body.index(delim) delim *= 2 end delim end
make_separator(src)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 233 def make_separator(src) sep = unique_separator(src.filename) sep *= 2 while src.text.index(sep) sep end
minimum_indent(lines)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 486 def minimum_indent(lines) lines.map {|line| n_indent(line) }.min end
n_indent(line)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 490 def n_indent(line) line.slice(/\A\s+/).size end
notice()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 124 def notice line %q[#] line %q[# DO NOT MODIFY!!!!] line %Q[# This file is automatically generated by Racc #{Racc::Version}] line %Q[# from Racc grammar file "#{@params.filename}".] line %q[#] end
parser_class(classname, superclass) { || ... }
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 149 def parser_class(classname, superclass) mods = classname.split('::') classid = mods.pop mods.each do |mod| indent; line "module #{mod}" cref_push mod end indent; line "class #{classid} < #{superclass}" cref_push classid yield cref_pop indent; line "end \# class #{classid}" mods.reverse_each do |mod| cref_pop indent; line "end \# module #{mod}" end end
parser_file()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 100 def parser_file shebang @params.interpreter if @params.make_executable? notice line if @params.embed_runtime? embed_library runtime_source() else require 'racc/parser.rb' end header parser_class(@params.classname, @params.superclass) { inner state_transition_table } footer end
put(src, convert_line = false)
click to toggle source
Low Level Routines
# File lib/racc/parserfilegenerator.rb, line 190 def put(src, convert_line = false) if convert_line replace_location(src) { @f.puts src.text } else @f.puts src.text end end
remove_blank_lines(src)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 463 def remove_blank_lines(src) body = src.text.dup line = src.lineno while body.slice!(/\A[ \t\f]*(?:\n|\r\n|\r)/) line += 1 end SourceText.new(body, src.filename, line) end
replace_location(src) { || ... }
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 225 def replace_location(src) sep = make_separator(src) @f.print 'self.class.' if toplevel? @f.puts "module_eval(<<'#{sep}', '#{src.filename}', #{src.lineno})" yield @f.puts sep end
require(feature)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 145 def require(feature) line "require '#{feature}'" end
runtime_source()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 132 def runtime_source SourceText.new(::Racc::PARSER_TEXT, 'racc/parser.rb', 1) end
serialize_integer_list_compressed(name, table)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 330 def serialize_integer_list_compressed(name, table) # TODO: this can be made a LOT more clean with a simple split/map sep = "\n" nsep = ",\n" buf = String.new com = '' ncom = ',' co = com @f.print 'clist = [' table.each do |i| buf << co << i.to_s; co = ncom if buf.size > 66 @f.print sep; sep = nsep @f.print "'", buf, "'" buf = String.new co = com end end unless buf.empty? @f.print sep @f.print "'", buf, "'" end line ' ]' @f.print(<<-End) #{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 End end
serialize_integer_list_std(name, table)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 366 def serialize_integer_list_std(name, table) sep = '' line "#{name} = [" table.each_slice(10) do |ns| @f.print sep; sep = ",\n" @f.print ns.map {|n| sprintf('%6s', n ? n.to_s : 'nil') }.join(',') end line ' ]' end
shebang(path)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 120 def shebang(path) line '#!' + (path == 'ruby' ? RUBY_PATH : path) end
state_transition_table()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 261 def state_transition_table table = @states.state_transition_table table.use_result_var = @params.result_var? table.debug_parser = @params.debug_parser? line "##### State transition tables begin ###" line integer_list 'racc_action_table', table.action_table line integer_list 'racc_action_check', table.action_check line integer_list 'racc_action_pointer', table.action_pointer line integer_list 'racc_action_default', table.action_default line integer_list 'racc_goto_table', table.goto_table line integer_list 'racc_goto_check', table.goto_check line integer_list 'racc_goto_pointer', table.goto_pointer line integer_list 'racc_goto_default', table.goto_default line i_i_sym_list 'racc_reduce_table', table.reduce_table line line "racc_reduce_n = #{table.reduce_n}" line line "racc_shift_n = #{table.shift_n}" line sym_int_hash 'racc_token_table', table.token_table line line "racc_nt_base = #{table.nt_base}" line line "racc_use_result_var = #{table.use_result_var}" line @f.print(unindent_auto(<<-End)) 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 ] End line string_list 'Racc_token_to_s_table', table.token_to_s_table line line "Racc_debug_parser = #{table.debug_parser}" line line '##### State transition tables end #####' actions end
string_list(name, list)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 396 def string_list(name, list) sep = " " line "#{name} = [" list.each do |s| @f.print sep; sep = ",\n " @f.print s.dump end line ' ]' end
sym_int_hash(name, h)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 386 def sym_int_hash(name, h) sep = "\n" @f.print "#{name} = {" h.to_a.sort_by {|sym, i| i }.each do |sym, i| @f.print sep; sep = ",\n" @f.printf " %s => %d", sym.serialize, i end line " }" end
toplevel?()
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 221 def toplevel? @cref.empty? end
unindent_auto(str)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 480 def unindent_auto(str) lines = str.lines.to_a n = minimum_indent(lines) lines.map {|line| detab(line).sub(indent_re(n), '').rstrip + "\n" }.join('') end
unique_separator(id)
click to toggle source
# File lib/racc/parserfilegenerator.rb, line 239 def unique_separator(id) sep = String.new "...end #{id}/module_eval..." while @used_separator.key?(sep) sep.concat sprintf('%02x', rand(255)) end @used_separator[sep] = true sep end