9 Corresponds to the return value

Introduction

In the previous article, Support multiple arguments. I would like to continue to correspond to the return value of the function.

What you want to do with the return value of the function

Make sure you want to do it easily. For example, if you have a program like the one below, the return value of the ʻadd3 ()function call is returned and assigned to the variablev. We aim to output the value 6 of the variable v` to the standard output.

function add3(a1, a2, a3) {
  return a1 + a2 + a3
}
v = add3(1,2,3)
println(v)

It's still the previous article that it doesn't correspond to variable scope.

How to implement

We will consider how to implement it in the order of parser and interpreter. Lexical analysis (Lexer) is not changed.

How to implement parsing

In implementing the parsing of return, you need to be careful about the syntax of return. The syntax of return may be a return value, such as return 1. In some cases, only return is specified and no return value is specified. If only return is syntactically correct, When return 1 is written, It can be taken as the syntax when a return value is specified, Considering that 1 is a syntax independent of return, It can also be used when no return value is specified. To easily solve this situation, we will take a sloppy approach. The method is when the } token comes after the return token, It is regarded as return if no return value is specified. On the contrary, if the } token does not come, it is regarded as return when the return value is specified. Parsing when no return value is specified is treated in the same way as a variable name. Parsing when a return value is specified is treated the same as a unary operator such as -1.

How to implement the Interpreter

The interpreter makes changes to the method body (), which executes expressions sequentially. If it is a return token inbody (), Suspends sequential execution and returns to the caller. Also, return can only be called inside a function. It also determines if it is a return call within the function.

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 return is a reserved word, I added return where there is <-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" });    // <-- Update
    }

It is a change of the part to be analyzed. Added an if statement that parses return to where <-Add exists. Unless the token next to the return token is ʻeob, which represents the type of closing brace. Judges as a return that returns a value, and holds the token that will be the return value in the left` field.

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")) {    // <-- Add
            token.kind = "ret";
            if (!token().kind.equals("eob")) {
                token.left = expression(0);
            }
            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.");
        }
    }

Interpreter.java

An implementation of Interpreter.java.

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

body () was a void type that does not return a return value, but I changed it to a ʻObjecttype so that it can return a return value. Addedboolean [] ret to the signature of body () . rethas two roles. The first is that ifret is not null, then returnis possible. The second is that if it wasreturn, it would propagate to the caller that it was return. The reason for making ret an array type of booleanis to return a value to the caller. It is used in an evil way, not for the purpose of using the original array. I wanted to make it easier to work like an argument with theref` keyword in C #.

The first thing in for is to determine if the token to be executed sequentially is return. If it is not return, it is the same process as the previousbody (). If it is return, it is judged whether it is possible to return. Substitute true to tell the caller that it was to return to ret. If there is a return value return, execute the token that is the return value with ʻexpression ()`.

Interpreter.java


    public Object body(List<Token> body, boolean[] ret) throws Exception {
        for (Token exprs : body) {
            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;
    }

This is a modification of the ʻinvoke ()method of theDynamicFuncclass. <-Updateis the change. It corresponds to the signature of thebody ()method and the change of the return value. You can assign an instance to the argumentret to indicate that you can return. The return value of body () is used as it is as the return value of ʻinvoke ().

Interpreter.java


    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]; // <-- Update
            return context.body(block, ret); // <-- Update
        }
    }

This is a modification of the run () method. <-Update is the change. It corresponds to the signature of the body () method and the change of the return value. The situation where run () is called is not inside the function. Since the situation cannot be return, the formal argument ret specifies null.

Interpreter.java


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

The program below using the above implementation

function add3(a1, a2, a3) {
  return a1 + a2 + a3
}
v = add3(1,2,3)
println(v)

To print the value 6 assigned to the variable v to the standard output.

Interpreter.java


    public static void main(String[] args) throws Exception {
        String text = "";
        text += "function add3(a1, a2, a3) {";
        text += "  return a1 + a2 + a3";
        text += "}";
        text += "v = add3(1,2,3)";
        text += "println(v)";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        new Interpreter().init(blk).run();
        // --> 6
    }

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-9-return-r2/Calc/src/main/java

There is a continuation article.

** Corresponds to if statement ** http://qiita.com/quwahara/items/96a68cdee4f2a0452836

Recommended Posts

9 Corresponds to the return value
12 Corresponds to the while statement
[Rails] Talk about paying attention to the return value of where
Ruby methods return the last evaluated value
How to pass the value to another screen
Corresponds to 17 arrays
Corresponds to Scope
Corresponds to 15 strings
How to return a value from Model to Controller using the [Swift5] protocol
Store the AWS SDK return value in DynamoDB
I want to get the value in Ruby
8 Corresponds to multiple arguments
10 Corresponds to if statement
14 Corresponds to function expressions
5 Corresponds to prioritizing parentheses
19 Corresponds to object creation
16 Corresponds to method invocation
Try Java return value
How to return to the previous screen by Swipe operation
[Java] How to get the maximum value of HashMap
I want to return the scroll position of UITableView!
When inserting from Java to MySQL, get Auto_Increment_ID (automatic numbering value) as the return value
Pass arguments to the method and receive the result of the operation as a return value
Let the code speak rather than comment (Maybe return value)
How to use Ruby return
18 Corresponds to JSON-like object definitions
How to specify an array in the return value / argument of the method in the CORBA IDL file
How to retrieve the hash value in an array in Ruby
4 Add println to the interpreter
Git How to easily return to the state before the change (before commit)
Create a method to return the tax rate in Java
[Java] [jackson] Corresponds to the trailing comma (trailing comma) when parsing JSON.
How to change the setting value of Springboot Hikari CP
20 Corresponds to static method invocation
Send the accelerometer value from Android to PC via UDP
I want to return multiple return values for the input argument
Input to the Java console
I want to return to the previous screen with kotlin and java!
How to display 0 on the left side of the standard input value
The return specification of compareTo can afford without going to the reference
How to output the value when there is an array in the array
Replace with a value according to the match with a Java regular expression
[Rails] Read the RSS of the site and return the contents to the front
I want to change the value of Attribute in Selenium of Ruby
How to increment the value of Map in one line in Java
Add Extended Attributes to the file
About the language to be learned
11 Corresponds to comparison and logical operators
Dynamically switch the database to connect to
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
How to use the wrapper class
I tried to explain the method
[Ruby] How to use is_a? Differences from kind_of? and instance_of ?. How to check the type and return a boolean value.
The story I wanted to unzip
Allow the TableView to scroll extra
Welcome to the Java Library Swamp! !!
How to return Rails API mode to Rails
How to add the delete function