代码重构
我们上一章成功给Qing
加上了类定义的实现,不过随着类定义功能的加入,代码似乎开始变得有些混乱了,为什么这么说呢,主要是依据以下几点
- 通过
Listener
来实现,我们是在遍历的过程中进行回调,可以看到所有的处理方法都是void
方法,如果想要获取某一个Token
的结果,只能维护中间变量进行处理,可以预想如果后续语义进一步补充之后,这些中间变量的编排和使用会是一个很大问题 - 相同
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); }
}