Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created May 11, 2011 07:32
Show Gist options
  • Save takehiko/966051 to your computer and use it in GitHub Desktop.
Save takehiko/966051 to your computer and use it in GitHub Desktop.
plus/minus/times/divide parser
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# plus/minus/times/divide parser
# by takehikom (http://d.hatena.ne.jp/takehikom/)
# ruby pmtd-parser.rb => 6÷2(1+2)=1
# ruby pmtd-parser.rb -t => 6÷2(1+2)=9
# ruby -d pmtd-parser.rb => ... 1
# ruby -d pmtd-parser.rb -t => ... 9
# ruby -d pmtd-parser.rb "6/2*(1+2)" => ... 9
# ruby -d pmtd-parser.rb -t "6/2*(1+2)" => ... 9
# see also: http://getnews.jp/archives/114382
if RUBY_VERSION < "1.9"
$KCODE = "u"
end
# http://raa.ruby-lang.org/project/syntax
# http://raa.ruby-lang.org/cache/syntax/syntax.rb
# http://jp.rubyist.net/magazine/?0008-RLR
require "./syntax.rb"
class PmtdParser
INF = +1.0/0
LOOP0 = 0..INF
LOOP1 = 1..INF
def initialize(opt_tw = false)
if opt_tw
op_muldiv = "*" | "/" | "×" | "÷" | " " | "・" | ""
else
op_muldiv = "*" | "/" | "×" | "÷"
end
# 式
@expr = Syntax::Pass.new()
# 数
@num = (("0".."9") * LOOP1).qualify{|x|
val = x.join.to_i()
debug_print("num", x, val)
val
}
# 括弧
@prim = @num.qualify{|x|
val = x
debug_print("prim_num", x, val)
val
} | ("(" + @expr + ")").qualify{|x|
val = x[1]
debug_print("prim_par", x, val)
val
}
# 連接(かけ算)
if opt_tw
@prim2 = @prim.qualify{|x|
val = x
debug_print("prim2_tw", x, val)
val
}
else
@prim2 = (@prim + ((" " | "・" | "") + @prim) * LOOP0).qualify{|x|
val = x[0]
x[1].each{|y|
val *= y[1]
}
debug_print("prim2", x, val)
val
}
end
# 符号処理を入れると,1+2が(「1(+2)」によって)2と評価されて
# しまうため,取り除いている.
# 乗除
@expr2 = (@prim2 + (op_muldiv + @prim2) * LOOP0).qualify{|x|
val = x[0]
x[1].each{|y|
case y[0]
when "*", "×", " ", "・", ""
val *= y[1]
when "/", "÷"
val /= y[1]
end
}
debug_print("expr2", x, val)
val
}
# 式(加減)
@expr << (@expr2 + (("+" | "-") + @expr2) * LOOP0).qualify{|x|
val = x[0]
x[1].each{|y|
case y[0]
when "+"
val += y[1]
when "-"
val -= y[1]
end
}
debug_print("expr", x, val)
val
}
end
def start(str)
print "#{str}="
puts if $DEBUG
p(@expr === RandomAccessStream.new(str))
end
def debug_print(name, x, val)
return unless $DEBUG
puts "#{name}: x=#{x.inspect}:#{x.class}, val=#{val}"
end
private :debug_print
end
if __FILE__ == $0
opt_tw = false
while /^-/ =~ ARGV[0]
if /t/ =~ ARGV[0]
opt_tw = true
end
ARGV.shift
end
PmtdParser.new(opt_tw).start(ARGV.shift || "6÷2(1+2)")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment