1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
# Taken from http://lukaszwrobel.pl/blog/math-parser-part-3-implementation
module ExpressionParser
class Parser
def parse(input)
@lexer = Lexer.new(input)
expression_value = expression
token = @lexer.get_next_token
if token.kind == Token::End
expression_value
else
compare_expr(token,expression_value,expression)
end
end
protected
def compare_expr(token,expression_value,expression)
case token.kind
when Token::GThan
expression_value > expression ? 1 : 0
when Token::LThan
expression_value < expression ? 1 : 0
when Token::Equal
expression_value == expression ? 1 : 0
when Token::NotEqual
expression_value != expression ? 1 : 0
when Token::GThanE
expression_value >= expression ? 1 : 0
when Token::LThanE
expression_value <= expression ? 1 : 0
else
raise 'End expected'
end
end
def expression
component1 = factor
additive_operators = [Token::Plus, Token::Minus]
token = @lexer.get_next_token
while additive_operators.include?(token.kind)
component2 = factor
if token.kind == Token::Plus
component1 += component2
else
component1 -= component2
end
token = @lexer.get_next_token
end
@lexer.revert
component1
end
def factor
factor1 = number
multiplicative_operators = [Token::Multiply, Token::Divide, Token::MOD]
token = @lexer.get_next_token
while multiplicative_operators.include?(token.kind)
factor2 = number
if token.kind == Token::Multiply
factor1 *= factor2
elsif token.kind == Token::MOD
factor1 %= factor2
else
factor1 /= factor2
end
token = @lexer.get_next_token
end
@lexer.revert
factor1
end
def number
token = @lexer.get_next_token
if token.kind == Token::LParen
value = expression
expected_rparen = @lexer.get_next_token
if [Token::GThan,Token::LThan,Token::Equal,Token::NotEqual,Token::GThanE,Token::LThanE].include?(expected_rparen.kind)
tmp = expression
value = compare_expr(expected_rparen,value,tmp)
expected_rparen = @lexer.get_next_token
end
expected_rparen
raise "Unbalanced parenthesis" unless expected_rparen.kind == Token::RParen
elsif token.kind == Token::Number
value = token.value
else
raise 'Not a number'
end
value
end
end
end
|