实现功能
本次实验完成了以下功能:
类型检查
重命名
实验设计
笔者参考老师上课的演示代码和助教在文档中的提示,做出如下类设计。该设计采取了依赖倒置原则。
在实现功能方面,笔者采用了如下思路:
通过 Visitor
对语法树进行遍历,遍历过程中输出语义错误;
在 visitTerminal
方法中,对每个 Symbol
记录变量名、函数名的出现位置,并存储待输出语法树内容;
如果语法树中无语义错误,则输出语法树的内容,输出过程中对待重命名的变量、函数进行重命名。
整个过程总共遍历语法树一遍 。
调用入口设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Main { public static void main (String[] args) throws IOException { ParseTree tree = sysYParser.program(); Visitor visitor = new Visitor (); visitor.visit(tree); if (!visitor.getErrorFound()) { for (Object obj : visitor.getMsgToPrint()) { if (obj instanceof Symbol) { if (((Symbol) obj).findUsage(lineNo, columnNo)) { System.err.print(name); } else { System.err.print(((Symbol) obj).getName()); } } else { System.err.print(obj); } } } } }
遍历过程 Visitor
设计
该类在项目中共 471 行,以下是 Visitor
类实现遍历的核心逻辑:
获得报错行号的方法:第 47 行
获得行号列号的方法:第 8 行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 public class Visitor extends SysYParserBaseVisitor <Void> { @Override public Void visitTerminal (TerminalNode node) { if (ruleName.equals("INTEGR_CONST" )) { tokenText = toDecimalInteger(tokenText); } else if (ruleName.equals("IDENT" )) { int lineNO = token.getLine(); int columnNO = token.getCharPositionInLine(); if (symbol != null ) { symbol.addUsage(lineNO, columnNO); } } if (!color.equals("no color" )) { } return super .visitTerminal(node); } @Override public Void visitProgram (SysYParser.ProgramContext ctx) { Void ret = super .visitProgram(ctx); return ret; } @Override public Void visitFuncDef (SysYParser.FuncDefContext ctx) { Void ret = super .visitFuncDef(ctx); return ret; } @Override public Void visitBlock (SysYParser.BlockContext ctx) { Void ret = super .visitBlock(ctx); return ret; } int getLineNo (ParserRuleContext ctx) { return ctx.getStart().getLine(); } @Override public Void visitVarDecl (SysYParser.VarDeclContext ctx) { for (SysYParser.VarDefContext varDefContext : ctx.varDef()) { if (varDefContext.ASSIGN() != null ) { } } return super .visitVarDecl(ctx); } @Override public Void visitConstDecl (SysYParser.ConstDeclContext ctx) { return super .visitConstDecl(ctx); } @Override public Void visitFuncFParam (SysYParser.FuncFParamContext ctx) { return super .visitFuncFParam(ctx); } private Type getLValType (SysYParser.LValContext ctx) { return varType; } @Override public Void visitLVal (SysYParser.LValContext ctx) { for (int i = 0 ; i < arrayDimension; ++i) { } return super .visitLVal(ctx); } @Override public Void visitStmt (SysYParser.StmtContext ctx) { if (ctx.ASSIGN() != null ) { } else if (ctx.RETURN() != null ) { } return super .visitStmt(ctx); } private Type getExpType (SysYParser.ExpContext ctx) { if (ctx.IDENT() != null ) { } else if (ctx.L_PAREN() != null ) { } else if (ctx.unaryOp() != null ) { } else if (ctx.lVal() != null ) { } else if (ctx.number() != null ) { } else if (ctx.MUL() != null || ctx.DIV() != null || ctx.MOD() != null || ctx.PLUS() != null || ctx.MINUS() != null ) { } return new BasicTypeSymbol ("noType" ); } @Override public Void visitExp (SysYParser.ExpContext ctx) { if (ctx.IDENT() != null ) { } else if (ctx.unaryOp() != null ) { } else if (ctx.MUL() != null || ctx.DIV() != null || ctx.MOD() != null || ctx.PLUS() != null || ctx.MINUS() != null ) { } return super .visitExp(ctx); } @Override public Void visitCond (SysYParser.CondContext ctx) { return super .visitCond(ctx); } }
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 int globalVar;int globalArray[2 ];void voidFunc1 () { return ; }void voidFunc2 (int param1) { return 1 ; }void voidFunc3 (int param1, int param2[]) { return param1; }int intFunc1 () { return 1 ; }int intFunc1 (int param) { return intFunc1(); }int intFunc2 (int param1) { return intFunc2(param1); }int intFunc3 (int param1, int param2[]) { return param2; }int voidFunc1 () { }int test (int i, int i) { return test(i + 1 ); }int main () { a = 3 ; int b = func(); int b; int c[3 ][3 ][3 ]; int d[2 ][2 ]; c[1 ] = d; c[1 ][1 ] = d; c[1 ][1 ] = d; int f = voidFunc1() + intFunc1(); int g = intFunc3(b); int h = intFunc3(b, globalArray); int i = b[5 ]; int j = c(); c = 6 ; voidFunc1 = 6 ; if (1 || globalArray || 2 || d) { } int k = voidFunc1(); int l = voidFunc(); int m = k; return z(); }