зеркало из https://github.com/github/ruby.git
501 строка
9.5 KiB
Ruby
501 строка
9.5 KiB
Ruby
#!/usr/bin/env ruby
|
|
# -*- ruby -*-
|
|
# $Id$
|
|
|
|
require 'mkmf'
|
|
require 'ftools'
|
|
|
|
$recursive = false
|
|
$force = false
|
|
$conly = true
|
|
$inc_path = []
|
|
$infilename= nil
|
|
$insert_require = true
|
|
|
|
def valid_ruby_code?(code)
|
|
begin
|
|
eval("BEGIN {return true}; #{code}")
|
|
rescue SyntaxError
|
|
return false
|
|
end
|
|
return false
|
|
end
|
|
|
|
def print_usage
|
|
print <<EOF
|
|
h2rb [-r] [-I <path>] [-d] [<filename>]
|
|
EOF
|
|
end
|
|
|
|
while( ARGV[0] )
|
|
case( ARGV[0] )
|
|
when "-r"
|
|
ARGV.shift
|
|
$recursive = true
|
|
when "-R"
|
|
ARGV.shift
|
|
$recursive = false
|
|
when "-l"
|
|
ARGV.shift
|
|
$insert_require = true
|
|
when "-L"
|
|
ARGV.shift
|
|
$insert_require = false
|
|
when "-c"
|
|
ARGV.shift
|
|
$conly = true
|
|
when "-C"
|
|
ARGV.shift
|
|
$conly = false
|
|
when "-f"
|
|
ARGV.shift
|
|
$force = true
|
|
when "-F"
|
|
ARGV.shift
|
|
$force = false
|
|
when "-I"
|
|
ARGV.shift
|
|
$inc_path << ARGV.shift
|
|
when "-d"
|
|
ARGV.shift
|
|
$DEBUG = true
|
|
when "-h","--help"
|
|
print_usage()
|
|
exit 0
|
|
when /-.*/
|
|
$stderr.print("unknown option '#{ARGV[0]}'.\n")
|
|
print_usage()
|
|
exit 0
|
|
else
|
|
$infilename = ARGV.shift
|
|
end
|
|
end
|
|
|
|
$inc_dir = File.join(CONFIG["prefix"], "lib", "ruby",
|
|
CONFIG["MAJOR"] + "." + CONFIG["MINOR"],
|
|
"dl")
|
|
|
|
class H2RBError < StandardError; end
|
|
|
|
|
|
class H2RB
|
|
def initialize(inc_dir = nil, inc_path = nil, insert_require = nil)
|
|
@inc_path = inc_path || []
|
|
@inc_dir = inc_dir || '.'
|
|
@indent = 0
|
|
@parsed_files = []
|
|
@insert_require = insert_require || false
|
|
end
|
|
|
|
def find_path(file)
|
|
if( ! file )
|
|
return nil
|
|
end
|
|
if( File.exist?(file) )
|
|
if( file[0] == ?/ )
|
|
return file
|
|
else
|
|
return file
|
|
end
|
|
end
|
|
@inc_path.each{|path|
|
|
full = File.join(path, file)
|
|
if( File.exist?(full) )
|
|
return full
|
|
end
|
|
}
|
|
return nil
|
|
end
|
|
|
|
def strip_comment(line)
|
|
if( @commented )
|
|
if( e = line.index("*/") )
|
|
line[0..(e+1)] = ""
|
|
@commented = false
|
|
else
|
|
line = ""
|
|
end
|
|
else
|
|
if( s = line.index("/*") )
|
|
if( e = line.index("*/") )
|
|
line[s..(e+1)] = ""
|
|
else
|
|
line[s..-1] = ""
|
|
@commented = true
|
|
end
|
|
elsif( s = line.index("//") )
|
|
line[s..(-1)] = ""
|
|
end
|
|
end
|
|
|
|
line.gsub!(/\s+$/,"")
|
|
return line
|
|
end
|
|
|
|
def up_indent
|
|
@indent += 1
|
|
end
|
|
|
|
def down_indent
|
|
@indent -= 1
|
|
if( @indent < 0 )
|
|
raise
|
|
end
|
|
end
|
|
|
|
def indent
|
|
" " * @indent
|
|
end
|
|
|
|
def rescue_begin
|
|
line = "#{indent}begin"
|
|
up_indent
|
|
return line
|
|
end
|
|
|
|
def rescue_nameerror
|
|
down_indent
|
|
line = [
|
|
"#{indent}rescue NameError => e",
|
|
"#{indent} raise e if( $DEBUG )",
|
|
"#{indent}end"].join($/)
|
|
return line
|
|
end
|
|
|
|
def parse_enum(line)
|
|
if( line =~ /enum\s+(\S+\s+)?\{(.+)\}/ )
|
|
enum_name = $1
|
|
enum_block = $2
|
|
if( enum_name )
|
|
line = "#{indent}# -- enum #{enum_name}\n"
|
|
else
|
|
line = "#{indent}# -- enum\n"
|
|
end
|
|
enums = enum_block.split(/,/).collect{|e| e.strip}
|
|
i = 0
|
|
enums.each{|elem|
|
|
var,val = elem.split(/=/).collect{|e| e.strip}
|
|
if( val )
|
|
i = val.to_i
|
|
end
|
|
line += "#{indent}#{var} = #{i.to_s}\n"
|
|
i += 1
|
|
}
|
|
line += "#{indent}# -- end of enum"
|
|
return line
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
def parse_define(line)
|
|
case line
|
|
when /^#\s*define\s+(\S+)\(\)/
|
|
line = nil
|
|
when /^#\s*define\s+(\S+)\((.+)\)\s+(.+)$/
|
|
if( @conly )
|
|
line = nil
|
|
else
|
|
defname = $1
|
|
defargs = $2
|
|
defval = $3
|
|
if( !valid_ruby_code?(defval) )
|
|
defval = "nil # #{defval}"
|
|
end
|
|
if( defname[0,1] =~ /^[A-Z]$/ )
|
|
line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}"
|
|
else
|
|
line = [
|
|
"#{indent}def #{defname}(#{defargs})",
|
|
"#{indent} #{defval}",
|
|
"#{indent}end"
|
|
].join("\n")
|
|
end
|
|
end
|
|
when /^#\s*define\s+(\S+)\((.+)\)$/
|
|
if( @conly )
|
|
line = nil
|
|
else
|
|
defname = $1
|
|
defargs = $2
|
|
defval = nil
|
|
if( !valid_ruby_code?(defval) )
|
|
defval = "nil # #{defval}"
|
|
end
|
|
if( defname[0,1] =~ /^[A-Z]$/ )
|
|
line = "#{indent}#{defname} = proc{|#{defargs}| #{defval}}"
|
|
else
|
|
line = [
|
|
"#{indent}def #{defname}(#{defargs})",
|
|
"#{indent} #{defval}",
|
|
"#{indent}end"
|
|
].join("\n")
|
|
end
|
|
end
|
|
when /^#\s*define\s+(\S+)\s+(.+)$/
|
|
defname = $1
|
|
defval = $2
|
|
if( !valid_ruby_code?(defval) )
|
|
defval = "nil # #{defval}"
|
|
end
|
|
line = [rescue_begin, "#{indent}#{defname} = #{defval}", rescue_nameerror].join($/)
|
|
when /^#\s*define\s+(\S+)$/
|
|
defname = $1
|
|
line = "#{indent}#{defname} = nil"
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_undef(line)
|
|
case line
|
|
when /^#\s*undef\s+([A-Z]\S+)$/
|
|
defname = $1
|
|
line = "#{indent}remove_const(:#{defname})"
|
|
when /^#\s*undef\s+(\S+)$/
|
|
defname = $1
|
|
line = "#{indent}#{defname} = nil"
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_ifdef(line)
|
|
case line
|
|
when /^#\s*ifdef\s+(\S+)$/
|
|
defname = $1
|
|
line = [
|
|
rescue_begin,
|
|
"#{indent}if( defined?(#{defname}) && ! #{defname}.nil? )"].join($/)
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_ifndef(line)
|
|
case line
|
|
when /^#\s*ifndef\s+(\S+)$/
|
|
defname = $1
|
|
line = [
|
|
rescue_begin,
|
|
"#{indent}if( ! defined?(#{defname}) || #{defname}.nil? )"].join($/)
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_if(line)
|
|
case line
|
|
when /^#\s*if\s+(.+)$/
|
|
cond = $1
|
|
cond.gsub!(/defined(.+)/){ "defined?(#{$1}) && ! #{$1}.nil?" }
|
|
if( valid_ruby_code?(cond) )
|
|
line = "#{indent}if( #{cond} )"
|
|
else
|
|
line = "#{indent}if( false ) # #{cond}"
|
|
end
|
|
line = [rescue_begin, line].join($/)
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_elif(line)
|
|
case line
|
|
when /^#\s*elif\s+(.+)$/
|
|
cond = $1
|
|
cond.gsub!("defined","defined?")
|
|
line = "#{indent}elsif( #{cond} )"
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_else(line)
|
|
case line
|
|
when /^#\s*else\s*/
|
|
line = "#{indent}else"
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_endif(line)
|
|
case line
|
|
when /^#\s*endif\s*$/
|
|
line = ["#{indent}end", rescue_nameerror].join($/)
|
|
else
|
|
line = nil
|
|
end
|
|
return line
|
|
end
|
|
|
|
def parse_include(line)
|
|
if( ! @insert_require )
|
|
return nil
|
|
end
|
|
|
|
file = nil
|
|
case line
|
|
when /^#\s*include "(.+)"$/
|
|
file = $1
|
|
line = "#{indent}require '#{file}'"
|
|
when /^#\s*include \<(.+)\>$/
|
|
file = $1
|
|
line = "#{indent}require '#{file}'"
|
|
else
|
|
line = nil
|
|
end
|
|
if( @recursive && file && (!@parsed_files.include?(file)) )
|
|
parse(file, @recursive, @force, @conly)
|
|
end
|
|
return line
|
|
end
|
|
|
|
|
|
def open_files(infilename)
|
|
if( ! infilename )
|
|
return [$stdin, $stdout]
|
|
end
|
|
|
|
old_infilename = infilename
|
|
infilename = find_path(infilename)
|
|
if( ! infilename )
|
|
$stderr.print("'#{old_infilename}' was not found.\n")
|
|
return [nil,nil]
|
|
end
|
|
|
|
if( infilename )
|
|
if( infilename[0,1] == '/' )
|
|
outfilename = File.join(@inc_dir, infilename[1..-1] + ".rb")
|
|
else
|
|
outfilename = infilename + ".rb"
|
|
end
|
|
File.mkpath(File.dirname(outfilename))
|
|
else
|
|
outfilename = nil
|
|
end
|
|
|
|
if( infilename )
|
|
fin = File.open(infilename,"r")
|
|
else
|
|
fin = $stdin
|
|
end
|
|
if( outfilename )
|
|
if( File.exist?(outfilename) && (!@force) )
|
|
$stderr.print("'#{outfilename}' have already existed.\n")
|
|
return [fin, nil]
|
|
end
|
|
fout = File.open(outfilename,"w")
|
|
else
|
|
fout = $stdout
|
|
end
|
|
|
|
$stderr.print("#{infilename} -> #{outfilename}\n")
|
|
if( fout )
|
|
dir = File.dirname(outfilename)
|
|
if( dir[0,1] != "." && dir != "" )
|
|
fout.print("if( ! $LOAD_PATH.include?('#{dir}') )\n",
|
|
" $LOAD_PATH.push('#{dir}')\n",
|
|
"end\n")
|
|
end
|
|
end
|
|
return [fin,fout]
|
|
end
|
|
|
|
def parse(infilename = nil, recursive = false, force = false, conly = false)
|
|
@commented = false
|
|
@recursive = recursive
|
|
@force = force
|
|
@conly = conly
|
|
@parsed_files << infilename
|
|
|
|
fin,fout = open_files(infilename)
|
|
if( !fin )
|
|
return
|
|
end
|
|
|
|
begin
|
|
line_number = 0
|
|
pre_line = nil
|
|
fin.each_line{|line|
|
|
line_number += 1
|
|
line.chop!
|
|
if( $DEBUG )
|
|
$stderr.print("#{line_number}:(#{@indent}):", line, "\n")
|
|
end
|
|
|
|
if( pre_line )
|
|
line = pre_line + line
|
|
pre_line = nil
|
|
end
|
|
|
|
if( line[-1,1] == "\\" )
|
|
pre_line = line[0..-2]
|
|
next
|
|
end
|
|
|
|
if( eidx = line.index("enum ") )
|
|
pre_line = line[eidx .. -1]
|
|
if( i = line.index("{") && j = line.index("}") )
|
|
line = line[0..j]
|
|
pre_line = nil
|
|
else
|
|
next
|
|
end
|
|
end
|
|
|
|
line = strip_comment(line)
|
|
case line
|
|
when /^enum\s/
|
|
line = parse_enum(line)
|
|
when /^#\s*define\s/
|
|
line = parse_define(line)
|
|
when /^#\s*undef\s/
|
|
line = parse_undef(line)
|
|
when /^#\s*ifdef\s/
|
|
line = parse_ifdef(line)
|
|
up_indent
|
|
when /^#\s*ifndef\s/
|
|
line = parse_ifndef(line)
|
|
up_indent
|
|
when /^#\s*if\s/
|
|
line = parse_if(line)
|
|
up_indent
|
|
when /^#\s*elif\s/
|
|
down_indent
|
|
line = parse_elif(line)
|
|
up_indent
|
|
when /^#\s*else/
|
|
down_indent
|
|
line = parse_else(line)
|
|
up_indent
|
|
when /^#\s*endif/
|
|
down_indent
|
|
line = parse_endif(line)
|
|
when /^#\s*include\s/
|
|
line = parse_include(line)
|
|
else
|
|
line = nil
|
|
end
|
|
if( line && fout )
|
|
fout.print(line, " # #{line_number}",$/)
|
|
end
|
|
}
|
|
ensure
|
|
fin.close if fin
|
|
fout.close if fout
|
|
end
|
|
end
|
|
end
|
|
|
|
h2rb = H2RB.new($inc_dir, $inc_path, $insert_require)
|
|
h2rb.parse($infilename, $recursive, $force, $conly)
|