Skip to content

Instantly share code, notes, and snippets.

@miura1729
Created March 22, 2010 21:27
Show Gist options
  • Save miura1729/340544 to your computer and use it in GitHub Desktop.
Save miura1729/340544 to your computer and use it in GitHub Desktop.
require 'rbconfig'
require 'pp'
class Lex
def initialize(str)
@tokens = str.scan(/#.*?\n|\/\*.*?\*\/|[a-zA-Z_][a-zA-Z_0-9]*|-?[0-9]+\.?[0-9]*|\S/m).each
@udtype_table = {}
end
def set_user_type_table(tab)
@udtype_table = tab
end
KEYWORD = {
'struct' => :struct,
'union' => :union,
'typedef' => :typedef,
'const' => :const,
'volatile' => :volatile,
'registor' => :regstor,
'unsigned' => :unsigned,
'signed' => :signed,
'char' => :char,
'int' => :int,
'VALUE' => :user_type,
'short' => :short,
'long' => :long,
'float' => :float,
'void' => :void,
'double' => :double,
}
def get_next_token
tok = @tokens.next
id = nil
if @udtype_table[tok] then
return [:user_type, tok]
end
if id = KEYWORD[tok] then
return [id, tok]
end
case tok
when /^#/
[:preprocess, tok]
when /^\/\*/
[:comment, tok]
when /^struct$/
[:struct, tok]
when /^union$/
[:union, tok]
when /[a-zA-Z_]/
[:id, tok]
when /[-0-9]/
[:number, tok]
when /\{/
[:open_bre, tok]
when /\(/
[:open_par, tok]
when /\*/
[:star, tok]
else
[:symbol, tok]
end
end
end
class VarInfo
def initialize(type, name)
@type = type
@name = name
end
def inspect
"#{@type} #{@name}\n"
end
def to_ytl
if @type.is_a?(String) then
"#{@type} #{@name}\n"
else
"#{@type.to_ytl} #{@name}\n"
end
end
def sizeof
case @type
when 'char', 'unsigned char', 'signed char'
1
when 'short', 'unsigned short'
2
when 'int', 'unsigned', 'unsigned long', 'long', 'VALUE', 'BDIGIT'
4
when 'double'
8
else
# if type = @userdef_type_table[@type] then
# type.sizeof
# else
@type.sizeof
# end
end
end
attr :type
attr :name
end
class StructInfo
def initialize(struct_union)
@kind = struct_union
@name = name
@member = []
end
def inspect
rs = "#{@kind.to_s} #{@name} {\n"
@member.each do |e|
rs += e.inspect
end
rs += "}\n"
end
def to_ytl
rs = "#{@kind.to_s} #{@name} {\n"
@member.each do |e|
if e.type.is_a?(String) then
rs += e.type
else
rs += e.type.to_ytl
end
rs += " #{e.name}"
end
rs += "}\n"
end
def sizeof
siz = 0
if @kind == :struct then
@member.each do |mem|
siz += mem.sizeof
end
siz
else
@member.map {|mem| mem.sizeof}.max
end
end
attr :member
attr_accessor :name
end
class FuncPtrInfo
def initialize(ret, arg, name)
@name = name
@return_type = ret
@argument_type = arg
end
def inspect
"#{@return_type.inspect} (*#{@name})(#{@argument_type.inspect})"
end
def to_ytl
"#{@return_type.inspect} (*#{@name})()\n"
end
def sizeof
4
end
def type
self
end
attr :name
attr :return_type
attr :argument_type
end
class PtrInfo
def initialize(ent)
@entity = ent
end
def inspect
"*#{@entity.inspect}"
end
def to_ytl
if @entity.is_a?(String) then
"*#{@entity}\n"
else
"*#{@entity.to_ytl}\n"
end
end
def sizeof
4
end
end
class ArrayInfo
def initialize(ent, size)
@entity = ent
@size = size
end
def inspect
"#{@entity.inspect}[#{@size}]"
end
def to_ytl
if @entity.is_a?(String) then
"#{@entity}[#{@size}]\n"
else
"#{@entity.to_ytl}[#{@size}]\n"
end
end
def sizeof
@entity.sizeof * @size.to_i
end
end
@struct_table = {}
@userdef_type_table = {}
@struct_stack = []
def top(l)
kind, tok = l.get_next_token
loop do
case kind
when :struct, :union
@struct_stack.push StructInfo.new(kind)
kind, tok = parse_struct(l)
@struct_stack.pop
when :typedef
kind, tok = l.get_next_token
tp = parse_declare(kind, tok, l)
if tp then
tp.each do |vd|
if vd then
@userdef_type_table[vd.name] = vd.type
l.set_user_type_table(@userdef_type_table)
end
end
else
p kind, tok
end
else
kind, tok = l.get_next_token
end
end
end
def parse_struct(l)
kind, tok = l.get_next_token
case kind
when :id
if @struct_table[tok] then
@struct_stack.pop
@struct_stack.push @struct_table[tok]
else
si = @struct_stack.last
si.name = tok
@struct_table[tok] = si
end
parse_struct_with_tag(tok, l)
when :open_bre
parse_struct_body(l)
else
[kind, tok]
end
end
def parse_struct_with_tag(tag, l)
kind, tok = l.get_next_token
if kind == :open_bre then
parse_struct_body(l)
else
[kind, tok]
end
end
def parse_struct_body(l)
kind, tok = l.get_next_token
while tok != '}' do
parse_declare(kind, tok, l)
kind, tok = l.get_next_token
end
l.get_next_token
end
def parse_declare(kind, tok, l)
case kind
when :signed, :unsigned
type = tok
kind, tok = l.get_next_token
rc = parse_declare_simple_type(kind, tok, l)
if rc == nil then
rc = parse_declare_vars('int', kind, tok, l)
end
rc
when :typedef, :const
type = tok
kind, tok = l.get_next_token
parse_declare(kind, tok, l)
when :struct, :union
@struct_stack.push StructInfo.new(kind)
kind, tok = parse_struct(l)
si = @struct_stack.pop
parse_declare_vars(si, kind, tok, l)
else
parse_declare_simple_type(kind, tok, l)
end
end
def parse_declare_simple_type(kind, tok, l)
if [:char, :int, :user_type, :long, :short, :float, :double, :void].include?(kind)
type = tok
kind, tok = l.get_next_token
parse_declare_vars(type, kind, tok, l)
else
nil
end
end
def parse_declare_var(type, kind, tok, l)
if kind == :open_par then
return [parse_declare_funcptr(type, l), kind, tok]
end
star_level = 0
array_level = []
var = tok
while kind == :star do
kind, tok = l.get_next_token
star_level += 1
var = tok
end
kind, tok = l.get_next_token
while tok == '[' do
kind, tok = l.get_next_token
array_level.push tok
kind, tok = l.get_next_token
end
while star_level > 0 do
star_level -= 1
type = PtrInfo.new(type)
end
while array_level.size > 0 do
as = array_level.pop
type = ArrayInfo.new(type, as)
end
res = VarInfo.new(type, var)
[res, kind, tok]
end
def parse_declare_vars(type, kind, tok, l)
vtab = []
if @struct_stack.last then
vtab = @struct_stack.last.member
end
begin
vinfo, kind, tok = parse_declare_var(type, kind, tok, l)
vtab.push vinfo
end while tok == ','
vtab
end
def parse_declare_funcargs(l)
begin
kind, tok = l.get_next_token
end while tok != ')'
[]
end
def parse_declare_funcptr(rettype, l)
kind, tok = l.get_next_token
vinfo, kind, tok = parse_declare_var(rettype, kind, tok, l)
kind, tok = l.get_next_token
if kind == :open_par then
args = parse_declare_funcargs(l)
FuncPtrInfo.new(rettype, args, vinfo)
else
vinfo
end
end
if $0 == __FILE__ then
f = File.read("#{Config::CONFIG["rubyhdrdir"]}/ruby/ruby.h")
l = Lex.new(f)
top(l)
@struct_table.each do |tag, body|
print body.to_ytl
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment