class Metasm::C::Declaration

Attributes

var[RW]

Public Class Methods

new(var) click to toggle source
# File metasm/parse_c.rb, line 777
def initialize(var)
        @var = var
end
precompile_dyn_initializer(compiler, scope, var, type, init) click to toggle source

turns an initializer to CExpressions in scope.statements

# File metasm/compile_c.rb, line 614
def self.precompile_dyn_initializer(compiler, scope, var, type, init)
        case type = type.untypedef
        when Array
                # XXX TODO type.length may be dynamic !!
                case init
                when CExpression
                        # char toto[] = "42"
                        if not init.kind_of? CExpression or init.op or init.lexpr or not init.rexpr.kind_of? ::String
                                raise "unknown initializer #{init.inspect} for #{var.inspect}"
                        end
                        init = init.rexpr.unpack('C*') + [0]
                        init.map! { |chr| CExpression.new(nil, nil, chr, type.type) }
                        precompile_dyn_initializer(compiler, scope, var, type, init)

                when ::Array
                        type.length ||= init.length
                        # len is an Integer
                        init.each_with_index { |it, idx|
                                next if not it
                                break if idx >= type.length
                                idx = CExpression.new(nil, nil, idx, BaseType.new(:long, :unsigned))
                                v = CExpression.new(var, :'[]', idx, type.type)
                                precompile_dyn_initializer(compiler, scope, v, type.type, it)
                        }
                else raise "unknown initializer #{init.inspect} for #{var.inspect}"
                end
        when Union
                case init
                when CExpression, Variable
                        if init.type.untypedef.kind_of? BaseType
                                # works for struct foo bar[] = {0}; ...
                                type.members.each { |m|
                                        v = CExpression.new(var, :'.', m.name, m.type)
                                        precompile_dyn_initializer(compiler, scope, v, v.type, init)
                                }
                        elsif init.type.untypedef.kind_of? type.class
                                CExpression.new(var, :'=', init, type).precompile(compiler, scope)
                        else
                                raise "bad initializer #{init.inspect} for #{var.inspect}"
                        end
                when ::Array
                        init.each_with_index{ |it, idx|
                                next if not it
                                m = type.members[idx]
                                v = CExpression.new(var, :'.', m.name, m.type)
                                precompile_dyn_initializer(compiler, scope, v, m.type, it)
                        }
                else raise "unknown initializer #{init.inspect} for #{var.inspect}"
                end
        else
                case init
                when CExpression
                        CExpression.new(var, :'=', init, type).precompile(compiler, scope)
                else raise "unknown initializer #{init.inspect} for #{var.inspect}"
                end
        end
end
precompile_static_initializer(compiler, type, init) click to toggle source

returns a precompiled static initializer (eg string constants)

# File metasm/compile_c.rb, line 673
def self.precompile_static_initializer(compiler, type, init)
        # TODO
        case type = type.untypedef
        when Array
                if init.kind_of? ::Array
                        init.map { |i| precompile_static_initializer(compiler, type.type, i) }
                else
                        init
                end
        when Union
                if init.kind_of? ::Array
                        init.zip(type.members).map { |i, m| precompile_static_initializer(compiler, m.type, i) }
                else
                        init
                end
        else
                if init.kind_of? CExpression and init = init.reduce(compiler) and init.kind_of? CExpression
                        if not init.op and init.rexpr.kind_of? ::String
                                v = Variable.new
                                v.storage = :static
                                v.name = 'char_' + init.rexpr.gsub(/[^a-zA-Z]/, '')[0, 8]
                                v.type = Array.new(type.type)
                                v.type.length = init.rexpr.length + 1
                                v.type.type.qualifier = [:const]
                                v.initializer = CExpression.new(nil, nil, init.rexpr, type)
                                Declaration.new(v).precompile(compiler, compiler.toplevel)
                                init.rexpr = v
                        end
                        init.rexpr = precompile_static_initializer(compiler, init.rexpr.type, init.rexpr) if init.rexpr.kind_of? CExpression
                        init.lexpr = precompile_static_initializer(compiler, init.lexpr.type, init.lexpr) if init.lexpr.kind_of? CExpression
                end
                init
        end
end

Public Instance Methods

dump(scope, r=[''], dep=[]) click to toggle source
# File metasm/parse_c.rb, line 3432
def dump(scope, r=[''], dep=[])
        tr, dep = @var.dump_def(scope, [''], dep)
        if @var.kind_of? Variable and @var.type.kind_of? Function and @var.initializer
                r << ''
                r.concat tr
        else
                r.pop if r.last == ''
                r.concat tr
                r.last << ';'
        end
        [r, dep]
end
precompile(compiler, scope) click to toggle source
# File metasm/compile_c.rb, line 551
def precompile(compiler, scope)
        if (@var.type.kind_of? Function and @var.initializer and scope != compiler.toplevel) or @var.storage == :static or compiler.check_reserved_name(@var)
                old = @var.name
                ref = scope.symbol.delete old
                if scope == compiler.toplevel or (@var.type.kind_of?(Function) and not @var.initializer)
                        if n = compiler.label_oldname.index(old)
                                # reuse same name as predeclarations
                                @var.name = n
                        else
                                newname = old
                                newname = compiler.new_label newname until newname != old
                                if not compiler.check_reserved_name(@var)
                                        compiler.label_oldname[newname] = old
                                end
                                @var.name = newname
                        end
                        ref ||= scope.symbol[@var.name] || @var
                        # append only one actual declaration for all predecls (the one with init, or the last uninit)
                        scope.statements << self if ref.eql?(@var)
                else
                        @var.name = compiler.new_label @var.name until @var.name != old
                        compiler.toplevel.statements << self
                end
                compiler.toplevel.symbol[@var.name] = ref
        else
                scope.symbol[@var.name] ||= @var
                appendme = true if scope.symbol[@var.name].eql?(@var)
        end

        if i = @var.initializer
                if @var.type.kind_of? Function
                        if @var.type.type.kind_of? Union
                                s = @var.type.type
                                v = Variable.new
                                v.name = compiler.new_label('return_struct_ptr')
                                v.type = Pointer.new(s)
                                CExpression.precompile_type(compiler, scope, v)
                                @var.type.args.unshift v
                                @var.type.type = v.type
                        end
                        i.function = @var
                        i.return_label = compiler.new_label('epilog')
                        i.nonauto_label = {}
                        i.precompile(compiler)
                        Label.new(i.return_label).precompile(compiler, i)
                        i.precompile_optimize
                        # append now so that static dependencies are declared before us
                        # TODO no pure inline if addrof(func) needed
                        scope.statements << self if appendme and not @var.attributes.to_a.include? 'inline'
                elsif scope != compiler.toplevel and @var.storage != :static
                        scope.statements << self if appendme
                        Declaration.precompile_dyn_initializer(compiler, scope, @var, @var.type, i)
                        @var.initializer = nil
                else
                        scope.statements << self if appendme
                        @var.initializer = Declaration.precompile_static_initializer(compiler, @var.type, i)
                end
        else
                scope.statements << self if appendme
        end
end
to_s() click to toggle source
# File metasm/parse_c.rb, line 3445
def to_s
        dump(Block.new(nil))[0].join(' ')
end