[JAVA] 12 Corresponds to the while statement

Introduction

In previous articles, Comparison and logical operators and Supports if statements )Did. I would like to support the while statement as an extension of that.

What you want to do with while statement support

Make sure you want to do it easily. For example, if you have a program like the one below Repeat with the while statement, skip the repetition when v becomes 2, and aim to output 2 withprintln ().

v = 0
while (v < 4) {
  v = v + 1
  if (v == 2) {
    break
  }
}
println(v)

How to implement

How to implement The implementation of the while statement is almost the same as correspondence of if statement. The implementation of the break statement is almost the same as Function return value support. So please refer to that for a detailed explanation and let's implement it immediately.

Try to implement in Java

Move on to implementation. About parser and interpreter Let's take a look at the changes and additions in order.

Parser.java

An implementation of Parser.java. Add a definition of how it works for the meaning of the token. Since while and break are reserved words, I added them to <-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("==", 40);
        degrees.put("!=", 40);
        degrees.put("<", 40);
        degrees.put("<=", 40);
        degrees.put(">", 40);
        degrees.put(">=", 40);
        degrees.put("&&", 30);
        degrees.put("||", 30);
        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", "while", "break"});  // <-- Update
    }

It is a change of the part to be analyzed. Added a call to the function that parses while to the first <-Add. Added the parsing of break to the second <-Add. The parsing of break is done by assigning to token.kind, determining the meaning of the token to brk.

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")) {
            return if_(token);
        } else if (token.kind.equals("ident") && token.value.equals("while")) { // <-- Add
            return while_(token);
        } else if (token.kind.equals("ident") && token.value.equals("break")) { // <-- Add
            token.kind = "brk";
            return 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.");
        }
    }

It is a change of the part to be analyzed. Added a method while_ () that parses while statements. As mentioned above, the analysis of the if statement is a simple explanation.

The analysis result of the while statement is summarized in the argument token.

The processing in the while_ () method is designed to trace the tokens in the while statement definition in order. First, assigning to token.kind determines the meaning of the token to while. Then it consumes the ( at the beginning of the conditional statement. The ʻexpression () method parses the conditional statement of the while statement and holds it in token.left. Then it consumes the end )` of the conditional statement.

Analysis of processing blocks. If there is a { at the beginning of the block, it is surrounded by {tokens and} tokens. Call the body () method that parses the processing block and hold it in token.block. If there is no { at the beginning of the block, it is considered that there is only one processing block and it is stored in token.block.

Parser.java


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

Interpreter.java

An implementation of Interpreter.java.

A change to the method body () that executes expressions sequentially.

Added boolean [] brk to the signature ofbody (). brk has two roles. The first is that if brk is not null, then break is possible. The second is that if it was break, it will be propagated to the caller as well. The reason for making brk an array type of boolean is to return a value to the caller.

At // <-Add 2, it is determined whether the token to be executed sequentially is break. If the token is break, determine if it is possible to break. Substitute true to tell the caller that it was break to brk.

Added a method call to process while statements to // <-Add 1. So that when return is called in the processing block of the while statement, it can return to the upper level. Determines if ret [0] is true and aborts thebody ()method.

Interpreter.java


    public Object body(List<Token> body, boolean[] ret, boolean[] brk) throws Exception {
        for (Token exprs : body) {
            if (exprs.kind.equals("if")) {
                Object val = if_(exprs, ret, brk);
                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 if (exprs.kind.equals("while")) { // <-- Add 1
                Object val = while_(exprs, ret);
                if (ret != null && ret[0]) {
                    return val;
                }
            } else if (exprs.kind.equals("brk")) { // <-- Add 2
                if (brk == null) {
                    throw new Exception("Can not break");
                }
                brk[0] = true;
                return null;
            } else {
                expression(exprs);
            }
        }
        return null;
    }

A while_ () method that executes a while statement. token.left holds the conditional expression. The ʻisTrue ()method determines if the conditional expression is true. Repeattoken.blockwhile the conditional expression is true. However, even if the conditional expression is true, in thebody ()method call, If it is areturn or break` token, the iteration will be interrupted.

Interpreter.java


    public Object while_(Token token, boolean[] ret) throws Exception {
        boolean[] brk = new boolean[1];
        Object val;
        while (isTrue(token.left)) {
            val = body(token.block, ret, brk);
            if (ret != null && ret[0]) {
                return val;
            }
            if (brk[0]) {
                return null;
            }
        }
        return null;
    }

Next is the response to changing the signature of the body () method.

Break may also be called in the if statement. Therefore, add a brk formal argument to the signature of the ʻif_ ()method, Pass it in the call to thebody ()` method.

Interpreter.java


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

This is a response to the change in the signature of the body () method.

In the call to the body () method in <-Update Because it is a process in a context where the break call cannot be made The argument brk of thebody ()method is called with null.

Interpreter.java


    public Map<String, Variable> run() throws Exception {
        body(body, null, null); // <-- Update
        return variables;
    }

    public static class DynamicFunc extends Func {

        public Interpreter context;
        public List<Token> params;
        public List<Token> block;

        @Override
        public Object invoke(List<Object> args) throws Exception {
            for (int i = 0; i < params.size(); ++i) {
                Token param = params.get(i);
                Variable v = context.variable(context.ident(param));
                if (i < args.size()) {
                    v.value = context.value(args.get(i));
                } else {
                    v.value = null;
                }
            }
            boolean[] ret = new boolean[1];
            return context.body(block, ret, null); // <-- Update
        }
    }

The program below using the above implementation

v = 0
while (v < 4) {
  v = v + 1
  if (v == 2) {
    break
  }
}
println(v)

To print 2 to standard output in sequence.

Interpreter.java


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

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

in conclusion

The full source is available here.

Calc https://github.com/quwahara/Calc/tree/article-12-while-r2/Calc/src/main/java

There is a continuation article.

** Corresponds to Scope ** http://qiita.com/quwahara/items/d9f932195da1b655b617

Recommended Posts

12 Corresponds to the while statement
10 Corresponds to if statement
Isn't the While statement evil?
9 Corresponds to the return value
Corresponds to 17 arrays
Corresponds to Scope
Corresponds to 15 strings
[Java] for statement, while statement
8 Corresponds to multiple arguments
14 Corresponds to function expressions
5 Corresponds to prioritizing parentheses
19 Corresponds to object creation
16 Corresponds to method invocation
# 3 [Note] do ~ while statement
I was addicted to looping the Update statement on MyBatis
18 Corresponds to JSON-like object definitions
Let's understand the if statement!
4 Add println to the interpreter
Let's understand the guard statement!
The idea of C # (lambda expression, for statement) to chew
[Ruby] Introduction to Ruby Error statement
[Java] [jackson] Corresponds to the trailing comma (trailing comma) when parsing JSON.
20 Corresponds to static method invocation
How to deal with the error ERROR: While executing gem ... (Gem :: FilePermissionError)
Let's understand the for-in statement!
Let's understand the switch statement!
I want to simplify the conditional if-else statement in Java
Input to the Java console
How to get the contents of Map using for statement Memorandum
How to use the link_to method
Add Extended Attributes to the file
About the language to be learned
How to use the include? method
11 Corresponds to comparison and logical operators
How to use the form_with method
Pass the i18n locale to JavaScript
[java8] To understand the Stream API
How to find the average angle
A story that I wanted to write a process equivalent to a while statement with the Stream API of Java8
How to use the wrapper class
Java learning memo (while statement, do-while statement)
I tried to explain the method
The story I wanted to unzip
Allow the TableView to scroll extra
Welcome to the Java Library Swamp! !!
How to add the delete function
The road from JavaScript to Java
[Ruby] I tried to diet the if statement code with the ternary operator
[Ruby basics] About the role of true and break in the while statement