Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created May 11, 2011 07:29
Show Gist options
  • Save takehiko/966047 to your computer and use it in GitHub Desktop.
Save takehiko/966047 to your computer and use it in GitHub Desktop.
plus/minus/times/divide parser (w/o Taiwanese-style calculation)
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# plus/minus/times/divide parser (w/o Taiwanese-style calculation)
# by takehikom (http://d.hatena.ne.jp/takehikom/)
# ruby pmtd-parser-no_tw.rb => 6÷2(1+2)=1
# ruby -d pmtd-parser-no_tw.rb => ... 1
# ruby -d pmtd-parser-no_tw.rb "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
# 式
@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
}
# 連接(かけ算)
@prim2 = (@prim + ((" " | "・" | "") + @prim) * LOOP0).qualify{|x|
val = x[0]
x[1].each{|y|
val *= y[1]
}
debug_print("prim2", x, val)
val
}
# 符号
@prim3 = @prim2.qualify{|x|
val = x
debug_print("prim3_num", x, val)
val
} | (("+" | "-") + @prim2).qualify{|x|
val = x[1]
val = -val if x[0] == "-"
debug_print("prim3_sign", x, val)
val
}
# 乗除
@expr2 = (@prim3 + (("*" | "/" | "×" | "÷") + @prim3) * 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
PmtdParser.new.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