class Metasm::C::Asm
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 931 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 935 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 << ' ' when :eol; body << "\n" 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=[''], dep=[])
click to toggle source
# File metasm/parse_c.rb, line 3882 def dump(scope, r=[''], dep=[]) r.last << 'asm ' r.last << 'volatile ' if @volatile r.last << '(' r.last << CExpression.string_inspect(@body) if @output or @input or @clobber if @output and @output != [] # TODO r << ': /* todo */' elsif (@input and @input != []) or (@clobber and @clobber != []) r.last << ' :' end end if @input or @clobber if @input and @input != [] # TODO r << ': /* todo */' elsif @clobber and @clobber != [] r.last << ' :' end end if @clobber and @clobber != [] r << (': ' << @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