简明解释器模式-2

简明解释器模式(5.3)

本节介绍一门新的表达式语言。用户输入代数表达式,如"(a*a+b)*(c-d)",程序按照优先级和括号的使用情况计算正确的结果。

1

一门语言,按照严格定义的规则,可以产生无穷多样的句子。描述语言的规则称为文法/语法。文法由四个元素构成,表示为一个四元组:G = {ST,SN,S,P}。

①终结符(terminal)的集合ST。终结符是语言的最小文法元素(token/语言符号)。前面一个例子中,终结符是(长度不限的)数字和操作符。本例,终结符是字母Alphabet(规定其字母表包含abcd)和操作符‘*‘,‘+‘,‘-‘。分隔符空格(‘ ‘)或括号不作为终结符。

Alph ={a|b|c|d}注意ab+c不合法,因为没有ab这种字母

Op={*|+|-}

②非终结符(nonterminal、语法变量)的集合SN。非终结符通常表示表达式、函数、语句等语法概念。本语言的非终结符仅仅有Exp,表示各种表达式(expression)。

③产生式集合P。产生式定义什么是合法的非终结符,产生式格式为“α→β”。例如:

Exp→Alph | Alph op Alph | Exp op Exp

即字母是表达式,用操作符连接两个字母是表达式,递归地,用操作符连接两个表达式是表达式。简化起见,本语言中不得使用空格。

④开始符号S。S是每个合法句子的最开始处使用的非终结符,取Exp即可。

2

你可能注意到,计算的优先级和括号没有包含在上面的文法定义中,因为我们宁可程序处理用户的原始输入也不愿意将文法定义复杂化。

这一文法定义,很容易按照乘除法解释器的模子,依葫芦画瓢写出Exp的类层次。唯一要注意的是,Exp定义的方法

public int interpret(Context c);

含有参数Context,Context如同一个布袋,Exp需要的数据或功能都放在其中

Context存放Exp需要的数据或功能。例如用户输入代数表达式"a +b *c+d",计算考试成绩+平时成绩+考勤成绩,而这些数据来自于数据库,我们可以用Context存放

用户将输入的代数表达式,通常来自于图形界面,我们以配置文件模拟

Exp的类层次代码略。

例程 7-4 Context如同一个布袋
package intent.interpreter.calculator2;
import java.util.HashMap;
public class Context{
    private HashMap<Character ,Integer> varList = new HashMap<>();
    public void put(Character var, int value) {        varList.put(var, value);    }
    public int get(Character var) {             return varList.get(var);    }

    public Context() {        initialize();    }
    //hardcoded
    private void initialize() {
        this.put('a', 5); put('b', 2);put('c', 7); put('d', 1);
    }
}

构建语法树是实现解释器模式的重点。[GoF]中并未解释如何创建一个抽象的语法树。因此,你学习解释器模式这一模式时,完全不需要知道这么多。

3

编程处理用户的原始输入,将带有计算的优先级和括号的中序表达式变成符合前述文法的后序表达式,而计算的优先级使用一个HashMap<String,String>保存,键为操作符,值为其优先级。代码见

中序表达式 to 后序表达式

你可以将这些静态方法放在Context中或者某个工具包中。

4

最后构建语法树,编写一些测试代码。

例程 7 6构建语法树
package intent.interpreter.calculator2;
import tool.God;
import java.util.HashMap;
import java.util.Stack;
public class Calculator {
    private String expression = (String)God.getValue("expression");
    private Context ctx;

    public static void main(String[] args) {
        Calculator calc = new Calculator();
        Context ctx = new Context();
        calc.setContext(ctx);
        System.out.println("代数变量: " + "a=" + ctx.get('a')
            + ", b=" + ctx.get('b') + ", c=" + ctx.get('c')
            + ", d=" + ctx.get('d'));
        System.out.println(" Expression = "+calc.expression);
        System.out.println(" Result = " + calc.interpret());
    }

    public void setContext(Context c) {        ctx = c;    }

    public int interpret() {
        String pfExpr = Context.inToPost(expression);
        Expr rootNode = buildTree(pfExpr);
        return rootNode.interpret(ctx);
    }

    private NonTerminalExp getNonTerminalExp(char op,Expr l, Expr r) {
        NonTerminalExp e = null;
        if (op=='+') {
            e=new AddExp(l, r);
        }else if (op=='-') {
            e=new SubtractExp(l, r);
        }else if (op=='*') {
            e=new MultiplyExp(l, r);
        }
        return e;
    }

    private Expr buildTree(String expr) {
        Stack<Expr> s = new Stack<>();
        char[]  cs = expr.trim().toCharArray();
        for (char x :cs) {
            if (!Context.isOperator(x)) {
                s.push( new TerminalExp(x) );
            } else {
                Expr r = (Expr) s.pop();
                Expr l = (Expr) s.pop();
                Expr now = getNonTerminalExp(x, l, r);
                s.push(now);
            }
        }//end for
        return (Expr) s.pop();
    }
}

构建语法树的代码与前面一节的代码没有太大的差别。这里使用了一个简单工厂

private /*static*/  NonTerminalExp getNonTerminalExp(char op,Expr l, Expr r)

如果反感if-else,可以尝试使用工厂方法。另外,请添加除法的相关代码。

时间: 2024-10-12 11:49:58

简明解释器模式-2的相关文章

简明解释器模式(5.3)

假设系统的一个文本框中,允许用户输入字符串表达式如"5除 2 乘3模4乘6",要求系统能够按照Java的整数乘除运算规则,计算出表达式结果,如12. 假设系统的一个文本框中,允许用户输入字符串表达式如"list 姓名 年龄 学号 sortby 学号", 要求系统能够从数据库中提取学生信息并按照学号排序. 当应用程序中频繁使用某种文本形式的句子(不管是用户输入的还是从文件中读取的)时,我们需要为定义字符串表达式的语言设计一个解释器(interpreter). 在实际的

解释器模式 Interpreter

代码例子 参考 1.解释器模式定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 说明:解释器模式设计到文法规则和抽象语法树. 2.解释器模式的结构 解释器模式包含四个角色: 1)抽象表达式(AbstractExpress):声明抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类. 2)终结符表达式(TerminalExpress):是抽象表达式的子类,实现了与文法中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例.

[工作中的设计模式]解释器模式模式Interpreter

一.模式解析 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 以上是解释器模式的类图,事实上我很少附上类图,但解释器模式确实比较抽象,为了便于理解还是放了上来,此模式的要点是: 1.客户端提供一个文本.表达式或者其他,约定解析格式 2.针对文本中可以分为终结符表达式和非终结符表达式, 3.终结符表达式无需进一步解析,但仍需要转化为抽象接口的实例 4.针对非终结表达式,没一种标示需要定义一种解

学习日记之解释器模式和Effective C++

解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. (1),如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言的句子.这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题. (2),当一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象的语法树时,可使用解释器模式. (3),容易改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变和扩展该文法

Head First设计模式之解释器模式

一.定义 给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子. 主要解决:对于一些固定文法构建一个解释句子的解释器. 何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子.这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题. 如何解决:构件语法树,定义终结符与非终结符. 二.结构 组成: AbstractExpression(抽象表达式):定义解释器的接口,约定解释器的解释操作. Termi

Java解释器模式`

解释器模式提供了一种评估计算语言语法或表达式的方法. 这种类型的模式属于行为模式. 这种模式涉及实现一个表达式接口,它告诉解释一个指定的上下文. 此模式用于SQL解析,符号处理引擎等. 实现示例 我们将创建一个接口Expression并且在具体的类实现这个Expression接口. 定义了一个TerminalExpression类,用作所讨论的上下文的主解释器. 其他的类 - OrExpression和AndExpression用于创建组合表达式. InterpreterPatternDemo这

《JAVA与模式》之解释器模式

解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 解释器模式的结构 下面就以一个示意性的系统为例,讨论解释器模式的结构.系统的结构图如下所示: 模式所涉及的角色如下所示: (1)抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口.这个接口主要是一个interpret()方法,称做解释操作. (2)终结符表达式(Terminal Expression)角色:

解释器模式(Interpreter Pattern)

解释器模式:为语言创建解释器,提供评估语言的语法或表达式的方法. 例子: public interface Expression { public abstract boolean interpret(String context); } public class TerminalExpression implements Expression { private String data; public TerminalExpression(String data) { this.data =

行为型模式之解释器模式

概述 解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器.在某些情况下,为了更好地描述某一些特定类型的问题,我们可以创建一种新的语言,这种语言拥有自己的表达式和结构,即文法规则,这些问题的实例将对应为该语言中的句子.此时,可以使用解释器模式来设计这种新的语言.对解释器模式的学习能够加深我们对面向对象思想的理解,并且掌握编程语言中文法规则的解释过程 定义 解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立