【问题标题】:Implementing operator precedence in my calculator interpreter在我的计算器解释器中实现运算符优先级
【发布时间】:2016-07-31 07:59:10
【问题描述】:

作为学习 Ruby 的一部分,我正在尝试实现一个基本的解释器,它可以读取输入并进行基本的算术计算。到目前为止,基本的算术运算都在工作,但在运算符优先级方面存在问题。尚未处理。这是代码。我处于初学者水平。这段代码中的任何错误都是由于我缺乏知识。如何修改此代码以处理运算符优先级。 样本输出

2+2+2 = 6 #correct
10+10/2 = 10 # incorrect as in irb answer must be 15

Github Repo of this interpreter

=begin
Basic calculator Interpreter
can add, substract, multiply , divide with any number of operands at a time
Drawback : Lacks operator precedence
=end
class Interpreter   
    attr_accessor :input
    def initialize
        @input = gets.chomp             
    end 
    def intepret        
        first_operand  = []     
        f              = []     
        operator       = '+'        
        array          = Array.new      
        lc             = 0

        @input.split.join.split("").each_with_index.map do |i, index|

            if i.is_number?
                first_operand.push(i)   
                if index == @input.length-1                     
                    array.push(first_operand.join("").to_i)                 
                end
            elsif i.is_plus?                
                f = first_operand
                first_operand = nil
                first_operand = []              
                array.push(f.join("").to_i)
                array.push("+")
            elsif i.is_minus?           
                f = first_operand
                first_operand = nil
                first_operand = []              
                operator = '-'              
                array.push(f.join("").to_i)
                array.push("-")
            elsif i.is_multi?               
                f = first_operand
                first_operand = nil
                first_operand = []              
                operator = '*'              
                array.push(f.join("").to_i)
                array.push("*")
            elsif i.is_divide?              
                f = first_operand
                first_operand = nil
                first_operand = []              
                operator = '/'              
                array.push(f.join("").to_i)
                array.push("/")
            else
                puts "Illegal input exiting.."
                exit            
            end             

            lc = lc+1

        end     
        #apply the appropriate operation on the inputs based on the operand         
        #puts "=======TOKENS======"     
        #puts array.inspect 
        result = 0
        array.each_with_index.map do |x, key|
            result = x if key == 0          
            if x == '+'
                if key == 0 
                    result = add(result, array[key+1])
                else
                    result = add(result, array [key+1])
                end
            elsif x == '-'
                if key == 0 
                    result = minus(result, array[key+1])
                else
                    result = minus(result, array [key+1])
                end
            elsif x == '*'
                if key == 0 
                    result = multi(result, array[key+1])
                else
                    result = multi(result, array [key+1])
                end 
            elsif x == '/'
                begin
                    if key == 0 
                        result = divide(result, array[key+1])
                    else
                        result = divide(result, array [key+1])
                    end 
                rescue
                    puts "Zero Divsion error"
                    exit
                end  
            end 
        end
        puts "Result is: "+result.to_s
    end 
    def print_token(type, value)
        puts type + ' '+ value
    end
    def add(f,s)
        return f.to_i + s.to_i
    end
    def minus(f,s)
        return f.to_i - s.to_i
    end
    def multi(f,s)
        return f.to_i * s.to_i
    end
    def divide(f,s)
        return f.to_i / s.to_i
    end
end
# Override the string class, to directly use methods like obj.is_number? rather than is_number?(obj)
class String
  def is_number?
    true if Float(self) rescue false
  end
  def is_plus?
    true if self == '+' rescue false
  end
  def is_minus?
    true if self == '-' rescue false
  end
  def is_multi?
    true if self == '*' rescue false
  end
  def is_divide?
    true if self == '/' rescue false
  end
end
#continue accepting inputs until exit CTRL + D
while true
    print 'pck>:'
    i_obj = Interpreter.new
    i_obj.intepret
end

【问题讨论】:

  • 你所有的字符串查询方法,除了is_number?,都可以简化为self == 'operator',因为它们不会报错,你可以安全地删除rescue
  • @SilverPhoenix 感谢您的帮助,但这并不能回答我的问题。

标签: ruby interpreter operator-precedence


【解决方案1】:

首先,使用Shunting-yard algorithm 处理输入。这应该在Reverse Polish notation (RPN) 中给出一个令牌列表。然后您可以评估 RPN 表达式。

【讨论】:

    猜你喜欢
    • 2018-04-12
    • 1970-01-01
    • 2012-07-17
    • 2014-01-30
    • 1970-01-01
    • 2015-07-09
    • 2014-09-09
    • 1970-01-01
    • 2011-10-14
    相关资源
    最近更新 更多