class Metasm::C::If

Attributes

belse[RW]
bthen[RW]
test[RW]

Public Class Methods

new(test, bthen, belse=nil) click to toggle source
# File metasm/parse_c.rb, line 799
def initialize(test, bthen, belse=nil)
        @test = test
        @bthen = bthen
        @belse = belse if belse
end
parse(parser, scope, nest) click to toggle source
# File metasm/parse_c.rb, line 805
def self.parse(parser, scope, nest)
        tok = nil
        raise tok || self, '"(" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != '('
        raise tok, 'expr expected' if not expr = CExpression.parse(parser, scope) or not expr.type.arithmetic?
        raise tok || self, '")" expected' if not tok = parser.skipspaces or tok.type != :punct or tok.raw != ')'
        bthen = parser.parse_statement scope, nest
        if tok = parser.skipspaces and tok.type == :string and tok.raw == 'else'
                belse = parser.parse_statement scope, nest
        else
                parser.unreadtok tok
        end

        new expr, bthen, belse
end

Public Instance Methods

dump(scope, r=[CRenderString.new], dep=[]) click to toggle source
# File metasm/parse_c.rb, line 3791
def dump(scope, r=[CRenderString.new], dep=[])
        r.last << CRenderString.new(self, 'if (')
        r, dep = CExpression.dump(@test, scope, r, dep)
        r.last << ')'
        r, dep = Statement.dump(@bthen, scope, r, dep)
        if belse
                @bthen.kind_of?(Block) ? (r.last << CRenderString.new(' else')) : (r << CRenderString.new(self, 'else'))
                if @belse.kind_of?(If)
                        # skip indent
                        r.last << ' '
                        r, dep = @belse.dump(scope, r, dep)
                else
                        r, dep = Statement.dump(@belse, scope, r, dep)
                end
        end
        [r, dep]
end
precompile(compiler, scope) click to toggle source
# File metasm/compile_c.rb, line 710
def precompile(compiler, scope)
        expr = lambda { |e| e.kind_of?(CExpression) ? e : CExpression.new(nil, nil, e, e.type) }

        if @bthen.kind_of? Goto or @bthen.kind_of? Break or @bthen.kind_of? Continue
                # if () goto l; else b; => if () goto l; b;
                if belse
                        t1 = @belse
                        @belse = nil
                end

                # need to convert user-defined Goto target !
                @bthen.precompile(compiler, scope)
                @bthen = scope.statements.pop       # break => goto break_label
        elsif belse
                # if () a; else b; => if () goto then; b; goto end; then: a; end:
                t1 = @belse
                t2 = @bthen
                l2 = compiler.new_label('if_then')
                @bthen = Goto.new(l2)
                @belse = nil
                l3 = compiler.new_label('if_end')
        else
                # if () a; => if (!) goto end; a; end:
                t1 = @bthen
                l2 = compiler.new_label('if_end')
                @bthen = Goto.new(l2)
                @test = CExpression.negate(@test)
        end

        @test = expr[@test]
        case @test.op
        when :'&&'
                # if (c1 && c2) goto a; => if (!c1) goto b; if (c2) goto a; b:
                l1 = compiler.new_label('if_nand')
                If.new(CExpression.negate(@test.lexpr), Goto.new(l1)).precompile(compiler, scope)
                @test = expr[@test.rexpr]
                precompile(compiler, scope)
        when :'||'
                l1 = compiler.new_label('if_or')
                If.new(expr[@test.lexpr], Goto.new(@bthen.target)).precompile(compiler, scope)
                @test = expr[@test.rexpr]
                precompile(compiler, scope)
        else
                @test = CExpression.precompile_inner(compiler, scope, @test)
                t = @test.reduce(compiler)
                if t.kind_of? ::Integer
                        if t == 0
                                Label.new(l1, nil).precompile(compiler, scope) if l1
                                t1.precompile(compiler, scope) if t1
                                Label.new(l2, nil).precompile(compiler, scope) if l2
                                Label.new(l3, nil).precompile(compiler, scope) if l3
                        else
                                scope.statements << @bthen
                                Label.new(l1, nil).precompile(compiler, scope) if l1
                                Label.new(l2, nil).precompile(compiler, scope) if l2
                                t2.precompile(compiler, scope) if t2
                                Label.new(l3, nil).precompile(compiler, scope) if l3
                        end
                        return
                end
                scope.statements << self
        end

        Label.new(l1, nil).precompile(compiler, scope) if l1
        t1.precompile(compiler, scope) if t1
        Goto.new(l3).precompile(compiler, scope) if l3
        Label.new(l2, nil).precompile(compiler, scope) if l2
        t2.precompile(compiler, scope) if t2
        Label.new(l3, nil).precompile(compiler, scope) if l3
end