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

                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 + "\00\\00"").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