读书笔记 仅供参考
简述
在 Interpreter 模式中,需要编写一个“翻译程序”,翻译自己定义的“迷你语言”,可以通过“迷你语言”编写“迷你程序”。
角色和 UML
AbstractExpression
定义了语法树节点的共同接口(API)。
TerminalExpression
对应 BNF 中的终结符表达式。
NonterminalExpression
对应 BNF 中的非终结符表达式。
Context
为解释器进行语法解析提供了必要的信息。
Client
为了推导语法树,Client 角色会调用 TerminalExpression 和 NonterminalExpression 角色。
UML
例子
例程是一个简单的语法解析器,能够识别文件中的“迷你代码”。迷你代码主要是操作机器人行走,程序都是由 “program”和“end”开始结尾。可以执行 go、left、right 等命令。
语法树
代码
public abstract class Node {
public abstract void parse(Context context) throws ParseException;
}
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) throws ParseException {
if (!token.equals(currentToken)) {
throw new ParseException("Waring: " + token + " is expected, but " + currentToken + " is found");
}
nextToken();
}
//获取当前标记对应的数值
public int currentNumber() throws ParseException {
int number = 0;
try {
number = Integer.parseInt(currentToken);
} catch (NumberFormatException e) {
throw new ParseException("Waring: " + e);
}
return number;
}
}
// 对应语法:<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 +
']';
}
}
// 对应语法 <command list> ::= <command>* end
public class CommandListNode extends Node {
private List<Node> 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();
}
}
// <repeat command> ::= repeat <number> <command list>
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 + "]";
}
}
// <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();
}
}
// <primitive command> ::= go | right | left
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;
}
}
public class Main {
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(
new FileReader("file/interpreter/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);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
program.txt
program end
program go end
program go right go right go right go right end
program repeat 4 go right end end
program repeat 4 repeat 3 go right go left end right end end
运行结果
其他迷你语言
- 正则表达式
- 检索表达式
- 批处理语言