📄 checker.java
字号:
/*
* @(#)Checker.java 2.1 2003/10/07
*
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
* and School of Computer and Math Sciences, The Robert Gordon University,
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
* All rights reserved.
*
* This software is provided free for educational use only. It may
* not be used for commercial purposes without the prior written permission
* of the authors.
*/
package Triangle.ContextualAnalyzer;
import Triangle.ErrorReporter;
import Triangle.StdEnvironment;
import Triangle.AbstractSyntaxTrees.AnyTypeDenoter;
import Triangle.AbstractSyntaxTrees.ArrayExpression;
import Triangle.AbstractSyntaxTrees.ArrayTypeDenoter;
import Triangle.AbstractSyntaxTrees.AssignCommand;
import Triangle.AbstractSyntaxTrees.BinaryExpression;
import Triangle.AbstractSyntaxTrees.BinaryOperatorDeclaration;
import Triangle.AbstractSyntaxTrees.BoolTypeDenoter;
import Triangle.AbstractSyntaxTrees.CallCommand;
import Triangle.AbstractSyntaxTrees.CallExpression;
import Triangle.AbstractSyntaxTrees.CharTypeDenoter;
import Triangle.AbstractSyntaxTrees.CharacterExpression;
import Triangle.AbstractSyntaxTrees.CharacterLiteral;
import Triangle.AbstractSyntaxTrees.ConstActualParameter;
import Triangle.AbstractSyntaxTrees.ConstDeclaration;
import Triangle.AbstractSyntaxTrees.ConstFormalParameter;
import Triangle.AbstractSyntaxTrees.Declaration;
import Triangle.AbstractSyntaxTrees.DotVname;
import Triangle.AbstractSyntaxTrees.EmptyActualParameterSequence;
import Triangle.AbstractSyntaxTrees.EmptyCommand;
import Triangle.AbstractSyntaxTrees.EmptyExpression;
import Triangle.AbstractSyntaxTrees.EmptyFormalParameterSequence;
import Triangle.AbstractSyntaxTrees.ErrorTypeDenoter;
import Triangle.AbstractSyntaxTrees.FieldTypeDenoter;
import Triangle.AbstractSyntaxTrees.FormalParameter;
import Triangle.AbstractSyntaxTrees.FormalParameterSequence;
import Triangle.AbstractSyntaxTrees.FuncActualParameter;
import Triangle.AbstractSyntaxTrees.FuncDeclaration;
import Triangle.AbstractSyntaxTrees.FuncFormalParameter;
import Triangle.AbstractSyntaxTrees.Identifier;
import Triangle.AbstractSyntaxTrees.IfCommand;
import Triangle.AbstractSyntaxTrees.IfExpression;
import Triangle.AbstractSyntaxTrees.IntTypeDenoter;
import Triangle.AbstractSyntaxTrees.IntegerExpression;
import Triangle.AbstractSyntaxTrees.IntegerLiteral;
import Triangle.AbstractSyntaxTrees.LetCommand;
import Triangle.AbstractSyntaxTrees.LetExpression;
import Triangle.AbstractSyntaxTrees.MultipleActualParameterSequence;
import Triangle.AbstractSyntaxTrees.MultipleArrayAggregate;
import Triangle.AbstractSyntaxTrees.MultipleFieldTypeDenoter;
import Triangle.AbstractSyntaxTrees.MultipleFormalParameterSequence;
import Triangle.AbstractSyntaxTrees.MultipleRecordAggregate;
import Triangle.AbstractSyntaxTrees.Operator;
import Triangle.AbstractSyntaxTrees.ProcActualParameter;
import Triangle.AbstractSyntaxTrees.ProcDeclaration;
import Triangle.AbstractSyntaxTrees.ProcFormalParameter;
import Triangle.AbstractSyntaxTrees.Program;
import Triangle.AbstractSyntaxTrees.RecordExpression;
import Triangle.AbstractSyntaxTrees.RecordTypeDenoter;
import Triangle.AbstractSyntaxTrees.SequentialCommand;
import Triangle.AbstractSyntaxTrees.SequentialDeclaration;
import Triangle.AbstractSyntaxTrees.SimpleTypeDenoter;
import Triangle.AbstractSyntaxTrees.SimpleVname;
import Triangle.AbstractSyntaxTrees.SingleActualParameterSequence;
import Triangle.AbstractSyntaxTrees.SingleArrayAggregate;
import Triangle.AbstractSyntaxTrees.SingleFieldTypeDenoter;
import Triangle.AbstractSyntaxTrees.SingleFormalParameterSequence;
import Triangle.AbstractSyntaxTrees.SingleRecordAggregate;
import Triangle.AbstractSyntaxTrees.SubscriptVname;
import Triangle.AbstractSyntaxTrees.Terminal;
import Triangle.AbstractSyntaxTrees.TypeDeclaration;
import Triangle.AbstractSyntaxTrees.TypeDenoter;
import Triangle.AbstractSyntaxTrees.UnaryExpression;
import Triangle.AbstractSyntaxTrees.UnaryOperatorDeclaration;
import Triangle.AbstractSyntaxTrees.VarActualParameter;
import Triangle.AbstractSyntaxTrees.VarDeclaration;
import Triangle.AbstractSyntaxTrees.VarFormalParameter;
import Triangle.AbstractSyntaxTrees.Visitor;
import Triangle.AbstractSyntaxTrees.VnameExpression;
import Triangle.AbstractSyntaxTrees.WhileCommand;
import Triangle.SyntacticAnalyzer.SourcePosition;
public final class Checker implements Visitor {
// Commands
// Always returns null. Does not use the given object.
public Object visitAssignCommand(AssignCommand ast, Object o) {
TypeDenoter vType = (TypeDenoter) ast.V.visit(this, null);
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
if (!ast.V.variable)
reporter.reportError ("LHS of assignment is not a variable", "", ast.V.position);
if (! eType.equals(vType))
reporter.reportError ("assignment incompatibilty", "", ast.position);
return null;
}
public Object visitCallCommand(CallCommand ast, Object o) {
Declaration binding = (Declaration) ast.I.visit(this, null);
if (binding == null)
reportUndeclared(ast.I);
else if (binding instanceof ProcDeclaration) {
ast.APS.visit(this, ((ProcDeclaration) binding).FPS);
} else if (binding instanceof ProcFormalParameter) {
ast.APS.visit(this, ((ProcFormalParameter) binding).FPS);
} else
reporter.reportError("\"%\" is not a procedure identifier",
ast.I.spelling, ast.I.position);
return null;
}
public Object visitEmptyCommand(EmptyCommand ast, Object o) {
return null;
}
public Object visitIfCommand(IfCommand ast, Object o) {
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
if (! eType.equals(StdEnvironment.booleanType))
reporter.reportError("Boolean expression expected here", "", ast.E.position);
ast.C1.visit(this, null);
ast.C2.visit(this, null);
return null;
}
public Object visitLetCommand(LetCommand ast, Object o) {
idTable.openScope();
ast.D.visit(this, null);
ast.C.visit(this, null);
idTable.closeScope();
return null;
}
public Object visitSequentialCommand(SequentialCommand ast, Object o) {
ast.C1.visit(this, null);
ast.C2.visit(this, null);
return null;
}
public Object visitWhileCommand(WhileCommand ast, Object o) {
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
if (! eType.equals(StdEnvironment.booleanType))
reporter.reportError("Boolean expression expected here", "", ast.E.position);
ast.C.visit(this, null);
return null;
}
// Expressions
// Returns the TypeDenoter denoting the type of the expression. Does
// not use the given object.
public Object visitArrayExpression(ArrayExpression ast, Object o) {
TypeDenoter elemType = (TypeDenoter) ast.AA.visit(this, null);
IntegerLiteral il = new IntegerLiteral(new Integer(ast.AA.elemCount).toString(),
ast.position);
ast.type = new ArrayTypeDenoter(il, elemType, ast.position);
return ast.type;
}
public Object visitBinaryExpression(BinaryExpression ast, Object o) {
TypeDenoter e1Type = (TypeDenoter) ast.E1.visit(this, null);
TypeDenoter e2Type = (TypeDenoter) ast.E2.visit(this, null);
Declaration binding = (Declaration) ast.O.visit(this, null);
if (binding == null)
reportUndeclared(ast.O);
else {
if (! (binding instanceof BinaryOperatorDeclaration))
reporter.reportError ("\"%\" is not a binary operator",
ast.O.spelling, ast.O.position);
BinaryOperatorDeclaration bbinding = (BinaryOperatorDeclaration) binding;
if (bbinding.ARG1 == StdEnvironment.anyType) {
// this operator must be "=" or "\="
if (! e1Type.equals(e2Type))
reporter.reportError ("incompatible argument types for \"%\"",
ast.O.spelling, ast.position);
} else if (! e1Type.equals(bbinding.ARG1))
reporter.reportError ("wrong argument type for \"%\"",
ast.O.spelling, ast.E1.position);
else if (! e2Type.equals(bbinding.ARG2))
reporter.reportError ("wrong argument type for \"%\"",
ast.O.spelling, ast.E2.position);
ast.type = bbinding.RES;
}
return ast.type;
}
public Object visitCallExpression(CallExpression ast, Object o) {
Declaration binding = (Declaration) ast.I.visit(this, null);
if (binding == null) {
reportUndeclared(ast.I);
ast.type = StdEnvironment.errorType;
} else if (binding instanceof FuncDeclaration) {
ast.APS.visit(this, ((FuncDeclaration) binding).FPS);
ast.type = ((FuncDeclaration) binding).T;
} else if (binding instanceof FuncFormalParameter) {
ast.APS.visit(this, ((FuncFormalParameter) binding).FPS);
ast.type = ((FuncFormalParameter) binding).T;
} else
reporter.reportError("\"%\" is not a function identifier",
ast.I.spelling, ast.I.position);
return ast.type;
}
public Object visitCharacterExpression(CharacterExpression ast, Object o) {
ast.type = StdEnvironment.charType;
return ast.type;
}
public Object visitEmptyExpression(EmptyExpression ast, Object o) {
ast.type = null;
return ast.type;
}
public Object visitIfExpression(IfExpression ast, Object o) {
TypeDenoter e1Type = (TypeDenoter) ast.E1.visit(this, null);
if (! e1Type.equals(StdEnvironment.booleanType))
reporter.reportError ("Boolean expression expected here", "",
ast.E1.position);
TypeDenoter e2Type = (TypeDenoter) ast.E2.visit(this, null);
TypeDenoter e3Type = (TypeDenoter) ast.E3.visit(this, null);
if (! e2Type.equals(e3Type))
reporter.reportError ("incompatible limbs in if-expression", "", ast.position);
ast.type = e2Type;
return ast.type;
}
public Object visitIntegerExpression(IntegerExpression ast, Object o) {
ast.type = StdEnvironment.integerType;
return ast.type;
}
public Object visitLetExpression(LetExpression ast, Object o) {
idTable.openScope();
ast.D.visit(this, null);
ast.type = (TypeDenoter) ast.E.visit(this, null);
idTable.closeScope();
return ast.type;
}
public Object visitRecordExpression(RecordExpression ast, Object o) {
FieldTypeDenoter rType = (FieldTypeDenoter) ast.RA.visit(this, null);
ast.type = new RecordTypeDenoter(rType, ast.position);
return ast.type;
}
public Object visitUnaryExpression(UnaryExpression ast, Object o) {
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
Declaration binding = (Declaration) ast.O.visit(this, null);
if (binding == null) {
reportUndeclared(ast.O);
ast.type = StdEnvironment.errorType;
} else if (! (binding instanceof UnaryOperatorDeclaration))
reporter.reportError ("\"%\" is not a unary operator",
ast.O.spelling, ast.O.position);
else {
UnaryOperatorDeclaration ubinding = (UnaryOperatorDeclaration) binding;
if (! eType.equals(ubinding.ARG))
reporter.reportError ("wrong argument type for \"%\"",
ast.O.spelling, ast.O.position);
ast.type = ubinding.RES;
}
return ast.type;
}
public Object visitVnameExpression(VnameExpression ast, Object o) {
ast.type = (TypeDenoter) ast.V.visit(this, null);
return ast.type;
}
// Declarations
// Always returns null. Does not use the given object.
public Object visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Object o) {
return null;
}
public Object visitConstDeclaration(ConstDeclaration ast, Object o) {
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
idTable.enter(ast.I.spelling, ast);
if (ast.duplicated)
reporter.reportError ("identifier \"%\" already declared",
ast.I.spelling, ast.position);
return null;
}
public Object visitFuncDeclaration(FuncDeclaration ast, Object o) {
ast.T = (TypeDenoter) ast.T.visit(this, null);
idTable.enter (ast.I.spelling, ast); // permits recursion
if (ast.duplicated)
reporter.reportError ("identifier \"%\" already declared",
ast.I.spelling, ast.position);
idTable.openScope();
ast.FPS.visit(this, null);
TypeDenoter eType = (TypeDenoter) ast.E.visit(this, null);
idTable.closeScope();
if (! ast.T.equals(eType))
reporter.reportError ("body of function \"%\" has wrong type",
ast.I.spelling, ast.E.position);
return null;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -