11 Corresponds to comparison and logical operators

Introduction

In the previous article, Supports if statements. Since there is no operator that can be specified in the conditional statement of the if statement, I would like to support it.

What you want to do with comparison operators and logical operators

Make sure you want to do it easily. For example, there is the following program. Since the inequality sign is correct on the first line, 1 representing the truth is output. Since the inequality sign with the equal sign is wrong on the second line, 0 indicating false is output. The third line outputs 1 because the result of the logical operation is true. In the example, it is only output, but it can be described as a conditional expression in the if statement.

println(10 > 1)
println(5 <= 1)
println(!(1 == 2) && (3 != 4))

How to implement

For the implementation method, see Implementation of parsing and Implementation of interpreter. Because of that Please refer to that because there is nothing new.

Try to implement in Java

Move on to implementation. About lexical analysis (Lexer), parser (Parser), interpreter (Interpreter) Let's take a look at the changes and additions in order.

Lexer.java

An implementation of Lexer.java. Corresponds to the added operator. Until now, all operators were one-letter, but it may be new that two-letter operators have also increased.

Lexer.java


    private boolean isSignStart(char c) {
        return c == '=' || c == '+' || c == '-' || c == '*' || c == '/' || c == '!' || c == '<' || c == '>' || c == '&'
                || c == '|';
    }

    private Token sign() throws Exception {
        Token t = new Token();
        t.kind = "sign";
        char c1 = next();
        char c2 = (char) 0;
        if (!isEOT()) {
            if (c1 == '=' || c1 == '!' || c1 == '<' || c1 == '>') {
                if (c() == '=') {
                    c2 = next();
                }
            } else if (c1 == '&') {
                if (c() == '&') {
                    c2 = next();
                }
            } else if (c1 == '|') {
                if (c() == '|') {
                    c2 = next();
                }
            }
        }
        String v;
        if (c2 == (char) 0) {
            v = Character.toString(c1);
        } else {
            v = Character.toString(c1) + Character.toString(c2);
        }
        t.value = v;
        return t;
    }

Parser.java

An implementation of Parser.java. Add a definition of how it works for the meaning of the token. A new operator has been added from <-Add. Since ! Is a unary operator, it is added 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); // <-- Add
        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[] { "+", "-", "!" });                 // <-- Update
        reserved = Arrays.asList(new String[] { "function", "return", "if", "else" });
    }

Interpreter.java

An implementation of Interpreter.java.

Since it is convenient for the method to judge whether the conditional expression is true, we added diversity by different argument types.

Interpreter.java


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

    public boolean isTrue(Integer value) throws Exception {
        return 0 != value;
    }

Truth values are represented by integers in this language, so prepare a method to convert the logical value type to an integer. True is converted to 1.

Interpreter.java


    public Integer toInteger(boolean b) {
        return b ? 1 : 0;
    }

A method that executes a unary operator. Added logical negation to <-Add.

Interpreter.java


    public Object unaryCalc(Token expr) throws Exception {
        Integer left = value(expression(expr.left));
        if (expr.value.equals("+")) {
            return left;
        } else if (expr.value.equals("-")) {
            return -left;
        } else if (expr.value.equals("!")) { // <-- Add
            return toInteger(!isTrue(left));
        } else {
            throw new Exception("Unknown sign for unary calc");
        }
    }

A method that executes a binary operator. From <-Add, we are adding a new arithmetic implementation.

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 if (expr.value.equals("==")) { // <-- Add
            return toInteger(left == right);
        } else if (expr.value.equals("!=")) {
            return toInteger(left != right);
        } else if (expr.value.equals("<")) {
            return toInteger(left < right);
        } else if (expr.value.equals("<=")) {
            return toInteger(left <= right);
        } else if (expr.value.equals(">")) {
            return toInteger(left > right);
        } else if (expr.value.equals(">=")) {
            return toInteger(left >= right);
        } else if (expr.value.equals("&&")) {
            return toInteger(isTrue(left) && isTrue(right));
        } else if (expr.value.equals("||")) {
            return toInteger(isTrue(left) || isTrue(right));
        } else {
            throw new Exception("Unknown sign for Calc");
        }
    }

The program below using the above implementation

println(10 > 1)
println(5 <= 1)
println(!(1 == 2) && (3 != 4))

Is executed, and 1, 0, and 1 are output to the standard output.

Interpreter.java


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

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-11-compare-r2/Calc/src/main/java

There is a continuation article.

** Corresponds to the while statement ** http://qiita.com/quwahara/items/36f6704ae9c756240068

Recommended Posts

11 Corresponds to comparison and logical operators
Comparison operators and conditionals
[Ruby] Boolean values ​​and logical operators
Things to keep in mind when combining if statements and logical operators
Corresponds to 17 arrays
Corresponds to Scope
Corresponds to 15 strings
8 Corresponds to multiple arguments
[Java] String comparison and && and ||
Evaluation of logical operators
10 Corresponds to if statement
[Ruby] Difficulty in refactoring logical operators (accuracy and readability)
14 Corresponds to function expressions
5 Corresponds to prioritizing parentheses
19 Corresponds to object creation
16 Corresponds to method invocation
Basic operators and operations
9 Corresponds to the return value
12 Corresponds to the while statement
Gradle to touch and remember
18 Corresponds to JSON-like object definitions
20 Corresponds to static method invocation