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