From 92e66882890693adee8d72b66c5ffefdf7afb8bd Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Sun, 7 Mar 2021 15:35:34 +0530 Subject: [PATCH 1/4] Added semantic check for duplicate local variable declaration --- .../common/analysis/types/FuncType.java | 6 +- .../java/chocopy/pa2/DeclarationAnalyzer.java | 67 +++++++++++++++++-- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/main/java/chocopy/common/analysis/types/FuncType.java b/src/main/java/chocopy/common/analysis/types/FuncType.java index 69fdefc..f729958 100644 --- a/src/main/java/chocopy/common/analysis/types/FuncType.java +++ b/src/main/java/chocopy/common/analysis/types/FuncType.java @@ -8,11 +8,15 @@ import java.util.List; /** Semantic information for a function or method. */ public class FuncType extends Type { + /** Function's name. */ + //public final String name; + /** Types of parameters. */ - public final List parameters; + public List parameters; /** Function's return type. */ public final ValueType returnType; + /** Create a FuncType returning RETURNTYPE0, initially parameterless. */ public FuncType(ValueType returnType0) { this(new ArrayList<>(), returnType0); diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java index 29aaf5a..9f9673f 100644 --- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java +++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java @@ -2,15 +2,14 @@ package chocopy.pa2; import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; -import chocopy.common.analysis.types.Type; -import chocopy.common.analysis.types.ValueType; +import chocopy.common.analysis.types.*; import chocopy.common.astnodes.*; /** Analyzes declarations to create a top-level symbol table. */ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { /** Current symbol table. Changes with new declarative region. */ - private final SymbolTable sym = new SymbolTable<>(); + private SymbolTable sym = new SymbolTable<>(); /** Global symbol table. */ private final SymbolTable globals = sym; /** Receiver for semantic error messages. */ @@ -30,9 +29,8 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { for (Declaration decl : program.declarations) { Identifier id = decl.getIdentifier(); String name = id.name; - Type type = decl.dispatch(this); - + if (type == null) { continue; } @@ -52,4 +50,63 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { public Type analyze(VarDef varDef) { return ValueType.annotationToValueType(varDef.var.type); } + @Override + public Type analyze(FuncDef node) { + FuncType current_func=new FuncType((ValueType) node.returnType.dispatch(this)); + SymbolTable current_scope=new SymbolTable<>(sym); + sym=current_scope; + for (TypedVar param : node.params) + { + + if (sym.declares(param.identifier.name)) + { + errors.semError( + node.name, "Duplicate declaration of identifier in same " + "scope: %s", param.identifier.name); + continue; + } + /* + else if (sym.get(param.identifier.name)!= null) + { + System.out.println("Error:"+sym.get(param.identifier.name)); + errors.semError( + node.name, "Parameter shadows class name: %s", param.identifier.name); + continue; + }*/ + + Type p = param.dispatch(this); + current_func.parameters.add((ValueType)p); + sym.put(param.identifier.name, p); + } + + for (Declaration decl : node.declarations) { + Identifier id = decl.getIdentifier(); + String name = id.name; + Type type = decl.dispatch(this); + + + if (type == null) { + continue; + } + + if (sym.declares(name)) { + errors.semError( + id, "Duplicate declaration of identifier in same " + "scope: %s", name); + } else { + sym.put(name, type); + } + } + sym = sym.getParent(); + return current_func; + } + @Override + public Type analyze(GlobalDecl node) + { + if (globals.declares(node.variable.name)==false) + { + errors.semError( + node.variable, "Not a global variable: %s", node.variable.name); + return null; + } + return globals.get(node.variable.name); + } } From 79be979e1366a6cbb5b501a93e9f9354cef57c66 Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Tue, 9 Mar 2021 16:33:48 +0530 Subject: [PATCH 2/4] Added class analyze method --- .../common/analysis/types/ClassVType.java | 56 ++++++++++ .../common/analysis/types/FuncType.java | 4 +- .../common/analysis/types/FuncValueType.java | 49 +++++++++ .../java/chocopy/pa2/DeclarationAnalyzer.java | 102 +++++++++++++++--- 4 files changed, 194 insertions(+), 17 deletions(-) create mode 100644 src/main/java/chocopy/common/analysis/types/ClassVType.java create mode 100644 src/main/java/chocopy/common/analysis/types/FuncValueType.java diff --git a/src/main/java/chocopy/common/analysis/types/ClassVType.java b/src/main/java/chocopy/common/analysis/types/ClassVType.java new file mode 100644 index 0000000..42a312f --- /dev/null +++ b/src/main/java/chocopy/common/analysis/types/ClassVType.java @@ -0,0 +1,56 @@ +package chocopy.common.analysis.types; + +import chocopy.common.astnodes.ClassType; +import chocopy.common.astnodes.Identifier; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import chocopy.common.analysis.SymbolTable; +import java.util.Objects; + +/** Represents the semantic value of a simple class reference. */ +public class ClassVType extends ValueType { + + /** The name of the class. */ + private final String className; + public SymbolTable scope; + public Identifier super_class; + /** A class type for the class named CLASSNAME. */ + @JsonCreator + public ClassVType(@JsonProperty String className) { + this.className = className; + } + + /** A class type for the class referenced by CLASSTYPEANNOTATION. */ + public ClassVType(ClassType classTypeAnnotation) { + this.className = classTypeAnnotation.className; + } + + @Override + @JsonProperty + public String className() { + return className; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ClassVType classType = (ClassVType) o; + return Objects.equals(className, classType.className); + } + + @Override + public int hashCode() { + return Objects.hash(className); + } + + @Override + public String toString() { + return className; + } +} diff --git a/src/main/java/chocopy/common/analysis/types/FuncType.java b/src/main/java/chocopy/common/analysis/types/FuncType.java index f729958..7d0f7a5 100644 --- a/src/main/java/chocopy/common/analysis/types/FuncType.java +++ b/src/main/java/chocopy/common/analysis/types/FuncType.java @@ -8,11 +8,9 @@ import java.util.List; /** Semantic information for a function or method. */ public class FuncType extends Type { - /** Function's name. */ - //public final String name; /** Types of parameters. */ - public List parameters; + public final List parameters; /** Function's return type. */ public final ValueType returnType; diff --git a/src/main/java/chocopy/common/analysis/types/FuncValueType.java b/src/main/java/chocopy/common/analysis/types/FuncValueType.java new file mode 100644 index 0000000..5e73b46 --- /dev/null +++ b/src/main/java/chocopy/common/analysis/types/FuncValueType.java @@ -0,0 +1,49 @@ +package chocopy.common.analysis.types; + +import com.fasterxml.jackson.annotation.JsonCreator; + +import java.util.ArrayList; +import java.util.List; + +/** Semantic information for a function or method. */ +public class FuncValueType extends Type { + + /** Function's name. */ + //public final String name; + + /** Types of parameters. */ + public List parameters; + /** Function's return type. */ + public final ValueType returnType; + + + /** Create a FuncType returning RETURNTYPE0, initially parameterless. */ + public FuncValueType(ValueType returnType0) { + this(new ArrayList<>(), returnType0); + } + + /** + * Create a FuncType for NAME0 with formal parameter types PARAMETERS0, returning type + * RETURNTYPE0. + */ + @JsonCreator + public FuncValueType(List parameters0, ValueType returnType0) { + this.parameters = parameters0; + this.returnType = returnType0; + } + + @Override + public boolean isFuncType() { + return true; + } + + /** Return the type of the K-th parameter. */ + public ValueType getParamType(int k) { + return parameters.get(k); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java index 9f9673f..33bfe91 100644 --- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java +++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java @@ -6,7 +6,8 @@ import chocopy.common.analysis.types.*; import chocopy.common.astnodes.*; /** Analyzes declarations to create a top-level symbol table. */ -public class DeclarationAnalyzer extends AbstractNodeAnalyzer { +public class DeclarationAnalyzer extends AbstractNodeAnalyzer +{ /** Current symbol table. Changes with new declarative region. */ private SymbolTable sym = new SymbolTable<>(); @@ -16,33 +17,63 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { private final Errors errors; /** A new declaration analyzer sending errors to ERRORS0. */ - public DeclarationAnalyzer(Errors errors0) { + public DeclarationAnalyzer(Errors errors0) + { errors = errors0; + ClassVType cvt = new ClassVType("object"); + FuncValueType init = new FuncValueType(Type.OBJECT_TYPE); + init.parameters.add(Type.OBJECT_TYPE); + sym.put("object", cvt); + cvt = new ClassVType("int"); + init = new FuncValueType(Type.INT_TYPE); + init.parameters.add(Type.INT_TYPE); + sym.put("int", cvt); + cvt = new ClassVType("str"); + init = new FuncValueType(Type.STR_TYPE); + init.parameters.add(Type.STR_TYPE); + sym.put("str", cvt); + cvt = new ClassVType("bool"); + init = new FuncValueType(Type.BOOL_TYPE); + init.parameters.add(Type.BOOL_TYPE); + sym.put("bool", cvt); } - public SymbolTable getGlobals() { + public SymbolTable getGlobals() + { return globals; } @Override - public Type analyze(Program program) { - for (Declaration decl : program.declarations) { + public Type analyze(Program program) + { + for (Declaration decl : program.declarations) + { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); - if (type == null) { + if (type == null) + { continue; } - if (sym.declares(name)) { + if (sym.declares(name)) + { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); - } else { + } + else + { sym.put(name, type); } } - + // Check for return statements at top + for (Stmt stmt : program.statements) + { + if (stmt instanceof ReturnStmt) + errors.semError( + stmt, "Return statement cannot appear at the top level"); + } return null; } @@ -52,7 +83,7 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { } @Override public Type analyze(FuncDef node) { - FuncType current_func=new FuncType((ValueType) node.returnType.dispatch(this)); + FuncValueType current_func=new FuncValueType((ValueType) node.returnType.dispatch(this)); SymbolTable current_scope=new SymbolTable<>(sym); sym=current_scope; for (TypedVar param : node.params) @@ -64,21 +95,21 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { node.name, "Duplicate declaration of identifier in same " + "scope: %s", param.identifier.name); continue; } - /* - else if (sym.get(param.identifier.name)!= null) + else if (sym.get(param.identifier.name)!= null && sym.get(param.identifier.name) instanceof ClassVType) { System.out.println("Error:"+sym.get(param.identifier.name)); errors.semError( node.name, "Parameter shadows class name: %s", param.identifier.name); continue; - }*/ + } Type p = param.dispatch(this); current_func.parameters.add((ValueType)p); sym.put(param.identifier.name, p); } - for (Declaration decl : node.declarations) { + for (Declaration decl : node.declarations) + { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); @@ -109,4 +140,47 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { } return globals.get(node.variable.name); } + @Override + public Type analyze(ClassDef node) + { + ClassVType cvt=new ClassVType(node.name.name); + SymbolTable current_scope=new SymbolTable<>(sym); + sym=current_scope; + Type super_class = sym.get(node.superClass.name); + cvt.super_class = node.superClass; + if (super_class == null) + { + errors.semError( + node.name, "Super-class not defined: %s", node.superClass.name); + } + else if ((super_class instanceof ClassVType)==false) + { + errors.semError( + node.name, "Super-class must be a class: %s", node.superClass.name); + } + else if (node.superClass.name.equals("int") || node.superClass.name.equals("bool") || node.superClass.name.equals("str")) + { + errors.semError( + node.name, "Cannot extend special class: %s", node.superClass.name); + } + else + { + for (Declaration decl : node.declarations) + { + Identifier id = decl.getIdentifier(); + String name = id.name; + Type type = decl.dispatch(this); + if (sym.declares(name)) { + errors.semError( + id, "Duplicate declaration of identifier in same " + "scope: %s", name); + } + else + { + sym.put(name, type); + } + } + } + sym = sym.getParent(); + return cvt; + } } From 84b1c679b9b0eaaa97aa36332bfa88331a17e82d Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Sat, 13 Mar 2021 16:03:23 +0530 Subject: [PATCH 3/4] Progress on class def node analyzer --- .../common/analysis/types/ClassVType.java | 4 +- .../java/chocopy/pa2/DeclarationAnalyzer.java | 135 +++++++++++++++--- 2 files changed, 116 insertions(+), 23 deletions(-) diff --git a/src/main/java/chocopy/common/analysis/types/ClassVType.java b/src/main/java/chocopy/common/analysis/types/ClassVType.java index 42a312f..af04de7 100644 --- a/src/main/java/chocopy/common/analysis/types/ClassVType.java +++ b/src/main/java/chocopy/common/analysis/types/ClassVType.java @@ -12,9 +12,9 @@ import java.util.Objects; public class ClassVType extends ValueType { /** The name of the class. */ - private final String className; + public final String className; public SymbolTable scope; - public Identifier super_class; + public ClassVType super_class; /** A class type for the class named CLASSNAME. */ @JsonCreator public ClassVType(@JsonProperty String className) { diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java index 33bfe91..d2e5fc3 100644 --- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java +++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java @@ -4,7 +4,7 @@ import chocopy.common.analysis.AbstractNodeAnalyzer; import chocopy.common.analysis.SymbolTable; import chocopy.common.analysis.types.*; import chocopy.common.astnodes.*; - +import java.util.*; /** Analyzes declarations to create a top-level symbol table. */ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { @@ -15,7 +15,7 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer private final SymbolTable globals = sym; /** Receiver for semantic error messages. */ private final Errors errors; - + private ClassVType current_class=null; /** A new declaration analyzer sending errors to ERRORS0. */ public DeclarationAnalyzer(Errors errors0) { @@ -23,18 +23,30 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer ClassVType cvt = new ClassVType("object"); FuncValueType init = new FuncValueType(Type.OBJECT_TYPE); init.parameters.add(Type.OBJECT_TYPE); + SymbolTable cvt_scope=new SymbolTable<>(sym); + cvt_scope.put("init",init); + cvt.scope=cvt_scope; sym.put("object", cvt); cvt = new ClassVType("int"); init = new FuncValueType(Type.INT_TYPE); init.parameters.add(Type.INT_TYPE); + cvt_scope=new SymbolTable<>(sym); + cvt_scope.put("init",init); + cvt.scope=cvt_scope; sym.put("int", cvt); cvt = new ClassVType("str"); init = new FuncValueType(Type.STR_TYPE); init.parameters.add(Type.STR_TYPE); + cvt_scope=new SymbolTable<>(sym); + cvt_scope.put("init",init); + cvt.scope=cvt_scope; sym.put("str", cvt); cvt = new ClassVType("bool"); init = new FuncValueType(Type.BOOL_TYPE); init.parameters.add(Type.BOOL_TYPE); + cvt_scope=new SymbolTable<>(sym); + cvt_scope.put("init",init); + cvt.scope=cvt_scope; sym.put("bool", cvt); } @@ -61,7 +73,13 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); - } + } + else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType) + { + errors.semError( + id, "Cannot shadow class name: %s", name); + continue; + } else { sym.put(name, type); @@ -76,11 +94,6 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer } return null; } - - @Override - public Type analyze(VarDef varDef) { - return ValueType.annotationToValueType(varDef.var.type); - } @Override public Type analyze(FuncDef node) { FuncValueType current_func=new FuncValueType((ValueType) node.returnType.dispatch(this)); @@ -95,11 +108,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer node.name, "Duplicate declaration of identifier in same " + "scope: %s", param.identifier.name); continue; } - else if (sym.get(param.identifier.name)!= null && sym.get(param.identifier.name) instanceof ClassVType) + else if (sym.get(param.identifier.name)!= null && sym.get(param.identifier.name) instanceof ClassVType) { - System.out.println("Error:"+sym.get(param.identifier.name)); errors.semError( - node.name, "Parameter shadows class name: %s", param.identifier.name); + param.identifier, "Cannot shadow class name: %s", param.identifier.name); continue; } @@ -114,18 +126,29 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer String name = id.name; Type type = decl.dispatch(this); - - if (type == null) { + if (type == null) + { continue; } - if (sym.declares(name)) { + if (sym.declares(name)) + { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); - } else { + continue; + } + else if (sym.get(name)!= null && sym.get(name) instanceof ClassVType) + { + errors.semError(id, "Cannot shadow class name: %s", name); + continue; + } + else + { sym.put(name, type); } } + /*for(String s:sym.getDeclaredSymbols()) + System.out.println(" "+s);*/ sym = sym.getParent(); return current_func; } @@ -140,14 +163,27 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer } return globals.get(node.variable.name); } + public boolean compare_functions(FuncValueType fun1, FuncValueType fun2) { + if (fun1.returnType.equals(fun2.returnType)==false) + return false; + if (fun1.parameters.size() != fun2.parameters.size()) + return false; + for (int i=1; i(sym); + SymbolTable current_scope=new SymbolTable<>(sym); sym=current_scope; + current_class=cvt; Type super_class = sym.get(node.superClass.name); - cvt.super_class = node.superClass; + cvt.super_class = (ClassVType)super_class; + SymbolTable super_scope=null; + Set super_syms=null; if (super_class == null) { errors.semError( @@ -165,22 +201,79 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer } else { + super_scope = cvt.super_class.scope; + super_syms = super_scope.getDeclaredSymbols(); for (Declaration decl : node.declarations) { Identifier id = decl.getIdentifier(); String name = id.name; Type type = decl.dispatch(this); - if (sym.declares(name)) { + + if (type == null) + continue; + + if (sym.declares(name)) + { errors.semError( id, "Duplicate declaration of identifier in same " + "scope: %s", name); } - else - { - sym.put(name, type); + if (type instanceof ClassVType || type instanceof ListValueType) + {//Check for attribute type + if (super_syms.contains(name)) + {//Check for redefined superclass attribute + errors.semError( + id, "Cannot re-define attribute: %s", name); + } + else + sym.put(name, type); } + else if(type instanceof FuncValueType) + {//For function declarations + List params = ((FuncValueType)type).parameters; + if(params.size() < 1 || (params.get(0) instanceof ClassVType==false) || ((ClassVType)params.get(0)).className.equals(current_class.className)==false) + errors.semError( + id, "First parameter of method must be of same class: %s", name); + if (super_syms.contains(name)) + { + if ((super_scope.get(id.name) instanceof FuncValueType)==false) + errors.semError(id, "Cannot re-define attribute: %s" + name); + else + { + FuncValueType super_func = (FuncValueType) super_scope.get(id.name); + FuncValueType current_func = (FuncValueType) type; + if (compare_functions(super_func, current_func)) + sym.put(name, type); + else + errors.semError( + id, "Method overridden with different type signature: %s" + name); + } + } + else + sym.put(name, type); + } } } + for (String super_sym : super_syms) + { + if (sym.getDeclaredSymbols().contains(super_sym)==false) + sym.put(super_sym, super_scope.get(super_sym)); + } sym = sym.getParent(); + current_class=null; return cvt; } + @Override + public Type analyze(VarDef node) + { + Type var_type = sym.get(node.var.identifier.name); + if (node.var.identifier.name!=current_class.className && var_type==null) + errors.semError( + node, "Cannot re-define attribute: %s", node.var.identifier.name); + return ValueType.annotationToValueType(node.var.type); + } + @Override + public Type analyze(ListType node) + { + return ValueType.annotationToValueType(node); + } } From 20f733aadfcce6d7c0f1b9a64a0907f139b6fe3c Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Wed, 17 Mar 2021 19:40:39 +0530 Subject: [PATCH 4/4] Create WORKLOG.md --- WORKLOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 WORKLOG.md diff --git a/WORKLOG.md b/WORKLOG.md new file mode 100644 index 0000000..eef9fd0 --- /dev/null +++ b/WORKLOG.md @@ -0,0 +1,15 @@ +# Compiler Construction PA2 Worklog + +## Team: +**Apoorva Ranade**(ar6496)   **Sanjar Ahmadov**(sa5640)   **Yinqi Sun**(ys3540) +
+ +## Passes: + - +## Recovery: + - + +## Challenges: + - +## Improvements: + - Added more tests to rigorously check program flow and indentation.