Skip to content

Instantly share code, notes, and snippets.

@nnabeyang
Last active May 8, 2017 04:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nnabeyang/ed7b373918ff4c6eb3ee52051fc2a9a9 to your computer and use it in GitHub Desktop.
Save nnabeyang/ed7b373918ff4c6eb3ee52051fc2a9a9 to your computer and use it in GitHub Desktop.
逆ポーランド記法の電卓
#usage: ruby main.rb
class Parser
def initialize
@stack = []
end
def parse(line)
scanner = Scanner.new(line)
while (token = scanner.next) do
add_token(token)
end
@stack.pop
end
def add_token(token)
token.append_to(@stack)
end
end
class Scanner
def initialize(line)
@buf = line.chomp.split(//)
@pos = 0
end
def peek
while is_space do
@pos += 1
end
(@buf.size > @pos)? token : nil
end
def next
v = peek; @pos = @e; v
end
private
def token
@e = @pos
if is_op
@e+=1
AST::Op.new(@buf[@e-1])
elsif is_number
while @buf.size > @pos && is_number(@e) do
@e+=1
end
AST::Num.new(@buf[@pos...@e].join)
else
raise "invalid expression: #{@buf.join}"
end
end
def is_space
@buf[@pos] == ' '
end
def is_number(pos=@pos)
/\d/.match(@buf[pos])
end
def is_op
/[\+\-\*]/.match(@buf[@pos])
end
end
module AST
class Exp
def initialize(l, op, r)
@l = l; @op = op; @r = r
end
def to_s
[@l, @r, @op].join(" ")
end
def append_to(stack)
stack.push(self)
end
def exec
case @op.to_s
when "+"; @l.exec + @r.exec
when "-"; @l.exec - @r.exec
when "*"; @l.exec * @r.exec
end
end
end
class Num
def initialize(v)
@v = v.to_i
end
def to_s; @v.to_s; end
def exec; @v; end
def append_to(stack)
stack.push(self)
end
end
class Op
def initialize(op)
@op = op
end
def to_s; @op.to_s; end
def append_to(stack)
r = stack.pop; l = stack.pop
stack.push(AST::Exp.new(l, self, r))
end
end
end
parser = Parser.new
DATA.each do |line|
prog = parser.parse(line)
puts "#{prog.to_s} = #{prog.exec}"
end
__END__
123 168 77 - +
11 7 * 6 +
15 7* 43 22 -+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment