From: tho_mica_l Date: 2007-12-03T03:25:02+09:00 Subject: Re: Postfix to Infix (#148) I'm sorry for spamming this list with my inferior solutions. But J Koppel's approach made me to reconsider my solution, which now supports custom output format (eg for Arrays), functions with 3+ arity, and functions for which the arity is defined by the last argument on the stack. Thomas. class Quiz148 class << self def run(args) iqueue = args.map {|e| e.split(/\s+/)}.flatten return Quiz148.new(iqueue).process end end def initialize(iqueue) @iqueue = iqueue @depth = 0 @stack = [] @ops = { '+' => [10], '-' => [10, 2, nil, [[Object, nil], [String, '(%s)']]], '*' => [5], '/' => [5], '%' => [5], '<<' => [3], '^' => [5, 2, nil, [[String, '(%s)'], [Numeric, nil]]], '**' => [5, 2, nil, [[String, '(%s)'], [Numeric, nil]]], 'sqrt' => [0, 1, '#{op}(#{vals})'], 'binom' => [0, 2, '#{op}(#{vals.join(\', \')})'], 'sum3' => [0, 3], 'Array' => [0, -1, '[#{vals.join(\', \')}]'], } @opnames = @ops.keys end def process @iqueue.each do |token| if @opnames.include?(token) op = token opp, arity, fmt, *patterns = @ops[op] case arity when -1 aop, arity = @stack.pop when nil arity = 2 end case arity when 1 fmt ||= '#{op}#{vals}' when 2 fmt ||= '#{vals.join(\' \' + op + \' \')}' else fmt ||= '#{op}(#{vals.join(\', \')})' end vals = (1..arity).inject([]) {|a, i| a << @stack.pop}.reverse idx = 0 vals.map! do |aop, val| if aop aopp, *aopatterns = @ops[aop] if opp > 0 and aopp > opp val = '(%s)' % val end end patterns.each do |pattern| p, e = pattern[idx] if (aop.nil? or aopp > 0) and val.kind_of?(p) if e val = e % val end break end end idx += 1 val end @stack << [op, eval("\"#{fmt}\"")] else @stack << [nil, eval(token)] end end # The stack should include only one element here. A check would # be necessary. o, v = @stack.pop v end end if __FILE__ == $0 if ARGV.empty? puts Quiz148.run('2 3 +') == '2 + 3' puts Quiz148.run('56 34 213.7 + * 678 -') == '56 * (34 + 213.7) - 678' puts Quiz148.run('1 56 35 + 16 9 - / +') == '1 + (56 + 35) / (16 - 9)' puts Quiz148.run('1 2 + 3 4 + +') == '1 + 2 + 3 + 4' puts Quiz148.run('1 2 - 3 4 - -') == '1 - 2 - (3 - 4)' puts Quiz148.run('1 3 4 - -') == '1 - (3 - 4)' puts Quiz148.run('2 2 ^ 2 ^') == '(2 ^ 2) ^ 2' puts Quiz148.run('2 2 2 ^ ^') == '2 ^ 2 ^ 2' puts Quiz148.run('2 sqrt 2 2 ^ ^') == 'sqrt(2) ^ 2 ^ 2' puts Quiz148.run('2 3 2 2 ^ ^ sqrt 3 + *') == '2 * (sqrt(3 ^ 2 ^ 2) + 3)' puts Quiz148.run('2 3 binom 2 2 ^ ^') == 'binom(2, 3) ^ 2 ^ 2' puts Quiz148.run('1 2 3 2 2 ^ ^ binom + 3 *') == '(1 + binom(2, 3 ^ 2 ^ 2)) * 3' puts Quiz148.run('2 3 2 2 ^ ^ binom') == 'binom(2, 3 ^ 2 ^ 2)' puts Quiz148.run('1 2 2 binom 3 2 ^ sum3') == 'sum3(1, binom(2, 2), 3 ^ 2)' puts Quiz148.run('1 2 2 binom 3 3 Array') == '[1, binom(2, 2), 3]' puts Quiz148.run('1 2 3 3 Array 4 <<') == '[1, 2, 3] << 4' puts Quiz148.run('1 2 3 3 Array 4 2 * <<') == '[1, 2, 3] << (4 * 2)' else puts Quiz148.run(ARGV) end end