[JAVA] 10 Correspond à l'instruction if

introduction

Correspondant à la valeur de retour de la fonction dans l'article précédent. Ensuite, je voudrais soutenir les déclarations if.

Ce que vous voulez faire avec la prise en charge des instructions if

Assurez-vous de vouloir le faire facilement. Par exemple, si vous avez un programme comme celui ci-dessous, le premier println () affichera 3. Le prochain println () vise à imprimer 4. Pour des raisons de simplicité, l'authenticité de l'instruction if est déterminée en supposant que non nul est vrai et 0 est faux.

function f(a) {
  if (a) {
    return 3
  } else {
    return 4
  }
}
println(f(1))
println(f(0))

Comment mettre en œuvre

Nous examinerons comment l'implémenter dans l'ordre de l'analyse syntaxique (Parser) et de l'interpréteur (Interpreter). L'analyse de phrase (Lexer) n'est pas modifiée.

Comment implémenter l'analyseur

Pour savoir comment implémenter l'analyse syntaxique de l'instruction if, voir [Analyse syntaxique de l'instruction de définition de fonction](http://qiita.com/quwahara/items/be71bac4b4359f5e6727#%E6%A7%8B%E6%96] implémentée dans l'article précédent. % 87% E8% A7% A3% E6% 9E% 90parser% E3% 81% AE% E5% AE% 9F% E8% A3% 85% E3% 81% AE% E4% BB% 95% E6% 96% B9 ) Est similaire. Puisqu'il y a un mot-clé «si» au début et que l'ordre d'apparition des jetons qui suivent est également décidé, les jetons sont tracés et analysés dans l'ordre.

Comment implémenter Interpreter

Dans l'interpréteur, la méthode body (), qui exécute les expressions séquentiellement Changer pour gérer les instructions if. C'est parce qu'il est facile à gérer quand il y a un return dans l'instruction if.

Essayez de mettre en œuvre en Java

Passez à la mise en œuvre. À propos de l'analyseur syntaxique (Parser) et de l'interpréteur (Interpreter) Jetons un coup d'œil aux modifications et aux ajouts dans l'ordre.

Parser.java

Une implémentation de Parser.java. Ajoutez une définition de la façon dont cela fonctionne pour la signification du jeton. Puisque ʻif et ʻelse sont des mots réservés, je les ai ajoutés là où il y a <-Update.

Parser.java


    public Parser() {
        degrees = new HashMap<>();
        degrees.put("(", 80);
        degrees.put("*", 60);
        degrees.put("/", 60);
        degrees.put("+", 50);
        degrees.put("-", 50);
        degrees.put("=", 10);
        factorKinds = Arrays.asList(new String[] { "digit", "ident" });
        binaryKinds = Arrays.asList(new String[] { "sign" });
        rightAssocs = Arrays.asList(new String[] { "=" });
        unaryOperators = Arrays.asList(new String[] { "+", "-" });
        reserved = Arrays.asList(new String[] { "function", "return", "if", "else" });  // <-- Update
    }

C'est un changement de pièce à analyser. Ajout d'un appel à la fonction qui analyse ʻif où se trouve le <-Add`.

Parser.java


    private Token lead(Token token) throws Exception {
        if (token.kind.equals("ident") && token.value.equals("function")) {
            return func(token);
        } else if (token.kind.equals("ident") && token.value.equals("return")) {
            token.kind = "ret";
            if (!token().kind.equals("eob")) {
                token.left = expression(0);
            }
            return token;
        } else if (token.kind.equals("ident") && token.value.equals("if")) {    // <-- Add
            return if_(token);
        } else if (factorKinds.contains(token.kind)) {
            return token;
        } else if (unaryOperators.contains(token.value)) {
            token.kind = "unary";
            token.left = expression(70);
            return token;
        } else if (token.kind.equals("paren") && token.value.equals("(")) {
            Token expr = expression(0);
            consume(")");
            return expr;
        } else {
            throw new Exception("The token cannot place there.");
        }
    }

C'est un changement de pièce à analyser. Ajout de la méthode ʻif_ () pour analyser les instructions if. Le résultat de l'analyse de l'instruction if est résumé dans le jeton d'argument. Pour résumer, nous ajoutons des variables de champ à la classe Token. La variable de champ ajoutée est blockOfElse. Ajouté pour contenir le bloc de traitement du côté ʻelse de l'instruction if. Le type est List \ <Token >.

Le traitement dans la méthode ʻif_ () trace les jetons dans la définition de l'instruction if dans l'ordre. Tout d'abord, l'assignation à token.kind détermine la signification du jeton à ʻif. Ensuite, il consomme le ( au début de l'instruction conditionnelle. La méthode ʻexpression () analyse l'instruction conditionnelle de l'instruction if et la conserve dans token.left. Ensuite, il consomme la fin )` de l'instruction conditionnelle.

Analyse des blocs de traitement. S'il y a un { au début du bloc, il est entouré d'un jeton { et d'un jeton }. Appelez la méthode body () qui analyse le bloc de traitement et maintenez-la dans token.block. S'il n'y a pas de { au début du bloc, on considère qu'il n'y a qu'un seul bloc de traitement et il est stocké dans token.block.

L'analyse du bloc de traitement de l'autre côté est presque la même.

Parser.java


    private Token if_(Token token) throws Exception {
        token.kind = "if";
        consume("(");
        token.left = expression(0);
        consume(")");
        if (token().value.equals("{")) {
            token.block = body();
        } else {
            token.block = new ArrayList<Token>();
            token.block.add(expression(0));
        }
        if (token().value.equals("else")) {
            consume("else");
            if (token().value.equals("{")) {
                token.blockOfElse = body();
            } else {
                token.blockOfElse = new ArrayList<Token>();
                token.blockOfElse.add(expression(0));
            }
        }
        return token;
    }

Analyse le bloc de traitement entouré par le jeton { et le jeton }. Même lorsque le bloc de traitement de la méthode func () est analysé Je faisais la même chose, alors je l'ai changé pour appeler cette méthode.

Parser.java


    private List<Token> body() throws Exception {
        consume("{");
        List<Token> block = block();
        consume("}");
        return block;
    }

Interpreter.java

Une implémentation d'Interpreter.java.

Ceci est une modification de la méthode body () qui exécute les expressions séquentiellement.

Ajout d'un appel de méthode pour traiter l'instruction if à // <-Add. Ainsi, si return est appelé dans le bloc de traitement de l'instruction if, il peut revenir au niveau supérieur. Détermine si ret [0] est true et abandonne la méthode body ().

Interpreter.java


    public Object body(List<Token> body, boolean[] ret) throws Exception {
        for (Token exprs : body) {
            if (exprs.kind.equals("if")) {      // <-- Add
                Object val = if_(exprs, ret);
                if (ret != null && ret[0]) {
                    return val;
                }
            } else if (exprs.kind.equals("ret")) {
                if (ret == null) {
                    throw new Exception("Can not return");
                }
                ret[0] = true;
                if (exprs.left == null) {
                    return null;
                } else {
                    return expression(exprs.left);
                }
            } else {
                expression(exprs);
            }
        }
        return null;
    }

La méthode ʻif_ () qui exécute l'instruction if. token.leftcontient l'expression conditionnelle. La méthode ʻisTrue ()détermine si l'expression conditionnelle est vraie. Si l'expression conditionnelle est vraie, exécutez token.block. Si faux, exécutez token.blockOfElse.

Interpreter.java


    public Object if_(Token token, boolean[] ret) throws Exception {
        List<Token> block;
        if (isTrue(token.left)) {
            block = token.block;
        } else {
            block = token.blockOfElse;
        }
        if (block != null) {
            return body(block, ret);
        } else {
            return null;
        }
    }

    public boolean isTrue(Token token) throws Exception {
        return 0 != value(expression(token));
    }

Le programme ci-dessous utilisant l'implémentation ci-dessus

function f(a) {
  if (a) {
    return 3
  } else {
    return 4
  }
}
println(f(1))
println(f(0))

Pour imprimer «3» et «4» sur la sortie standard en séquence.

Interpreter.java


    public static void main(String[] args) throws Exception {
        String text = "";
        text += "function f(a) {";
        text += "  if (a) {";
        text += "    return 3";
        text += "  } else {";
        text += "    return 4";
        text += "  }";
        text += "}";
        text += "println(f(1))";
        text += "println(f(0))";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        new Interpreter().init(blk).run();
        // --> 3
        // --> 4
    }

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

en conclusion

La source complète est disponible ici.

Calc https://github.com/quwahara/Calc/tree/article-10-if-r2/Calc/src/main/java

Il y a un article de suite.

** Correspond à la comparaison et aux opérateurs logiques ** http://qiita.com/quwahara/items/162d01c5af7c69cfa0ed

Recommended Posts

10 Correspond à l'instruction if
12 Correspond à l'instruction while
if déclaration
17 Correspond à un tableau
Correspond à la portée
Correspond à 15 chaînes
8 Correspond à plusieurs arguments
Comment écrire une instruction if pour améliorer la lisibilité-java
Étude de l'instruction Java-Part 10-if
14 Correspond à une expression de fonction
5 Correspond aux parenthèses prioritaires
19 Correspond à la création d'objet
16 Correspond à l'invocation de méthode
Si Pikachu compte jusqu'à 100
À propos de l'instruction et de l'instruction if
9 Correspond à la valeur de retour
18 Correspond à la définition d'objet de type JSON
Points pour la refactorisation (si instruction)
20 Correspond aux appels de méthode statiques
[Ruby] problème avec l'instruction if
11 Correspond aux opérateurs de comparaison et logiques
Étude de Java # 4 (branchement conditionnel / instruction if)
Traitement des relevés et des succursales
à_ ○
[Introduction à Java] Branchement conditionnel (instruction if, instruction if-else, instruction else if, opérateur ternaire, instruction switch)
Si vous osez comparer Integer avec "==" ...
Java, instruction if / instruction switch à partir du débutant