I made an interpreter (compiler?) With about 80 lines in Ruby.

After studying Ruby, I made it like an interpreter that can perform four arithmetic operations.

code

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

Impressions

Ruby, multiple assignment is good. Lambda is also easy to write. I wanted to make it a little shorter (someone please).

Recommended Posts

I made an interpreter (compiler?) With about 80 lines in Ruby.
I made an annotation in Java.
I made an eco server with scala
I made a risky die with Ruby
I made blackjack with Ruby (I tried using minitest)
I made a Ruby extension library in C
I made a portfolio with Ruby On Rails
About eval in Ruby
I made an iPhone Theremin with Vision framework + AudioKit
I wrote about Java downcast in an easy-to-understand manner
[Ruby] I made a crawler with anemone and nokogiri.
I made an Android application that GETs with HTTP
I tried DI with Ruby
I want to push an app made with Rails 6 to GitHub
I made roulette in Java.
I made an adapter for communication class with Retrofit2 + Rx2
I updated my own blackjack made with Ruby for my portfolio
I searched for a web framework with Gem in Ruby
About regular expressions in Ruby
I checked with Ruby whether there is a Kaprekar number in an integer within a certain range
I tried to create an API to get data from a spreadsheet in Ruby (with service account)
[Ruby] I want to put an array in a variable. I want to convert to an array
I sent an email in Java
Ruby: I made a FizzBuzz program!
I made a GUI with Swing
About creating an application with springboot
[Super Introduction] About Symbols in Ruby
Run an application made with Java8 with Java6
Make Ruby segfault in two lines
I thought about an extension that can select the color of placeHolder in one shot with UITextFiled
CentOS8 doesn't have unar binaries so I made an alternative with bash
I made an app to scribble with PencilKit on a PDF file
I tried to solve the tribonacci sequence problem in Ruby, with recursion.
I thought about the best way to create a ValueObject in Ruby
I want to ForEach an array with a Lambda expression in Java
A story about an arithmetic overflow that you shouldn't encounter in Ruby
I tried a calendar problem in Ruby
Send an email from gmail with Ruby
[Ruby] I made a simple Ping client
I made various Fibonacci sequence functions (Ruby)
Methods that I found useful in Ruby
I made a rock-paper-scissors app with kotlin
I made a rock-paper-scissors app with android
I get an error when I try to use "^" or "$" in ruby ​​regular expression
A story about saving an image with carrierwave in a nested form using a form object.
[Ruby] Difference between methods with and without self in the class. About class methods and instance methods.