[JAVA] 10 Entspricht der if-Anweisung

Einführung

Entspricht dem Rückgabewert der Funktion im vorherigen Artikel. Als nächstes möchte ich if-Aussagen unterstützen.

Was möchten Sie mit if-Anweisungsunterstützung tun?

Stellen Sie sicher, dass Sie es einfach machen möchten. Wenn Sie beispielsweise ein Programm wie das folgende haben, gibt das erste println () 3 aus. Das nächste "println ()" zielt darauf ab, "4" zu drucken. Der Einfachheit halber wird die Authentizität der if-Anweisung bestimmt, indem angenommen wird, dass Nicht-Null wahr und 0 falsch ist.

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

Wie zu implementieren

Wir werden überlegen, wie es in der Reihenfolge Syntaxanalyse (Parser) und Interpreter (Interpreter) implementiert werden kann. Die Phrasenanalyse (Lexer) wird nicht geändert.

So implementieren Sie Parser

Informationen zum Implementieren der Syntaxanalyse der if-Anweisung finden Sie unter Syntaxanalyse der Funktionsdefinitionsanweisung, die im vorherigen Artikel implementiert wurde. % 87% E8% A7% A3% E6% 9E% 90 Parser% E3% 81% AE% E5% AE% 9F% E8% A3% 85% E3% 81% AE% E4% BB% 95% E6% 96% B9 ) Ist ähnlich. Da am Anfang ein Schlüsselwort "if" steht und auch die Reihenfolge des Auftretens der darauf folgenden Token festgelegt wird, werden die Token nacheinander verfolgt und analysiert.

So implementieren Sie Interpreter

Im Interpreter wird die Methode body (), die Ausdrücke nacheinander ausführt, Ändern Sie, um if-Anweisungen zu behandeln. Dies liegt daran, dass es einfach zu handhaben ist, wenn die if-Anweisung ein "return" enthält.

Versuchen Sie, in Java zu implementieren

Fahren Sie mit der Implementierung fort. Informationen zu Syntaxparser (Parser) und Interpreter (Interpreter) Schauen wir uns die Änderungen und Ergänzungen der Reihe nach an.

Parser.java

Eine Implementierung von Parser.java. Fügen Sie eine Definition hinzu, wie es für die Bedeutung des Tokens funktioniert. Da "if" und "else" reservierte Wörter sind, habe ich sie dort hinzugefügt, wo "<-Update" steht.

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
    }

Es ist eine Änderung des zu analysierenden Teils. Es wurde ein Aufruf für die Funktion hinzugefügt, die "if" analysiert, wobei "<-Add" ist.

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

Es ist eine Änderung des zu analysierenden Teils. Methode if_ () hinzugefügt, um if-Anweisungen zu analysieren. Das Analyseergebnis der if-Anweisung wird im Argument-Token zusammengefasst. Zusammenfassend fügen wir der Token-Klasse Feldvariablen hinzu. Die hinzugefügte Feldvariable ist "blockOfElse". Hinzugefügt, um den Verarbeitungsblock auf der Seite "else" der if-Anweisung zu halten. Der Typ ist List \ <Token >.

Die Verarbeitung in der if_ () -Methode verfolgt die Token in der if-Anweisungsdefinition der Reihe nach. Erstens bestimmt die Zuweisung zu "token.kind" die Bedeutung des Tokens zu "if". Dann verbraucht es das ( am Anfang der bedingten Anweisung. Die Methode expression () analysiert die bedingte Anweisung der if-Anweisung und hält sie in token.left. Dann verbraucht es das Ende ) der bedingten Anweisung.

Analyse von Verarbeitungsblöcken. Wenn sich am Anfang des Blocks ein { befindet, ist es von einem { Token und einem } Token umgeben. Rufen Sie die body () Methode auf, die den Verarbeitungsblock analysiert, und halten Sie ihn in token.block. Wenn am Anfang des Blocks kein "{" steht, wird davon ausgegangen, dass es nur einen Verarbeitungsblock gibt, der in "token.block" gespeichert ist.

Die Analyse des Verarbeitungsblocks auf der anderen Seite ist fast dieselbe.

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

Analysiert den Verarbeitungsblock, der vom Token "{" und vom Token "}" eingeschlossen ist. Auch dort, wo der Verarbeitungsblock der Methode func () analysiert wird Ich habe das Gleiche getan, also habe ich es geändert, um diese Methode aufzurufen.

Parser.java


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

Interpreter.java

Eine Implementierung von Interpreter.java.

Dies ist eine Änderung der Methode body (), die Ausdrücke nacheinander ausführt.

Es wurde ein Methodenaufruf zur Verarbeitung der if-Anweisung zu // <-Add hinzugefügt. Wenn also "return" im Verarbeitungsblock der if-Anweisung aufgerufen wird, kann es zur oberen Ebene zurückkehren. Bestimmt, ob "ret [0]" "true" ist, und bricht die "body ()" - Methode ab.

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

Die if_ () Methode, die die if-Anweisung ausführt. token.left enthält den bedingten Ausdruck. Die Methode isTrue () bestimmt, ob der bedingte Ausdruck wahr ist. Wenn der bedingte Ausdruck wahr ist, führen Sie "token.block" aus. Wenn false, führen Sie token.blockOfElse aus.

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

Das folgende Programm verwendet die obige Implementierung

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

Drucken von "3" und "4" nacheinander auf die Standardausgabe.

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
    }

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

abschließend

Die vollständige Quelle finden Sie hier.

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

Es gibt einen Folgeartikel.

** Entspricht Vergleichs- und logischen Operatoren ** http://qiita.com/quwahara/items/162d01c5af7c69cfa0ed

Recommended Posts

10 Entspricht der if-Anweisung
12 Entspricht der while-Anweisung
if-Anweisung
17 Entspricht einem Array
Entspricht dem Geltungsbereich
Entspricht 15 Zeichenfolgen
8 Entspricht mehreren Argumenten
Wie schreibe ich eine if-Anweisung, um die Lesbarkeit von Java zu verbessern?
Studieren der Java-Part 10-if-Anweisung
14 Entspricht einem Funktionsausdruck
5 Entspricht priorisierten Klammern
19 Entspricht der Objekterstellung
16 Entspricht dem Methodenaufruf
Wenn Pikachu bis zu 100 zählt
Über für Anweisung und wenn Anweisung
9 Entspricht dem Rückgabewert
18 Entspricht der JSON-ähnlichen Objektdefinition
Punkte für das Refactoring (if-Anweisung)
20 Entspricht statischen Methodenaufrufen
[Ruby] Problem mit der if-Anweisung
11 Entspricht Vergleichs- und logischen Operatoren
Java # 4 studieren (bedingte Verzweigung / if-Anweisung)
If-Anweisung und Verzweigungsverarbeitung
to_ ○
[Einführung in Java] Bedingte Verzweigung (if-Anweisung, if-else-Anweisung, else if-Anweisung, ternärer Operator, switch-Anweisung)
Wenn Sie es wagen, Integer mit "==" zu vergleichen ...
Java, if-Anweisung / switch-Anweisung ab Anfänger