3 Implementieren Sie einen einfachen Interpreter in Java

Einführung

In einem früheren Artikel habe ich eine Syntaxanalyse implementiert (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). Übrigens möchte ich damit einen einfachen Interpreter implementieren.

Was Sie mit dem Dolmetscher machen wollen

Bestätigen Sie, was Sie in der Implementierung tun möchten. Was ich mit dem Interpreter machen möchte, ist die Berechnung der programmatischen Zeichenfolge. Am Beispiel der folgenden Formel wollen wir schließlich "23" "a" zuweisen.

a = 3 + 4 * 5

Wie man rechnet

Lassen Sie uns überlegen, wie man berechnet. Ich habe den Ausdruck im vorherigen Artikel analysiert (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). Der syntaktisch analysierte Ausdruck wurde analysiert, so dass die Operator-Token "links" und "rechts" Werte hatten, die von diesem Operator berechnet wurden. Zum Beispiel ist im Ausdruck "6-7" das Operator-Token "-", "links" hat "6", "rechts" hat "7" und so weiter. Außerdem können "links" und "rechts" nicht nur Werte haben, sondern auch Formeln, die in der Berechnungsreihenfolge an erster Stelle stehen. Zum Beispiel hat der Ausdruck "3 + 4 * 5" das Operator-Token "+", "links" hat "3" und "rechts" hat "4 * 5". Da es eine solche Datenstruktur hat, gehen Sie zur Berechnung die Operator-Token "links" und "rechts" nach unten. Wenn Sie den Terminalbetreiber erreichen, berechnen Sie ihn. Basierend auf dem Berechnungsergebnis wird der nächsthöhere Operator berechnet. Sie können berechnen, indem Sie diesen Vorgang bis zum Anfang wiederholen. In der Formel "3 + 4 * 5" im vorherigen Beispiel ist der Terminaloperator "*" von "4 * 5", daher wird er mit "20" berechnet. Das Berechnungsergebnis wird verwendet, um den nächsthöheren Operator "+" zu berechnen. Da "links" "3" und "rechts" das Berechnungsergebnis "20" ist, wird es zu "23" addiert und die Berechnung ist abgeschlossen.

Versuchen Sie, in Java zu implementieren

Fahren Sie mit der Implementierung fort. Lassen Sie uns einen Teil der Implementierung des Interpreters betrachten.

Erstens ist der Initialisierungsteil. Empfängt die durch Syntaxanalyse analysierte Token-Liste. Berechnen Sie diese Token-Liste. Da der Interpreter einer Variablen entspricht, bereiten Sie eine Map vor, die den Variablennamen und seinen Wert enthält.

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;
    }

Dies ist eine Beschreibung des Teils, mit dem die Berechnung gestartet wird. run () berechnet den zuvor übergebenen Token-Liste body und gibt eine variable Map zurück, die das Berechnungsergebnis enthält.

Interpreter.java


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

Dies ist die Erklärung des zu berechnenden Teils. body () nimmt das Token für einen Ausdruck aus der zuvor übergebenen Token-Liste body und übergibt es an expression (), der den Ausdruck verarbeitet.

Interpreter.java


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

expression () ruft die Methoden auf, die je nach Bedeutung des Tokens jeweils verarbeitet werden, und gibt das Ergebnis unverändert zurück.

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 () nimmt ein numerisches Token und macht es zu 'Integer`.

Interpreter.java


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

var () empfängt das Token der Variablen und macht es zum Variablennamen. Wenn der Variablenname nicht in der Variablenzuordnung registriert ist, registrieren Sie den Wert mit "0".

Interpreter.java


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

assign () weist einer Variablen einen Wert zu.

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 () ist der Prozess vonassign ()und stellt sicher, dass das Ergebnis von expr.left der Variablenname ist.

Interpreter.java


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

value () wird zu einem numerischen Wert gemacht, der durch expr.right der Verarbeitung von assign () und der Verarbeitung der vier später beschriebenen Regeloperationen berechnet werden kann. Wenn das Argument "Wert" "Ganzzahl" ist, wird es unverändert zurückgegeben. Wenn es sich um "String" handelt, wird der Wert aus der Variablen "Map" abgerufen und zurückgegeben.

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 () führt vier Regeln aus.

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");
        }
    }

Unter Verwendung der obigen Implementierung die Zeichenfolge, die das Beispielprogramm ist

a = 3 + 4 * 5

Drucken Sie die Variablen und ihre Werte in die Standardausgabe.

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
    }
}

Das ist alles für die Implementierung. Vielen Dank.

abschließend

Die Quelle finden Sie hier.

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

Es gibt einen Folgeartikel.

** Println zum Interpreter hinzufügen ** http://qiita.com/quwahara/items/82067b00cbe1cb974e4a

Abschließend werde ich Ihnen eine Zusammenfassung der Dolmetscherklassen geben.

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 Implementieren Sie einen einfachen Interpreter in Java
2 Implementieren Sie eine einfache Syntaxanalyse in Java
Ein einfaches Beispiel für Rückrufe in Java
1 Implementieren Sie eine einfache Phrasenanalyse in Java
Implementieren Sie so etwas wie einen Stack in Java
Interpreter-Implementierung durch Java
Einfache HTML-Spezialchars in Java
Implementierung der zweistufigen Authentifizierung in Java
Implementieren Sie die Standardauthentifizierung in Java
Suchen Sie eine Teilmenge in Java
Implementieren Sie eine Kombination aus Mathematik in Java
[Java] Zeichnen Sie ein einfaches Muster
Implementieren Sie das Senden von E-Mails in Java
Implementieren Sie eine funktionsähnliche schnelle Sortierung in Java
Implementieren Sie rm -rf in Java.
Implementieren Sie die XML-Signatur in Java
Ich habe ein einfaches Berechnungsproblemspiel in Java gemacht
[Persönliches Memo] Erstellen Sie eine einfache, tiefe Kopie mit Java
Implementieren Sie Singleton mit Enum schnell in Java
Implementieren Sie einen tabellengesteuerten Test in Java 14
Sehr einfacher Eingangsempfang in Java
Ich habe ein PDF mit Java erstellt.
Implementieren Sie eine einfache Anmeldefunktion in Rails
Implementieren Sie reCAPTCHA v3 in Java / Spring
Implementieren Sie die PHP-Implodierungsfunktion in Java
Implementieren Sie den gRPC-Client in Ruby
Implementieren Sie ein Kontaktformular in Rails
Versuchen Sie, Yuma in Java zu implementieren
Bleiben Sie in einem Java Primer stecken
[Rails] Eine einfache Möglichkeit, eine Selbsteinführungsfunktion in Ihrem Profil zu implementieren
So implementieren Sie einen Job, der die Java-API in JobScheduler verwendet
Informationen zum Zurückgeben einer Referenz in einem Java Getter
Was ist eine Klasse in der Java-Sprache (3 /?)
Bei der Suche nach mehreren in einem Java-Array
So implementieren Sie den Kalman-Filter mit Java
Implementieren Sie API Gateway Lambda Authorizer in Java Lambda
Versuchen Sie, n-ary Addition in Java zu implementieren
[Erstellen] Ein Memorandum über das Codieren in Java
Java erstellt eine Tabelle in einem Word-Dokument
Java erstellt ein Kreisdiagramm in Excel
Was ist eine Klasse in der Java-Sprache (1 /?)
Was ist eine Klasse in der Java-Sprache (2 /?)
Erstellen Sie eine TODO-App in Java 7 Create Header
So erzwingen Sie Codierungskonventionen in Java
Lassen Sie uns eine Taschenrechner-App mit Java erstellen
Teilen Sie eine Zeichenfolge in Java mit ". (Dot)"
Erstellen einer Matrixklasse in Java Teil 1
Partisierung in Java
Änderungen in Java 11
Janken in Java
Umfangsrate in Java
FizzBuzz in Java
[Java] Implementieren Sie eine Funktion, die eine im Builder-Muster implementierte Klasse verwendet
GetInstance () aus einer @ Singleton-Klasse in Groovy aus Java
Zwei Möglichkeiten, einen Thread in Java + @ zu starten
Lesen Sie eine Zeichenfolge in einer PDF-Datei mit Java
Erstellen Sie eine CSR mit erweiterten Informationen in Java
Erstellen Sie mit Java + MySQL ein einfaches Bulletin Board
Implementieren Sie Benutzerverwaltungsfunktionen in einem Assistentenformat
Eine Geschichte über das JDK in der Java 11-Ära
So zeigen Sie eine Webseite in Java an