October 7, 2021 - Interpreter mode for design mode

Chapter 21: Interpreter Mode

1. Introduction to Modes

1) Compilation principle: an arithmetic expression forms lexical units through lexical parsers, which then construct a grammar analysis tree through a grammar parser, resulting in an abstract grammar analysis tree. Lexical parsers and grammar parsers can both be considered interpreters.

2) Interpreter mode: Given a language, define a representation of its grammar and define an interpreter that can be used to interpret expressions in a language.

3) Scenarios:

  • Some recurring problems can be expressed in a simple language (regular expressions)
  • Scenarios where a simple grammar needs to be interpreted (Operational Expression Calculations)
  • A sentence in a language that needs to be interpreted for execution is represented as an abstract grammar tree (compiler, interpreter, robot)

Basic Class Diagram:

  • Context: Contains global information outside the interpreter
  • AbstractExpression: An abstract expression that declares the interpreter behavior of an expression
  • TerminalExpression: The termination expression is the leaf node on the grammar analysis tree
  • NonTerminalExpression: A non-terminal expression, a non-leaf node in a grammar analysis tree

2. Actual Cases

The user enters an arithmetic expression, such as a + b + c. We need to implement an interpreter that can interpret this arithmetic expression.

Why do we need an Interpreter pattern to implement expression operations directly in a method?

Is scalability really that good?

Abstract expression class

public abstract class Expression {
    public abstract int interpreter(HashMap<String, Integer> vars);
}

Final expression

public class VarExpression extends Expression {
    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpreter(HashMap<String, Integer> vars) {
        return vars.get(this.key);
    }
}

Non-terminal expression

public class AddExpression extends SymbolExpression {
    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> vars) {
        return super.left.interpreter(vars) + super.right.interpreter(vars);
    }
}
public class SubExpression extends SymbolExpression {
    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> vars) {
        return super.left.interpreter(vars) - super.right.interpreter(vars);
    }
}

Calculator class (Generate parse tree)

public class Caculator {
    private Expression expression;

    public Caculator(String expStr) {
        Stack<Expression> stack = new Stack<>();
        Expression left = null;
        Expression right = null;
        for (int i = 0; i < expStr.length(); i++) {
            switch (expStr.charAt(i)) {
                case '+':
                    left = stack.pop();
                    right = new VarExpression(expStr.valueOf(expStr.charAt(++i)));
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(expStr.valueOf(expStr.charAt(++i)));
                    stack.push(new SubExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(expStr.valueOf(expStr.charAt(i))));
            }
        }
        this.expression = stack.pop();
    }

    public int run(HashMap<String, Integer> vars) {
        return expression.interpreter(vars);
    }
}

Test Class

public class InterpreterTest {
    public static void main(String[] args) {
        String expStr = "a + b - c";
        Caculator caculator = new Caculator(expStr);
        HashMap<String, Integer> vars = new HashMap<>();
        vars.put("a", 1);
        vars.put("b", 2);
        vars.put("c", 3);
        System.out.println(caculator.run(vars));
    }
}

3. Summary of Modes

Advantages: good scalability

Disadvantages: class expansion, complex debugging

Tags: Java Design Pattern regex compiler

Posted on Thu, 07 Oct 2021 13:00:34 -0400 by ledtear