After studying Ruby, I made it like an interpreter that can perform four arithmetic operations.
Interpreter body
class Interpreter
def calc(code)
create_tokens(code)
exec(stmt)
end
private
def create_tokens(code)
@tokens = []
while !code.empty?
arr = [
[/^[0-9]+(\.[0-9]+)?/, "num"],
[/^[\+\-\*\/]/, "bin"],
[/^[()]/, "bra"],
[/^\;/, "semicolon"],
]
token = arr.map { |(regex, type)|
val = code[regex]
{ type: type, val: val } if !val.nil?
}.compact.first
if token.nil?
code.slice!(0)
else
@tokens << token
code.slice!(0...token[:val].length)
end
end
end
def stmt
child = [expr]
if @tokens.first[:type] == "semicolon"
item = @tokens.shift
child << stmt if [email protected]?
{ item: item, child: child }
end
end
def bin(filter, parse)
node = parse.call
while [email protected]? && filter.call(@tokens.first[:val])
node = { item: @tokens.shift, child: [node, parse.call] }
end
node
end
def expr
bin(-> (token) { token == "+" || token == "-" }, -> { term })
end
def term
bin(-> (token) { token == "*" || token == "/" }, -> { fact })
end
def fact
if @tokens.first[:val] == "("
@tokens.shift
node = expr
@tokens.shift if @tokens.first[:val] == ")"
node
else
{ item: @tokens.shift }
end
end
def exec(node)
type = node[:item][:type]
if type == "semicolon"
left, right = node[:child]
puts "#{exec(left)}"
exec(right) if !right.nil?
elsif type == "bin"
left, right = node[:child]
case node[:item][:val]
when "+"
exec(left) + exec(right)
when "-"
exec(left) - exec(right)
when "*"
exec(left) * exec(right)
when "/"
exec(left) / exec(right)
end
elsif type == "num"
node[:item][:val].to_f
end
end
end
Execution method
ip = Interpreter.new
ip.calc "12345679 * 8 + 0.1; 3.1415926535 * 2;"
ip.calc "18782+18782;"
Execution result
$ ruby interpreter.rb
98765432.1
6.283185307
37564.0
Ruby, multiple assignment is good. Lambda is also easy to write. I wanted to make it a little shorter (someone please).
Recommended Posts