代码重构

我们上一章成功给Qing加上了类定义的实现,不过随着类定义功能的加入,代码似乎开始变得有些混乱了,为什么这么说呢,主要是依据以下几点

  1. 通过Listener来实现,我们是在遍历的过程中进行回调,可以看到所有的处理方法都是void方法,如果想要获取某一个Token的结果,只能维护中间变量进行处理,可以预想如果后续语义进一步补充之后,这些中间变量的编排和使用会是一个很大问题
  2. 相同Token的处理会比较复杂,比如定义变量的语句可以在很多地方出现(方法域中、类成员变量…),而出现在不同的地方实际是要用不同的方式编译的,这样就导致相同的Token需要分离处理,会比较麻烦

为了解决上述的问题,我们使用之前一直没用到的Visitor进行重构处理,他和Listener相比一个有点就是有了返回值,我们可以通过迭代调用的方式组装数据了

  • 定义类访问器,这个访问器访问类定义上下文并返回ClassDeclaration
public class ClassVisitor extends QingBaseVisitor<ClassDeclaration> {
private Map<String, Variable> variableMap = new HashMap<>();
@Override
public ClassDeclaration visitClassDeclaration(QingParser.ClassDeclarationContext ctx) {
String name = ctx.className().getText();
ClassDeclaration classDeclaration = new ClassDeclaration(name);
QingParser.ClassBodyContext classBodyContext = ctx.classBody();
Queue<Instruction> instructionsQueue = classBodyContext.children.stream().map(visitStatement())
.collect(Collectors.toCollection(
(Supplier<Queue<Instruction>>) ArrayDeque::new
));
classDeclaration.setInstructionsQueue(instructionsQueue);
return classDeclaration;
}
private Function<ParseTree, Instruction> visitStatement() {
VariableVisitor variableVisitor = new VariableVisitor(variableMap);
PrintVisitor printVisitor = new PrintVisitor(variableMap);
return a -> {
if (a instanceof QingParser.VariableContext) {
return a.accept(variableVisitor);
}
if (a instanceof QingParser.PrintContext) {
return a.accept(printVisitor);
}
throw new RuntimeException("存在语句未识别");
};
}
}
  • 变量定义以及变量打印访问器,代码基本只是换了一个结构
public class PrintVisitor extends QingBaseVisitor<Instruction> {
private Map<String,Variable> variableMap;
public PrintVisitor(Map<String, Variable> variableMap) {
this.variableMap = variableMap;
}
@Override
public Instruction visitPrint(QingParser.PrintContext ctx) {
final TerminalNode varName = ctx.ID();
boolean printedVarNotDeclared = !variableMap.containsKey(varName.getText());
if (printedVarNotDeclared) {
throw new RuntimeException(String.format("你要打印的变量%s从未定义过", varName.getText()));
}
final Variable variable = variableMap.get(varName.getText());
log.info("你要打印一个变量,变量名为{},实际值为{}", varName.getText(), variableMap.get(varName.getText()).getValue());
return new PrintVariableInstruction(variable);
}
}
public class VariableVisitor extends QingBaseVisitor<Instruction> {
private Map<String,Variable> variableMap;
public VariableVisitor(Map<String, Variable> variableMap) {
this.variableMap = variableMap;
}
@Override
public Instruction visitVariable(QingParser.VariableContext ctx) {
final TerminalNode varName = ctx.ID();
final QingParser.ValueContext varValue = ctx.value();
final int varType = varValue.getStart().getType();
final int varIndex = variableMap.size();
final String varTextValue = varValue.getText();
Variable var = new Variable(varIndex, varType, varTextValue);
if (variableMap.containsKey(varName.getText())) {
throw new RuntimeException(String.format("你要定义变量%s,这个变量已经定义过了", varName.getText()));
}
variableMap.put(varName.getText(), var);
log.info("你定义了一个变量,变量名为{},它的值为{}", varName.getText(), varValue.getText());
return new VariableDeclarationInstruction(var);
}
}