摘要:本文深入浅出的讲述了设计模式中的解释器模式,并给出了简单的示例,例子浅显易懂,并附带源代码。
解释器模式属于行为型模式,其意图是给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。如果一种特定类型的问题发生的频率足够高,那么就可值得将该问题的各个实例表述为一个简单语言的句子,这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。解释器模式使用类来表达每一条文法规则,在规则右边的符号是这些类的实例变量。
适用性:
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树,可以使用解释器模式。而当存在以下情况时该模式效果最好
l 该文法的类层次结构变得庞大而无法管理。此时语法分析程序生成器这样的工具是最好的选择。他们无需构建抽象语法树即可解释表达式,这样可以节省空间而且还可能节省时间。
l 效率不是一个关键问题,最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将他们装换成另一种形式,例如,正则表达式通常被装换成状态机,即使在这种情况下,转换器仍可用解释器模式实现,该模式仍是有用的。
参与者:
AbstractException:抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
TerminalExpression:终结符表达式。实现与文法中的终结符相关联的解释操作,一个句子中的每个终结符需要该类的一个实例。
NonterminalExpression:非终结符表达式,对于文法中的每一条规则R::=R1R2..都需要一个NonterminalExpression类。为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。为文法中的非终结符实现解释操作,解释操作一般要递归地调用表示R1到Rn的那些对象的解释操作。
Context:上下文,包含解释器需要解释的全局信息。
Client:构建表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。调用解释操作等。
协作:
Client构建一个句子,它是NonterminalExpression和TerminalExpress的实例的一个抽象语法树,然后初始化上下文并调用解释操作。然后初始化上下文并调用解释操作。
每一个非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
每一节点的解释操作用上下文来存储和访问解释器的状态。
例如有文法表达式:
program::=commandlist
commandlist::=(space|print|break|linebreak|repeat|)*
repeat::=commandlist
图1 文法解释器的类图
如果输入相应的程序代码为
PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE SPACE SPACE SPACE PRINT momor LINEBREAK END END
则可以通过解释器的解释执行。
相应的代码:
Node代码:
package interpreter;
public interface Node{
public void parse(Context text);
public void execute();
}
Context代码:
package interpreter;
import java.util.*;
public class Context{
private StringTokenizer tokenizer;
private String currentToken;
public Context(String text){
tokenizer = new StringTokenizer(text);
nextToken();
}
public String nextToken(){
if(tokenizer.hasMoreTokens()){
currentToken = tokenizer.nextToken();
}
else{
currentToken = null;
}
return currentToken;
}
public String currentToken(){
return currentToken;
}
public void skipToken(String token){
if(!token.equals(currentToken)){
System.err.println("Warning:"+token+" is Expected,but"+currentToken + " is found");
}
nextToken();
}
public int currentNumber(){
int number = 0;
try{
number = Integer.parseInt(currentToken);
}
catch(NumberFormatException e){
System.err.println("Warning:"+e);
}
return number;
}
}
Client代码:
package interpreter;
import java.util.*;
import java.io.*;
public class Client{
public static void main(String[] args){
try{
BufferedReader reader = new BufferedReader(new FileReader("prog.txt"));
String text;
text = reader.readLine();
System.out.println(text);
Node node = new ProgramNode();
node.parse(new Context(text));
System.out.println("node = " + node);
node.execute();
}
catch(ArrayIndexOutOfBoundsException e){
System.err.println("Usage java interpreter.Client!");
}
catch(Exception e){
e.printStackTrace();
}
}
}
其余的代码不一一列举,请下载附件查看其余的代码。
总结:解释器模式为制作编译器提供了指导思路,在使用面向对象语言实现的编译器中得到了广泛的应用。
本文转自凌辉博客51CTO博客,原文链接http://blog.51cto.com/tianli/41998如需转载请自行联系原作者
lili00okok