class Metasm::C::Asm

inline asm statement

Attributes

backtrace[RW]
body[RW]
clobber[RW]
input[RW]
output[RW]
volatile[RW]

Public Class Methods

new(body, backtrace, output=nil, input=nil, clobber=nil, volatile=nil) click to toggle source
# File metasm/parse_c.rb, line 945
def initialize(body, backtrace, output=nil, input=nil, clobber=nil, volatile=nil)
        @body, @backtrace, @output, @input, @clobber, @volatile = body, backtrace, output, input, clobber, volatile
end
parse(parser, scope) click to toggle source
# File metasm/parse_c.rb, line 949
def self.parse(parser, scope)
        if tok = parser.skipspaces and tok.type == :string and (tok.raw == 'volatile' or tok.raw == '__volatile__')
                volatile = true
                tok = parser.skipspaces
        end
        if not tok or tok.type != :punct or tok.raw != '('
                # detect MS-style inline asm: "__asm .* __asm .*" or "asm { [\s.]* }"
                ftok = tok
                body = ''
                if tok.type == :punct and tok.raw == '{'
                        loop do
                                raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
                                break if tok.type == :punct and tok.raw == '}'
                                case tok.type
                                when :space; body << ' ' unless body.empty?
                                when :eol; body << "\n" unless body.empty?
                                when :punct; body << tok.raw
                                when :quoted; body << CExpression.string_inspect(tok.value)       # concat adjacent c strings
                                when :string
                                        body << \
                                        case tok.raw
                                        when 'asm', '__asm', '__asm__'; "\n"
                                        when '_emit'; 'db'
                                        else tok.raw
                                        end
                                end
                        end
                # allow shell-style heredoc: asm <<EOS\n<asm>\nEOS
                elsif tok.type == :punct and tok.raw == '<'
                        raise ftok, 'bad asm heredoc' if not tok = parser.lexer.readtok or tok.type != :punct or tok.raw != '<'
                        delimiter = parser.lexer.readtok
                        if delimiter.type == :punct and delimiter.raw == '-'
                                skipspc = true
                                delimiter = parser.lexer.readtok
                        end
                        raise ftok, 'bad asm heredoc delim' if delimiter.type != :string or not tok = parser.lexer.readtok or tok.type != :eol
                        nl = true
                        loop do
                                raise ftok, 'unterminated heredoc' if not tok = parser.lexer.readtok
                                break if nl and tok.raw == delimiter.raw
                                raw = tok.raw
                                raw = "\n" if skipspc and tok.type == :eol
                                body << raw
                                nl = (tok.type == :eol and (raw[-1] == ?\n or raw[-1] == ?\r))
                        end
                # MS single-instr: asm inc eax;
                # also allow asm "foo bar\nbaz";
                else
                        parser.lexer.unreadtok tok
                        loop do
                                break if not tok = parser.lexer.readtok or tok.type == :eol
                                case tok.type
                                when :space; body << ' '
                                when :punct
                                        case tok.raw
                                        when '}'
                                                parser.lexer.unreadtok tok
                                                break
                                        else body << tok.raw
                                        end
                                when :quoted; body << (body.empty? ? tok.value : CExpression.string_inspect(tok.value))   # asm "pop\nret"  VS  asm add al, 'z'
                                when :string
                                        body << \
                                        case tok.raw
                                        when 'asm', '__asm', '__asm__'; "\n"
                                        when '_emit'; 'db'
                                        else tok.raw
                                        end
                                end
                        end
                end
                return new(body, ftok, nil, nil, nil, volatile)
        end
        raise tok || parser, '"(" expected' if not tok or tok.type != :punct or tok.raw != '('
        raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
        body = tok
        ret = new body.value, body
        tok = parser.skipspaces
        raise tok || parser, '":" or ")" expected' if not tok or tok.type != :punct or (tok.raw != ':' and tok.raw != ')')

        if tok.raw == ':'
                ret.output = []
                raise parser if not tok = parser.skipspaces
                while tok.type == :quoted
                        type = tok.value
                        raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
                        ret.output << [type, var]
                        raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
                        break if tok.raw == ':' or tok.raw == ')'
                        raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
                end
        end
        if tok.raw == ':'
                ret.input = []
                raise parser if not tok = parser.skipspaces
                while tok.type == :quoted
                        type = tok.value
                        raise tok, 'expr expected' if not var = CExpression.parse_value(parser, scope)
                        ret.input << [type, var]
                        raise tok || parser, '":" or "," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')' and tok.raw != ':')
                        break if tok.raw == ':' or tok.raw == ')'
                        raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
                end
        end
        if tok.raw == ':'
                ret.clobber = []
                raise parser if not tok = parser.skipspaces
                while tok.type == :quoted
                        ret.clobber << tok.value
                        raise tok || parser, '"," or ")" expected' if not tok = parser.skipspaces or tok.type != :punct or (tok.raw != ',' and tok.raw != ')')
                        break if tok.raw == ')'
                        raise tok || parser, 'qstring expected' if not tok = parser.skipspaces or tok.type != :quoted
                end
        end
        raise tok || parser, '")" expected' if not tok or tok.type != :punct or tok.raw != ')'
        ret.parse_attributes(parser)
        parser.checkstatementend(tok)
        ret
end

Public Instance Methods

dump(scope, r=[CRenderString.new], dep=[]) click to toggle source
# File metasm/parse_c.rb, line 3932
def dump(scope, r=[CRenderString.new], dep=[])
        r.last << CRenderString.new(self, 'asm ')
        r.last << 'volatile ' if @volatile
        r.last << '('
        r.last << CRenderString.new(self, CExpression.string_inspect(@body))
        if @output or @input or @clobber
                if @output and @output != []
                        # TODO
                        r << CRenderString.new(': /* todo */')
                elsif (@input and @input != []) or (@clobber and @clobber != [])
                        r.last << ' :'
                end
        end
        if @input or @clobber
                if @input and @input != []
                        # TODO
                        r << CRenderString.new(': /* todo */')
                elsif @clobber and @clobber != []
                        r.last << ' :'
                end
        end
        if @clobber and @clobber != []
                r << (CRenderString.new(': ') << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
        end
        r.last << ');'
        [r, dep]
end
precompile(compiler, scope) click to toggle source
# File metasm/compile_c.rb, line 953
def precompile(compiler, scope)
        scope.statements << self
        # TODO CExpr.precompile_type(clobbers)
end