After trinking some coffee, I added functions and templates:

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, nil, [Object, String, false,
true]],
                    '*'     => [5],
                    '/'     => [5],
                    '%'     => [5],
                    '^'     => [5, nil, [String, Numeric, true,
false]],
                    '**'    => [5, nil, [String, Numeric, true,
false]],
                    'sqrt'  => [0, nil, [Object, true]],
                    'binom' => [5, '#{op}(#{val1}, #{val2})'],
        }
        @opnames = @ops.keys
    end

    def get_elt(op, idx=-1)
        val = @stack.delete_at(idx)
        case val
        when Array
            eop, val = val
        else
            eop = nil
        end
        if op and eop
            opp, *opatterns  = @ops[op]
            eopp, *epatterns = @ops[eop]
            if opp != 0 and eopp > opp
                return '(%s)' % val
            end
        end
        return val
    end

    def process
        @iqueue.each do |token|
            if @opnames.include?(token)
                op = token
                opp, fmt, *patterns  = @ops[op]
                if opp == 0
                    fmt ||= '#{op}#{val1}'
                    val1 = get_elt(token, -1)
                    patterns.each do |p1, e1|
                        if val1.kind_of?(p1)
                            val1 = '(%s)' % val1 if e1
                            break
                        end
                    end
                    @stack << [token, eval("\"#{fmt}\"")]
                else
                    fmt ||= '#{val1} #{op} #{val2}'
                    val1 = get_elt(token, -2)
                    val2 = get_elt(token, -1)
                    patterns.each do |p1, p2, e1, e2|
                        if val1.kind_of?(p1) and val2.kind_of?(p2)
                            val1 = '(%s)' % val1 if e1
                            val2 = '(%s)' % val2 if e2
                            break
                        end
                    end
                    @stack << [token, eval("\"#{fmt}\"")]
                end
            else
                @stack << eval(token)
            end
        end
        # The stack should include only one element here. A check
would
        # be necessary.
        get_elt(nil)
    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)'
    else
        puts Quiz148.run(ARGV)
    end
end