// TypeCheckVisitor.java
package semant;
import syntaxtree.*;
import java.util.Vector;
import java.util.StringTokenizer;
public class TypeCheckVisitor extends visitor.TypeDepthFirstVisitor {
// By extending TypeDepthFirstVisitor, we only have to override those
// methods that differ from the generic visitor.
private errormsg.ErrorMsg errorMsg;
private SymbolTable classTable;
private ClassInfo currClass;
private MethodInfo currMethod;
public int errCounter;
private boolean T;
private String[] primitives = {"int","boolean","class", "int[]"};
// Type constants
final IntegerType INTTY = new IntegerType();
final IntArrayType INTARRTY = new IntArrayType();
final BooleanType BOOLTY = new BooleanType();
public TypeCheckVisitor(errormsg.ErrorMsg e, SymbolTable s){
errorMsg = e;
classTable = s;
currClass = null;
currMethod = null;
T = false;
}
// Identifier i1,i2;
// Statement s;
public Type visit(MainClass n)
{
String id = n.i1.toString();
currClass = classTable.get(id);
T = true;
n.i2.accept(this);
n.s.accept(this);
T = false;
return new IdentifierType(currClass.getName());
}
// MainClass m;
// ClassDeclList cl;
public Type visit(Program n) {
n.m.accept(this);
for (int i = 0; i < n.cl.size()-1; i++)
{
n.cl.elementAt(i).accept(this);
}
return null;
}
// Identifier i;
// List vl;
// MethodDeclList ml;
public Type visit(ClassDeclSimple n) {
String iX = n.i.toString();
currClass = classTable.get(iX);
for(int i=0; i<n.vl.size();i++) {
n.vl.elementAt(i).accept(this);
}
for(int i=0; i<n.ml.size();i++){
n.ml.elementAt(i).accept(this);
}
n.i.accept(this);
return new IdentifierType(currClass.getName());
}
// Type t;
// Identifier i;
public Type visit(Formal n) {
n.t.accept(this);
n.i.accept(this);
return null;
}
// Exp e;
// Statement s1,s2;
public Type visit(If n) {
Type t = n.e.accept(this);
if (!equal(t,BOOLTY,BOOLTY)) {
errCounter++;
errorMsg.error(n.pos, "Err: Condition of if must be of type boolean");
}
n.s1.accept(this);
n.s2.accept(this);
return t;
}
// Exp e;
// Statement s;
public Type visit(While n) {
Type t = n.e.accept(this);
if (!equal(t,BOOLTY,BOOLTY)) {
errCounter++;
errorMsg.error(n.pos, "Err:Condition of while must be of type boolean");
}
n.s.accept(this);
return t;
}
// Exp e;
public Type visit(Print n) {
Type t = n.e.accept(this);
return t;
}
// Identifier i;
// Exp e;
public Type visit(Assign n){
Type eType = n.e.accept(this);
VariableInfo vi = null;
if(currMethod!=null){
vi = currMethod.getVar(n.i.toString());
if(vi!=null && (!equal(vi.type,eType,vi.type))){
errCounter++;
errorMsg.error(n.pos, "Err:"+eIncompTypes(eType.toString(),vi.type.toString()));
}
}
else{
vi = currClass.getField(n.i.toString());
if(vi!=null && (!equal(vi.type,eType,vi.type)) ){
errCounter++;
errorMsg.error(n.pos, "Err:"+eIncompTypes(eType.toString(),vi.type.toString()));
}
}
return eType;
}
// Identifier i;
// Exp e1,e2;
public Type visit(ArrayAssign n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
VariableInfo vi = currClass.getField(n.i.toString());
if(vi==null && currMethod!=null){
vi = currMethod.getVar(n.i.toString());
}
Type IdType = vi.type;
if ((!(t1 instanceof IntegerType))&& t1!=null) {
errCounter++;
errorMsg.error(n.e1.pos, "Err:"+eIncompTypes(t1.toString(),INTTY.toString()));
}
if ((!(t2 instanceof IntegerType)) && t2!=null) {
errCounter++;
errorMsg.error(n.e1.pos, "Err:"+eIncompTypes(t2.toString(),INTTY.toString()));
}
return IdType;
}
// Type t;
// Identifier i;
public Type visit(VarDecl n) {
n.t.accept(this);
n.i.accept(this);
VariableInfo vi=null;
Type tx=null;
if(currMethod!=null){
vi = currMethod.getVar(n.i.toString());
}
if(vi==null && currClass!=null){
vi=currClass.getField(n.i.toString());
}
if(vi!=null){
tx = vi.type;
}
if(tx==null){
errCounter++;
errorMsg.error(n.pos,"Err: Cannot resolve symbol "+n.i.toString());
}
else{
int c=0;
for(int i=0; i<4;i++){
if(!tx.toString().equals(primitives[i])){ c++;}
}
if(c==4 && ( classTable.get(tx.toString()) == null ) ){
errCounter++;
errorMsg.error(n.pos,"Err:\""+ tx.toString()+"\" is not a class or a type");
}
}
return tx;
}
// Type t;
// Identifier i;
// FormalList fl;
// VarDeclList vl;
// StatementList sl;
// Exp e;
public Type visit(MethodDecl n) {
String id = n.i.toString();
currMethod = currClass.getMethod(id);
Type eType = n.e.accept(this);
Type retType = currMethod.getReturnType();
for ( int i = 0; i < n.fl.size(); i++ ) {
n.fl.elementAt(i).accept(this);
}
for ( int i = 0; i < n.vl.size(); i++ ) {
n.vl.elementAt(i).accept(this);
}
for ( int i = 0; i < n.sl.size(); i++ ) {
n.sl.elementAt(i).accept(this);
}
//We have to compare the return type of the method
//with the actual returned parameter
//and report error when necessary
if(eType!=null){
if(!retType.toString().equals(eType.toString())){
errCounter++;
errorMsg.error(n.pos,errCounter+":"+eIncompTypes(eType.toString(),retType.toString()));
}
}
return retType;
}
public Type visit(And n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if (!equal(t1, t2, BOOLTY)){
errCounter++;
errorMsg.error(n.pos,"Err:"+ eIncompBiop("&&", t1.toString(), t2.toString()));
}
return BOOLTY;
}
// Exp e1,e2;
public Type visit(LessThan n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if (!equal(t1, t2, INTTY)){
errCounter++;
errorMsg.error(n.pos,"Err:"+ eIncompBiop("<", t1.toString(), t2.toString()));
}
return BOOLTY;
}
// Exp e1,e2;
public Type visit(Minus n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if (!equal(t1, t2, INTTY)){
errCounter++;
errorMsg.error(n.pos,"Err:"+ eIncompBiop("-", t1.toString(), t2.toString()));
}
return INTTY;
}
// Exp e1,e2;
public Type visit(Times n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if (!equal(t1, t2, INTTY)){
errCounter++;
errorMsg.error(n.pos,"Err:"+ eIncompBiop("*", t1.toString(), t2.toString()));
}
return INTTY;
}
// Exp e1,e2;
public Type visit(ArrayLookup n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if(!(t2 instanceof IntegerType)){
errCounter++;
errorMsg.error(n.pos,"Err:"+eIncompTypes(t2.toString(),INTTY.toString() ));
}
return INTTY;
}
// Exp e;
public Type visit(ArrayLength n) {
Type t = n.e.accept(this);
if (t!=null && !(t instanceof IntArrayType) ) {
errCounter++;
errorMsg.error(n.e.pos, "Err: int required.");
}
return INTTY ;
}
// Exp e;
// Identifier i;
// ExpList el;
public Type visit(Call n) {
Type t = n.e.accept(this);
n.i.accept(this);
ClassInfo classInfo = classTable.get(t.toString());
if (classInfo==null){
errCounter++;
errorMsg.error(n.pos, "Err: Not a valid class or Object. ");
return null;
}
MethodInfo method = classInfo.getMethod(n.i.toString());
if (method==null){
errCounter++;
errorMsg.error(n.pos,"Err: Cannot resolve method "+n.i.toString());
return null;
}
//Fillout the fullname field
n.fullname = classInfo.getName()+"$"+method.getName();
Vector v = new Vector();
for(int i=0; i<n.el.size();i++){
Type type = n.el.elementAt(i).accept(this);
if (type != null)
v.add(type.toString());
else{
return null;
}
}
String formalsF = v.toString();
formalsF = "("+formalsF.substring(1,formalsF.length()-1)+")";
String formals = method.getFormalsTypes();
if(!(formals.equals(formalsF))){
errCounter++;
errorMsg.error(n.pos,"Err: Cannot apply "+classInfo.getName()+"."+
method.getName()+formals+ " to " + formalsF);
}
return null;
}
// int i;
public Type visit(IntegerLiteral n) {
return INTTY;
}
public Type visit(True n) {
return BOOLTY;
}
public Type visit(False n) {
return BOOLTY;
}
// String s;
public Type visit(IdentifierExp n) {
Type t;
VariableInfo vi = null;
if(currMethod!=null){
vi =currMethod.getVar(n.s.toString());
if(vi==null){
}
else{
}
}
if( vi == null && currClass!=null ){
vi = currClass.getField(n.s.toString());
}
if(vi!=null){
t= vi.type;
return t;
}
else{
errCounter++;
errorMsg.error(n.pos, "Err: Cannot resolve symbol "+n.s+ " in class " + currClass.getName());
}
return null;
}
public Type visit(This n) {
if(T){
errCounter++;
errorMsg.error(n.pos,"Err: non-static variable \"this\" cannot be referenced from a static context");
}
else{
if(currClass !=null){
return new IdentifierType(currClass.getName());
}
}
return null;
}
// Exp e;
public Type visit(NewArray n) {
Type t = n.e.accept(this);
if (! (t instanceof IntegerType) ) {
errCounter++;
errorMsg.error(n.e.pos, "Err: int required.");
}
return INTARRTY;
}
// Identifier i;
public Type visit(NewObject n) {
return new IdentifierType(n.i.s);
}
// Exp e;
public Type visit(Not n) {
Type t = n.e.accept(this);
if (! (t instanceof BooleanType) ) {
errCounter++;
errorMsg.error(n.e.pos, "Err: boolean required.");
}
return BOOLTY;
}
// Exp e1,e2;
public Type visit(Plus n) {
Type t1 = n.e1.accept(this);
Type t2 = n.e2.accept(this);
if (!equal(t1, t2, INTTY)){
errCounter++;
errorMsg.error(n.pos,"Err:"+ eIncompBiop("+", t1.toString(), t2.toString()));
}
return INTTY;
}
// Check whether t1 == t2 == target, but suppress error messages if
// either t1 or t2 is null.
private boolean equal(Type t1, Type t2, Type target) {
if ( t1 == null || t2 == null )
return true;
if (target == null){
throw new Error("target argument in method equal cannot be null");
}
if (target instanceof IdentifierType && t1 instanceof IdentifierType
&& t2 instanceof IdentifierType)
return ((IdentifierType) t1).s.equals(((IdentifierType) t2).s );
if (!(target instanceof IdentifierType) &&
t1.toString().equals(target.toString()) &&
t2.toString().equals(target.toString()))
return true;
return false;
}
// Methods for error reporting:
private String eIncompTypes(String t1, String t2) {
return "incompatible types \nfound : " + t1
+ "\nrequired: " + t2 ;
}
private String eIncompBiop(String op, String t1, String t2) {
return "operator \"" + op + "\" cannot be applied to " + t1 + "," + t2 ;
}
www.cpccci.com
www.cpcwebsolutions.com
www.cpcwebdevelopment.com