My solution is a bit different than all the ones I've seen so far.  I 
had no intention of writing an expression parser :-)  All it does is

1. Define a method (to_bc) to have a fixnum return its own bytecode
2. Redefine the array operators to return the appropriate bytecode 
representations
3. Add .to_bc after every number in the expression string

Here it is:

class Compiler
  def self.compile(str)
    
eval(str.gsub(/(\d+)([^\d])/,'\1.to_bc\2').gsub(/([^\d])(\d+)$/,'\1\2.to_bc'))
  end
end

class Fixnum
  def to_bc
    return (self >= 0 ? [1,self/256,self%256] : 
[1,(self+32768)/256+128,(self+32768)%256]) if self <= 32767 and self >= 
-32768
    res = [(24..30),(16..23),(8..15),(0..7)].map { |range| range.map { 
|x| self[x] } }.map { |byte| byte.inject_with_index(0) { |s,x,i| 
s+x*2**i } }
    ([2] << (self > 0 ? res[0] : res[0]+128) << res[1..3]).flatten
  end
end

class Array
  {:+ => 10, :- => 11, :* => 12, :** => 13, :/ => 14, :% => 15}.each do 
|op,opcode|
    define_method(op) { |x| self.concat(x).concat([opcode]) }
  end
  def inject_with_index(sum)
    each_with_index { |x,i| sum = yield(sum,x,i) }
    sum
  end
end