一、解释器模式基本介绍

  1、基本介绍

    (1)在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器。

    (2)解释器模式(Interpreter Pattern):是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式);

    (3)应用场景

      ① 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;

      ② 一些重复出现的问题可以用一种简单的语言来表达;

      ③ 一个简单语法需要解释的场景;

    (4)这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等;

  2、原理类图

    

 

     对原理类图的说明——即(解释器模式的角色及职责)

    (1)Context:是环境角色,含有解释器之外的全局信息;

    (2)AbstractExpression:抽象表达式,声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享;

    (3)TerminalExpression:为终结符表达式,实现与文法中的终结符相关的解释操作;

    (4)NonTerminalExpression:为非终结符表达式,为文法中的非终结符实现解释操作;

    (5)说明:输入 Context 和 TerminalExpression 信息通过 Client 输入即可;

 

二、解释器模式实现四则运算

  1、应用实例要求

    通过解释器模式来实现四则运算,如计算 a+b-c 的值;

  2、思路分析和类图

      

 

  3、代码实现

    抽象类表达式:

 1 /**
 2  * 抽象类表达式,通过 HashMap 键值对,可以获取到变量的值
 3  *
 4  */
 5 public abstract class Expression {
 6 
 7     /**
 8      * a + b - c
 9      * 解释公式和数值的关系
10      * key 就是公式(表达式) 参数,例如:a,b,c,d
11      * vaule 就是具体的值
12      *
13      * HashMap {a=10, b=20, c=5}
14      * @param var
15      * @return
16      */
17     public abstract int interpreter(HashMap<String, Integer> var);
18 }

 

    终端类(变量)解析器:

 1 /**
 2  *  变量的解释器
 3  */
 4 public class VarExpression extends Expression{
 5 
 6     /**
 7      * key 就是变量,例如:key=a,key=b,key=c
 8      */
 9     private String key;
10 
11     public VarExpression(String key) {
12         this.key = key;
13     }
14 
15 
16     /**
17      * var 就是{a=10, b=20}
18      *
19      * interpreter 根据变量名称,返回对应值
20      * @param var
21      * @return
22      */
23     @Override
24     public int interpreter(HashMap<String, Integer> var) {
25         return var.get(key);
26     }
27 }

 

    非终端类(符号)解析器:

 1 /**
 2  * 抽象运算符号解析器,这里,每个运算符号都只和自己左右两个数字有关系
 3  * 但左右两个数字有可能也是一个解析的结果,无论何种类型,都是 Expression 类的实现类
 4  */
 5 public class SymbolExpression extends Expression{
 6 
 7     protected Expression left;
 8     protected Expression right;
 9 
10     public SymbolExpression(Expression left, Expression right) {
11         this.left = left;
12         this.right = right;
13     }
14 
15     /**
16      * 因为 SymbolExpression 是让其子类来实现,
17      * 因此该方法是默认实现
18      * @param var
19      * @return
20      */
21     @Override
22     public int interpreter(HashMap<String, Integer> var) {
23         return 0;
24     }
25 }

 

    加号解析器:

 1 /**
 2  * 加法解释器
 3  */
 4 public class AddExpression extends SymbolExpression{
 5 
 6     public AddExpression(Expression left, Expression right) {
 7         super(left, right);
 8     }
 9 
10     /**
11      * 处理相加
12      *
13      * var 仍然是{a=10, b=20}
14      *
15      * @param var
16      * @return
17      */
18     @Override
19     public int interpreter(HashMap<String, Integer> var) {
20         //super.left.interpreter(var):返回 left 表达式对应的值 a=10
21         //super.right.interpreter(var):返回 right 表达式对应的值 b=20
22         return super.left.interpreter(var) + super.right.interpreter(var);
23     }
24 
25 
26 }

 

    减号解析器:

 1 public class SubExpression extends SymbolExpression{
 2     public SubExpression(Expression left, Expression right) {
 3         super(left, right);
 4     }
 5 
 6     /**
 7      * 相减
 8      * 求出 left 和 right 表达式相减后的结果
 9      * @param var
10      * @return
11      */
12     @Override
13     public int interpreter(HashMap<String, Integer> var) {
14         return super.left.interpreter(var) - super.right.interpreter(var);
15     }
16 }

 

    计算器:

 1 public class Calculator {
 2 
 3     /**
 4      * 定义表达式
 5      */
 6     private Expression expression;
 7 
 8     /**
 9      * 构造函数传参,并解析
10      * @param expStr
11      */
12     public Calculator(String expStr) {  //expStr = a + b - c
13         //安排运算先后顺序
14         Stack<Expression> stack = new Stack<>();
15         //表达式拆分成字符数组 如:[a, +, b, -, c]
16         char[] charArray = expStr.toCharArray();
17 
18         Expression left = null;
19         Expression right = null;
20 
21         //遍历字符数组,即遍历 [a, +, b, -, c]
22         //针对不同的情况,做相应处理
23         for (int i = 0; i < charArray.length; i++) {
24             switch (charArray[i]) {
25                 case '+':
26                     //从 stack 中取出 left,表示 + 号左边表达式 => 'a'
27                     left = stack.pop();
28                     // right 表示 右边的表达式 => 'b'
29                     right = new VarExpression(String.valueOf(charArray[++i]));
30                     //然后根据得到 left 和 right 构建 AddExpression 加入栈stack
31                     stack.push(new AddExpression(left, right));
32                     break;
33 
34                 case '-':
35                     left = stack.pop();
36                     right = new VarExpression(String.valueOf(charArray[++i]));
37                     stack.push(new SubExpression(left, right));
38                     break;
39 
40                 default:
41                     //如果是一个 var,就创建一个 VarExpression,并 push 到 stack
42                     stack.push(new VarExpression(String.valueOf(charArray[i])));
43                     break;
44             }
45         }
46         //当遍历完整个 charArray 数组后,stack 就得到最后 Expression
47         this.expression = stack.pop();
48     }
49 
50     public int run(HashMap<String, Integer> var) {
51         //最后将表达式a+b和 var={a=10,b=20}
52         //然后传递给 expression 的 interpreter 进行解释执行
53         return this.expression.interpreter(var);
54     }
55 }

 

    客户端:

 1 public class Client {
 2     public static void main(String[] args) throws IOException {
 3         String expStr = getExpStr(); //a + b
 4 
 5         HashMap<String, Integer> var = getValue(expStr); //var{a=10.b=20}
 6 
 7         Calculator calculator = new Calculator(expStr);
 8         System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
 9 
10     }
11 
12     /**
13      * 获取表达式
14      * @return
15      * @throws IOException
16      */
17     public static String getExpStr() throws IOException {
18         System.out.println("请输入表达式:");
19         return (new BufferedReader(new InputStreamReader(System.in))).readLine();
20     }
21 
22     public static HashMap<String, Integer> getValue(String expStr) throws IOException {
23         HashMap<String, Integer> map = new HashMap<>();
24 
25         for (char ch : expStr.toCharArray()) {
26             if (ch != '+' && ch != '-') {
27                 if (!map.containsKey(String.valueOf(ch))) {
28                     System.out.println("请输入" + String.valueOf(ch) + "的值");
29                     String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
30                     map.put(String.valueOf(ch), Integer.valueOf(in));
31                 }
32             }
33         }
34         return map;
35     }
36 }

 

posted on 2021-02-28 10:18  格物致知_Tony  阅读(227)  评论(0编辑  收藏  举报