应用场景
这个在编译器的语义分析过程中常用的一种模式,即分析虚拟语法树(AST),但它并不能解决如何生成语法树的问题。
在实际的工作中,有时也会遇到一些类似的工作,比如我们会使用DSL来解决一些复杂的业务问题,这时候就需要我们来定义一些简单的语法来实现。再比如
比如前段时间需要开发一个maven的插件,需要对一些依赖的版本大小限制(比如guava>18.0),以及一些依赖之间互斥(A|B),这些规则可以自定义(以方便扩展);所以我开发的插件的工作是解析配置文件,然后判断项目的依赖是否满足规则,如果不满足则退出编译。
模式图(UML)
Context:可以理解为变量值,用来替换表达式中的变量;比如a+b;则context应该包含的内容为a=10,b=2
AbstractExpression:也可以定义为interface,包含一个接口用来返回表达式的值
TerminalExpression:可以理解为变量a, b
NonterminalExpression:可以理解为操作符:+,-*,/等;由于操作符至少要包含一个操作数,所以它又包含了多个AbstractExpresion
Client 依赖于Context 和 Expression,即实现对语法树进行计算
示例
context
@AllArgsConstructor
public class Context {
private Map<String, Expression> variables;
public int getValue(String key) {
if (variables.containsKey(key)) {
return variables.get(key).interpreter(this);
}
return 0;
}
}
expression
public interface Expression {
public int interpreter(Context context);
}
TerminalExpression
@AllArgsConstructor
public class Number implements Expression {
private int number;
public int interpreter(Context context) {
return number;
}
}
/**
* TerminalExpression
*/
@AllArgsConstructor
public class VariableExpression implements Expression {
private String variable;
public int interpreter(Context context) {
return context.getValue(variable);
}
}
NonterminalExpression
@AllArgsConstructor
public class MinusExpression implements Expression {
// 左操作数
private Expression left;
// 右操作数
private Expression right;
public int interpreter(Context context) {
return left.interpreter(context) - right.interpreter(context);
}
}
@AllArgsConstructor
public class MinusExpression implements Expression {
// 左操作数
private Expression left;
// 右操作数
private Expression right;
public int interpreter(Context context) {
return left.interpreter(context) - right.interpreter(context);
}
}
client
/**
*
* 这个严格来说并不能算是解释器的一部分,因为它还完成了token解析, 可以当成一个client来操作
*/
@AllArgsConstructor
public class Evaluator implements Expression {
private Expression syntaxTree;
public Evaluator(String expression) {
Stack<Expression> expressionStack = new Stack<Expression>();
for (String token : expression.split(" ")) {
if (token.equals("+")) {
Expression subExpression = new PlusExpression(expressionStack.pop(), expressionStack.pop());
expressionStack.push(subExpression);
} else if (token.equals("-")) {
// it's necessary remove first the right operand from the stack
Expression right = expressionStack.pop();
// ..and after the left one
Expression left = expressionStack.pop();
Expression subExpression = new MinusExpression(left, right);
expressionStack.push(subExpression);
} else
expressionStack.push(new VariableExpression(token));
}
syntaxTree = expressionStack.pop();
}
public int interpreter(Context context) {
return syntaxTree.interpreter(context);
}
public static void main(String[] args) {
String expression = "w x z - +";
Evaluator sentence = new Evaluator(expression);
Map<String,Expression> variables = new HashMap<String,Expression>();
variables.put("w", new Number(5));
variables.put("x", new Number(10));
variables.put("z", new Number(42));
int result = sentence.interpreter(new Context(variables));
System.out.println(result);
}
}
注:网上的很多理解都是错误的,而且有很多将其翻译成“解析模式”,更是大错特错