3 Implement a simple interpreter in Java

Introduction

In a previous article, I implemented parsing (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). By the way, I would like to use it to implement a simple interpreter.

What you want to do with the interpreter

Confirm what you want to do in implementation. What we want to do with the interpreter is to calculate the programmed strings. Considering the following formula as an example, we aim to finally have 23 assigned to ʻa`.

a = 3 + 4 * 5

How to calculate

Now let's think about how to calculate. I parsed the expression in previous article. The parsed expression was parsed so that the operator tokens left and right have values calculated by that operator. For example, in the expression 6-7, the operator token is -, left has 6, right has 7, and so on. Also, left and right may have not only values but also formulas that come first in the calculation order. For example, the expression 3 + 4 * 5 has the operator token+, left has 3, and right has 4 * 5. Since it has such a data structure, in order to calculate, go down the operator tokens left and right in order. When you reach the terminal operator, calculate it. Based on the calculation result, the operator one level higher is calculated. Calculation can be performed by repeating this operation up to the top. In the formula 3 + 4 * 5 in the previous example, the terminal operator is*of 4 * 5, so it is calculated to be 20. The calculation result is used to calculate the operator + one level above. Since left is 3 and right is the calculation result 20, it is added to 23 and the calculation is completed.

Try to implement in Java

Move on to implementation. Let's take a look at the implementation of the interpreter.

First is the initialization part. Receives a list of tokens parsed by parsing. Calculate this token list. Also, since the interpreter corresponds to a variable, prepare a Map that holds the variable name and its value.

Interpreter.java


public class Interpreter {
    
    public Map<String, Integer> variables;
    List<Token> body;
    
    public Interpreter init(List<Token> body) {
        variables = new HashMap<>();
        this.body = body;
        return this;
    }

This is a description of the part that starts the calculation. run () calculates the token list body passed earlier and returns a variable Map that holds the calculation result.

Interpreter.java


    public Map<String, Integer> run() throws Exception {
        body(body);
        return variables;
    }

It is the explanation of the part to be calculated. body () takes the token for one expression from the token list body passed earlier and passes it to ʻexpression ()` that processes the expression.

Interpreter.java


    public void body(List<Token> body) throws Exception {
        for (Token exprs : body) {
            expression(exprs);
        }
    }

ʻExpression ()` calls the methods that process each token, depending on the meaning of the token, and returns the result as is.

Interpreter.java


    public Object expression(Token expr) throws Exception {
        if (expr.kind.equals("digit")) {
            return digit(expr);
        } else if (expr.kind.equals("variable")) {
            return var(expr);
        } else if (expr.kind.equals("sign") && expr.value.equals("=")) {
            return assign(expr);
        } else if (expr.kind.equals("sign")) {
            return calc(expr);
        } else {
            throw new Exception("Expression error");
        }
    }

digit () takes a numeric token and makes it ʻInteger`.

Interpreter.java


    public Integer digit(Token token) {
        return Integer.decode(token.value);
    }

var () takes the token of the variable and makes it the variable name. If the variable name is not registered in the variable Map, register the value with 0.

Interpreter.java


    public Object var(Token token) {
        String name = token.value;
        if (!variables.containsKey(name)) {
            variables.put(name, 0);
        }
        return name;
    }

ʻAssign ()` assigns a value to a variable.

Interpreter.java


    public String assign(Token expr) throws Exception {
        String name = variable(expression(expr.left));
        Integer value = value(expression(expr.right));
        variables.put(name, value);
        return name;
    }

variable () is the process of ʻassign () and makes sure that the result of ʻexpr.left is the variable name.

Interpreter.java


    public String variable(Object value) throws Exception {
        if (value instanceof String) {
            return (String) value;
        } else {
            throw new Exception("left value error");
        }
    }

value () is tailored to a numerical value that can be calculated by ʻexpr.right in the processing of ʻassign () and the processing of the four arithmetic operations described later. If the argument value is ʻInteger, it is returned as is. If it is String`, the value is fetched from the variable Map and returned.

Interpreter.java


    public Integer value(Object value) throws Exception {
        if (value instanceof Integer) {
            return (Integer) value;
        } else if (value instanceof String) {
            return variables.get((String) value);
        } else {
            throw new Exception("right value error");
        }
    }

calc () performs four arithmetic operations.

Interpreter.java


    public Object calc(Token expr) throws Exception {
        Integer left = value(expression(expr.left));
        Integer right = value(expression(expr.right));
        if (expr.value.equals("+")) {
            return left + right;
        } else if (expr.value.equals("-")) {
            return left - right;
        } else if (expr.value.equals("*")) {
            return left * right;
        } else if (expr.value.equals("/")) {
            return left / right;
        } else {
            throw new Exception("Unknown sign for Calc");
        }
    }

Using the above implementation, the string that is the example program

a = 3 + 4 * 5

And print the variable and its value to standard output.

Interpreter.java


    public static void main(String[] args) throws Exception {
        String text = "a = 3 + 4 * 5";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        Map<String, Integer> variables = new Interpreter().init(blk).run();
        for (Map.Entry<String, Integer> variable : variables.entrySet()) {
            System.out.println(variable.getKey() + " " + variable.getValue());
        }
        // --> a 23
    }
}

That's all for the implementation. Thank you very much.

in conclusion

The source is available here.

Calc https://github.com/quwahara/Calc/tree/article-3-interpreter/Calc/src/main/java

There is a continuation article.

** Add println to the interpreter ** http://qiita.com/quwahara/items/82067b00cbe1cb974e4a

Finally, I will give you a summary of the Interpreter classes.

Interpreter.java


import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Interpreter {

    public Map<String, Integer> variables;
    List<Token> body;

    public Interpreter init(List<Token> body) {
        variables = new HashMap<>();
        this.body = body;
        return this;
    }

    public Map<String, Integer> run() throws Exception {
        body(body);
        return variables;
    }

    public void body(List<Token> body) throws Exception {
        for (Token exprs : body) {
            expression(exprs);
        }
    }

    public Object expression(Token expr) throws Exception {
        if (expr.kind.equals("digit")) {
            return digit(expr);
        } else if (expr.kind.equals("variable")) {
            return var(expr);
        } else if (expr.kind.equals("sign") && expr.value.equals("=")) {
            return assign(expr);
        } else if (expr.kind.equals("sign")) {
            return calc(expr);
        } else {
            throw new Exception("Expression error");
        }
    }

    public Integer digit(Token token) {
        return Integer.decode(token.value);
    }

    public Object var(Token token) {
        String name = token.value;
        if (!variables.containsKey(name)) {
            variables.put(name, 0);
        }
        return name;
    }

    public String assign(Token expr) throws Exception {
        String name = variable(expression(expr.left));
        Integer value = value(expression(expr.right));
        variables.put(name, value);
        return name;
    }

    public String variable(Object value) throws Exception {
        if (value instanceof String) {
            return (String) value;
        } else {
            throw new Exception("left value error");
        }
    }

    public Integer value(Object value) throws Exception {
        if (value instanceof Integer) {
            return (Integer) value;
        } else if (value instanceof String) {
            return variables.get((String) value);
        } else {
            throw new Exception("right value error");
        }
    }

    public Object calc(Token expr) throws Exception {
        Integer left = value(expression(expr.left));
        Integer right = value(expression(expr.right));
        if (expr.value.equals("+")) {
            return left + right;
        } else if (expr.value.equals("-")) {
            return left - right;
        } else if (expr.value.equals("*")) {
            return left * right;
        } else if (expr.value.equals("/")) {
            return left / right;
        } else {
            throw new Exception("Unknown sign for Calc");
        }
    }

    public static void main(String[] args) throws Exception {
        String text = "a = 3 + 4 * 5";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        Map<String, Integer> variables = new Interpreter().init(blk).run();
        for (Map.Entry<String, Integer> variable : variables.entrySet()) {
            System.out.println(variable.getKey() + " " + variable.getValue());
        }
        // --> a 23
    }
}

Recommended Posts

3 Implement a simple interpreter in Java
2 Implement simple parsing in Java
A simple sample callback in Java
1 Implement simple lexical analysis in Java
Implement something like a stack in Java
Interpreter implementation in Java
Simple htmlspecialchars in Java
Implement two-step verification in Java
Implement Basic authentication in Java
Find a subset in Java
Implement math combinations in Java
[Java] Draw a simple pattern
Implement Email Sending in Java
Implement functional quicksort in Java
Implement rm -rf in Java.
Implement XML signature in Java
I made a simple calculation problem game in Java
[Personal memo] Make a simple deep copy in Java
Quickly implement a singleton with an enum in Java
Implement Table Driven Test in Java 14
Very simple input reception in Java
I created a PDF in Java.
Implement simple login function in Rails
Implement reCAPTCHA v3 in Java / Spring
Implement PHP implode function in Java
Implement a gRPC client in Ruby
Implement a contact form in Rails
Try to implement Yubaba in Java
Get stuck in a Java primer
[Rails] A simple way to implement a self-introduction function in your profile
How to implement a job that uses Java API in JobScheduler
About returning a reference in a Java Getter
What is a class in Java language (3 /?)
When seeking multiple in a Java array
How to implement Kalman filter in Java
Implement API Gateway Lambda Authorizer in Java Lambda
Try to implement n-ary addition in Java
[Creating] A memorandum about coding in Java
Java creates a table in a Word document
Java creates a pie chart in Excel
What is a class in Java language (1 /?)
What is a class in Java language (2 /?)
Create a TODO app in Java 7 Create Header
How to implement coding conventions in Java
Try making a calculator app in Java
Split a string with ". (Dot)" in Java
Creating a matrix class in Java Part 1
Partization in Java
Changes in Java 11
Rock-paper-scissors in Java
Pi in Java
FizzBuzz in Java
[Java] Implement a function that uses a class implemented in the Builder pattern
GetInstance () from a @Singleton class in Groovy from Java
Two ways to start a thread in Java + @
Read a string in a PDF file with Java
Create a CSR with extended information in Java
Create a simple bulletin board with Java + MySQL
Implement user management functions in a wizard format
A story about the JDK in the Java 11 era
How to display a web page in Java