class Metasm::Preprocessor::PPExpression
parses a preprocessor expression (similar to Expression
, + handles “defined(foo)”), returns an Expression
Public Class Methods
parse(lexer)
click to toggle source
# File metasm/preprocessor.rb, line 1261 def parse(lexer) opstack = [] stack = [] return if not e = parse_value(lexer) stack << e while op = readop(lexer) nil while ntok = lexer.readtok and ntok.type == :space lexer.unreadtok ntok until opstack.empty? or Expression::OP_PRIO[op.value][opstack.last] stack << Expression.new(opstack.pop, stack.pop, stack.pop) end if op.value == :'?' a1 = parse(lexer) if not tok = lexer.readtok or tok.type != :punct or tok.raw != ':' raise op, 'expected ":" ternary operator' end a2 = parse(lexer) case Expression[stack.pop].reduce when 0; stack << a2 when ::Integer; stack << a1 else; stack << a2 end next end opstack << op.value raise op, 'need rhs' if not e = parse_value(lexer) stack << e end until opstack.empty? stack << Expression.new(opstack.pop, stack.pop, stack.pop) end Expression[stack.first] end
parse_intfloat(lexer, tok)
click to toggle source
handles floats and “defined” keyword
# File metasm/preprocessor.rb, line 1190 def parse_intfloat(lexer, tok) if tok.type == :string and tok.raw == 'defined' nil while ntok = lexer.readtok_nopp and ntok.type == :space raise tok if not ntok if ntok.type == :punct and ntok.raw == '(' nil while ntok = lexer.readtok_nopp and ntok.type == :space nil while rtok = lexer.readtok_nopp and rtok.type == :space raise tok if not rtok or rtok.type != :punct or rtok.raw != ')' end raise tok if not ntok or ntok.type != :string tok.value = lexer.definition[ntok.raw] ? 1 : 0 return elsif tok.type == :string and tok.raw == 'L' ntok = lexer.readtok_nopp if ntok.type == :quoted and ntok.raw[0] == ?' tok.raw << ntok.raw tok.value = (ntok.value + "\0\0").unpack('v') # XXX endianness else lexer.unreadtok ntok end end Expression.parse_num_value(lexer, tok) end
parse_value(lexer)
click to toggle source
returns the next value from lexer (parenthesised expression, immediate, variable, unary operators) single-line only, and does not handle multibyte char string
# File metasm/preprocessor.rb, line 1217 def parse_value(lexer) nil while tok = lexer.readtok and tok.type == :space return if not tok case tok.type when :string parse_intfloat(lexer, tok) val = tok.value || tok.raw when :quoted if tok.raw[0] != ?' or tok.value.length > 1 # allow single-char lexer.unreadtok tok return end val = tok.value[0] when :punct case tok.raw when '(' val = parse(lexer) nil while ntok = lexer.readtok and ntok.type == :space raise tok, "')' expected after #{val.inspect} got #{ntok.inspect}" if not ntok or ntok.type != :punct or ntok.raw != ')' when '!', '+', '-', '~' nil while ntok = lexer.readtok and ntok.type == :space lexer.unreadtok ntok raise tok, 'need expression after unary operator' if not val = parse_value(lexer) val = Expression[tok.raw.to_sym, val] when '.' parse_intfloat(lexer, tok) if not tok.value lexer.unreadtok tok return end val = tok.value else lexer.unreadtok tok return end else lexer.unreadtok tok return end nil while tok = lexer.readtok and tok.type == :space lexer.unreadtok tok val end
readop(lexer)
click to toggle source
reads an operator from the lexer, returns the corresponding symbol or nil
# File metasm/preprocessor.rb, line 1145 def readop(lexer) if not tok = lexer.readtok or tok.type != :punct lexer.unreadtok tok return end op = tok case op.raw # may be followed by itself or '=' when '>', '<' if ntok = lexer.readtok and ntok.type == :punct and (ntok.raw == op.raw or ntok.raw == '=') op = op.dup op.raw << ntok.raw else lexer.unreadtok ntok end # may be followed by itself when '|', '&' if ntok = lexer.readtok and ntok.type == :punct and ntok.raw == op.raw op = op.dup op.raw << ntok.raw else lexer.unreadtok ntok end # must be followed by '=' when '!', '=' if not ntok = lexer.readtok or ntok.type != :punct and ntok.raw != '=' lexer.unreadtok ntok lexer.unreadtok tok return end op = op.dup op.raw << ntok.raw # ok when '^', '+', '-', '*', '/', '%', '>>', '<<', '>=', '<=', '||', '&&', '!=', '==', '?' # unknown else lexer.unreadtok tok return end op.value = op.raw.to_sym op end