類圖
定義
給定一門語言,定義它的文法的一種表示,並定義一個解釋器,該解釋器使用該表
示來解釋語言中的句子
優點
- 擴展性好,修改語法規則只要修改相應的非終結符表達式就可以了缺點
- 容易引起類膨脹。每個語法都要產生一個非終結符表達式
- 採用遞歸方法,不易調試
- 效率問題。大量使用了循環和遞歸
注意事項
解釋器模式一般用來解析比較標準的字符集,如SQL語法分析等
抽象表達式
public abstract class AbstractExpression {
public abstract Object interpret(Context ctx);
/**
* 檢驗兩個表達式在結構上是否相同
*
* @param exp 表達式
* @return 是否相同
*/
public abstract boolean equals(AbstractExpression exp);
}
終結符表達式
public abstract class TerminalExpression extends AbstractExpression {
}
非終結符表達式
public abstract class NonterminalExpression extends AbstractExpression {
/**
* 校驗表達式結果是否是Boolean類型
*
* @param result 表達式結果
* @param expStr 表達式
* @throws IllegalArgumentException
*/
public void checkBoolean(Object result, String expStr) throws IllegalArgumentException {
if (!(result instanceof Boolean)) {
throw new IllegalArgumentException("表達式" + expStr + "參數類型錯誤,參數類型應爲:Boolean");
}
}
/**
* 校驗表達式結果是否是Integer類型
*
* @param result 表達式結果
* @param expStr 表達式
* @throws IllegalArgumentException
*/
public void checkInteger(Object result, String expStr) throws IllegalArgumentException {
if (!(result instanceof Integer)) {
throw new IllegalArgumentException("表達式" + expStr + "參數類型錯誤,參數類型應爲:Integer");
}
}
}
變量終結符
public class Variable extends TerminalExpression {
private String name;
/**
* 變量
*
* @param name 變量名
*/
public Variable(String name) {
this.name = name;
}
@Override
public Object interpret(Context ctx) {
return ctx.lookup(this);
}
@Override
public boolean equals(AbstractExpression obj) {
if (obj != null && obj instanceof Variable) {
return this.name.equals(((Variable) obj).name);
}
return false;
}
@Override
public String toString() {
return name;
}
}
整型終結符
public class MyInt extends TerminalExpression {
private final int value;
public MyInt(int value) {
this.value = value;
}
@Override
public Object interpret(Context ctx) {
return value;
}
@Override
public boolean equals(AbstractExpression exp) {
if (exp != null && exp instanceof MyInt) {
return this.value == ((MyInt) exp).value;
}
return false;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
布爾型終結符
public class MyBoolean extends TerminalExpression {
public static final MyBoolean TRUE = new MyBoolean(true);
public static final MyBoolean FALSE = new MyBoolean(false);
private final boolean value;
public MyBoolean(boolean value) {
this.value = value;
}
@Override
public Object interpret(Context ctx) {
return value;
}
@Override
public boolean equals(AbstractExpression obj) {
if (obj != null && obj instanceof MyBoolean) {
return this.value == ((MyBoolean) obj).value;
}
return false;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
上下文
public class Context {
/**
* 變量存儲區
*/
private Map<Variable, TerminalExpression> map = new HashMap<>();
/**
* 變量賦值
*
* @param var 變量
* @param value 值
*/
public void assign(Variable var, TerminalExpression value) {
map.put(var, value);
}
/**
* 查看變量內容
*
* @param var 變量
* @return 變量值
* @throws IllegalArgumentException
*/
public Object lookup(Variable var) throws IllegalArgumentException {
TerminalExpression value = map.get(var);
if (value == null) {
throw new IllegalArgumentException();
}
return value.interpret(this);
}
}
加運算表達式
public class Add extends NonterminalExpression {
private final AbstractExpression left, right;
public Add(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public Object interpret(Context ctx) {
Object leftObj = left.interpret(ctx);
Object rightObj = right.interpret(ctx);
//參數檢查
checkInteger(leftObj, left.toString());
checkInteger(rightObj, right.toString());
return (Integer) leftObj + (Integer) rightObj;
}
@Override
public boolean equals(AbstractExpression exp) {
if (exp != null && exp instanceof Add) {
return left.equals(((Add) exp).left) &&
right.equals(((Add) exp).right);
}
return false;
}
@Override
public String toString() {
return "(" + left.toString() + " + " + right.toString() + ")";
}
}
乘運算表達式
public class Multiply extends NonterminalExpression {
private final AbstractExpression left, right;
public Multiply(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public Object interpret(Context ctx) {
Object leftObj = left.interpret(ctx);
Object rightObj = right.interpret(ctx);
//參數檢查
checkInteger(leftObj,left.toString());
checkInteger(rightObj,right.toString());
return (Integer) leftObj * (Integer) rightObj;
}
@Override
public boolean equals(AbstractExpression exp) {
if (exp != null && exp instanceof Multiply) {
return left.equals(((Multiply) exp).left) &&
right.equals(((Multiply) exp).right);
}
return false;
}
@Override
public String toString() {
return "(" + left.toString() + " * " + right.toString() + ")";
}
}
與運算表達式
public class And extends NonterminalExpression {
private final AbstractExpression left, right;
public And(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public Object interpret(Context ctx) {
Object leftObj = left.interpret(ctx);
Object rightObj = right.interpret(ctx);
//參數檢查
checkBoolean(leftObj, left.toString());
checkBoolean(rightObj, right.toString());
return (Boolean) leftObj && (Boolean) rightObj;
}
@Override
public boolean equals(AbstractExpression obj) {
if (obj != null && obj instanceof And) {
return left.equals(((And) obj).left) &&
right.equals(((And) obj).right);
}
return false;
}
@Override
public String toString() {
return "(" + left.toString() + " AND " + right.toString() + ")";
}
}
或運算表達式
public class Or extends NonterminalExpression {
private AbstractExpression left, right;
public Or(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
@Override
public Object interpret(Context ctx) {
Object leftObj = left.interpret(ctx);
Object rightObj = right.interpret(ctx);
//參數檢查
checkBoolean(leftObj, left.toString());
checkBoolean(rightObj, right.toString());
return (Boolean) leftObj || (Boolean) rightObj;
}
@Override
public boolean equals(AbstractExpression obj) {
if (obj != null && obj instanceof Or) {
return left.equals(((Or) obj).left) &&
right.equals(((Or) obj).right);
}
return false;
}
@Override
public String toString() {
return "(" + left.toString() + " OR " + right.toString() + ")";
}
}
非運算表達式
public class Not extends NonterminalExpression {
private AbstractExpression exp;
public Not(AbstractExpression exp) {
this.exp = exp;
}
@Override
public Object interpret(Context ctx) {
Object expObj = exp.interpret(ctx);
//參數檢查
checkBoolean(expObj, exp.toString());
return !(Boolean) exp.interpret(ctx);
}
@Override
public boolean equals(AbstractExpression obj) {
if (obj != null && obj instanceof Not) {
return exp.equals(((Not) obj).exp);
}
return false;
}
@Override
public String toString() {
return "(NOT " + exp.toString() + ")";
}
}
場景類
public class Client {
public static void main(String[] args) {
Context ctx = new Context();
// 變量x
Variable x = new Variable("x");
// 變量y
Variable y = new Variable("y");
// 變量z
Variable z = new Variable("z");
// 變量賦值
ctx.assign(x, MyBoolean.FALSE);
ctx.assign(y, MyBoolean.TRUE);
ctx.assign(z, new MyInt(5));
System.out.println("x=" + x.interpret(ctx));
System.out.println("y=" + y.interpret(ctx));
System.out.println("z=" + z.interpret(ctx));
// 表達式(true AND x)
AbstractExpression exp1 = new And(MyBoolean.TRUE, x);
System.out.println(exp1.toString() + "=" + exp1.interpret(ctx));
// 表達式((true AND x) OR (y AND (NOT x)))
AbstractExpression exp2 = new Or(new And(MyBoolean.TRUE, x), new And(y, new Not(x)));
System.out.println(exp2.toString() + "=" + exp2.interpret(ctx));
// 表達式((z + 3) + 2)
AbstractExpression exp3 = new Add(new Add(z, new MyInt(3)), new MyInt(2));
System.out.println(exp3.toString() + "=" + exp3.interpret(ctx));
// 表達式(2 + (z * 3))
AbstractExpression exp4 = new Add(new MyInt(2), new Multiply(z, new MyInt(3)));
System.out.println(exp4.toString() + "=" + exp4.interpret(ctx));
System.out.println("表達式1,2是否是同一個表達式:" + exp1.equals(exp2));
}
}
運行結果
x=false
y=true
z=5
(true AND x)=false
((true AND x) OR (y AND (NOT x)))=true
((z + 3) + 2)=10
(2 + (z * 3))=17
表達式1,2是否是同一個表達式:false