add support for unary plus/minus
This commit is contained in:
@@ -151,23 +151,6 @@ module RubyAlgebra
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Subtraction < Addition
|
|
||||||
attr_reader :lhs, :rhs
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
|
||||||
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
|
||||||
|
|
||||||
result = need_parentheses_left ? "(#{lhs}) - " : "#{lhs} - "
|
|
||||||
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
:sub
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class Constant < Expression
|
class Constant < Expression
|
||||||
attr_reader :value
|
attr_reader :value
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ module RubyAlgebra
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class OperatorToken < Token
|
class BinaryOperatorToken < Token
|
||||||
attr_reader :op
|
attr_reader :op
|
||||||
|
|
||||||
def initialize(op)
|
def initialize(op)
|
||||||
@@ -33,6 +33,15 @@ module RubyAlgebra
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class UnaryOperatorToken < Token
|
||||||
|
attr_reader :op
|
||||||
|
|
||||||
|
def initialize(op)
|
||||||
|
@type = :unary_op
|
||||||
|
@op = op
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class ParenthesisToken < Token
|
class ParenthesisToken < Token
|
||||||
attr_reader :closing
|
attr_reader :closing
|
||||||
|
|
||||||
@@ -54,34 +63,42 @@ module RubyAlgebra
|
|||||||
while i < e.length
|
while i < e.length
|
||||||
c = e[i]
|
c = e[i]
|
||||||
if c.match?(/\p{Alpha}/)
|
if c.match?(/\p{Alpha}/)
|
||||||
yield OperatorToken.new(:mult) if add_implicit_mul
|
yield BinaryOperatorToken.new(:mult) if add_implicit_mul
|
||||||
j = i + 1
|
j = i + 1
|
||||||
j += 1 while j < e.length && e[j].match?(/\p{Alnum}/)
|
j += 1 while j < e.length && e[j].match?(/\p{Alnum}/)
|
||||||
add_implicit_mul = true
|
add_implicit_mul = true
|
||||||
yield IdentifierToken.new(e[i...j])
|
yield IdentifierToken.new(e[i...j])
|
||||||
i = j
|
i = j
|
||||||
elsif c.match?(/[+\-*\/^()]/)
|
elsif c.match?(/[+\-*\/^()]/)
|
||||||
yield OperatorToken.new(:mult) if c == "(" && add_implicit_mul
|
yield BinaryOperatorToken.new(:mult) if c == "(" && add_implicit_mul
|
||||||
i += 1
|
i += 1
|
||||||
add_implicit_mul = c == ")"
|
|
||||||
case c
|
case c
|
||||||
when "+"
|
when "+"
|
||||||
yield OperatorToken.new(:add)
|
if add_implicit_mul
|
||||||
|
yield BinaryOperatorToken.new(:add)
|
||||||
|
else
|
||||||
|
yield UnaryOperatorToken.new(:positive)
|
||||||
|
end
|
||||||
when "-"
|
when "-"
|
||||||
yield OperatorToken.new(:sub)
|
if add_implicit_mul
|
||||||
|
yield BinaryOperatorToken.new(:sub)
|
||||||
|
else
|
||||||
|
yield UnaryOperatorToken.new(:negative)
|
||||||
|
end
|
||||||
when "*"
|
when "*"
|
||||||
yield OperatorToken.new(:mult)
|
yield BinaryOperatorToken.new(:mult)
|
||||||
when "/"
|
when "/"
|
||||||
yield OperatorToken.new(:div)
|
yield BinaryOperatorToken.new(:div)
|
||||||
when "^"
|
when "^"
|
||||||
yield OperatorToken.new(:pow)
|
yield BinaryOperatorToken.new(:pow)
|
||||||
when "("
|
when "("
|
||||||
yield ParenthesisToken.new(false)
|
yield ParenthesisToken.new(false)
|
||||||
when ")"
|
when ")"
|
||||||
yield ParenthesisToken.new(true)
|
yield ParenthesisToken.new(true)
|
||||||
end
|
end
|
||||||
|
add_implicit_mul = c == ")"
|
||||||
elsif c.match?(/\p{Digit}|\./)
|
elsif c.match?(/\p{Digit}|\./)
|
||||||
yield OperatorToken.new(:mult) if add_implicit_mul
|
yield BinaryOperatorToken.new(:mult) if add_implicit_mul
|
||||||
j = i + 1
|
j = i + 1
|
||||||
j += 1 while j < e.length && e[j].match?(/\p{Digit}|\./)
|
j += 1 while j < e.length && e[j].match?(/\p{Digit}|\./)
|
||||||
s = e[i...j]
|
s = e[i...j]
|
||||||
@@ -109,16 +126,15 @@ module RubyAlgebra
|
|||||||
def parse(expr)
|
def parse(expr)
|
||||||
operators = []
|
operators = []
|
||||||
out_stack = []
|
out_stack = []
|
||||||
prev = nil
|
|
||||||
tokenize(expr) do |token|
|
tokenize(expr) do |token|
|
||||||
|
pp token
|
||||||
if token.type == :num
|
if token.type == :num
|
||||||
out_stack.push(Constant.new(token.value))
|
out_stack.push(Constant.new(token.value))
|
||||||
elsif token.type == :end
|
elsif token.type == :end
|
||||||
# тут надо обработку незакрытых (
|
|
||||||
_parse_make_op(operators, out_stack) until operators.empty?
|
_parse_make_op(operators, out_stack) until operators.empty?
|
||||||
elsif token.type == :op
|
elsif token.type == :op || token.type == :unary_op
|
||||||
p = _parse_op_prio token
|
p = _parse_op_prio token
|
||||||
while operators.length != 0 && operators.last.type == :op && (_parse_op_prio(operators.last) > p || (_parse_op_prio(operators.last) == p && token.op != :pow))
|
while operators.length != 0 && (operators.last.type == :op || operators.last.type == :unary_op) && (_parse_op_prio(operators.last) > p || (_parse_op_prio(operators.last) == p && token.op != :pow && token.op != :positive && token.op != :negative))
|
||||||
_parse_make_op(operators, out_stack)
|
_parse_make_op(operators, out_stack)
|
||||||
end
|
end
|
||||||
operators.push(token)
|
operators.push(token)
|
||||||
@@ -128,7 +144,7 @@ module RubyAlgebra
|
|||||||
_parse_make_op(operators, out_stack)
|
_parse_make_op(operators, out_stack)
|
||||||
end
|
end
|
||||||
if operators.empty? || operators.last.type != :paren || operators.last.closing
|
if operators.empty? || operators.last.type != :paren || operators.last.closing
|
||||||
puts "Missing ( in expression"
|
raise Exception.new
|
||||||
else
|
else
|
||||||
operators.pop
|
operators.pop
|
||||||
end
|
end
|
||||||
@@ -138,17 +154,21 @@ module RubyAlgebra
|
|||||||
elsif token.type == :id
|
elsif token.type == :id
|
||||||
out_stack.push(Variable.new(token.name))
|
out_stack.push(Variable.new(token.name))
|
||||||
end
|
end
|
||||||
prev = token
|
|
||||||
end
|
end
|
||||||
out_stack[0]
|
out_stack[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def _parse_make_op(operators, out_stack)
|
def _parse_make_op(operators, out_stack)
|
||||||
oper = operators.pop
|
oper = operators.pop
|
||||||
raise Exception.new unless oper.type == :op
|
unless (oper.type == :op && out_stack.length >= 2) || (oper.type == :unary_op && out_stack.length >= 1)
|
||||||
raise Exception.new unless out_stack.length >= 2
|
raise Exception.new
|
||||||
b = out_stack.pop
|
end
|
||||||
|
b = out_stack.pop if oper.type == :op
|
||||||
a = out_stack.pop
|
a = out_stack.pop
|
||||||
|
|
||||||
|
puts "make unary op #{oper.op} from (#{a})" if oper.type == :unary_op
|
||||||
|
puts "make binary op #{oper.op} from (#{a}), (#{b})" if oper.type == :op
|
||||||
|
|
||||||
case oper.op
|
case oper.op
|
||||||
when :add
|
when :add
|
||||||
out_stack.push Addition.new(a, b)
|
out_stack.push Addition.new(a, b)
|
||||||
@@ -160,6 +180,10 @@ module RubyAlgebra
|
|||||||
out_stack.push Division.new(a, b)
|
out_stack.push Division.new(a, b)
|
||||||
when :pow
|
when :pow
|
||||||
out_stack.push Power.new(a, b)
|
out_stack.push Power.new(a, b)
|
||||||
|
when :positive
|
||||||
|
out_stack.push a
|
||||||
|
when :negative
|
||||||
|
out_stack.push Multiplication.new(Constant.new(-1), a)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -169,7 +193,7 @@ module RubyAlgebra
|
|||||||
1
|
1
|
||||||
when :mult, :div
|
when :mult, :div
|
||||||
2
|
2
|
||||||
when :pow
|
when :pow, :positive, :negative
|
||||||
3
|
3
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user