语法规则也是类
1.基本介绍
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
类的一览表
2.具体实现
Node抽象类
/**
* @author Jay
* @date 2019/7/5 23:00
* @description 节点类
*/
public abstract class Node {
/**
* 解析
*
* @param context 上下文
* @throws ParseException 解析异常
*/
public abstract void parse(Context context) throws ParseException;
}
ParseException类
/**
* @author Jay
* @date 2019/7/5 23:01
* @description 解析异常类
*/
public class ParseException extends Exception{
public ParseException(String msg) {
super(msg);
}
}
ProgramNode类
/**
* @author Jay
* @date 2019/7/5 23:02
* @description 程序节点类
* <program> ::= program <command list>
*/
public class ProgramNode extends Node {
/**
* 命令列表节点
*/
private Node commandListNode;
@Override
public void parse(Context context) throws ParseException {
context.skipToken("program");
commandListNode = new CommandListNode();
commandListNode.parse(context);
}
@Override
public String toString() {
return "[program " + commandListNode + "]";
}
}
CommandListNode类
/**
* @author Jay
* @date 2019/7/5 23:03
* @description 命令列表节点类
* <command list> ::= <command>* end
*/
public class CommandListNode extends Node {
/**
* 命令列表
*/
private ArrayList list = new ArrayList();
@Override
public void parse(Context context) throws ParseException {
while (true) {
if (context.currentToken() == null) {
throw new ParseException("Missing 'end'");
} else if (context.currentToken().equals("end")) {
context.skipToken("end");
break;
} else {
Node commandNode = new CommandNode();
commandNode.parse(context);
list.add(commandNode);
}
}
}
@Override
public String toString() {
return list.toString();
}
}
CommandNode类
/**
* @author Jay
* @date 2019/7/5 23:04
* @description 命令节点类
* <command> ::= <repeat command> | <primitive command>
*/
public class CommandNode extends Node {
/**
* 节点
*/
private Node node;
@Override
public void parse(Context context) throws ParseException {
if (context.currentToken().equals("repeat")) {
node = new RepeatCommandNode();
node.parse(context);
} else {
node = new PrimitiveCommandNode();
node.parse(context);
}
}
@Override
public String toString() {
return node.toString();
}
}
RepeatCommandNode类
/**
* @author Jay
* @date 2019/7/5 23:04
* @description 命令节点类
*/
public class RepeatCommandNode extends Node {
/**
* 重复次数
*/
private int number;
/**
* 命令列表节点
*/
private Node commandListNode;
@Override
public void parse(Context context) throws ParseException {
context.skipToken("repeat");
number = context.currentNumber();
context.nextToken();
commandListNode = new CommandListNode();
commandListNode.parse(context);
}
@Override
public String toString() {
return "[repeat " + number + " " + commandListNode + "]";
}
}
PrimitiveCommandNode类
/**
* @author Jay
* @date 2019/7/5 23:05
* @description 原始命令节点类
*/
public class PrimitiveCommandNode extends Node {
/**
* 名字
*/
private String name;
@Override
public void parse(Context context) throws ParseException {
name = context.currentToken();
context.skipToken(name);
if (!name.equals("go") && !name.equals("right") && !name.equals("left")) {
throw new ParseException(name + " is undefined");
}
}
@Override
public String toString() {
return name;
}
}
Context类
/**
* @author Jay
* @date 2019/7/5 23:06
* @description 上下文类
*/
public class Context {
/**
* 分词器
*/
private StringTokenizer tokenizer;
/**
* 当前符号
*/
private String currentToken;
public Context(String text) {
this.tokenizer = new StringTokenizer(text);
this.nextToken();
}
/**
* 返回下一个符号
*
* @return 下一个符号
*/
public String nextToken() {
if (tokenizer.hasMoreTokens()) {
this.currentToken = this.tokenizer.nextToken();
} else {
this.currentToken = null;
}
return this.currentToken;
}
/**
* 返回当前符号
*
* @return 当前符号
*/
public String currentToken() {
return this.currentToken;
}
/**
* 跳过指定符号
*
* @param token 指定符号
* @throws ParseException 解析异常
*/
public void skipToken(String token) throws ParseException {
if (!token.equals(this.currentToken)) {
throw new ParseException("Warning: " + token + " is expected, but " + currentToken + " is found.");
}
this.nextToken();
}
/**
* 解析数值
*
* @return 数值
* @throws ParseException 解析异常
*/
public int currentNumber() throws ParseException {
int number = 0;
try {
number = Integer.parseInt(currentToken);
} catch (NumberFormatException e) {
throw new ParseException("Warning: " + e);
}
return number;
}
}
测试类
/**
* @author Jay
* @date 2019/7/5 23:06
* @description
*/
public class InterpreterTest {
/**
* 测试解释器模式
*/
@Test
public void testInterpreter() {
try {
BufferedReader reader = new BufferedReader(new FileReader(System.getProperty("user.dir")
+ "/src/main/java/com/pc/interpreter/example/program.txt"));
String text;
while ((text = reader.readLine()) != null) {
System.out.println("text = \"" + text + "\"");
Node node = new ProgramNode();
node.parse(new Context(text));
System.out.println("node = " + node);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
text = "program end"
node = [program []]
text = "program go end"
node = [program [go]]
text = "program go right go right go right go right end"
node = [program [go, right, go, right, go, right, go, right]]
text = "program repeat 4 go right end end"
node = [program [[repeat 4 [go, right]]]]
text = "program repeat 4 repeat 3 go right go left end right end end"
node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]
解释器模式中的角色
AbstractExpression(抽象表达式)
AbstractExpression角色定义了语法树节点的共同接口(API)。在案例中,由Node类扮演此角色。在案例中,共同接口(API)的名字是parse,不过在类图中它的名字是interpreter。
TerminalExpression(终结符表达式)
TerminalExpression角色对应BNF中的终结特表达式。在案例中,由PrimitiveCommandNode类扮演此角色。
NonterminalExpression(非终结符表达式)
NonterminalExpression角色对应BNF中的非终结符表达式。在案例中,由ProgramNode类、CommandNode类、RepeatCommandNode类和CommandListNode 类扮演此角色。
Context(文脉、上下文)
Context 角色为解释器进行语法解析提供了必要的信息。在案例中,由Context 类扮演此角色。
Client(请求者)
为了推导语法树, Client 角色会调用TerminalExpression 角色和Nonterm inalExpression 角色。在案例中,由Main 类扮演此角色。