Skip to content

Instantly share code, notes, and snippets.

@kyontan
Last active August 29, 2015 14:26
Show Gist options
  • Save kyontan/fa9fd8611d50bf6a0cd2 to your computer and use it in GitHub Desktop.
Save kyontan/fa9fd8611d50bf6a0cd2 to your computer and use it in GitHub Desktop.
逆ポーランド記法で計算するやつ
#!/usr/bin/env ruby
class Array
alias_method :top, :last
end
def eval_rpn(stack)
commands = {
"+": ->x, y { x + y },
"-": ->x, y { x - y },
"*": ->x, y { x * y },
"x": ->x, y { x * y },
"/": ->x, y { x / y },
"^": ->x, y { x ** y },
pow: ->x, y { x ** y },
sin: ->x { Math.sin x },
cos: ->x { Math.cos x },
tan: ->x { Math.tan x },
asin: ->x { Math.asin x },
acos: ->x { Math.acos x },
atan: ->x { Math.atan x },
sinh: ->x { Math.sinh x },
cosh: ->x { Math.cosh x },
tanh: ->x { Math.tanh x },
asinh: ->x { Math.asinh x },
acosh: ->x { Math.acosh x },
atanh: ->x { Math.atanh x },
exp: ->x { Math.exp x },
sqrt: ->x { Math.sqrt x },
cbrt: ->x { Math.cbrt x },
hypot: ->x, y { Math.hypot x, y },
gamma: ->x { Math.gamma x },
log: ->x, y { Math.log y, x },
log2: ->x { Math.log2 x },
log10: ->x { Math.log10 x },
rec: ->x { 1 / x.to_f },
pi: -> { Math::PI },
e: -> { Math::E },
}
sys_commands = {
p: ->stack { puts "{ #{stack.join(", ")} }" },
print: ->stack { puts "{ #{stack.join(", ")} }" },
help: ->stack { puts "defined commands: #{commands.keys.join(", ")}" },
}
while stack.size != 0
if stack.top.is_a? Numeric
break
end
unless stack.top.is_a? String # error
raise "member of stack must be Number or String"
end
command = stack.pop.to_sym
if proc = sys_commands[command]
proc.call(stack)
next
end
proc = commands[command]
if proc.nil?
raise "undefined command: #{command}"
elsif stack.size < proc.arity
raise "insufficient arguments of #{command} (expected #{proc.arity}, actual #{stack.size})"
end
arguments = stack.pop(proc.arity)
begin
stack << proc[*arguments]
rescue => e
puts "Error: #{e}"
stack += arguments
end
end
return stack
end
def parse(str)
if /^\d+(\.\d)?$/ === str
str.to_f
else
str.downcase
end
end
# main loop
stack = []
loop do
input = gets.strip
if input.length == 0
next
end
adding = []
if /\s/ === input
adding += input.split.map{|x| parse(x) }.reverse
else
adding << parse(input)
end
begin
until adding.empty?
stack << adding.pop
stack = eval_rpn(stack)
end
rescue => e
puts "Error: #{e}"
end
puts "Res: #{stack.top}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment