3 Implémentez un interpréteur simple en Java

introduction

Dans un article précédent, j'ai implémenté une analyse de syntaxe (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). En passant, je voudrais l'utiliser pour implémenter un interpréteur simple.

Ce que vous voulez faire avec l'interprète

Confirmez ce que vous souhaitez faire lors de la mise en œuvre. Ce que je veux faire avec l'interpréteur est de calculer la chaîne de programmation. En prenant la formule suivante à titre d'exemple, nous visons à avoir finalement «23» assigné à «a».

a = 3 + 4 * 5

Comment calculer

Réfléchissons à la façon de calculer. J'ai analysé l'expression dans l'article précédent (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). L'expression syntaxiquement analysée a été analysée afin que les jetons d'opérateur «gauche» et «droite» aient les valeurs calculées par cet opérateur. Par exemple, dans l'expression «6-7», le jeton d'opérateur est «-», «gauche» a «6», «droite» a «7», et ainsi de suite. De plus, «gauche» et «droite» peuvent avoir non seulement des valeurs mais aussi des formules qui viennent en premier dans l'ordre de calcul. Par exemple, l'expression «3 + 4 * 5» a le jeton d'opérateur «+», «gauche» a «3» et «droite» a «4 * 5». Puisqu'il a une telle structure de données, afin de calculer, descendez les jetons d'opérateur «gauche» et «droite» dans l'ordre. Lorsque vous atteignez l'opérateur du terminal, calculez-le. Sur la base du résultat du calcul, l'opérateur immédiatement supérieur est calculé. Vous pouvez calculer en répétant cette opération jusqu'en haut. Dans la formule "3 + 4 * 5" de l'exemple précédent, l'opérateur du terminal est "*" de "4 * 5", donc il est calculé comme étant "20". Le résultat du calcul est utilisé pour calculer l'opérateur supérieur suivant «+». Puisque «gauche» est «3» et «droite» est le résultat du calcul «20», il est ajouté à «23» et le calcul est terminé.

Essayez de mettre en œuvre en Java

Passez à la mise en œuvre. Jetons un coup d'œil partiel à l'implémentation de l'interpréteur.

La première est la partie d'initialisation. Reçoit la liste de jetons analysée par l'analyse syntaxique. Calculez cette liste de jetons. De plus, puisque l'interpréteur correspond à une variable, préparez une carte contenant le nom de la variable et sa valeur.

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

Ceci est une description de la partie qui démarre le calcul. run () calcule le corps de la liste de jetons `passé plus tôt et renvoie une variable Map qui contient le résultat du calcul.

Interpreter.java


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

C'est l'explication de la pièce à calculer. body () prend le jeton pour une expression de la liste de jetons passée précédemment body et le passe à ʻexpression () `qui traite l'expression.

Interpreter.java


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

Selon la signification du jeton, ʻexpression () `appelle la méthode qui traite chacun et renvoie le résultat tel quel.

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 () prend un jeton numérique et le rend ʻInteger`.

Interpreter.java


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

var () reçoit le jeton de la variable et en fait le nom de la variable. Si le nom de la variable n'est pas enregistré dans la variable Map, enregistrez la valeur avec «0».

Interpreter.java


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

ʻAssign () `attribue une valeur à une 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 () est le processus de ʻassign () et confirme que le résultat de ʻexpr.left est le nom de la variable.

Interpreter.java


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

value () est adapté à une valeur qui peut être calculée par ʻexpr.rightdans le traitement de ʻassign ()et le traitement des quatre opérations de règles décrites plus loin. Si l'argument valeur est ʻInteger`, il est renvoyé tel quel. S'il s'agit de «String», la valeur est extraite de la variable Map et renvoyée.

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 () exécute quatre règles.

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

En utilisant l'implémentation ci-dessus, la chaîne de caractères qui est l'exemple de programme

a = 3 + 4 * 5

Et imprimez les variables et leurs valeurs sur la sortie standard.

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

C'est tout pour la mise en œuvre. Merci beaucoup.

en conclusion

La source est disponible ici.

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

Il y a un article de suite.

** Ajouter println à l'interpréteur ** http://qiita.com/quwahara/items/82067b00cbe1cb974e4a

Enfin, je vais vous donner un résumé des cours d'interprète.

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 Implémentez un interpréteur simple en Java
2 Implémentez une analyse syntaxique simple en Java
Un exemple simple de rappels en Java
1 Implémentez une analyse de phrase simple en Java
Implémenter quelque chose comme une pile en Java
Implémentation de l'interpréteur par Java
Simple htmlspecialchars en Java
Implémentation de l'authentification en deux étapes en Java
Implémenter l'authentification de base en Java
Rechercher un sous-ensemble en Java
Implémenter une combinaison de mathématiques en Java
[Java] Dessine un motif simple
Implémenter l'envoi d'e-mails en Java
Implémenter un tri rapide de type fonction en Java
Implémentez rm -rf en Java.
Implémenter la signature XML en Java
J'ai fait un jeu de problèmes de calcul simple en Java
[Mémo personnel] Créez une copie complète simple avec Java
Implémentez rapidement singleton avec enum en Java
Implémenter un test piloté par table dans Java 14
Réception d'entrée très simple en Java
J'ai créé un PDF avec Java.
Implémenter une fonction de connexion simple dans Rails
Implémenter reCAPTCHA v3 dans Java / Spring
Implémenter la fonction PHP implode en Java
Implémenter le client gRPC dans Ruby
Implémenter un formulaire de contact dans Rails
Essayez d'implémenter Yuma en Java
Restez coincé dans un Java Primer
[Rails] Un moyen simple d'implémenter une fonction d'auto-introduction dans votre profil
Comment implémenter un travail qui utilise l'API Java dans JobScheduler
A propos du renvoi d'une référence dans un Java Getter
Qu'est-ce qu'une classe en langage Java (3 /?)
Lors de la recherche de plusieurs dans un tableau Java
Comment implémenter le filtre de Kalman par Java
Implémenter l'autorisation API Gateway Lambda dans Java Lambda
Essayez d'implémenter l'ajout n-aire en Java
[Création] Un mémorandum sur le codage en Java
Java crée un tableau dans un document Word
Java crée un graphique circulaire dans Excel
Qu'est-ce qu'une classe en langage Java (1 /?)
Qu'est-ce qu'une classe en langage Java (2 /?)
Créer une application TODO dans Java 7 Créer un en-tête
Comment appliquer les conventions de codage en Java
Créons une application de calcul avec Java
Diviser une chaîne avec ". (Dot)" en Java
Création d'une classe de matrice dans Java Partie 1
Partition en Java
Changements dans Java 11
Janken à Java
Taux circonférentiel à Java
FizzBuzz en Java
[Java] Implémenter une fonction qui utilise une classe implémentée dans le modèle Builder
GetInstance () à partir d'une classe @Singleton dans Groovy à partir de Java
Deux façons de démarrer un thread en Java + @
Lire une chaîne dans un fichier PDF avec Java
Créer un CSR avec des informations étendues en Java
Créez un tableau d'affichage simple avec Java + MySQL
Mettre en œuvre des fonctions de gestion des utilisateurs dans un format d'assistant
Une histoire sur le JDK à l'ère de Java 11
Comment afficher une page Web en Java