From 19052eb85b9429a3dfd02c2ed93eb24cc3925579 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 6 Apr 2023 16:41:16 +0100 Subject: [PATCH 001/253] Made symbolTable and reports list private fields in Analysis class --- src/main/pt/up/fe/comp2023/Analysis.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index aaa64e7..3224e14 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -8,9 +8,11 @@ import java.util.ArrayList; public class Analysis implements JmmAnalysis { + private MySymbolTable symbolTable; + private final ArrayList reports = new ArrayList<>(); @Override public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { - MySymbolTable symbolTable = new MySymbolTable(parserResult.getRootNode()); - return new JmmSemanticsResult(parserResult, symbolTable, new ArrayList()); + this.symbolTable = new MySymbolTable(parserResult.getRootNode()); + return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); } } From 49f1841c60bfb2e7c7d0fc037a0a835b46511519 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 6 Apr 2023 16:46:03 +0100 Subject: [PATCH 002/253] Added Semantic Analysis Stage --- src/main/pt/up/fe/comp2023/Launcher.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 34b7c39..f363adb 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -6,6 +6,7 @@ import java.util.Map; import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.parser.JmmParserResult; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsLogs; @@ -49,6 +50,15 @@ public static void main(String[] args) { // Output Symbol Table System.out.println(symbolTable.print()); + // Instantiate Analysis + Analysis analysis = new Analysis(); + + // Semantic Analysis Stage + JmmSemanticsResult semanticsResult = analysis.semanticAnalysis(parserResult); + + // Check if there are semantic errors + TestUtils.noErrors(semanticsResult.getReports()); + // ... add remaining stages } From e99fb8bf7a94d06737a31882721f2718ba84bf2f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 02:08:57 +0100 Subject: [PATCH 003/253] Added basic structure of class ClassDeclAnalysis --- src/main/pt/up/fe/comp2023/Analysis.java | 14 ++++++++ .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 34 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index 3224e14..0347e49 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -2,17 +2,31 @@ import pt.up.fe.comp.jmm.analysis.JmmAnalysis; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.parser.JmmParserResult; import pt.up.fe.comp.jmm.report.Report; import java.util.ArrayList; +import java.util.List; public class Analysis implements JmmAnalysis { private MySymbolTable symbolTable; private final ArrayList reports = new ArrayList<>(); @Override public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { + JmmNode root = parserResult.getRootNode(); this.symbolTable = new MySymbolTable(parserResult.getRootNode()); + + ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root); + classDeclAnalysis.checkImportedSuperClass(); + + List methodNodes = classDeclAnalysis.getMethodNodes(); + for (JmmNode node : methodNodes){ + //TODO: if (mainMethod), check parameter type == 'String' + //TODO: validate each statement + // ... + } + return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); } } diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java new file mode 100644 index 0000000..4031fc5 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -0,0 +1,34 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; + +import java.util.ArrayList; +import java.util.List; + +public class ClassDeclAnalysis extends AJmmVisitor { + private JmmNode classDeclNode; + private final List methodNodes = new ArrayList<>(); + + public ClassDeclAnalysis(JmmNode rootNode){ + this.classDeclNode = rootNode.getJmmChild(rootNode.getNumChildren() - 1); + } + + @Override + protected void buildVisitor() { + addVisit("MethodDecl", this::addMethodNode); + addVisit("VoidMethodDecl", this::addMethodNode); + addVisit("MainMethodDecl", this::addMethodNode); + } + + public void checkImportedSuperClass() { + } + + private Void addMethodNode(JmmNode methodNode, Void unused) { + return null; + } + + public List getMethodNodes() { + return this.methodNodes; + } +} From b954dc75ec3098ce79e45b39d49a92f3cac36ae8 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 02:25:05 +0100 Subject: [PATCH 004/253] Implemented getters and addReport() in Analysis.java --- src/main/pt/up/fe/comp2023/Analysis.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index 0347e49..3e44238 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -26,7 +26,18 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { //TODO: validate each statement // ... } - return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); } + + public MySymbolTable getSymbolTable(){ + return this.symbolTable; + } + + public List getReports(){ + return this.reports; + } + + public void addReport(Report report) { + this.reports.add(report); + } } From b234d864524280d76a6dc8a485d5ab6185eedd92 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 02:34:55 +0100 Subject: [PATCH 005/253] Implemented method to check if super class is imported --- src/main/pt/up/fe/comp2023/Analysis.java | 2 +- .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index 3e44238..f5c4a00 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -17,7 +17,7 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { JmmNode root = parserResult.getRootNode(); this.symbolTable = new MySymbolTable(parserResult.getRootNode()); - ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root); + ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this); classDeclAnalysis.checkImportedSuperClass(); List methodNodes = classDeclAnalysis.getMethodNodes(); diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index 4031fc5..0bd54d2 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -2,16 +2,22 @@ import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.report.ReportType; +import pt.up.fe.comp.jmm.report.Stage; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class ClassDeclAnalysis extends AJmmVisitor { private JmmNode classDeclNode; + private Analysis analysis; private final List methodNodes = new ArrayList<>(); - public ClassDeclAnalysis(JmmNode rootNode){ + public ClassDeclAnalysis(JmmNode rootNode, Analysis analysis){ this.classDeclNode = rootNode.getJmmChild(rootNode.getNumChildren() - 1); + this.analysis = analysis; } @Override @@ -22,13 +28,34 @@ protected void buildVisitor() { } public void checkImportedSuperClass() { + String superClass = analysis.getSymbolTable().getSuper(); + + if(superClass != null && !findImport(superClass)){ + String message = "Cannot find super class '" + superClass + "'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for (JmmNode child: classDeclNode.getChildren()) + visit(child); } private Void addMethodNode(JmmNode methodNode, Void unused) { + this.methodNodes.add(methodNode); return null; } public List getMethodNodes() { return this.methodNodes; } + + Boolean findImport (String string) { + List imports = analysis.getSymbolTable().getImports(); + + for(String imported : imports){ + List splitImport = List.of(imported.split("\\.")); + if (Objects.equals(splitImport.get(splitImport.size() - 1), string)) + return true; + } + return false; + } } From 94eb148ac5bfd1988056b229504635d86ae048f8 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 15:53:56 +0100 Subject: [PATCH 006/253] Added basic structure of class MethodAnalysis --- src/main/pt/up/fe/comp2023/Analysis.java | 10 ++-- .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 4 +- .../pt/up/fe/comp2023/MethodAnalysis.java | 46 +++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/main/pt/up/fe/comp2023/MethodAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index f5c4a00..c1bc984 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -20,11 +20,11 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this); classDeclAnalysis.checkImportedSuperClass(); - List methodNodes = classDeclAnalysis.getMethodNodes(); - for (JmmNode node : methodNodes){ - //TODO: if (mainMethod), check parameter type == 'String' - //TODO: validate each statement - // ... + for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ + MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this); + for (JmmNode statementNode : methodAnalysis.getStatementNodes()){ + //TODO: validate each statement + } } return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); } diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index 0bd54d2..f2ac292 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -11,8 +11,8 @@ import java.util.Objects; public class ClassDeclAnalysis extends AJmmVisitor { - private JmmNode classDeclNode; - private Analysis analysis; + private final JmmNode classDeclNode; + private final Analysis analysis; private final List methodNodes = new ArrayList<>(); public ClassDeclAnalysis(JmmNode rootNode, Analysis analysis){ diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java new file mode 100644 index 0000000..3cd436c --- /dev/null +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -0,0 +1,46 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; + +import java.util.ArrayList; +import java.util.List; + +public class MethodAnalysis extends AJmmVisitor { + private Analysis analysis; + private final List statementNodes = new ArrayList<>(); + + public MethodAnalysis(JmmNode methodNode, Analysis analysis) { + this.analysis = analysis; + visit(methodNode); + } + + @Override + protected void buildVisitor() { + addVisit("MainMethodDecl", this::checkMainMethodParameterType); + addVisit("CodeBlock", this::addStatement); + addVisit("Condition", this::addStatement); + addVisit("Cycle", this::addStatement); + addVisit("Expr", this::addStatement); + addVisit("Assignment", this::addStatement); + addVisit("ArrayAssignment", this::addStatement); + } + + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { + return null; + } + + private Void addStatement(JmmNode jmmNode, Void unused) { + return null; + } + + public List getStatementNodes() { + return this.statementNodes; + } +} From b51a9800a0cb5ff1c15120c84538d25f6955a487 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 16:01:42 +0100 Subject: [PATCH 007/253] Implemented method to validate the parameter type of main() --- src/main/pt/up/fe/comp2023/MethodAnalysis.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index 3cd436c..bce5f39 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -2,9 +2,13 @@ import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.report.ReportType; +import pt.up.fe.comp.jmm.report.Stage; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class MethodAnalysis extends AJmmVisitor { private Analysis analysis; @@ -33,6 +37,14 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { + String parameterType = jmmNode.get("parametertype"); + if(!Objects.equals(parameterType, "String")) { + String message = "Main method expected a parameter of type 'String' but found '" + parameterType + "'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for (JmmNode child: jmmNode.getChildren()) + visit(child); return null; } From 1af63c0926cc15d263b5ea267fafa4cde89494e9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 16:19:40 +0100 Subject: [PATCH 008/253] Output semantic errors --- src/main/pt/up/fe/comp2023/Launcher.java | 6 ++++++ src/main/pt/up/fe/comp2023/MethodAnalysis.java | 4 +++- src/main/pt/up/fe/comp2023/MySymbolTable.java | 1 - 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index f363adb..ba4c248 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -8,6 +8,7 @@ import pt.up.fe.comp.TestUtils; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.parser.JmmParserResult; +import pt.up.fe.comp.jmm.report.Report; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsLogs; import pt.up.fe.specs.util.SpecsSystem; @@ -56,6 +57,11 @@ public static void main(String[] args) { // Semantic Analysis Stage JmmSemanticsResult semanticsResult = analysis.semanticAnalysis(parserResult); + // Output Semantic Errors + for(Report report : analysis.getReports()){ + System.out.println(report.toString()); + } + // Check if there are semantic errors TestUtils.noErrors(semanticsResult.getReports()); diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index bce5f39..a80f32a 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -11,7 +11,7 @@ import java.util.Objects; public class MethodAnalysis extends AJmmVisitor { - private Analysis analysis; + private final Analysis analysis; private final List statementNodes = new ArrayList<>(); public MethodAnalysis(JmmNode methodNode, Analysis analysis) { @@ -21,6 +21,7 @@ public MethodAnalysis(JmmNode methodNode, Analysis analysis) { @Override protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); addVisit("MainMethodDecl", this::checkMainMethodParameterType); addVisit("CodeBlock", this::addStatement); addVisit("Condition", this::addStatement); @@ -49,6 +50,7 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { } private Void addStatement(JmmNode jmmNode, Void unused) { + this.statementNodes.add(jmmNode); return null; } diff --git a/src/main/pt/up/fe/comp2023/MySymbolTable.java b/src/main/pt/up/fe/comp2023/MySymbolTable.java index 165c524..b9347b6 100644 --- a/src/main/pt/up/fe/comp2023/MySymbolTable.java +++ b/src/main/pt/up/fe/comp2023/MySymbolTable.java @@ -64,7 +64,6 @@ public List getLocalVariables(String methodSignature) { @Override protected void buildVisitor() { - System.out.println("This is the visitor"); setDefaultVisit(this::setDefaultVisit); addVisit("ImportDecl", this::dealWithImport); addVisit("ClassDecl", this::dealWithClass); From 97bfb9bf6c51e091a05c660e1e6f5a8151f44df2 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 16:45:46 +0100 Subject: [PATCH 009/253] Added basic structure of class StatementAnalysis --- src/main/pt/up/fe/comp2023/Analysis.java | 2 +- .../pt/up/fe/comp2023/StatementAnalysis.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/main/pt/up/fe/comp2023/StatementAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index c1bc984..73a2d8d 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -23,7 +23,7 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this); for (JmmNode statementNode : methodAnalysis.getStatementNodes()){ - //TODO: validate each statement + new StatementAnalysis(statementNode, this); } } return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java new file mode 100644 index 0000000..fd09a36 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -0,0 +1,46 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; + +public class StatementAnalysis extends AJmmVisitor { + private Analysis analysis; + + public StatementAnalysis(JmmNode statementNode, Analysis analysis){ + this.analysis = analysis; + visit(statementNode); + } + + + @Override + protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); + addVisit("Condition", this::checkBooleanCondition); + addVisit("Cycle", this::checkBooleanCondition); + addVisit("Expr", this::expressionVisitor); + addVisit("Assignment", this::checkCompatibleAssignment); + addVisit("ArrayAssignment", this::validateArrayAssignment); + } + + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { + return null; + } + + private Void expressionVisitor(JmmNode jmmNode, Void unused) { + return null; + } + + private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { + return null; + } + + private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { + return null; + } +} From 54488b7bf2b542826663e0d29a96185beab9a27b Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 18:25:31 +0100 Subject: [PATCH 010/253] Added basic structure of ExpressionAnalysis --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 81 +++++++++++++++++++ .../pt/up/fe/comp2023/StatementAnalysis.java | 5 +- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/main/pt/up/fe/comp2023/ExpressionAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java new file mode 100644 index 0000000..5268160 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -0,0 +1,81 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.analysis.table.Type; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; + +public class ExpressionAnalysis extends AJmmVisitor { + private String methodName; + private Analysis analysis; + public ExpressionAnalysis (String methodName, Analysis analysis){ + this.analysis = analysis; + } + + @Override + protected void buildVisitor() { + addVisit("ParenthesesExpr", this::dealWithParenthesesExpr); + addVisit("NegationExpr", this::checkBooleanExpression); + addVisit("BinExpr", this::checkOperandsType); + addVisit("ArraySubscript", this::dealWithArraySubscript); + addVisit("LengthFieldAccess", this::dealWithLengthFieldAccess); + addVisit("MethodCall", this::dealWithMethodCall); + addVisit("ArrayCreation", this::checkIntegerLength); + addVisit("ObjectCreation", this::dealWithObjectCreation); + addVisit("Integer", this::dealWithInteger); + addVisit("Boolean", this::dealWithBoolean); + addVisit("This", this::dealWithThis); + addVisit("Identifier", this::dealWithIdentifier); + } + + private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { + return null; + } + + private Type checkBooleanExpression(JmmNode jmmNode, Type type) { + return null; + } + + private Type checkOperandsType(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithMethodCall(JmmNode jmmNode, Type type) { + return null; + } + + private Type checkIntegerLength(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithArrayCreation(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithInteger(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithBoolean(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithThis(JmmNode jmmNode, Type type) { + return null; + } + + private Type dealWithIdentifier(JmmNode jmmNode, Type type) { + return null; + } +} \ No newline at end of file diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index fd09a36..459a567 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -5,13 +5,16 @@ public class StatementAnalysis extends AJmmVisitor { private Analysis analysis; + private ExpressionAnalysis expressionAnalysis; public StatementAnalysis(JmmNode statementNode, Analysis analysis){ this.analysis = analysis; + String methodName = statementNode.getJmmParent().get("methodname"); + this.expressionAnalysis = new ExpressionAnalysis(methodName, analysis); + visit(statementNode); } - @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); From f2bc0c9a7d037f2dd9ce763449ae9acc891edfa8 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 18:37:11 +0100 Subject: [PATCH 011/253] Implemented dealWithBoolean() and dealWithInteger() in ExpressionAnalysis.java --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 5268160..3bc8c9c 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -55,20 +55,18 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { return null; } - private Type dealWithArrayCreation(JmmNode jmmNode, Type type) { - return null; - } - private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return null; } private Type dealWithInteger(JmmNode jmmNode, Type type) { - return null; + jmmNode.put("typename", "int"); + return new Type("int", false); } private Type dealWithBoolean(JmmNode jmmNode, Type type) { - return null; + jmmNode.put("typename", "boolean"); + return new Type("boolean", false); } private Type dealWithThis(JmmNode jmmNode, Type type) { From 366bcd40985db464a359995f06cb596c4896527f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 18:58:37 +0100 Subject: [PATCH 012/253] Implemented method to perform semantic analysis of #This node --- .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 2 +- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 18 +++++++++++++++++- src/main/pt/up/fe/comp2023/MethodAnalysis.java | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index f2ac292..f371cac 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -32,7 +32,7 @@ public void checkImportedSuperClass() { if(superClass != null && !findImport(superClass)){ String message = "Cannot find super class '" + superClass + "'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } for (JmmNode child: classDeclNode.getChildren()) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 3bc8c9c..62963db 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -3,6 +3,11 @@ import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.report.ReportType; +import pt.up.fe.comp.jmm.report.Stage; + +import java.util.Objects; public class ExpressionAnalysis extends AJmmVisitor { private String methodName; @@ -70,7 +75,18 @@ private Type dealWithBoolean(JmmNode jmmNode, Type type) { } private Type dealWithThis(JmmNode jmmNode, Type type) { - return null; + if (Objects.equals(this.methodName, "main")) { + String message = "'this' expression cannot be used in a static method."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + return new Type("unknown", false); + } + + else { + String className = analysis.getSymbolTable().getClassName(); + jmmNode.put("typename", className); + return new Type(className, false); + } } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index a80f32a..1202cf5 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -41,7 +41,7 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { String parameterType = jmmNode.get("parametertype"); if(!Objects.equals(parameterType, "String")) { String message = "Main method expected a parameter of type 'String' but found '" + parameterType + "'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } for (JmmNode child: jmmNode.getChildren()) From 71301fb8863306ba74e6491683845dc89f0eae2d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 19:18:59 +0100 Subject: [PATCH 013/253] Implemented method to check if length is integer in 'ArrayCreation' nodes --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 62963db..4355583 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -57,7 +57,17 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { } private Type checkIntegerLength(JmmNode jmmNode, Type type) { - return null; + String indexType = visit(jmmNode.getJmmChild(0)).getName(); + if (!Objects.equals(indexType, "int")){ + String message = "Expected array length to be 'int' but found '" + indexType + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + + jmmNode.put("typename", "unknown"); + return new Type("unknown", false); + } + + jmmNode.put("typename", "array"); + return new Type("int", true); } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { From 1dfac18b72f46906d8de481ee60b7d87541acc13 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 19:33:15 +0100 Subject: [PATCH 014/253] Implemented method to check if expression of #NegationExpr is boolean --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 4355583..59dedb4 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -11,7 +11,7 @@ public class ExpressionAnalysis extends AJmmVisitor { private String methodName; - private Analysis analysis; + private final Analysis analysis; public ExpressionAnalysis (String methodName, Analysis analysis){ this.analysis = analysis; } @@ -37,7 +37,16 @@ private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { } private Type checkBooleanExpression(JmmNode jmmNode, Type type) { - return null; + String expressionType = visit(jmmNode.getJmmChild(0)).getName(); + + if(Objects.equals(expressionType, "boolean")){ + jmmNode.put("typename", "boolean"); + return new Type("boolean", false); + } + String message = "Expected expression of type 'boolean' but found '" + expressionType + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + return new Type("unknown", false); } private Type checkOperandsType(JmmNode jmmNode, Type type) { @@ -57,17 +66,16 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { } private Type checkIntegerLength(JmmNode jmmNode, Type type) { - String indexType = visit(jmmNode.getJmmChild(0)).getName(); - if (!Objects.equals(indexType, "int")){ - String message = "Expected array length to be 'int' but found '" + indexType + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + String lengthType = visit(jmmNode.getJmmChild(0)).getName(); - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + if (Objects.equals(lengthType, "int")){ + jmmNode.put("typename", "array"); + return new Type("int", true); } - - jmmNode.put("typename", "array"); - return new Type("int", true); + String message = "Expected array length to be 'int' but found '" + lengthType + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + return new Type("unknown", false); } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { @@ -91,12 +99,9 @@ private Type dealWithThis(JmmNode jmmNode, Type type) { jmmNode.put("typename", "unknown"); return new Type("unknown", false); } - - else { - String className = analysis.getSymbolTable().getClassName(); - jmmNode.put("typename", className); - return new Type(className, false); - } + String className = analysis.getSymbolTable().getClassName(); + jmmNode.put("typename", className); + return new Type(className, false); } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { From cc1b5dcd42b9aedcec333f396645ba656c637d17 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 19:48:28 +0100 Subject: [PATCH 015/253] Implemented method to compute type of ParenthesesExpr node --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 59dedb4..202723b 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -33,7 +33,12 @@ protected void buildVisitor() { } private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { - return null; + Type expressionType = visit(jmmNode.getJmmChild(0)); + if(expressionType.isArray()) + jmmNode.put("typename", "array"); + else + jmmNode.put("typename", expressionType.getName()); + return expressionType; } private Type checkBooleanExpression(JmmNode jmmNode, Type type) { From 0537590d091430e5de873acc1d1efc8dd8dad1a6 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 20:18:40 +0100 Subject: [PATCH 016/253] Small fix in checkIntegerLength() --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 202723b..060df05 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -71,9 +71,9 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { } private Type checkIntegerLength(JmmNode jmmNode, Type type) { - String lengthType = visit(jmmNode.getJmmChild(0)).getName(); + Type lengthType = visit(jmmNode.getJmmChild(0)); - if (Objects.equals(lengthType, "int")){ + if (Objects.equals(lengthType.getName(), "int") && !lengthType.isArray()){ jmmNode.put("typename", "array"); return new Type("int", true); } From 9097fe7c0d440836286d2646891205d7deb8cd34 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 7 Apr 2023 23:11:41 +0100 Subject: [PATCH 017/253] Updated grammar to better separate different types of operators --- src/main/antlr/comp2023/grammar/Javamm.g4 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index 390d426..43a8b4c 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -60,11 +60,11 @@ statement expression : '(' expression ')' #ParenthesesExpr | '!' expression #NegationExpr - | expression op=('*' | '/') expression #BinExpr - | expression op=('+' | '-') expression #BinExpr - | expression op=('<' | '>') expression #BinExpr - | expression op='&&' expression #BinExpr - | expression op='||' expression #BinExpr + | expression op=('*' | '/') expression #ArithmeticExpr + | expression op=('+' | '-') expression #ArithmeticExpr + | expression op=('<' | '>') expression #ComparisonExpr + | expression op='&&' expression #LogicalExpr + | expression op='||' expression #LogicalExpr | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall From 9f3450a0b44abbb970dee1dcc1b86e240eda001a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 01:12:24 +0100 Subject: [PATCH 018/253] Implemented method to verify arithmetic operands --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 060df05..931d064 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -20,7 +20,9 @@ public ExpressionAnalysis (String methodName, Analysis analysis){ protected void buildVisitor() { addVisit("ParenthesesExpr", this::dealWithParenthesesExpr); addVisit("NegationExpr", this::checkBooleanExpression); - addVisit("BinExpr", this::checkOperandsType); + addVisit("ArithmeticExpr", this::checkArithmeticOperandsType); + addVisit("ComparisonExpr", this::checkComparisonOperandsType); + addVisit("LogicalExpr", this::checkLogicalOperandsType); addVisit("ArraySubscript", this::dealWithArraySubscript); addVisit("LengthFieldAccess", this::dealWithLengthFieldAccess); addVisit("MethodCall", this::dealWithMethodCall); @@ -54,7 +56,35 @@ private Type checkBooleanExpression(JmmNode jmmNode, Type type) { return new Type("unknown", false); } - private Type checkOperandsType(JmmNode jmmNode, Type type) { + private Type checkArithmeticOperandsType(JmmNode jmmNode, Type type) { + Type leftOperandType = visit(jmmNode.getJmmChild(0)); + Type rightOperandType = visit(jmmNode.getJmmChild(1)); + + if(!Objects.equals(leftOperandType.getName(), "int") || leftOperandType.isArray()) { + String message = "Expected operand of type 'int' but found '" + leftOperandType.getName() + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + } + + if(!Objects.equals(rightOperandType.getName(), "int") || rightOperandType.isArray()) { + String message = "Expected operand of type 'int' but found '" + leftOperandType.getName() + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + if(!jmmNode.getAttributes().contains("typename")) + jmmNode.put("typename", "unknown"); + } + + if(!jmmNode.getAttributes().contains("typename")) { //left and right operands are integers + jmmNode.put("typename", "int"); + return new Type("int", false); + } + return new Type("unknown", false); + } + + private Type checkComparisonOperandsType(JmmNode jmmNode, Type type) { + return null; + } + + private Type checkLogicalOperandsType(JmmNode jmmNode, Type type) { return null; } From 5f876f35d422b64179289a5c34991be42e36a8ca Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 01:26:27 +0100 Subject: [PATCH 019/253] Rename method 'checkArithmeticOperandsType' to 'checkIntegerOperands' --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 931d064..8e98ac7 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -20,7 +20,7 @@ public ExpressionAnalysis (String methodName, Analysis analysis){ protected void buildVisitor() { addVisit("ParenthesesExpr", this::dealWithParenthesesExpr); addVisit("NegationExpr", this::checkBooleanExpression); - addVisit("ArithmeticExpr", this::checkArithmeticOperandsType); + addVisit("ArithmeticExpr", this::checkIntegerOperands); addVisit("ComparisonExpr", this::checkComparisonOperandsType); addVisit("LogicalExpr", this::checkLogicalOperandsType); addVisit("ArraySubscript", this::dealWithArraySubscript); @@ -56,7 +56,7 @@ private Type checkBooleanExpression(JmmNode jmmNode, Type type) { return new Type("unknown", false); } - private Type checkArithmeticOperandsType(JmmNode jmmNode, Type type) { + private Type checkIntegerOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); From d9ad9a17d37a21a32032d6e937b49fec348c0ecf Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 01:31:21 +0100 Subject: [PATCH 020/253] Set checkIntegerOperands() as visitor of 'ComparisonExpr' node --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 8e98ac7..9945fbc 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -21,7 +21,7 @@ protected void buildVisitor() { addVisit("ParenthesesExpr", this::dealWithParenthesesExpr); addVisit("NegationExpr", this::checkBooleanExpression); addVisit("ArithmeticExpr", this::checkIntegerOperands); - addVisit("ComparisonExpr", this::checkComparisonOperandsType); + addVisit("ComparisonExpr", this::checkIntegerOperands); addVisit("LogicalExpr", this::checkLogicalOperandsType); addVisit("ArraySubscript", this::dealWithArraySubscript); addVisit("LengthFieldAccess", this::dealWithLengthFieldAccess); @@ -73,15 +73,16 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { jmmNode.put("typename", "unknown"); } - if(!jmmNode.getAttributes().contains("typename")) { //left and right operands are integers + if(jmmNode.getAttributes().contains("typename")) //Semantic errors were found + return new Type("unknown", false); + + if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { jmmNode.put("typename", "int"); return new Type("int", false); } - return new Type("unknown", false); - } - private Type checkComparisonOperandsType(JmmNode jmmNode, Type type) { - return null; + jmmNode.put("typename", "boolean"); + return new Type("boolean", false); } private Type checkLogicalOperandsType(JmmNode jmmNode, Type type) { From badea51953b7b2c458ffa05864075177351d19d1 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 01:35:17 +0100 Subject: [PATCH 021/253] Renamed checkLogicalOperandsType() to checkBooleanOperands() and implemented it --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 9945fbc..f0ae116 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -22,7 +22,7 @@ protected void buildVisitor() { addVisit("NegationExpr", this::checkBooleanExpression); addVisit("ArithmeticExpr", this::checkIntegerOperands); addVisit("ComparisonExpr", this::checkIntegerOperands); - addVisit("LogicalExpr", this::checkLogicalOperandsType); + addVisit("LogicalExpr", this::checkBooleanOperands); addVisit("ArraySubscript", this::dealWithArraySubscript); addVisit("LengthFieldAccess", this::dealWithLengthFieldAccess); addVisit("MethodCall", this::dealWithMethodCall); @@ -85,8 +85,27 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { return new Type("boolean", false); } - private Type checkLogicalOperandsType(JmmNode jmmNode, Type type) { - return null; + private Type checkBooleanOperands(JmmNode jmmNode, Type type) { + Type leftOperandType = visit(jmmNode.getJmmChild(0)); + Type rightOperandType = visit(jmmNode.getJmmChild(1)); + + if(!Objects.equals(leftOperandType.getName(), "boolean") || leftOperandType.isArray()) { + String message = "Expected operand of type 'boolean' but found '" + leftOperandType.getName() + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + } + + if(!Objects.equals(rightOperandType.getName(), "boolean") || rightOperandType.isArray()) { + String message = "Expected operand of type 'boolean' but found '" + leftOperandType.getName() + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + if(!jmmNode.getAttributes().contains("typename")) + jmmNode.put("typename", "unknown"); + } + + if(jmmNode.getAttributes().contains("typename")) //Semantic errors were found + return new Type("unknown", false); + jmmNode.put("typename", "boolean"); + return new Type("boolean", false); } private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { From d0738842ee452b7a22efecdce7bd8dfa92ba7e47 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 01:49:46 +0100 Subject: [PATCH 022/253] First implementation of dealWithObjectCreation() --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 16 +++++++++++++++- .../pt/up/fe/comp2023/StatementAnalysis.java | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index f0ae116..05ac171 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -109,14 +109,17 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { } private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { + //TODO return null; } private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { + //TODO return null; } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { + //TODO return null; } @@ -134,7 +137,17 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { - return null; + String declaredClassName = analysis.getSymbolTable().getClassName(); + String objectClassName = jmmNode.get("classname"); + + if(Objects.equals(objectClassName, declaredClassName)){ + jmmNode.put("typename", declaredClassName); + return new Type(declaredClassName, false); + } + + //TODO: check if objectClassName was imported + + return new Type("unknown", false); } private Type dealWithInteger(JmmNode jmmNode, Type type) { @@ -160,6 +173,7 @@ private Type dealWithThis(JmmNode jmmNode, Type type) { } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { + //TODO return null; } } \ No newline at end of file diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 459a567..7219344 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -32,18 +32,22 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { + //TODO return null; } private Void expressionVisitor(JmmNode jmmNode, Void unused) { + //TODO return null; } private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { + //TODO return null; } private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { + //TODO return null; } } From 71d9d1c68a36aea6391520275d0c842423c92136 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 02:13:12 +0100 Subject: [PATCH 023/253] Moved findImport() to new SemanticUtils class --- .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 16 +++------------- src/main/pt/up/fe/comp2023/MySymbolTable.java | 1 - src/main/pt/up/fe/comp2023/SemanticUtils.java | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 src/main/pt/up/fe/comp2023/SemanticUtils.java diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index f371cac..36412a6 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -8,7 +8,8 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; + +import static pt.up.fe.comp2023.SemanticUtils.findImport; public class ClassDeclAnalysis extends AJmmVisitor { private final JmmNode classDeclNode; @@ -30,7 +31,7 @@ protected void buildVisitor() { public void checkImportedSuperClass() { String superClass = analysis.getSymbolTable().getSuper(); - if(superClass != null && !findImport(superClass)){ + if(superClass != null && !findImport(analysis.getSymbolTable().getImports(), superClass)){ String message = "Cannot find super class '" + superClass + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } @@ -47,15 +48,4 @@ private Void addMethodNode(JmmNode methodNode, Void unused) { public List getMethodNodes() { return this.methodNodes; } - - Boolean findImport (String string) { - List imports = analysis.getSymbolTable().getImports(); - - for(String imported : imports){ - List splitImport = List.of(imported.split("\\.")); - if (Objects.equals(splitImport.get(splitImport.size() - 1), string)) - return true; - } - return false; - } } diff --git a/src/main/pt/up/fe/comp2023/MySymbolTable.java b/src/main/pt/up/fe/comp2023/MySymbolTable.java index b9347b6..35c9afb 100644 --- a/src/main/pt/up/fe/comp2023/MySymbolTable.java +++ b/src/main/pt/up/fe/comp2023/MySymbolTable.java @@ -7,7 +7,6 @@ import pt.up.fe.comp.jmm.ast.JmmNode; import java.util.*; -import java.util.stream.Collectors; public class MySymbolTable extends AJmmVisitor implements SymbolTable { diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java new file mode 100644 index 0000000..6b8de16 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -0,0 +1,15 @@ +package pt.up.fe.comp2023; + +import java.util.List; +import java.util.Objects; + +public class SemanticUtils { + public static boolean findImport(List imports, String className) { + for(String imported : imports){ + List splitImport = List.of(imported.split("\\.")); + if (Objects.equals(splitImport.get(splitImport.size() - 1), className)) + return true; + } + return false; + } +} From d003f059d3a95c10e195e6c2f2292cf578cf0adb Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 02:15:34 +0100 Subject: [PATCH 024/253] Completed implementation of dealWithObjectCreation() --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 05ac171..298f219 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -9,6 +9,8 @@ import java.util.Objects; +import static pt.up.fe.comp2023.SemanticUtils.findImport; + public class ExpressionAnalysis extends AJmmVisitor { private String methodName; private final Analysis analysis; @@ -145,7 +147,10 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return new Type(declaredClassName, false); } - //TODO: check if objectClassName was imported + if(findImport(analysis.getSymbolTable().getImports(), objectClassName)){ + jmmNode.put("typename", objectClassName); + return new Type(objectClassName, false); + } return new Type("unknown", false); } From 48ea07e8d12ad5bc8a0ea5c9d04aea07972b52c9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 02:57:40 +0100 Subject: [PATCH 025/253] Implemented dealWithArraySubscript() --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 298f219..047c442 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -71,11 +71,11 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { if(!Objects.equals(rightOperandType.getName(), "int") || rightOperandType.isArray()) { String message = "Expected operand of type 'int' but found '" + leftOperandType.getName() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - if(!jmmNode.getAttributes().contains("typename")) + if(!jmmNode.hasAttribute("typename")) jmmNode.put("typename", "unknown"); } - if(jmmNode.getAttributes().contains("typename")) //Semantic errors were found + if(jmmNode.hasAttribute("typename")) //Semantic errors were found return new Type("unknown", false); if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { @@ -100,19 +100,36 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { if(!Objects.equals(rightOperandType.getName(), "boolean") || rightOperandType.isArray()) { String message = "Expected operand of type 'boolean' but found '" + leftOperandType.getName() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - if(!jmmNode.getAttributes().contains("typename")) + if(!jmmNode.hasAttribute("typename")) jmmNode.put("typename", "unknown"); } - if(jmmNode.getAttributes().contains("typename")) //Semantic errors were found + if(jmmNode.hasAttribute("typename")) //Semantic errors were found return new Type("unknown", false); jmmNode.put("typename", "boolean"); return new Type("boolean", false); } private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { - //TODO - return null; + Type variableType = visit(jmmNode.getJmmChild(0)); + Type indexType = visit(jmmNode.getJmmChild(1)); + + if (!(Objects.equals(variableType.getName(), "int") && !variableType.isArray())) { + String message = "Expected array type but found '" + variableType.getName() + "'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + } + + if (!(Objects.equals(indexType.getName(), "int") && !indexType.isArray())) { + String message = "Expected index expression of type 'integer' but found '" + indexType.getName() + "'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + if(!jmmNode.hasAttribute("typename")) + jmmNode.put("typename", "unknown"); + } + + if(jmmNode.hasAttribute("typename")) //Semantic errors were found + return new Type("unknown", false); + return new Type ("int", false); } private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { From b7816bcc5eb04b5c45d7e56fafe094ba398b5d6a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 03:15:50 +0100 Subject: [PATCH 026/253] Implemented dealWithLengthFieldAccess() --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 047c442..984e0f4 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -133,8 +133,16 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { } private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { - //TODO - return null; + Type expressionType = visit(jmmNode.getJmmChild(0)); + + if(expressionType.isArray()){ + jmmNode.put("typename", "int"); + return new Type ("int", false); + } + String message = "Cannot resolve symbol 'length'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + return new Type("unknown", false); } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { From 581f81946fe42e137f670c0288d764782cdc7d28 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 03:38:10 +0100 Subject: [PATCH 027/253] Implemented SemanticUtils getIdentifierType() --- src/main/pt/up/fe/comp2023/SemanticUtils.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index 6b8de16..fbb6c72 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -1,5 +1,8 @@ package pt.up.fe.comp2023; +import pt.up.fe.comp.jmm.analysis.table.Symbol; +import pt.up.fe.comp.jmm.analysis.table.Type; + import java.util.List; import java.util.Objects; @@ -12,4 +15,29 @@ public static boolean findImport(List imports, String className) { } return false; } + + public static Type getIdentifierType(String methodName, String identifier, MySymbolTable symbolTable){ + List localVariables = symbolTable.getLocalVariables(methodName); + for (Symbol localVariable : localVariables) { + if(Objects.equals(localVariable.getName(), identifier)) + return localVariable.getType(); + } + + List parameters = symbolTable.getParameters(methodName); + for (Symbol parameter : parameters) { + if(Objects.equals(parameter.getName(), identifier)) + return parameter.getType(); + } + + List fields = symbolTable.getFields(); + for (Symbol field : fields) { + if(Objects.equals(field.getName(), identifier)) + return field.getType(); + } + + if(findImport(symbolTable.getImports(), identifier)) + return new Type(identifier, false); + + return new Type("unknown", false); + } } From 94ae8de0604c6907a40c96747f6bb7349f50bd2d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 04:02:17 +0100 Subject: [PATCH 028/253] Implemented dealWithIdentifier() --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 984e0f4..7b58791 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -1,5 +1,6 @@ package pt.up.fe.comp2023; +import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; @@ -7,9 +8,11 @@ import pt.up.fe.comp.jmm.report.ReportType; import pt.up.fe.comp.jmm.report.Stage; +import java.util.List; import java.util.Objects; import static pt.up.fe.comp2023.SemanticUtils.findImport; +import static pt.up.fe.comp2023.SemanticUtils.getIdentifierType; public class ExpressionAnalysis extends AJmmVisitor { private String methodName; @@ -203,7 +206,18 @@ private Type dealWithThis(JmmNode jmmNode, Type type) { } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { - //TODO - return null; + String identifier = jmmNode.get("value"); + Type identifierType = getIdentifierType(this.methodName, identifier, analysis.getSymbolTable()); + + if(Objects.equals(identifierType.getName(), "unknown")){ + String message = "'" + identifier + "' is not declared."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + } + else if(identifierType.isArray()) + jmmNode.put("typename", "array"); + else + jmmNode.put("typename", identifierType.getName()); + return identifierType; } } \ No newline at end of file From a362e43919fec1e8494075ad2b1743f78768f21e Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 13:43:21 +0100 Subject: [PATCH 029/253] Started implementation of dealWithMethodCall() --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 7b58791..0bad549 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -130,7 +130,7 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { jmmNode.put("typename", "unknown"); } - if(jmmNode.hasAttribute("typename")) //Semantic errors were found + if(jmmNode.hasAttribute("typename")) //Semantic errors were found return new Type("unknown", false); return new Type ("int", false); } @@ -149,7 +149,35 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { - //TODO + String method = jmmNode.get("methodcall"); + String declaredClass = analysis.getSymbolTable().getClassName(); + + if(analysis.getSymbolTable().getMethods().contains(method)){ + String expressionType = visit(jmmNode.getJmmChild(0)).getName(); + + if(!Objects.equals(expressionType, declaredClass)){ + String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; + analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); + } + + //TODO: check parameters + + if(jmmNode.hasAttribute("typename")) //Semantic errors were found + return new Type("unknown", false); + else + return analysis.getSymbolTable().getReturnType(method); + } + + //TODO: if the class extends another class: + //TODO: check if class is imported + //TODO: check if expression.type == classDeclared or superClass + //TODO: compute node type + + //TODO: else (it is a method of a imported class) + //TODO: check if expression.type (=classname) is imported + //TODO: compute node type + return null; } @@ -180,6 +208,8 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return new Type(objectClassName, false); } + //TODO: create report + //TODO: set node typename return new Type("unknown", false); } From 2d57e1e6d48be8e959a773c208f898e0936f25f6 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 14:16:16 +0100 Subject: [PATCH 030/253] Improved semantic error messages --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 55 +++++++++---------- .../pt/up/fe/comp2023/MethodAnalysis.java | 2 +- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 0bad549..1902758 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -41,21 +41,18 @@ protected void buildVisitor() { private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { Type expressionType = visit(jmmNode.getJmmChild(0)); - if(expressionType.isArray()) - jmmNode.put("typename", "array"); - else - jmmNode.put("typename", expressionType.getName()); + jmmNode.put("typename", expressionType.print()); return expressionType; } private Type checkBooleanExpression(JmmNode jmmNode, Type type) { - String expressionType = visit(jmmNode.getJmmChild(0)).getName(); + Type expressionType = visit(jmmNode.getJmmChild(0)); - if(Objects.equals(expressionType, "boolean")){ + if(Objects.equals(expressionType.print(), "boolean")){ jmmNode.put("typename", "boolean"); return new Type("boolean", false); } - String message = "Expected expression of type 'boolean' but found '" + expressionType + "'."; + String message = "Expected expression of type 'boolean' but found '" + expressionType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); return new Type("unknown", false); @@ -65,14 +62,14 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(!Objects.equals(leftOperandType.getName(), "int") || leftOperandType.isArray()) { - String message = "Expected operand of type 'int' but found '" + leftOperandType.getName() + "'."; + if(!Objects.equals(leftOperandType.print(), "int")) { + String message = "Expected operand of type 'int' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); } - if(!Objects.equals(rightOperandType.getName(), "int") || rightOperandType.isArray()) { - String message = "Expected operand of type 'int' but found '" + leftOperandType.getName() + "'."; + if(!Objects.equals(rightOperandType.print(), "int")) { + String message = "Expected operand of type 'int' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute("typename")) jmmNode.put("typename", "unknown"); @@ -94,14 +91,14 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(!Objects.equals(leftOperandType.getName(), "boolean") || leftOperandType.isArray()) { - String message = "Expected operand of type 'boolean' but found '" + leftOperandType.getName() + "'."; + if(!Objects.equals(leftOperandType.print(), "boolean")) { + String message = "Expected operand of type 'boolean' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); } - if(!Objects.equals(rightOperandType.getName(), "boolean") || rightOperandType.isArray()) { - String message = "Expected operand of type 'boolean' but found '" + leftOperandType.getName() + "'."; + if(!Objects.equals(rightOperandType.print(), "boolean")) { + String message = "Expected operand of type 'boolean' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute("typename")) jmmNode.put("typename", "unknown"); @@ -117,14 +114,14 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { Type variableType = visit(jmmNode.getJmmChild(0)); Type indexType = visit(jmmNode.getJmmChild(1)); - if (!(Objects.equals(variableType.getName(), "int") && !variableType.isArray())) { - String message = "Expected array type but found '" + variableType.getName() + "'."; + if (!Objects.equals(variableType.print(), "int[]")) { + String message = "Expected 'int[]' type but found '" + variableType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); } - if (!(Objects.equals(indexType.getName(), "int") && !indexType.isArray())) { - String message = "Expected index expression of type 'integer' but found '" + indexType.getName() + "'."; + if (!Objects.equals(indexType.print(), "int")) { + String message = "Expected index expression of type 'int' but found '" + indexType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute("typename")) jmmNode.put("typename", "unknown"); @@ -153,7 +150,7 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { String declaredClass = analysis.getSymbolTable().getClassName(); if(analysis.getSymbolTable().getMethods().contains(method)){ - String expressionType = visit(jmmNode.getJmmChild(0)).getName(); + String expressionType = visit(jmmNode.getJmmChild(0)).print(); if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; @@ -184,11 +181,11 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { private Type checkIntegerLength(JmmNode jmmNode, Type type) { Type lengthType = visit(jmmNode.getJmmChild(0)); - if (Objects.equals(lengthType.getName(), "int") && !lengthType.isArray()){ - jmmNode.put("typename", "array"); + if (Objects.equals(lengthType.print(), "int")){ + jmmNode.put("typename", "int[]"); return new Type("int", true); } - String message = "Expected array length to be 'int' but found '" + lengthType + "'."; + String message = "Expected array length to be 'int' but found '" + lengthType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); return new Type("unknown", false); @@ -208,8 +205,9 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return new Type(objectClassName, false); } - //TODO: create report - //TODO: set node typename + String message = "Cannot find '" + objectClassName + "'."; + this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + jmmNode.put("typename", "unknown"); return new Type("unknown", false); } @@ -239,15 +237,12 @@ private Type dealWithIdentifier(JmmNode jmmNode, Type type) { String identifier = jmmNode.get("value"); Type identifierType = getIdentifierType(this.methodName, identifier, analysis.getSymbolTable()); - if(Objects.equals(identifierType.getName(), "unknown")){ + if(Objects.equals(identifierType.print(), "unknown")){ String message = "'" + identifier + "' is not declared."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put("typename", "unknown"); } - else if(identifierType.isArray()) - jmmNode.put("typename", "array"); - else - jmmNode.put("typename", identifierType.getName()); + jmmNode.put("typename", identifierType.print()); return identifierType; } } \ No newline at end of file diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index 1202cf5..1011dcd 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -40,7 +40,7 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { String parameterType = jmmNode.get("parametertype"); if(!Objects.equals(parameterType, "String")) { - String message = "Main method expected a parameter of type 'String' but found '" + parameterType + "'."; + String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } From 39df32497f5cfd5fbba783b4d4c802e0fc68ffd3 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 14:59:04 +0100 Subject: [PATCH 031/253] Declared SemanticUtils constants --- src/main/pt/up/fe/comp2023/SemanticUtils.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index fbb6c72..1ddfb9c 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -7,6 +7,23 @@ import java.util.Objects; public class SemanticUtils { + //Types + public static final Type ARRAY_TYPE = new Type("int", true); + public static final Type BOOLEAN_TYPE = new Type("boolean", false); + public static final Type INT_TYPE = new Type("int", false); + public static final Type INVALID_TYPE = new Type("#invalid", false); + public static final Type UNDEFINED_TYPE = new Type("#undefined", false); + + //Type names + public static final String ARRAY = ARRAY_TYPE.print(); + public static final String BOOLEAN = BOOLEAN_TYPE.print(); + public static final String INT = INT_TYPE.print(); + public static final String INVALID = INVALID_TYPE.print(); + public static final String UNDEFINED = UNDEFINED_TYPE.print(); + + //Typename attribute + public static final String TYPENAME = "typename"; + public static boolean findImport(List imports, String className) { for(String imported : imports){ List splitImport = List.of(imported.split("\\.")); @@ -37,7 +54,6 @@ public static Type getIdentifierType(String methodName, String identifier, MySym if(findImport(symbolTable.getImports(), identifier)) return new Type(identifier, false); - - return new Type("unknown", false); + return new Type("#invalid", false); } } From 00d7e54350f1d0cddd266834e1de35e73e4aa3c5 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 15:53:26 +0100 Subject: [PATCH 032/253] Refactored ExpressionAnalysis class using constants --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 145 +++++++++--------- src/main/pt/up/fe/comp2023/SemanticUtils.java | 2 +- 2 files changed, 72 insertions(+), 75 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 1902758..797d47e 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -11,8 +11,7 @@ import java.util.List; import java.util.Objects; -import static pt.up.fe.comp2023.SemanticUtils.findImport; -import static pt.up.fe.comp2023.SemanticUtils.getIdentifierType; +import static pt.up.fe.comp2023.SemanticUtils.*; public class ExpressionAnalysis extends AJmmVisitor { private String methodName; @@ -41,108 +40,106 @@ protected void buildVisitor() { private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { Type expressionType = visit(jmmNode.getJmmChild(0)); - jmmNode.put("typename", expressionType.print()); + jmmNode.put(TYPENAME, expressionType.print()); return expressionType; } private Type checkBooleanExpression(JmmNode jmmNode, Type type) { Type expressionType = visit(jmmNode.getJmmChild(0)); - if(Objects.equals(expressionType.print(), "boolean")){ - jmmNode.put("typename", "boolean"); - return new Type("boolean", false); + if(expressionType.equals(BOOLEAN_TYPE)){ + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; } - String message = "Expected expression of type 'boolean' but found '" + expressionType.print() + "'."; + String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + jmmNode.put(TYPENAME, INVALID); + return INVALID_TYPE; } private Type checkIntegerOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(!Objects.equals(leftOperandType.print(), "int")) { - String message = "Expected operand of type 'int' but found '" + leftOperandType.print() + "'."; + if(leftOperandType.equals(INT_TYPE)) { + String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); + jmmNode.put(TYPENAME, INVALID); } - if(!Objects.equals(rightOperandType.print(), "int")) { - String message = "Expected operand of type 'int' but found '" + leftOperandType.print() + "'."; + if(rightOperandType.equals(INT_TYPE)) { + String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - if(!jmmNode.hasAttribute("typename")) - jmmNode.put("typename", "unknown"); + if(!jmmNode.hasAttribute(TYPENAME)) + jmmNode.put(TYPENAME, INVALID); } - if(jmmNode.hasAttribute("typename")) //Semantic errors were found - return new Type("unknown", false); - + if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found + return INVALID_TYPE; if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { - jmmNode.put("typename", "int"); - return new Type("int", false); + jmmNode.put(TYPENAME, INT); + return INT_TYPE; } - - jmmNode.put("typename", "boolean"); - return new Type("boolean", false); + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; } private Type checkBooleanOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(!Objects.equals(leftOperandType.print(), "boolean")) { - String message = "Expected operand of type 'boolean' but found '" + leftOperandType.print() + "'."; + if(leftOperandType.equals(BOOLEAN_TYPE)) { + String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); + jmmNode.put(TYPENAME, INVALID); } - if(!Objects.equals(rightOperandType.print(), "boolean")) { - String message = "Expected operand of type 'boolean' but found '" + leftOperandType.print() + "'."; + if(rightOperandType.equals(BOOLEAN_TYPE)) { + String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - if(!jmmNode.hasAttribute("typename")) - jmmNode.put("typename", "unknown"); + if(!jmmNode.hasAttribute(TYPENAME)) + jmmNode.put(TYPENAME, INVALID); } - if(jmmNode.hasAttribute("typename")) //Semantic errors were found - return new Type("unknown", false); - jmmNode.put("typename", "boolean"); - return new Type("boolean", false); + if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found + return INVALID_TYPE; + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; } private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { Type variableType = visit(jmmNode.getJmmChild(0)); Type indexType = visit(jmmNode.getJmmChild(1)); - if (!Objects.equals(variableType.print(), "int[]")) { - String message = "Expected 'int[]' type but found '" + variableType.print() + "'."; + if (variableType.equals(ARRAY_TYPE)) { + String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); + jmmNode.put(TYPENAME, INVALID); } - if (!Objects.equals(indexType.print(), "int")) { - String message = "Expected index expression of type 'int' but found '" + indexType.print() + "'."; + if (indexType.equals(INT_TYPE)) { + String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - if(!jmmNode.hasAttribute("typename")) - jmmNode.put("typename", "unknown"); + if(!jmmNode.hasAttribute(TYPENAME)) + jmmNode.put(TYPENAME, INVALID); } - if(jmmNode.hasAttribute("typename")) //Semantic errors were found - return new Type("unknown", false); - return new Type ("int", false); + if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found + return INVALID_TYPE; + return INT_TYPE; } private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { Type expressionType = visit(jmmNode.getJmmChild(0)); - if(expressionType.isArray()){ - jmmNode.put("typename", "int"); - return new Type ("int", false); + if(expressionType.equals(ARRAY_TYPE)){ + jmmNode.put(TYPENAME, INT); + return INT_TYPE; } String message = "Cannot resolve symbol 'length'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + jmmNode.put(TYPENAME, INVALID); + return INVALID_TYPE; } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { @@ -155,21 +152,21 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); + jmmNode.put(TYPENAME, INVALID); } //TODO: check parameters - if(jmmNode.hasAttribute("typename")) //Semantic errors were found - return new Type("unknown", false); + if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found + return INVALID_TYPE; else return analysis.getSymbolTable().getReturnType(method); } //TODO: if the class extends another class: //TODO: check if class is imported - //TODO: check if expression.type == classDeclared or superClass - //TODO: compute node type + //TODO: check if expression.type == declaredClass or superClass + //TODO: compute node type(undefined) //TODO: else (it is a method of a imported class) //TODO: check if expression.type (=classname) is imported @@ -181,14 +178,14 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { private Type checkIntegerLength(JmmNode jmmNode, Type type) { Type lengthType = visit(jmmNode.getJmmChild(0)); - if (Objects.equals(lengthType.print(), "int")){ - jmmNode.put("typename", "int[]"); - return new Type("int", true); + if (lengthType.equals(INT_TYPE)){ + jmmNode.put(TYPENAME, ARRAY); + return ARRAY_TYPE; } - String message = "Expected array length to be 'int' but found '" + lengthType.print() + "'."; + String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + jmmNode.put(TYPENAME, INVALID); + return INVALID_TYPE; } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { @@ -196,40 +193,40 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { String objectClassName = jmmNode.get("classname"); if(Objects.equals(objectClassName, declaredClassName)){ - jmmNode.put("typename", declaredClassName); + jmmNode.put(TYPENAME, declaredClassName); return new Type(declaredClassName, false); } if(findImport(analysis.getSymbolTable().getImports(), objectClassName)){ - jmmNode.put("typename", objectClassName); + jmmNode.put(TYPENAME, objectClassName); return new Type(objectClassName, false); } String message = "Cannot find '" + objectClassName + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + jmmNode.put(TYPENAME, INVALID); + return INVALID_TYPE; } private Type dealWithInteger(JmmNode jmmNode, Type type) { - jmmNode.put("typename", "int"); - return new Type("int", false); + jmmNode.put(TYPENAME, INT); + return INT_TYPE; } private Type dealWithBoolean(JmmNode jmmNode, Type type) { - jmmNode.put("typename", "boolean"); - return new Type("boolean", false); + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; } private Type dealWithThis(JmmNode jmmNode, Type type) { if (Objects.equals(this.methodName, "main")) { String message = "'this' expression cannot be used in a static method."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); - return new Type("unknown", false); + jmmNode.put(TYPENAME, INVALID); + return INVALID_TYPE; } String className = analysis.getSymbolTable().getClassName(); - jmmNode.put("typename", className); + jmmNode.put(TYPENAME, className); return new Type(className, false); } @@ -237,10 +234,10 @@ private Type dealWithIdentifier(JmmNode jmmNode, Type type) { String identifier = jmmNode.get("value"); Type identifierType = getIdentifierType(this.methodName, identifier, analysis.getSymbolTable()); - if(Objects.equals(identifierType.print(), "unknown")){ + if(Objects.equals(identifierType.print(), INVALID)){ String message = "'" + identifier + "' is not declared."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put("typename", "unknown"); + jmmNode.put(TYPENAME, INVALID); } jmmNode.put("typename", identifierType.print()); return identifierType; diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index 1ddfb9c..68c02f3 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -54,6 +54,6 @@ public static Type getIdentifierType(String methodName, String identifier, MySym if(findImport(symbolTable.getImports(), identifier)) return new Type(identifier, false); - return new Type("#invalid", false); + return INVALID_TYPE; } } From d3a7867df7a5e028093c1dad9930d67d5ed9b2c3 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 15:59:54 +0100 Subject: [PATCH 033/253] [refactor] renamed constant 'INVALID' to 'UNKNOWN' --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 48 +++++++++---------- src/main/pt/up/fe/comp2023/SemanticUtils.java | 6 +-- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 797d47e..32d5474 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -1,6 +1,5 @@ package pt.up.fe.comp2023; -import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; @@ -8,7 +7,6 @@ import pt.up.fe.comp.jmm.report.ReportType; import pt.up.fe.comp.jmm.report.Stage; -import java.util.List; import java.util.Objects; import static pt.up.fe.comp2023.SemanticUtils.*; @@ -53,8 +51,8 @@ private Type checkBooleanExpression(JmmNode jmmNode, Type type) { } String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); - return INVALID_TYPE; + jmmNode.put(TYPENAME, UNKNOWN); + return UNKNOWN_TYPE; } private Type checkIntegerOperands(JmmNode jmmNode, Type type) { @@ -64,18 +62,18 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { if(leftOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if(rightOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return INVALID_TYPE; + return UNKNOWN_TYPE; if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { jmmNode.put(TYPENAME, INT); return INT_TYPE; @@ -91,18 +89,18 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { if(leftOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if(rightOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return INVALID_TYPE; + return UNKNOWN_TYPE; jmmNode.put(TYPENAME, BOOLEAN); return BOOLEAN_TYPE; } @@ -114,18 +112,18 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { if (variableType.equals(ARRAY_TYPE)) { String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if (indexType.equals(INT_TYPE)) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return INVALID_TYPE; + return UNKNOWN_TYPE; return INT_TYPE; } @@ -138,8 +136,8 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { } String message = "Cannot resolve symbol 'length'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); - return INVALID_TYPE; + jmmNode.put(TYPENAME, UNKNOWN); + return UNKNOWN_TYPE; } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { @@ -152,13 +150,13 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } //TODO: check parameters if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return INVALID_TYPE; + return UNKNOWN_TYPE; else return analysis.getSymbolTable().getReturnType(method); } @@ -184,8 +182,8 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { } String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); - return INVALID_TYPE; + jmmNode.put(TYPENAME, UNKNOWN); + return UNKNOWN_TYPE; } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { @@ -204,8 +202,8 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { String message = "Cannot find '" + objectClassName + "'."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); - return INVALID_TYPE; + jmmNode.put(TYPENAME, UNKNOWN); + return UNKNOWN_TYPE; } private Type dealWithInteger(JmmNode jmmNode, Type type) { @@ -222,8 +220,8 @@ private Type dealWithThis(JmmNode jmmNode, Type type) { if (Objects.equals(this.methodName, "main")) { String message = "'this' expression cannot be used in a static method."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); - return INVALID_TYPE; + jmmNode.put(TYPENAME, UNKNOWN); + return UNKNOWN_TYPE; } String className = analysis.getSymbolTable().getClassName(); jmmNode.put(TYPENAME, className); @@ -234,10 +232,10 @@ private Type dealWithIdentifier(JmmNode jmmNode, Type type) { String identifier = jmmNode.get("value"); Type identifierType = getIdentifierType(this.methodName, identifier, analysis.getSymbolTable()); - if(Objects.equals(identifierType.print(), INVALID)){ + if(Objects.equals(identifierType.print(), UNKNOWN)){ String message = "'" + identifier + "' is not declared."; this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, INVALID); + jmmNode.put(TYPENAME, UNKNOWN); } jmmNode.put("typename", identifierType.print()); return identifierType; diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index 68c02f3..f9a2a44 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -11,14 +11,14 @@ public class SemanticUtils { public static final Type ARRAY_TYPE = new Type("int", true); public static final Type BOOLEAN_TYPE = new Type("boolean", false); public static final Type INT_TYPE = new Type("int", false); - public static final Type INVALID_TYPE = new Type("#invalid", false); + public static final Type UNKNOWN_TYPE = new Type("#unknown", false); public static final Type UNDEFINED_TYPE = new Type("#undefined", false); //Type names public static final String ARRAY = ARRAY_TYPE.print(); public static final String BOOLEAN = BOOLEAN_TYPE.print(); public static final String INT = INT_TYPE.print(); - public static final String INVALID = INVALID_TYPE.print(); + public static final String UNKNOWN = UNKNOWN_TYPE.print(); public static final String UNDEFINED = UNDEFINED_TYPE.print(); //Typename attribute @@ -54,6 +54,6 @@ public static Type getIdentifierType(String methodName, String identifier, MySym if(findImport(symbolTable.getImports(), identifier)) return new Type(identifier, false); - return INVALID_TYPE; + return UNKNOWN_TYPE; } } From 1886d28288112a2cef692b71e8a152f767e8f2c2 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 16:08:39 +0100 Subject: [PATCH 034/253] Set symbolTable and report list as private fields of ClassDeclAnalysis --- src/main/pt/up/fe/comp2023/Analysis.java | 2 +- src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index 73a2d8d..1790408 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -17,7 +17,7 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { JmmNode root = parserResult.getRootNode(); this.symbolTable = new MySymbolTable(parserResult.getRootNode()); - ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this); + ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, symbolTable, reports); classDeclAnalysis.checkImportedSuperClass(); for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index 36412a6..382ccad 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -13,12 +13,14 @@ public class ClassDeclAnalysis extends AJmmVisitor { private final JmmNode classDeclNode; - private final Analysis analysis; + private final MySymbolTable symbolTable; + private final List reports; private final List methodNodes = new ArrayList<>(); - public ClassDeclAnalysis(JmmNode rootNode, Analysis analysis){ + public ClassDeclAnalysis(JmmNode rootNode, MySymbolTable symbolTable, List reports){ this.classDeclNode = rootNode.getJmmChild(rootNode.getNumChildren() - 1); - this.analysis = analysis; + this.symbolTable = symbolTable; + this.reports = reports; } @Override @@ -29,11 +31,11 @@ protected void buildVisitor() { } public void checkImportedSuperClass() { - String superClass = analysis.getSymbolTable().getSuper(); + String superClass = this.symbolTable.getSuper(); - if(superClass != null && !findImport(analysis.getSymbolTable().getImports(), superClass)){ + if(superClass != null && !findImport(this.symbolTable.getImports(), superClass)){ String message = "Cannot find super class '" + superClass + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } for (JmmNode child: classDeclNode.getChildren()) From 7408973d2126fdc97b1fe700684c342222dd7e3b Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 16:12:47 +0100 Subject: [PATCH 035/253] Set symbolTable and reports list as private fields of MethodAnalysis --- src/main/pt/up/fe/comp2023/Analysis.java | 4 ++-- src/main/pt/up/fe/comp2023/MethodAnalysis.java | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index 1790408..cffc1d6 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -17,11 +17,11 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { JmmNode root = parserResult.getRootNode(); this.symbolTable = new MySymbolTable(parserResult.getRootNode()); - ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, symbolTable, reports); + ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this.symbolTable, this.reports); classDeclAnalysis.checkImportedSuperClass(); for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ - MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this); + MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this.symbolTable, this.reports); for (JmmNode statementNode : methodAnalysis.getStatementNodes()){ new StatementAnalysis(statementNode, this); } diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index 1011dcd..0e338f4 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -11,11 +11,13 @@ import java.util.Objects; public class MethodAnalysis extends AJmmVisitor { - private final Analysis analysis; + private final MySymbolTable symbolTable; + private final List reports; private final List statementNodes = new ArrayList<>(); - public MethodAnalysis(JmmNode methodNode, Analysis analysis) { - this.analysis = analysis; + public MethodAnalysis(JmmNode methodNode, MySymbolTable symbolTable, List reports) { + this.symbolTable = symbolTable; + this.reports = reports; visit(methodNode); } @@ -41,7 +43,7 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { String parameterType = jmmNode.get("parametertype"); if(!Objects.equals(parameterType, "String")) { String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } for (JmmNode child: jmmNode.getChildren()) From 0ea15b20d3c67c6abb41605bfb5f2f352d73e50b Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 16:25:27 +0100 Subject: [PATCH 036/253] ExpressionAnalysis and StatementAnalysis with symbolTable and reports as private fields --- src/main/pt/up/fe/comp2023/Analysis.java | 2 +- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 52 ++++++++++--------- .../pt/up/fe/comp2023/StatementAnalysis.java | 13 +++-- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index cffc1d6..a78eeb2 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -23,7 +23,7 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this.symbolTable, this.reports); for (JmmNode statementNode : methodAnalysis.getStatementNodes()){ - new StatementAnalysis(statementNode, this); + new StatementAnalysis(statementNode, this.symbolTable, this.reports); } } return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 32d5474..0c3e1c3 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -7,15 +7,19 @@ import pt.up.fe.comp.jmm.report.ReportType; import pt.up.fe.comp.jmm.report.Stage; +import java.util.List; import java.util.Objects; import static pt.up.fe.comp2023.SemanticUtils.*; public class ExpressionAnalysis extends AJmmVisitor { - private String methodName; - private final Analysis analysis; - public ExpressionAnalysis (String methodName, Analysis analysis){ - this.analysis = analysis; + private final String methodName; + private final MySymbolTable symbolTable; + private final List reports; + public ExpressionAnalysis (String methodName, MySymbolTable symbolTable, List reports){ + this.methodName = methodName; + this.symbolTable = symbolTable; + this.reports = reports; } @Override @@ -50,7 +54,7 @@ private Type checkBooleanExpression(JmmNode jmmNode, Type type) { return BOOLEAN_TYPE; } String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -61,13 +65,13 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { if(leftOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } if(rightOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -88,13 +92,13 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { if(leftOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } if(rightOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -111,13 +115,13 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { if (variableType.equals(ARRAY_TYPE)) { String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } if (indexType.equals(INT_TYPE)) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -135,21 +139,21 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { return INT_TYPE; } String message = "Cannot resolve symbol 'length'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { String method = jmmNode.get("methodcall"); - String declaredClass = analysis.getSymbolTable().getClassName(); + String declaredClass = this.symbolTable.getClassName(); - if(analysis.getSymbolTable().getMethods().contains(method)){ + if(this.symbolTable.getMethods().contains(method)){ String expressionType = visit(jmmNode.getJmmChild(0)).print(); if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; - analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } @@ -158,7 +162,7 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found return UNKNOWN_TYPE; else - return analysis.getSymbolTable().getReturnType(method); + return this.symbolTable.getReturnType(method); } //TODO: if the class extends another class: @@ -181,13 +185,13 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { return ARRAY_TYPE; } String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { - String declaredClassName = analysis.getSymbolTable().getClassName(); + String declaredClassName = this.symbolTable.getClassName(); String objectClassName = jmmNode.get("classname"); if(Objects.equals(objectClassName, declaredClassName)){ @@ -195,13 +199,13 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return new Type(declaredClassName, false); } - if(findImport(analysis.getSymbolTable().getImports(), objectClassName)){ + if(findImport(this.symbolTable.getImports(), objectClassName)){ jmmNode.put(TYPENAME, objectClassName); return new Type(objectClassName, false); } String message = "Cannot find '" + objectClassName + "'."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -219,22 +223,22 @@ private Type dealWithBoolean(JmmNode jmmNode, Type type) { private Type dealWithThis(JmmNode jmmNode, Type type) { if (Objects.equals(this.methodName, "main")) { String message = "'this' expression cannot be used in a static method."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } - String className = analysis.getSymbolTable().getClassName(); + String className = this.symbolTable.getClassName(); jmmNode.put(TYPENAME, className); return new Type(className, false); } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { String identifier = jmmNode.get("value"); - Type identifierType = getIdentifierType(this.methodName, identifier, analysis.getSymbolTable()); + Type identifierType = getIdentifierType(this.methodName, identifier, this.symbolTable); if(Objects.equals(identifierType.print(), UNKNOWN)){ String message = "'" + identifier + "' is not declared."; - this.analysis.addReport(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } jmmNode.put("typename", identifierType.print()); diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 7219344..e96aa91 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -2,15 +2,20 @@ import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.report.Report; + +import java.util.List; public class StatementAnalysis extends AJmmVisitor { - private Analysis analysis; + private final MySymbolTable symbolTable; + private final List reports; private ExpressionAnalysis expressionAnalysis; - public StatementAnalysis(JmmNode statementNode, Analysis analysis){ - this.analysis = analysis; + public StatementAnalysis(JmmNode statementNode, MySymbolTable symbolTable, List reports){ + this.symbolTable = symbolTable; + this.reports = reports; String methodName = statementNode.getJmmParent().get("methodname"); - this.expressionAnalysis = new ExpressionAnalysis(methodName, analysis); + this.expressionAnalysis = new ExpressionAnalysis(methodName, symbolTable, reports); visit(statementNode); } From c1053b02062021285dcde5d76810fee0f0dc274c Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 8 Apr 2023 20:09:56 +0100 Subject: [PATCH 037/253] Refactor checkImportedSuperClass --- src/main/pt/up/fe/comp2023/Analysis.java | 1 - .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index a78eeb2..d2f6bce 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -18,7 +18,6 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { this.symbolTable = new MySymbolTable(parserResult.getRootNode()); ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this.symbolTable, this.reports); - classDeclAnalysis.checkImportedSuperClass(); for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this.symbolTable, this.reports); diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java index 382ccad..c814708 100644 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java @@ -12,25 +12,32 @@ import static pt.up.fe.comp2023.SemanticUtils.findImport; public class ClassDeclAnalysis extends AJmmVisitor { - private final JmmNode classDeclNode; private final MySymbolTable symbolTable; private final List reports; private final List methodNodes = new ArrayList<>(); public ClassDeclAnalysis(JmmNode rootNode, MySymbolTable symbolTable, List reports){ - this.classDeclNode = rootNode.getJmmChild(rootNode.getNumChildren() - 1); this.symbolTable = symbolTable; this.reports = reports; + visit(rootNode); } @Override protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); + addVisit("ClassDecl", this::checkImportedSuperClass); addVisit("MethodDecl", this::addMethodNode); addVisit("VoidMethodDecl", this::addMethodNode); addVisit("MainMethodDecl", this::addMethodNode); } - public void checkImportedSuperClass() { + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { String superClass = this.symbolTable.getSuper(); if(superClass != null && !findImport(this.symbolTable.getImports(), superClass)){ @@ -38,8 +45,9 @@ public void checkImportedSuperClass() { this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - for (JmmNode child: classDeclNode.getChildren()) + for (JmmNode child: jmmNode.getChildren()) visit(child); + return null; } private Void addMethodNode(JmmNode methodNode, Void unused) { From c09c9cbfbf6ede08e40b161855e3c8337c281ff6 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 10 Apr 2023 00:31:19 +0100 Subject: [PATCH 038/253] Implemented checkBooleanCondition in StatementAnalysis --- .../pt/up/fe/comp2023/StatementAnalysis.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index e96aa91..1734e74 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -1,15 +1,20 @@ package pt.up.fe.comp2023; +import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.report.ReportType; +import pt.up.fe.comp.jmm.report.Stage; import java.util.List; +import static pt.up.fe.comp2023.SemanticUtils.*; + public class StatementAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; private final List reports; - private ExpressionAnalysis expressionAnalysis; + private final ExpressionAnalysis expressionAnalysis; public StatementAnalysis(JmmNode statementNode, MySymbolTable symbolTable, List reports){ this.symbolTable = symbolTable; @@ -37,7 +42,17 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { - //TODO + JmmNode expressionNode = jmmNode.getJmmChild(0); + + Type conditionType = expressionAnalysis.visit(expressionNode); + if(conditionType.equals(BOOLEAN_TYPE)) { + String message = "Expected condition of type '" + BOOLEAN + "' but found '" + conditionType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for(int i= 1; i < jmmNode.getNumChildren(); i++){ + visit(jmmNode.getJmmChild(i)); + } return null; } From 10820565711f61425005783121c7fd47839accfa Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 10 Apr 2023 13:12:03 +0100 Subject: [PATCH 039/253] Implemented checkCompatibleAssignment() in StatementAnalysis --- .../pt/up/fe/comp2023/StatementAnalysis.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 1734e74..f853db9 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -14,12 +14,15 @@ public class StatementAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; private final List reports; + private final String methodName; private final ExpressionAnalysis expressionAnalysis; + public StatementAnalysis(JmmNode statementNode, MySymbolTable symbolTable, List reports){ this.symbolTable = symbolTable; this.reports = reports; String methodName = statementNode.getJmmParent().get("methodname"); + this.methodName = methodName; this.expressionAnalysis = new ExpressionAnalysis(methodName, symbolTable, reports); visit(statementNode); @@ -57,12 +60,27 @@ private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { } private Void expressionVisitor(JmmNode jmmNode, Void unused) { - //TODO + expressionAnalysis.visit(jmmNode); return null; } private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { - //TODO + String varName = jmmNode.get("varname"); + JmmNode expressionNode = jmmNode.getJmmChild(0); + Type left = getIdentifierType(this.methodName, varName, this.symbolTable); + Type right = expressionAnalysis.visit(expressionNode); + + if(left.equals(UNKNOWN_TYPE)){ + String message = "'" + varName + "' is not declared."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + else if (right.equals(UNDEFINED_TYPE)) { + expressionNode.put(TYPENAME, left.print()); + } + else if (!right.equals(left)) { + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } return null; } From 0f943ead1f7302ac4c6e75123b5318058dff8071 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 10 Apr 2023 13:54:46 +0100 Subject: [PATCH 040/253] Implemented validateArrayAssignment() in StatementAnalysis --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 13 ++++++----- .../pt/up/fe/comp2023/StatementAnalysis.java | 23 ++++++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 0c3e1c3..7febdbd 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -63,13 +63,13 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(leftOperandType.equals(INT_TYPE)) { + if(!leftOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } - if(rightOperandType.equals(INT_TYPE)) { + if(!rightOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) @@ -90,13 +90,13 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { Type leftOperandType = visit(jmmNode.getJmmChild(0)); Type rightOperandType = visit(jmmNode.getJmmChild(1)); - if(leftOperandType.equals(BOOLEAN_TYPE)) { + if(!leftOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } - if(rightOperandType.equals(BOOLEAN_TYPE)) { + if(!rightOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) @@ -113,13 +113,13 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { Type variableType = visit(jmmNode.getJmmChild(0)); Type indexType = visit(jmmNode.getJmmChild(1)); - if (variableType.equals(ARRAY_TYPE)) { + if (!variableType.equals(ARRAY_TYPE)) { String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } - if (indexType.equals(INT_TYPE)) { + if (!indexType.equals(INT_TYPE)) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values if(!jmmNode.hasAttribute(TYPENAME)) @@ -128,6 +128,7 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found return UNKNOWN_TYPE; + jmmNode.put(TYPENAME, INT); return INT_TYPE; } diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index f853db9..4d0dd6d 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -85,7 +85,28 @@ else if (!right.equals(left)) { } private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { - //TODO + String varName = jmmNode.get("arrayname"); + JmmNode valueNode = jmmNode.getJmmChild(1); + Type varType = getIdentifierType(this.methodName, varName, this.symbolTable); + Type indexType = expressionAnalysis.visit(jmmNode.getJmmChild(0)); + Type valueType = expressionAnalysis.visit(valueNode); + + if(!valueType.isArray()){ + String message = "'" + varName + "' must be an array."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + } + if(!indexType.equals(INT_TYPE)){ + String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + } + + if(valueType.equals(UNDEFINED_TYPE)){ + valueNode.put(TYPENAME, INT); + } + else if(!valueType.equals(INT_TYPE)){ + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } return null; } } From af22d3fa151683bfe65c4f43b4618aec32461e5f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 10 Apr 2023 15:02:19 +0100 Subject: [PATCH 041/253] Added method checkReturnType to MethodAnalysis --- .../pt/up/fe/comp2023/MethodAnalysis.java | 21 ++++++++++++++++++- .../pt/up/fe/comp2023/StatementAnalysis.java | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index 0e338f4..3ffd56c 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -1,5 +1,6 @@ package pt.up.fe.comp2023; +import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.report.Report; @@ -10,14 +11,16 @@ import java.util.List; import java.util.Objects; -public class MethodAnalysis extends AJmmVisitor { +public class MethodAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; private final List reports; private final List statementNodes = new ArrayList<>(); + private final ExpressionAnalysis expressionAnalysis; public MethodAnalysis(JmmNode methodNode, MySymbolTable symbolTable, List reports) { this.symbolTable = symbolTable; this.reports = reports; + this.expressionAnalysis = new ExpressionAnalysis(methodNode.get("methodname"), symbolTable, reports); visit(methodNode); } @@ -25,6 +28,7 @@ public MethodAnalysis(JmmNode methodNode, MySymbolTable symbolTable, List Date: Tue, 11 Apr 2023 12:17:05 +0100 Subject: [PATCH 042/253] Updated grammar --- src/main/antlr/comp2023/grammar/Javamm.g4 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index 43a8b4c..ec97e65 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -24,9 +24,9 @@ classDeclaration ; methodDeclaration - : ('public')? type methodname=ID '(' methodDeclarationParameters ')' '{' (varDeclaration | statement)* 'return' expression ';' '}' #MethodDecl - | ('public')? 'void' methodname=ID '(' methodDeclarationParameters ')' '{' (varDeclaration | statement)* ('return' ';')? '}' #VoidMethodDecl - | ('public')? 'static' 'void' methodname='main' '(' parametertype=ID '[' ']' parametername=ID ')' '{' (varDeclaration | statement)* '}' #MainMethodDecl + : ('public')? type methodname=ID '(' methodDeclarationParameters ')' '{' varDeclaration* statement* 'return' expression ';' '}' #MethodDecl + | ('public')? 'void' methodname=ID '(' methodDeclarationParameters ')' '{' varDeclaration* statement* ('return' ';')? '}' #VoidMethodDecl + | ('public')? 'static' 'void' methodname='main' '(' parametertype=ID '[' ']' parametername=ID ')' '{' varDeclaration* statement* '}' #MainMethodDecl ; methodDeclarationParameters From 200329f975f81707af5a7829133f855fd699cffe Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 11 Apr 2023 12:18:20 +0100 Subject: [PATCH 043/253] Updated checkCompatibleAssignment to handle extends/imports assignments --- .../pt/up/fe/comp2023/StatementAnalysis.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 79cecbc..901ca9a 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -8,6 +8,7 @@ import pt.up.fe.comp.jmm.report.Stage; import java.util.List; +import java.util.Objects; import static pt.up.fe.comp2023.SemanticUtils.*; @@ -69,18 +70,27 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { JmmNode expressionNode = jmmNode.getJmmChild(0); Type left = getIdentifierType(this.methodName, varName, this.symbolTable); Type right = expressionAnalysis.visit(expressionNode); + String superClass = this.symbolTable.getSuper(); + String className = this.symbolTable.getClassName(); if(left.equals(UNKNOWN_TYPE)){ String message = "'" + varName + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - else if (right.equals(UNDEFINED_TYPE)) { + else if (right.equals(UNDEFINED_TYPE)) expressionNode.put(TYPENAME, left.print()); - } - else if (!right.equals(left)) { - String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } + + else if(right.equals(left)) + return null; + + else if (Objects.equals(left.print(), className) && Objects.equals(right.print(), superClass)) + return null; + + else if (findImport(symbolTable.getImports(), left.print()) && !right.equals(UNKNOWN_TYPE)) + return null; + + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values return null; } From 31100b7db6ce85b3a7968e43f05fbc32e5aa91a9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 12 Apr 2023 08:47:11 +0100 Subject: [PATCH 044/253] Small fix in checkCompatibleAssignment() --- src/main/pt/up/fe/comp2023/StatementAnalysis.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 901ca9a..3d4fb04 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -83,10 +83,10 @@ else if (right.equals(UNDEFINED_TYPE)) else if(right.equals(left)) return null; - else if (Objects.equals(left.print(), className) && Objects.equals(right.print(), superClass)) + else if (Objects.equals(left.print(), superClass) && Objects.equals(right.print(), className)) return null; - else if (findImport(symbolTable.getImports(), left.print()) && !right.equals(UNKNOWN_TYPE)) + else if (findImport(symbolTable.getImports(), left.print()) && findImport(symbolTable.getImports(), left.print())) return null; String message = "Type of the assignee is not compatible with the assigned."; From 0db8c243fa6b680b8cb03061f0ad491f8e869479 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 01:05:14 +0100 Subject: [PATCH 045/253] completed method call analysis to detect extended/imported method --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 31 ++++++++++--------- .../pt/up/fe/comp2023/StatementAnalysis.java | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 7febdbd..3543e64 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -148,34 +148,35 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { private Type dealWithMethodCall(JmmNode jmmNode, Type type) { String method = jmmNode.get("methodcall"); String declaredClass = this.symbolTable.getClassName(); + String superClass = this.symbolTable.getSuper(); + String expressionType = visit(jmmNode.getJmmChild(0)).print(); if(this.symbolTable.getMethods().contains(method)){ - String expressionType = visit(jmmNode.getJmmChild(0)).print(); - if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - jmmNode.put(TYPENAME, UNKNOWN); } //TODO: check parameters - if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return UNKNOWN_TYPE; - else - return this.symbolTable.getReturnType(method); + jmmNode.put(TYPENAME, symbolTable.getReturnType(method).print()); + return this.symbolTable.getReturnType(method); } - //TODO: if the class extends another class: - //TODO: check if class is imported - //TODO: check if expression.type == declaredClass or superClass - //TODO: compute node type(undefined) + else if(Objects.equals(expressionType, declaredClass) || Objects.equals(expressionType, superClass)){ + if(!findImport(this.symbolTable.getImports(), superClass)){ + String message = "Cannot find super class '" + superClass + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + } - //TODO: else (it is a method of a imported class) - //TODO: check if expression.type (=classname) is imported - //TODO: compute node type + else if(!findImport(this.symbolTable.getImports(), expressionType)){ + String message = "'" + expressionType + "' is not declared."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } - return null; + jmmNode.put(TYPENAME, UNDEFINED); + return UNDEFINED_TYPE; } private Type checkIntegerLength(JmmNode jmmNode, Type type) { diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java index 3d4fb04..b2f237d 100644 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ b/src/main/pt/up/fe/comp2023/StatementAnalysis.java @@ -61,7 +61,7 @@ private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { } private Void expressionVisitor(JmmNode jmmNode, Void unused) { - expressionAnalysis.visit(jmmNode); + expressionAnalysis.visit(jmmNode.getJmmChild(0)); return null; } From 63a23c8baf9be3320172b9041bf0a26935647415 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 02:17:30 +0100 Subject: [PATCH 046/253] Completed method call analysis to verify argument types --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 28 +++++++++++++++---- .../pt/up/fe/comp2023/MethodAnalysis.java | 4 ++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 3543e64..a0ac62c 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -146,19 +146,17 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { - String method = jmmNode.get("methodcall"); String declaredClass = this.symbolTable.getClassName(); String superClass = this.symbolTable.getSuper(); String expressionType = visit(jmmNode.getJmmChild(0)).print(); + String method = jmmNode.get("methodcall"); if(this.symbolTable.getMethods().contains(method)){ if(!Objects.equals(expressionType, declaredClass)){ String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - - //TODO: check parameters - + this.verifyArgumentTypes(jmmNode.getJmmChild(1), method); jmmNode.put(TYPENAME, symbolTable.getReturnType(method).print()); return this.symbolTable.getReturnType(method); } @@ -174,11 +172,31 @@ else if(!findImport(this.symbolTable.getImports(), expressionType)){ String message = "'" + expressionType + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - jmmNode.put(TYPENAME, UNDEFINED); return UNDEFINED_TYPE; } + private void verifyArgumentTypes(JmmNode jmmNode, String method) { + int numDeclaredParams = symbolTable.getParameters(method).size(); + int numCallParams = jmmNode.getNumChildren(); + + if(numDeclaredParams != numCallParams){ + String message = "Method '" + method + "' expected " + numDeclaredParams + " but found " + numCallParams + "."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for(int i=0; i < numDeclaredParams && i < numCallParams; i++){ + Type declaredParamType = symbolTable.getParameters(method).get(i).getType(); + Type callParamType = visit(jmmNode.getJmmChild(i)); + + if(!declaredParamType.equals(callParamType)){ + String declaredArgumentName = symbolTable.getParameters(method).get(i).getName(); + String message = "Method '" + method + "' expected argument '" + declaredArgumentName + "' to be '" + declaredParamType.print() + "' but found '" + callParamType.print() + "."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + } + } + private Type checkIntegerLength(JmmNode jmmNode, Type type) { Type lengthType = visit(jmmNode.getJmmChild(0)); diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java index 3ffd56c..392543f 100644 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ b/src/main/pt/up/fe/comp2023/MethodAnalysis.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.Objects; +import static pt.up.fe.comp2023.SemanticUtils.*; + public class MethodAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; private final List reports; @@ -60,7 +62,7 @@ private Void checkReturnType(JmmNode jmmNode, Void unused) { Type returnType = this.symbolTable.getReturnType(jmmNode.get("methodname")); Type returnNodeType = expressionAnalysis.visit(returnNode); - if(!returnType.equals(returnNodeType)){ + if(!returnNodeType.equals(returnType) && !returnNodeType.equals(UNDEFINED_TYPE)){ String message = "Make method '" + jmmNode.get("methodname") +"' return " + returnType.print() + "."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } From d7a0c862691889b2f565d607b78fcb221f81de79 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 03:07:32 +0100 Subject: [PATCH 047/253] [refactor] created SemanticAnalysis class --- src/main/pt/up/fe/comp2023/Analysis.java | 10 +- .../pt/up/fe/comp2023/SemanticAnalysis.java | 176 ++++++++++++++++++ 2 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 src/main/pt/up/fe/comp2023/SemanticAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index d2f6bce..cfdcc37 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -17,14 +17,8 @@ public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { JmmNode root = parserResult.getRootNode(); this.symbolTable = new MySymbolTable(parserResult.getRootNode()); - ClassDeclAnalysis classDeclAnalysis = new ClassDeclAnalysis(root, this.symbolTable, this.reports); - - for (JmmNode methodNode : classDeclAnalysis.getMethodNodes()){ - MethodAnalysis methodAnalysis = new MethodAnalysis(methodNode,this.symbolTable, this.reports); - for (JmmNode statementNode : methodAnalysis.getStatementNodes()){ - new StatementAnalysis(statementNode, this.symbolTable, this.reports); - } - } + SemanticAnalysis semanticAnalysis = new SemanticAnalysis(root, this.symbolTable, this.reports); + return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); } diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java new file mode 100644 index 0000000..c98ca8d --- /dev/null +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -0,0 +1,176 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.analysis.table.Type; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.report.ReportType; +import pt.up.fe.comp.jmm.report.Stage; + +import java.util.List; +import java.util.Objects; + +import static pt.up.fe.comp2023.SemanticUtils.*; +import static pt.up.fe.comp2023.SemanticUtils.BOOLEAN; + +public class SemanticAnalysis extends AJmmVisitor { + private final MySymbolTable symbolTable; + private final List reports; + private String currentMethodName; + private ExpressionAnalysis expressionAnalysis; + + public SemanticAnalysis (JmmNode rootNode, MySymbolTable symbolTable, List reports){ + this.symbolTable = symbolTable; + this.reports = reports; + visit(rootNode); + } + + @Override + protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); + addVisit("ClassDecl", this::checkImportedSuperClass); + addVisit("MethodDecl", this::checkReturnType); + addVisit("VoidMethodDecl", this::dealWithVoidMethod); + addVisit("MainMethodDecl", this::checkMainMethodParameterType); + addVisit("Condition", this::checkBooleanCondition); + addVisit("Cycle", this::checkBooleanCondition); + addVisit("Expr", this::expressionVisitor); + addVisit("Assignment", this::checkCompatibleAssignment); + addVisit("ArrayAssignment", this::validateArrayAssignment); + } + + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { + String superClass = this.symbolTable.getSuper(); + + if(superClass != null && !findImport(this.symbolTable.getImports(), superClass)){ + String message = "Cannot find super class '" + superClass + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void checkReturnType(JmmNode jmmNode, Void unused) { + this.currentMethodName = jmmNode.get("methodname"); + this.expressionAnalysis = new ExpressionAnalysis(this.currentMethodName, this.symbolTable, this.reports); + + JmmNode returnNode = jmmNode.getJmmChild(jmmNode.getNumChildren() - 1); + Type returnType = this.symbolTable.getReturnType(jmmNode.get("methodname")); + Type returnNodeType = expressionAnalysis.visit(returnNode); + + if(!returnNodeType.equals(returnType) && !returnNodeType.equals(UNDEFINED_TYPE)){ + String message = "Make method '" + jmmNode.get("methodname") +"' return " + returnType.print() + "."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + public Void dealWithVoidMethod(JmmNode jmmNode, Void unused) { + this.currentMethodName = jmmNode.get("methodname"); + this.expressionAnalysis = new ExpressionAnalysis(this.currentMethodName, this.symbolTable, this.reports); + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { + this.currentMethodName = jmmNode.get("methodname"); + this.expressionAnalysis = new ExpressionAnalysis(this.currentMethodName, this.symbolTable, this.reports); + + String parameterType = jmmNode.get("parametertype"); + if(!Objects.equals(parameterType, "String")) { + String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { + JmmNode expressionNode = jmmNode.getJmmChild(0); + + Type conditionType = expressionAnalysis.visit(expressionNode); + if(!conditionType.equals(BOOLEAN_TYPE)) { + String message = "Expected condition of type '" + BOOLEAN + "' but found '" + conditionType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + + for(int i= 1; i < jmmNode.getNumChildren(); i++){ + visit(jmmNode.getJmmChild(i)); + } + return null; + } + + private Void expressionVisitor(JmmNode jmmNode, Void unused) { + expressionAnalysis.visit(jmmNode.getJmmChild(0)); + return null; + } + + private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { + String varName = jmmNode.get("varname"); + JmmNode expressionNode = jmmNode.getJmmChild(0); + Type left = getIdentifierType(this.currentMethodName, varName, this.symbolTable); + Type right = expressionAnalysis.visit(expressionNode); + String superClass = this.symbolTable.getSuper(); + String className = this.symbolTable.getClassName(); + + if(left.equals(UNKNOWN_TYPE)){ + String message = "'" + varName + "' is not declared."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + else if (right.equals(UNDEFINED_TYPE)) + expressionNode.put(TYPENAME, left.print()); + + else if(right.equals(left)) + return null; + + else if (Objects.equals(left.print(), superClass) && Objects.equals(right.print(), className)) + return null; + + else if (findImport(symbolTable.getImports(), left.print()) && findImport(symbolTable.getImports(), right.print())) + return null; + + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + return null; + } + + private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { + String varName = jmmNode.get("arrayname"); + JmmNode valueNode = jmmNode.getJmmChild(1); + Type varType = getIdentifierType(this.currentMethodName, varName, this.symbolTable); + Type indexType = expressionAnalysis.visit(jmmNode.getJmmChild(0)); + Type valueType = expressionAnalysis.visit(valueNode); + + if(!valueType.isArray()){ + String message = "'" + varName + "' must be an array."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + } + if(!indexType.equals(INT_TYPE)){ + String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + } + + if(valueType.equals(UNDEFINED_TYPE)){ + valueNode.put(TYPENAME, INT); + } + else if(!valueType.equals(INT_TYPE)){ + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + } + return null; + } +} From 584ef48df7fc79aaf7a8e5f2aa44b573368fb3c3 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 03:17:22 +0100 Subject: [PATCH 048/253] Set className,superClass and imports as private fields of SemanticAnalysis and ExpressionAnalysis --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 34 ++++++++++--------- .../pt/up/fe/comp2023/SemanticAnalysis.java | 14 +++++--- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index a0ac62c..fe484d1 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -16,10 +16,16 @@ public class ExpressionAnalysis extends AJmmVisitor { private final String methodName; private final MySymbolTable symbolTable; private final List reports; + private final String className; + private final String superClass; + private final List imports; public ExpressionAnalysis (String methodName, MySymbolTable symbolTable, List reports){ this.methodName = methodName; this.symbolTable = symbolTable; this.reports = reports; + this.className = this.symbolTable.getClassName(); + this.superClass = this.symbolTable.getSuper(); + this.imports = this.symbolTable.getImports(); } @Override @@ -146,14 +152,12 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { - String declaredClass = this.symbolTable.getClassName(); - String superClass = this.symbolTable.getSuper(); String expressionType = visit(jmmNode.getJmmChild(0)).print(); String method = jmmNode.get("methodcall"); if(this.symbolTable.getMethods().contains(method)){ - if(!Objects.equals(expressionType, declaredClass)){ - String message = "Expected expression of type '" + declaredClass + "' but found '" + expressionType + "'."; + if(!Objects.equals(expressionType, this.className)){ + String message = "Expected expression of type '" + this.className + "' but found '" + expressionType + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } this.verifyArgumentTypes(jmmNode.getJmmChild(1), method); @@ -161,14 +165,14 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { return this.symbolTable.getReturnType(method); } - else if(Objects.equals(expressionType, declaredClass) || Objects.equals(expressionType, superClass)){ - if(!findImport(this.symbolTable.getImports(), superClass)){ - String message = "Cannot find super class '" + superClass + "'."; + else if(Objects.equals(expressionType, this.className) || Objects.equals(expressionType, this.superClass)){ + if(!findImport(this.imports, this.superClass)){ + String message = "Cannot find super class '" + this.superClass + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } } - else if(!findImport(this.symbolTable.getImports(), expressionType)){ + else if(!findImport(this.imports, expressionType)){ String message = "'" + expressionType + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } @@ -211,15 +215,14 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { - String declaredClassName = this.symbolTable.getClassName(); String objectClassName = jmmNode.get("classname"); - if(Objects.equals(objectClassName, declaredClassName)){ - jmmNode.put(TYPENAME, declaredClassName); - return new Type(declaredClassName, false); + if(Objects.equals(objectClassName, this.className)){ + jmmNode.put(TYPENAME, this.className); + return new Type(this.className, false); } - if(findImport(this.symbolTable.getImports(), objectClassName)){ + if(findImport(this.imports, objectClassName)){ jmmNode.put(TYPENAME, objectClassName); return new Type(objectClassName, false); } @@ -247,9 +250,8 @@ private Type dealWithThis(JmmNode jmmNode, Type type) { jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } - String className = this.symbolTable.getClassName(); - jmmNode.put(TYPENAME, className); - return new Type(className, false); + jmmNode.put(TYPENAME, this.className); + return new Type(this.className, false); } private Type dealWithIdentifier(JmmNode jmmNode, Type type) { diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index c98ca8d..c5b0e3c 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -16,12 +16,18 @@ public class SemanticAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; private final List reports; + private final String className; + private final String superClass; + private final List imports; private String currentMethodName; private ExpressionAnalysis expressionAnalysis; public SemanticAnalysis (JmmNode rootNode, MySymbolTable symbolTable, List reports){ this.symbolTable = symbolTable; this.reports = reports; + this.className = this.symbolTable.getClassName(); + this.superClass = this.symbolTable.getSuper(); + this.imports = this.symbolTable.getImports(); visit(rootNode); } @@ -48,7 +54,7 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { String superClass = this.symbolTable.getSuper(); - if(superClass != null && !findImport(this.symbolTable.getImports(), superClass)){ + if(superClass != null && !findImport(this.imports, superClass)){ String message = "Cannot find super class '" + superClass + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } @@ -124,8 +130,6 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { JmmNode expressionNode = jmmNode.getJmmChild(0); Type left = getIdentifierType(this.currentMethodName, varName, this.symbolTable); Type right = expressionAnalysis.visit(expressionNode); - String superClass = this.symbolTable.getSuper(); - String className = this.symbolTable.getClassName(); if(left.equals(UNKNOWN_TYPE)){ String message = "'" + varName + "' is not declared."; @@ -137,10 +141,10 @@ else if (right.equals(UNDEFINED_TYPE)) else if(right.equals(left)) return null; - else if (Objects.equals(left.print(), superClass) && Objects.equals(right.print(), className)) + else if (Objects.equals(left.print(), this.superClass) && Objects.equals(right.print(), this.className)) return null; - else if (findImport(symbolTable.getImports(), left.print()) && findImport(symbolTable.getImports(), right.print())) + else if (findImport(this.imports, left.print()) && findImport(this.imports, right.print())) return null; String message = "Type of the assignee is not compatible with the assigned."; From a06cbb84e969cedf33e0d5c355c1ac95caa254f7 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 03:19:51 +0100 Subject: [PATCH 049/253] Removed unused classes --- .../pt/up/fe/comp2023/ClassDeclAnalysis.java | 61 --------- .../pt/up/fe/comp2023/MethodAnalysis.java | 83 ------------ .../pt/up/fe/comp2023/StatementAnalysis.java | 122 ------------------ 3 files changed, 266 deletions(-) delete mode 100644 src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java delete mode 100644 src/main/pt/up/fe/comp2023/MethodAnalysis.java delete mode 100644 src/main/pt/up/fe/comp2023/StatementAnalysis.java diff --git a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java b/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java deleted file mode 100644 index c814708..0000000 --- a/src/main/pt/up/fe/comp2023/ClassDeclAnalysis.java +++ /dev/null @@ -1,61 +0,0 @@ -package pt.up.fe.comp2023; - -import pt.up.fe.comp.jmm.ast.AJmmVisitor; -import pt.up.fe.comp.jmm.ast.JmmNode; -import pt.up.fe.comp.jmm.report.Report; -import pt.up.fe.comp.jmm.report.ReportType; -import pt.up.fe.comp.jmm.report.Stage; - -import java.util.ArrayList; -import java.util.List; - -import static pt.up.fe.comp2023.SemanticUtils.findImport; - -public class ClassDeclAnalysis extends AJmmVisitor { - private final MySymbolTable symbolTable; - private final List reports; - private final List methodNodes = new ArrayList<>(); - - public ClassDeclAnalysis(JmmNode rootNode, MySymbolTable symbolTable, List reports){ - this.symbolTable = symbolTable; - this.reports = reports; - visit(rootNode); - } - - @Override - protected void buildVisitor() { - setDefaultVisit(this::setDefaultVisit); - addVisit("ClassDecl", this::checkImportedSuperClass); - addVisit("MethodDecl", this::addMethodNode); - addVisit("VoidMethodDecl", this::addMethodNode); - addVisit("MainMethodDecl", this::addMethodNode); - } - - private Void setDefaultVisit(JmmNode jmmNode, Void unused) { - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { - String superClass = this.symbolTable.getSuper(); - - if(superClass != null && !findImport(this.symbolTable.getImports(), superClass)){ - String message = "Cannot find super class '" + superClass + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - private Void addMethodNode(JmmNode methodNode, Void unused) { - this.methodNodes.add(methodNode); - return null; - } - - public List getMethodNodes() { - return this.methodNodes; - } -} diff --git a/src/main/pt/up/fe/comp2023/MethodAnalysis.java b/src/main/pt/up/fe/comp2023/MethodAnalysis.java deleted file mode 100644 index 392543f..0000000 --- a/src/main/pt/up/fe/comp2023/MethodAnalysis.java +++ /dev/null @@ -1,83 +0,0 @@ -package pt.up.fe.comp2023; - -import pt.up.fe.comp.jmm.analysis.table.Type; -import pt.up.fe.comp.jmm.ast.AJmmVisitor; -import pt.up.fe.comp.jmm.ast.JmmNode; -import pt.up.fe.comp.jmm.report.Report; -import pt.up.fe.comp.jmm.report.ReportType; -import pt.up.fe.comp.jmm.report.Stage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import static pt.up.fe.comp2023.SemanticUtils.*; - -public class MethodAnalysis extends AJmmVisitor { - private final MySymbolTable symbolTable; - private final List reports; - private final List statementNodes = new ArrayList<>(); - private final ExpressionAnalysis expressionAnalysis; - - public MethodAnalysis(JmmNode methodNode, MySymbolTable symbolTable, List reports) { - this.symbolTable = symbolTable; - this.reports = reports; - this.expressionAnalysis = new ExpressionAnalysis(methodNode.get("methodname"), symbolTable, reports); - visit(methodNode); - } - - @Override - protected void buildVisitor() { - setDefaultVisit(this::setDefaultVisit); - addVisit("MainMethodDecl", this::checkMainMethodParameterType); - addVisit("MethodDecl", this::checkReturnType); - addVisit("CodeBlock", this::addStatement); - addVisit("Condition", this::addStatement); - addVisit("Cycle", this::addStatement); - addVisit("Expr", this::addStatement); - addVisit("Assignment", this::addStatement); - addVisit("ArrayAssignment", this::addStatement); - } - - private Void setDefaultVisit(JmmNode jmmNode, Void unused) { - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { - String parameterType = jmmNode.get("parametertype"); - if(!Objects.equals(parameterType, "String")) { - String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - private Void checkReturnType(JmmNode jmmNode, Void unused) { - JmmNode returnNode = jmmNode.getJmmChild(jmmNode.getNumChildren() - 1); - Type returnType = this.symbolTable.getReturnType(jmmNode.get("methodname")); - Type returnNodeType = expressionAnalysis.visit(returnNode); - - if(!returnNodeType.equals(returnType) && !returnNodeType.equals(UNDEFINED_TYPE)){ - String message = "Make method '" + jmmNode.get("methodname") +"' return " + returnType.print() + "."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - private Void addStatement(JmmNode jmmNode, Void unused) { - this.statementNodes.add(jmmNode); - return null; - } - - public List getStatementNodes() { - return this.statementNodes; - } -} diff --git a/src/main/pt/up/fe/comp2023/StatementAnalysis.java b/src/main/pt/up/fe/comp2023/StatementAnalysis.java deleted file mode 100644 index b2f237d..0000000 --- a/src/main/pt/up/fe/comp2023/StatementAnalysis.java +++ /dev/null @@ -1,122 +0,0 @@ -package pt.up.fe.comp2023; - -import pt.up.fe.comp.jmm.analysis.table.Type; -import pt.up.fe.comp.jmm.ast.AJmmVisitor; -import pt.up.fe.comp.jmm.ast.JmmNode; -import pt.up.fe.comp.jmm.report.Report; -import pt.up.fe.comp.jmm.report.ReportType; -import pt.up.fe.comp.jmm.report.Stage; - -import java.util.List; -import java.util.Objects; - -import static pt.up.fe.comp2023.SemanticUtils.*; - -public class StatementAnalysis extends AJmmVisitor { - private final MySymbolTable symbolTable; - private final List reports; - private final String methodName; - private final ExpressionAnalysis expressionAnalysis; - - - public StatementAnalysis(JmmNode statementNode, MySymbolTable symbolTable, List reports){ - this.symbolTable = symbolTable; - this.reports = reports; - String methodName = statementNode.getJmmParent().get("methodname"); - this.methodName = methodName; - this.expressionAnalysis = new ExpressionAnalysis(methodName, symbolTable, reports); - - visit(statementNode); - } - - @Override - protected void buildVisitor() { - setDefaultVisit(this::setDefaultVisit); - addVisit("Condition", this::checkBooleanCondition); - addVisit("Cycle", this::checkBooleanCondition); - addVisit("Expr", this::expressionVisitor); - addVisit("Assignment", this::checkCompatibleAssignment); - addVisit("ArrayAssignment", this::validateArrayAssignment); - } - - private Void setDefaultVisit(JmmNode jmmNode, Void unused) { - for (JmmNode child: jmmNode.getChildren()) - visit(child); - return null; - } - - private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { - JmmNode expressionNode = jmmNode.getJmmChild(0); - - Type conditionType = expressionAnalysis.visit(expressionNode); - if(!conditionType.equals(BOOLEAN_TYPE)) { - String message = "Expected condition of type '" + BOOLEAN + "' but found '" + conditionType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - - for(int i= 1; i < jmmNode.getNumChildren(); i++){ - visit(jmmNode.getJmmChild(i)); - } - return null; - } - - private Void expressionVisitor(JmmNode jmmNode, Void unused) { - expressionAnalysis.visit(jmmNode.getJmmChild(0)); - return null; - } - - private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { - String varName = jmmNode.get("varname"); - JmmNode expressionNode = jmmNode.getJmmChild(0); - Type left = getIdentifierType(this.methodName, varName, this.symbolTable); - Type right = expressionAnalysis.visit(expressionNode); - String superClass = this.symbolTable.getSuper(); - String className = this.symbolTable.getClassName(); - - if(left.equals(UNKNOWN_TYPE)){ - String message = "'" + varName + "' is not declared."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - else if (right.equals(UNDEFINED_TYPE)) - expressionNode.put(TYPENAME, left.print()); - - else if(right.equals(left)) - return null; - - else if (Objects.equals(left.print(), superClass) && Objects.equals(right.print(), className)) - return null; - - else if (findImport(symbolTable.getImports(), left.print()) && findImport(symbolTable.getImports(), left.print())) - return null; - - String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - return null; - } - - private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { - String varName = jmmNode.get("arrayname"); - JmmNode valueNode = jmmNode.getJmmChild(1); - Type varType = getIdentifierType(this.methodName, varName, this.symbolTable); - Type indexType = expressionAnalysis.visit(jmmNode.getJmmChild(0)); - Type valueType = expressionAnalysis.visit(valueNode); - - if(!valueType.isArray()){ - String message = "'" + varName + "' must be an array."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); - } - if(!indexType.equals(INT_TYPE)){ - String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); - } - - if(valueType.equals(UNDEFINED_TYPE)){ - valueNode.put(TYPENAME, INT); - } - else if(!valueType.equals(INT_TYPE)){ - String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values - } - return null; - } -} From f272d59e7ab25525bf9f9375343af1c231801408 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 16 Apr 2023 03:22:16 +0100 Subject: [PATCH 050/253] Removed unused methods of Analysis class --- src/main/pt/up/fe/comp2023/Analysis.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/Analysis.java index cfdcc37..01d4dff 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/Analysis.java @@ -10,27 +10,17 @@ import java.util.List; public class Analysis implements JmmAnalysis { - private MySymbolTable symbolTable; private final ArrayList reports = new ArrayList<>(); @Override public JmmSemanticsResult semanticAnalysis(JmmParserResult parserResult) { JmmNode root = parserResult.getRootNode(); - this.symbolTable = new MySymbolTable(parserResult.getRootNode()); + MySymbolTable symbolTable = new MySymbolTable(parserResult.getRootNode()); + SemanticAnalysis semanticAnalysis = new SemanticAnalysis(root, symbolTable, this.reports); - SemanticAnalysis semanticAnalysis = new SemanticAnalysis(root, this.symbolTable, this.reports); - - return new JmmSemanticsResult(parserResult, this.symbolTable, this.reports); - } - - public MySymbolTable getSymbolTable(){ - return this.symbolTable; + return new JmmSemanticsResult(parserResult, symbolTable, this.reports); } public List getReports(){ return this.reports; } - - public void addReport(Report report) { - this.reports.add(report); - } } From 7f368df57e4cdef4b22c34a85df2ac8d06759135 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 17 Apr 2023 23:00:16 +0100 Subject: [PATCH 051/253] Implemented functions that retrieve node line and column --- src/main/pt/up/fe/comp2023/SemanticUtils.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index f9a2a44..681c191 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -2,10 +2,13 @@ import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.Type; +import pt.up.fe.comp.jmm.ast.JmmNode; import java.util.List; import java.util.Objects; +import static java.lang.Integer.parseInt; + public class SemanticUtils { //Types public static final Type ARRAY_TYPE = new Type("int", true); @@ -56,4 +59,12 @@ public static Type getIdentifierType(String methodName, String identifier, MySym return new Type(identifier, false); return UNKNOWN_TYPE; } + + public static int getNodeLine(JmmNode jmmNode){ + return parseInt(jmmNode.get("lineStart")); + } + + public static int getNodeColumn(JmmNode jmmNode){ + return parseInt(jmmNode.get("colStart")); + } } From 823c7b237c292ed11669f4f2331e423953deffde Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 17 Apr 2023 23:23:26 +0100 Subject: [PATCH 052/253] [refactor] Implemented setCurrentMethodName --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 6 ++++- .../pt/up/fe/comp2023/SemanticAnalysis.java | 23 ++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index fe484d1..76ebadb 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -13,7 +13,7 @@ import static pt.up.fe.comp2023.SemanticUtils.*; public class ExpressionAnalysis extends AJmmVisitor { - private final String methodName; + private String methodName; private final MySymbolTable symbolTable; private final List reports; private final String className; @@ -28,6 +28,10 @@ public ExpressionAnalysis (String methodName, MySymbolTable symbolTable, List { private final MySymbolTable symbolTable; @@ -20,7 +19,7 @@ public class SemanticAnalysis extends AJmmVisitor { private final String superClass; private final List imports; private String currentMethodName; - private ExpressionAnalysis expressionAnalysis; + private final ExpressionAnalysis expressionAnalysis; public SemanticAnalysis (JmmNode rootNode, MySymbolTable symbolTable, List reports){ this.symbolTable = symbolTable; @@ -28,9 +27,15 @@ public SemanticAnalysis (JmmNode rootNode, MySymbolTable symbolTable, List Date: Tue, 18 Apr 2023 00:23:20 +0100 Subject: [PATCH 053/253] Fixed some semantic analysis errors --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 16 +++++++++------- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 8 ++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 76ebadb..7e1a205 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -88,12 +88,14 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found return UNKNOWN_TYPE; - if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { + else if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { jmmNode.put(TYPENAME, INT); return INT_TYPE; } - jmmNode.put(TYPENAME, BOOLEAN); - return BOOLEAN_TYPE; + else { + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; + } } private Type checkBooleanOperands(JmmNode jmmNode, Type type) { @@ -165,7 +167,7 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } this.verifyArgumentTypes(jmmNode.getJmmChild(1), method); - jmmNode.put(TYPENAME, symbolTable.getReturnType(method).print()); + jmmNode.put(TYPENAME, this.symbolTable.getReturnType(method).print()); return this.symbolTable.getReturnType(method); } @@ -189,7 +191,7 @@ private void verifyArgumentTypes(JmmNode jmmNode, String method) { int numCallParams = jmmNode.getNumChildren(); if(numDeclaredParams != numCallParams){ - String message = "Method '" + method + "' expected " + numDeclaredParams + " but found " + numCallParams + "."; + String message = "Method '" + method + "' expected " + numDeclaredParams + " arguments but found " + numCallParams + "."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } @@ -226,7 +228,7 @@ private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { return new Type(this.className, false); } - if(findImport(this.imports, objectClassName)){ + else if(findImport(this.imports, objectClassName)){ jmmNode.put(TYPENAME, objectClassName); return new Type(objectClassName, false); } @@ -267,7 +269,7 @@ private Type dealWithIdentifier(JmmNode jmmNode, Type type) { this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values jmmNode.put(TYPENAME, UNKNOWN); } - jmmNode.put("typename", identifierType.print()); + jmmNode.put(TYPENAME, identifierType.print()); return identifierType; } } \ No newline at end of file diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 17d7628..8698b0f 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -63,7 +63,6 @@ public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { String message = "Cannot find super class '" + superClass + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - for (JmmNode child: jmmNode.getChildren()) visit(child); return null; @@ -79,7 +78,6 @@ private Void checkReturnType(JmmNode jmmNode, Void unused) { String message = "Make method '" + jmmNode.get("methodname") +"' return " + returnType.print() + "."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - for (JmmNode child: jmmNode.getChildren()) visit(child); return null; @@ -101,7 +99,6 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values } - for (JmmNode child: jmmNode.getChildren()) visit(child); return null; @@ -109,8 +106,8 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { JmmNode expressionNode = jmmNode.getJmmChild(0); - Type conditionType = expressionAnalysis.visit(expressionNode); + if(!conditionType.equals(BOOLEAN_TYPE)) { String message = "Expected condition of type '" + BOOLEAN + "' but found '" + conditionType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values @@ -160,7 +157,7 @@ private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { Type indexType = expressionAnalysis.visit(jmmNode.getJmmChild(0)); Type valueType = expressionAnalysis.visit(valueNode); - if(!valueType.isArray()){ + if(!varType.isArray()){ String message = "'" + varName + "' must be an array."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); } @@ -168,7 +165,6 @@ private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); } - if(valueType.equals(UNDEFINED_TYPE)){ valueNode.put(TYPENAME, INT); } From 289e05520570fb0731eabf0c07e494f2b1253d89 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 00:45:30 +0100 Subject: [PATCH 054/253] Improved type grammar rules --- src/main/antlr/comp2023/grammar/Javamm.g4 | 9 ++++----- src/main/pt/up/fe/comp2023/MySymbolTable.java | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index ec97e65..6787d82 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -41,11 +41,10 @@ varDeclaration : type varname=ID ';' #VarDecl ; -type - : typename='int' '[' ']' #TypeArray - | typename='boolean' #TypeBoolean - | typename='int' #TypeInt - | typename=ID #TypeID +type locals[boolean isArray = false] + : typename='int' (('[' ']') { $isArray = true; })? + | typename='boolean' + | typename=ID ; statement diff --git a/src/main/pt/up/fe/comp2023/MySymbolTable.java b/src/main/pt/up/fe/comp2023/MySymbolTable.java index 35c9afb..9a51220 100644 --- a/src/main/pt/up/fe/comp2023/MySymbolTable.java +++ b/src/main/pt/up/fe/comp2023/MySymbolTable.java @@ -140,7 +140,7 @@ private Void dealWithMainMethod(JmmNode jmmNode, Void unused) { private Type dealWithType(JmmNode jmmNode) { String name = jmmNode.get("typename"); - boolean isArray = jmmNode.getKind().equals("TypeArray"); + boolean isArray = Boolean.parseBoolean(jmmNode.get("isArray")); return new Type(name, isArray); } From b9d230c820b0b3546072982e3b15715404f7d336 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 11:05:51 +0100 Subject: [PATCH 055/253] Changed line and column values of some reports --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 61 +++++++++++-------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 7e1a205..96d5d0a 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -57,31 +57,34 @@ private Type dealWithParenthesesExpr(JmmNode jmmNode, Type type) { } private Type checkBooleanExpression(JmmNode jmmNode, Type type) { - Type expressionType = visit(jmmNode.getJmmChild(0)); + JmmNode expressionNode = jmmNode.getJmmChild(0); + Type expressionType = visit(expressionNode); if(expressionType.equals(BOOLEAN_TYPE)){ jmmNode.put(TYPENAME, BOOLEAN); return BOOLEAN_TYPE; } String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } private Type checkIntegerOperands(JmmNode jmmNode, Type type) { - Type leftOperandType = visit(jmmNode.getJmmChild(0)); - Type rightOperandType = visit(jmmNode.getJmmChild(1)); + JmmNode leftNode = jmmNode.getJmmChild(0); + JmmNode rightNode = jmmNode.getJmmChild(1); + Type leftOperandType = visit(leftNode); + Type rightOperandType = visit(rightNode); if(!leftOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(leftNode), getNodeColumn(leftNode), message)); jmmNode.put(TYPENAME, UNKNOWN); } if(!rightOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -99,18 +102,20 @@ else if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { } private Type checkBooleanOperands(JmmNode jmmNode, Type type) { - Type leftOperandType = visit(jmmNode.getJmmChild(0)); - Type rightOperandType = visit(jmmNode.getJmmChild(1)); + JmmNode leftNode = jmmNode.getJmmChild(0); + JmmNode rightNode = jmmNode.getJmmChild(1); + Type leftOperandType = visit(leftNode); + Type rightOperandType = visit(rightNode); if(!leftOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(leftNode), getNodeColumn(leftNode), message)); jmmNode.put(TYPENAME, UNKNOWN); } if(!rightOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -122,18 +127,20 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { } private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { - Type variableType = visit(jmmNode.getJmmChild(0)); - Type indexType = visit(jmmNode.getJmmChild(1)); + JmmNode variableNode = jmmNode.getJmmChild(0); + JmmNode indexNode = jmmNode.getJmmChild(1); + Type variableType = visit(variableNode); + Type indexType = visit(indexNode); if (!variableType.equals(ARRAY_TYPE)) { String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(variableNode), getNodeColumn(variableNode), message)); jmmNode.put(TYPENAME, UNKNOWN); } if (!indexType.equals(INT_TYPE)) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(indexNode), getNodeColumn(indexNode), message)); if(!jmmNode.hasAttribute(TYPENAME)) jmmNode.put(TYPENAME, UNKNOWN); } @@ -152,7 +159,7 @@ private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { return INT_TYPE; } String message = "Cannot resolve symbol 'length'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -164,7 +171,7 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { if(this.symbolTable.getMethods().contains(method)){ if(!Objects.equals(expressionType, this.className)){ String message = "Expected expression of type '" + this.className + "' but found '" + expressionType + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } this.verifyArgumentTypes(jmmNode.getJmmChild(1), method); jmmNode.put(TYPENAME, this.symbolTable.getReturnType(method).print()); @@ -174,13 +181,13 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { else if(Objects.equals(expressionType, this.className) || Objects.equals(expressionType, this.superClass)){ if(!findImport(this.imports, this.superClass)){ String message = "Cannot find super class '" + this.superClass + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } } else if(!findImport(this.imports, expressionType)){ String message = "'" + expressionType + "' is not declared."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } jmmNode.put(TYPENAME, UNDEFINED); return UNDEFINED_TYPE; @@ -192,30 +199,32 @@ private void verifyArgumentTypes(JmmNode jmmNode, String method) { if(numDeclaredParams != numCallParams){ String message = "Method '" + method + "' expected " + numDeclaredParams + " arguments but found " + numCallParams + "."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } for(int i=0; i < numDeclaredParams && i < numCallParams; i++){ + JmmNode callParamNode = jmmNode.getJmmChild(i); Type declaredParamType = symbolTable.getParameters(method).get(i).getType(); - Type callParamType = visit(jmmNode.getJmmChild(i)); + Type callParamType = visit(callParamNode); if(!declaredParamType.equals(callParamType)){ String declaredArgumentName = symbolTable.getParameters(method).get(i).getName(); String message = "Method '" + method + "' expected argument '" + declaredArgumentName + "' to be '" + declaredParamType.print() + "' but found '" + callParamType.print() + "."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(callParamNode), getNodeColumn(callParamNode), message)); } } } private Type checkIntegerLength(JmmNode jmmNode, Type type) { - Type lengthType = visit(jmmNode.getJmmChild(0)); + JmmNode lengthNode = jmmNode.getJmmChild(0); + Type lengthType = visit(lengthNode); if (lengthType.equals(INT_TYPE)){ jmmNode.put(TYPENAME, ARRAY); return ARRAY_TYPE; } String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(lengthNode), getNodeColumn(lengthNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -234,7 +243,7 @@ else if(findImport(this.imports, objectClassName)){ } String message = "Cannot find '" + objectClassName + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); //TODO: use column of 'classname' jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -252,7 +261,7 @@ private Type dealWithBoolean(JmmNode jmmNode, Type type) { private Type dealWithThis(JmmNode jmmNode, Type type) { if (Objects.equals(this.methodName, "main")) { String message = "'this' expression cannot be used in a static method."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } @@ -266,7 +275,7 @@ private Type dealWithIdentifier(JmmNode jmmNode, Type type) { if(Objects.equals(identifierType.print(), UNKNOWN)){ String message = "'" + identifier + "' is not declared."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); jmmNode.put(TYPENAME, UNKNOWN); } jmmNode.put(TYPENAME, identifierType.print()); From e2e90f2e50f39f891dbf577b4ea9cf6c641442c7 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 11:13:01 +0100 Subject: [PATCH 056/253] Changed line and column values of remaining reports --- .../pt/up/fe/comp2023/SemanticAnalysis.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 8698b0f..dc6b7f2 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -61,7 +61,7 @@ public Void checkImportedSuperClass(JmmNode jmmNode, Void unused) { if(superClass != null && !findImport(this.imports, superClass)){ String message = "Cannot find super class '" + superClass + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } for (JmmNode child: jmmNode.getChildren()) visit(child); @@ -76,7 +76,7 @@ private Void checkReturnType(JmmNode jmmNode, Void unused) { if(!returnNodeType.equals(returnType) && !returnNodeType.equals(UNDEFINED_TYPE)){ String message = "Make method '" + jmmNode.get("methodname") +"' return " + returnType.print() + "."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(returnNode), getNodeColumn(returnNode), message)); } for (JmmNode child: jmmNode.getChildren()) visit(child); @@ -97,7 +97,7 @@ private Void checkMainMethodParameterType(JmmNode jmmNode, Void unused) { if(!Objects.equals(parameterType, "String")) { String message = "Main method expected a parameter of type 'String[]' but found '" + parameterType + "[]'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } for (JmmNode child: jmmNode.getChildren()) visit(child); @@ -110,7 +110,7 @@ private Void checkBooleanCondition(JmmNode jmmNode, Void unused) { if(!conditionType.equals(BOOLEAN_TYPE)) { String message = "Expected condition of type '" + BOOLEAN + "' but found '" + conditionType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); } for(int i= 1; i < jmmNode.getNumChildren(); i++){ visit(jmmNode.getJmmChild(i)); @@ -131,7 +131,7 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { if(left.equals(UNKNOWN_TYPE)){ String message = "'" + varName + "' is not declared."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } else if (right.equals(UNDEFINED_TYPE)) expressionNode.put(TYPENAME, left.print()); @@ -146,31 +146,32 @@ else if (findImport(this.imports, left.print()) && findImport(this.imports, righ return null; String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); return null; } private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { String varName = jmmNode.get("arrayname"); JmmNode valueNode = jmmNode.getJmmChild(1); + JmmNode indexNode = jmmNode.getJmmChild(0); Type varType = getIdentifierType(this.currentMethodName, varName, this.symbolTable); - Type indexType = expressionAnalysis.visit(jmmNode.getJmmChild(0)); + Type indexType = expressionAnalysis.visit(indexNode); Type valueType = expressionAnalysis.visit(valueNode); if(!varType.isArray()){ String message = "'" + varName + "' must be an array."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } if(!indexType.equals(INT_TYPE)){ String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(indexNode), getNodeColumn(indexNode), message)); } if(valueType.equals(UNDEFINED_TYPE)){ valueNode.put(TYPENAME, INT); } else if(!valueType.equals(INT_TYPE)){ String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, 1, 1, message)); //TODO: change line and column values + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(valueNode), getNodeColumn(valueNode), message)); } return null; } From a667221019ad4ac3375589c417348488d72b92ef Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 11:39:26 +0100 Subject: [PATCH 057/253] Corrected getIdentifierType to check field access in static method --- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 3 +++ src/main/pt/up/fe/comp2023/SemanticUtils.java | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index dc6b7f2..db18e13 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -129,6 +129,9 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { Type left = getIdentifierType(this.currentMethodName, varName, this.symbolTable); Type right = expressionAnalysis.visit(expressionNode); + if(right.equals(UNKNOWN_TYPE)) + return null; + if(left.equals(UNKNOWN_TYPE)){ String message = "'" + varName + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/SemanticUtils.java index 681c191..ee8033c 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/SemanticUtils.java @@ -49,10 +49,12 @@ public static Type getIdentifierType(String methodName, String identifier, MySym return parameter.getType(); } - List fields = symbolTable.getFields(); - for (Symbol field : fields) { - if(Objects.equals(field.getName(), identifier)) - return field.getType(); + if (!Objects.equals(methodName, "main")){ + List fields = symbolTable.getFields(); + for (Symbol field : fields) { + if(Objects.equals(field.getName(), identifier)) + return field.getType(); + } } if(findImport(symbolTable.getImports(), identifier)) From d7c1edc89695ba77df3d6ff32e7f101fcdfbf686 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 18 Apr 2023 11:41:30 +0100 Subject: [PATCH 058/253] Refactor: Added jasmin folder --- config.properties | 2 +- src/main/pt/up/fe/comp2023/Launcher.java | 3 +-- .../pt/up/fe/comp2023/{ => jasmin}/JVMInstructionUtils.java | 2 +- src/main/pt/up/fe/comp2023/{ => jasmin}/JasminGenerator.java | 2 +- src/main/pt/up/fe/comp2023/{ => jasmin}/JasminUtils.java | 2 +- test/pt/up/fe/comp/cp2/JasminTest.java | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) rename src/main/pt/up/fe/comp2023/{ => jasmin}/JVMInstructionUtils.java (99%) rename src/main/pt/up/fe/comp2023/{ => jasmin}/JasminGenerator.java (98%) rename src/main/pt/up/fe/comp2023/{ => jasmin}/JasminUtils.java (99%) diff --git a/config.properties b/config.properties index d8ef55f..dce78ce 100644 --- a/config.properties +++ b/config.properties @@ -8,5 +8,5 @@ AnalysisClass = pt.up.fe.comp2023.Analysis OptimizationClass = # The fully qualified name of your class that implements the interface JasminBackend -BackendClass = pt.up.fe.comp2023.JasminGenerator +BackendClass = pt.up.fe.comp2023.jasmin.JasminGenerator diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index c6da2c1..c4983c6 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -6,9 +6,8 @@ import java.util.Map; import pt.up.fe.comp.TestUtils; -import pt.up.fe.comp.jmm.jasmin.JasminResult; -import pt.up.fe.comp.jmm.ollir.OllirResult; import pt.up.fe.comp.jmm.parser.JmmParserResult; +import pt.up.fe.comp2023.jasmin.JasminGenerator; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsLogs; import pt.up.fe.specs.util.SpecsSystem; diff --git a/src/main/pt/up/fe/comp2023/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java similarity index 99% rename from src/main/pt/up/fe/comp2023/JVMInstructionUtils.java rename to src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 7105d44..efef3d9 100644 --- a/src/main/pt/up/fe/comp2023/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.jasmin; import org.specs.comp.ollir.*; diff --git a/src/main/pt/up/fe/comp2023/JasminGenerator.java b/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java similarity index 98% rename from src/main/pt/up/fe/comp2023/JasminGenerator.java rename to src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java index 2ab8416..121c228 100644 --- a/src/main/pt/up/fe/comp2023/JasminGenerator.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.jasmin; import org.specs.comp.ollir.ClassUnit; import org.specs.comp.ollir.Field; diff --git a/src/main/pt/up/fe/comp2023/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java similarity index 99% rename from src/main/pt/up/fe/comp2023/JasminUtils.java rename to src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index e2fd465..aab6fda 100644 --- a/src/main/pt/up/fe/comp2023/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.jasmin; import org.specs.comp.ollir.*; diff --git a/test/pt/up/fe/comp/cp2/JasminTest.java b/test/pt/up/fe/comp/cp2/JasminTest.java index 394da50..77a97f9 100644 --- a/test/pt/up/fe/comp/cp2/JasminTest.java +++ b/test/pt/up/fe/comp/cp2/JasminTest.java @@ -4,7 +4,7 @@ import pt.up.fe.comp.TestUtils; import pt.up.fe.comp.jmm.jasmin.JasminResult; import pt.up.fe.comp.jmm.ollir.OllirResult; -import pt.up.fe.comp2023.JasminGenerator; +import pt.up.fe.comp2023.jasmin.JasminGenerator; import pt.up.fe.specs.util.SpecsCheck; import pt.up.fe.specs.util.SpecsIo; import utils.ProjectTestUtils; From a37c97e674a66211f4e15be0fecd61e3d24541ad Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 11:43:23 +0100 Subject: [PATCH 059/253] Small fix in checkCompatibleAssignment() --- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index db18e13..3102143 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -129,9 +129,6 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { Type left = getIdentifierType(this.currentMethodName, varName, this.symbolTable); Type right = expressionAnalysis.visit(expressionNode); - if(right.equals(UNKNOWN_TYPE)) - return null; - if(left.equals(UNKNOWN_TYPE)){ String message = "'" + varName + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); @@ -148,6 +145,9 @@ else if (Objects.equals(left.print(), this.superClass) && Objects.equals(right.p else if (findImport(this.imports, left.print()) && findImport(this.imports, right.print())) return null; + else if (right.equals(UNKNOWN_TYPE)) + return null; + String message = "Type of the assignee is not compatible with the assigned."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); return null; From 7ce4cbe3e0cb56abb48e55f6a1c01c3f149bc602 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 12:05:03 +0100 Subject: [PATCH 060/253] Fixed methodCall assignment --- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 3102143..1f16349 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -148,8 +148,10 @@ else if (findImport(this.imports, left.print()) && findImport(this.imports, righ else if (right.equals(UNKNOWN_TYPE)) return null; - String message = "Type of the assignee is not compatible with the assigned."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); + else { + String message = "Type of the assignee is not compatible with the assigned."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); + } return null; } From 7bf1283e0c845f012479d5428cca305a98a39cf4 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 18 Apr 2023 12:19:32 +0100 Subject: [PATCH 061/253] Added jasmin test example where stack isn't empty at the end --- test/pt/up/fe/comp/cp2/JasminTest.java | 6 +++++ .../jasmin/OllirToJasminNonEmptyStack.ollir | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/pt/up/fe/comp/cp2/jasmin/OllirToJasminNonEmptyStack.ollir diff --git a/test/pt/up/fe/comp/cp2/JasminTest.java b/test/pt/up/fe/comp/cp2/JasminTest.java index 77a97f9..94ef171 100644 --- a/test/pt/up/fe/comp/cp2/JasminTest.java +++ b/test/pt/up/fe/comp/cp2/JasminTest.java @@ -48,6 +48,11 @@ public void ollirToJasminFields() { testOllirToJasmin("pt/up/fe/comp/cp2/jasmin/OllirToJasminFields.ollir"); } + @Test + public void ollirToJasminNonEmptyStack() { + testOllirToJasmin("pt/up/fe/comp/cp2/jasmin/OllirToJasminNonEmptyStack.ollir"); + } + public static void testOllirToJasmin(String resource, String expectedOutput) { SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); @@ -67,6 +72,7 @@ public static void testOllirToJasmin(String resource, String expectedOutput) { OllirResult ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); JasminGenerator jasminGenerator = new JasminGenerator(); JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); + System.out.println(jasminResult.getJasminCode()); TestUtils.runJasmin(jasminResult.getJasminCode()); } diff --git a/test/pt/up/fe/comp/cp2/jasmin/OllirToJasminNonEmptyStack.ollir b/test/pt/up/fe/comp/cp2/jasmin/OllirToJasminNonEmptyStack.ollir new file mode 100644 index 0000000..2dc6ee3 --- /dev/null +++ b/test/pt/up/fe/comp/cp2/jasmin/OllirToJasminNonEmptyStack.ollir @@ -0,0 +1,22 @@ +Test { + .construct Test().V { + invokespecial(this, "").V; + } + + .method foo2().i32 { + ret.i32 2.i32; + } + + .method public foo1().i32 { + intLocal1.i32 :=.i32 0.i32; + boolLocal1.bool :=.bool 1.bool; + invokevirtual(this, "foo2").i32; + + ret.i32 0.i32; + } + + .method public static main(args.array.String).V { + ret.V; + } + +} From 6c3946fa66860baf297d5a8444017c6219a01265 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 15:12:17 +0100 Subject: [PATCH 062/253] Improved method call analysis --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 4 ++-- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 96d5d0a..24484da 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -169,8 +169,8 @@ private Type dealWithMethodCall(JmmNode jmmNode, Type type) { String method = jmmNode.get("methodcall"); if(this.symbolTable.getMethods().contains(method)){ - if(!Objects.equals(expressionType, this.className)){ - String message = "Expected expression of type '" + this.className + "' but found '" + expressionType + "'."; + if(!Objects.equals(expressionType, this.className) && !Objects.equals(expressionType, this.superClass)){ + String message = "Expected expression of type '" + this.className + "' or '" + this.superClass + "' but found '" + expressionType + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } this.verifyArgumentTypes(jmmNode.getJmmChild(1), method); diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 1f16349..392b99f 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -133,10 +133,14 @@ private Void checkCompatibleAssignment(JmmNode jmmNode, Void unused) { String message = "'" + varName + "' is not declared."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } + + else if (right.equals(UNKNOWN_TYPE)) + return null; + else if (right.equals(UNDEFINED_TYPE)) expressionNode.put(TYPENAME, left.print()); - else if(right.equals(left)) + else if (right.equals(left)) return null; else if (Objects.equals(left.print(), this.superClass) && Objects.equals(right.print(), this.className)) @@ -145,9 +149,6 @@ else if (Objects.equals(left.print(), this.superClass) && Objects.equals(right.p else if (findImport(this.imports, left.print()) && findImport(this.imports, right.print())) return null; - else if (right.equals(UNKNOWN_TYPE)) - return null; - else { String message = "Type of the assignee is not compatible with the assigned."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); From cb2d0cac48e6f7e8d3edc82aeb1bdc2dcd01497e Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 15:25:02 +0100 Subject: [PATCH 063/253] Changed return type of some expressions --- .../pt/up/fe/comp2023/ExpressionAnalysis.java | 57 +++++++------------ .../pt/up/fe/comp2023/SemanticAnalysis.java | 2 +- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 24484da..424339e 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -60,14 +60,13 @@ private Type checkBooleanExpression(JmmNode jmmNode, Type type) { JmmNode expressionNode = jmmNode.getJmmChild(0); Type expressionType = visit(expressionNode); - if(expressionType.equals(BOOLEAN_TYPE)){ - jmmNode.put(TYPENAME, BOOLEAN); - return BOOLEAN_TYPE; + if(!expressionType.equals(BOOLEAN_TYPE)){ + String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); } - String message = "Expected expression of type '" + BOOLEAN + "' but found '" + expressionType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(expressionNode), getNodeColumn(expressionNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); - return UNKNOWN_TYPE; + + jmmNode.put(TYPENAME, BOOLEAN); + return BOOLEAN_TYPE; } private Type checkIntegerOperands(JmmNode jmmNode, Type type) { @@ -79,19 +78,13 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { if(!leftOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(leftNode), getNodeColumn(leftNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); } - if(!rightOperandType.equals(INT_TYPE)) { String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); - if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, UNKNOWN); } - if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return UNKNOWN_TYPE; - else if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { + if(Objects.equals(jmmNode.getKind(), "ArithmeticExpr")) { jmmNode.put(TYPENAME, INT); return INT_TYPE; } @@ -110,18 +103,13 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { if(!leftOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(leftNode), getNodeColumn(leftNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); } if(!rightOperandType.equals(BOOLEAN_TYPE)) { String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); - if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, UNKNOWN); } - if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return UNKNOWN_TYPE; jmmNode.put(TYPENAME, BOOLEAN); return BOOLEAN_TYPE; } @@ -135,18 +123,13 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { if (!variableType.equals(ARRAY_TYPE)) { String message = "Expected '" + ARRAY_TYPE + "' type but found '" + variableType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(variableNode), getNodeColumn(variableNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); } if (!indexType.equals(INT_TYPE)) { String message = "Expected index expression of type '" + INT +"' but found '" + indexType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(indexNode), getNodeColumn(indexNode), message)); - if(!jmmNode.hasAttribute(TYPENAME)) - jmmNode.put(TYPENAME, UNKNOWN); } - if(jmmNode.hasAttribute(TYPENAME)) //Semantic errors were found - return UNKNOWN_TYPE; jmmNode.put(TYPENAME, INT); return INT_TYPE; } @@ -154,14 +137,13 @@ private Type dealWithArraySubscript(JmmNode jmmNode, Type type) { private Type dealWithLengthFieldAccess(JmmNode jmmNode, Type type) { Type expressionType = visit(jmmNode.getJmmChild(0)); - if(expressionType.equals(ARRAY_TYPE)){ - jmmNode.put(TYPENAME, INT); - return INT_TYPE; + if(!expressionType.equals(ARRAY_TYPE)){ + String message = "Cannot resolve symbol 'length'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } - String message = "Cannot resolve symbol 'length'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); - return UNKNOWN_TYPE; + + jmmNode.put(TYPENAME, INT); + return INT_TYPE; } private Type dealWithMethodCall(JmmNode jmmNode, Type type) { @@ -219,14 +201,13 @@ private Type checkIntegerLength(JmmNode jmmNode, Type type) { JmmNode lengthNode = jmmNode.getJmmChild(0); Type lengthType = visit(lengthNode); - if (lengthType.equals(INT_TYPE)){ - jmmNode.put(TYPENAME, ARRAY); - return ARRAY_TYPE; + if (!lengthType.equals(INT_TYPE)){ + String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(lengthNode), getNodeColumn(lengthNode), message)); } - String message = "Expected array length to be '" + INT + "' but found '" + lengthType.print() + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(lengthNode), getNodeColumn(lengthNode), message)); - jmmNode.put(TYPENAME, UNKNOWN); - return UNKNOWN_TYPE; + + jmmNode.put(TYPENAME, ARRAY); + return ARRAY_TYPE; } private Type dealWithObjectCreation(JmmNode jmmNode, Type type) { diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 392b99f..dc8a39b 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -164,7 +164,7 @@ private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { Type indexType = expressionAnalysis.visit(indexNode); Type valueType = expressionAnalysis.visit(valueNode); - if(!varType.isArray()){ + if(!varType.equals(ARRAY_TYPE)){ String message = "'" + varName + "' must be an array."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); } From 5c09ec5349ffd5faf866cec90985769db1375abf Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 18 Apr 2023 15:46:03 +0100 Subject: [PATCH 064/253] Improved assignment analysis --- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index dc8a39b..91195e0 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -146,6 +146,9 @@ else if (right.equals(left)) else if (Objects.equals(left.print(), this.superClass) && Objects.equals(right.print(), this.className)) return null; + else if (Objects.equals(left.print(), this.className) && !Objects.equals(right.print(), this.superClass) && findImport(this.imports, right.print())) + return null; + else if (findImport(this.imports, left.print()) && findImport(this.imports, right.print())) return null; From 8fc3fc26d23d99fad7982a3ed0c20cfadfe6aa1d Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 18 Apr 2023 17:03:24 +0100 Subject: [PATCH 065/253] Added stack pop whenever there's call instruction without assign --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++-- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index efef3d9..e9588ad 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -86,7 +86,7 @@ public static String createInvokeInstructionArgument(CallInstruction instruction "/" + JasminUtils.createMethodSignature( ((LiteralElement)instruction.getSecondArg()).getLiteral().replace("\"", ""), instruction.getListOfOperands(), - instruction.getReturnType(), + instruction.getReturnType(), true ); } @@ -169,7 +169,7 @@ public static String createAssignStatement(AssignInstruction instruction, HashMa Element assignElement = instruction.getDest(); String statementList = ""; - statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable); + statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); statementList += getStoreInstruction(assignElement, varTable); return statementList; diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index aab6fda..06c9274 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -93,7 +93,7 @@ public static String createMethodDeclaration(Method method) { return methodDirective; } - public static String handleInstruction(Instruction instruction, HashMap varTable) { + public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -107,6 +107,8 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Thu, 20 Apr 2023 18:00:50 +0100 Subject: [PATCH 066/253] Corrected type used in report message for invalid right operand --- src/main/pt/up/fe/comp2023/ExpressionAnalysis.java | 4 ++-- src/main/pt/up/fe/comp2023/SemanticAnalysis.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java index 424339e..3452627 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java @@ -80,7 +80,7 @@ private Type checkIntegerOperands(JmmNode jmmNode, Type type) { this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(leftNode), getNodeColumn(leftNode), message)); } if(!rightOperandType.equals(INT_TYPE)) { - String message = "Expected operand of type '" + INT + "' but found '" + leftOperandType.print() + "'."; + String message = "Expected operand of type '" + INT + "' but found '" + rightOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); } @@ -106,7 +106,7 @@ private Type checkBooleanOperands(JmmNode jmmNode, Type type) { } if(!rightOperandType.equals(BOOLEAN_TYPE)) { - String message = "Expected operand of type '" + BOOLEAN + "' but found '" + leftOperandType.print() + "'."; + String message = "Expected operand of type '" + BOOLEAN + "' but found '" + rightOperandType.print() + "'."; this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(rightNode), getNodeColumn(rightNode), message)); } diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java index 91195e0..f242c9c 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/SemanticAnalysis.java @@ -161,8 +161,8 @@ else if (findImport(this.imports, left.print()) && findImport(this.imports, righ private Void validateArrayAssignment(JmmNode jmmNode, Void unused) { String varName = jmmNode.get("arrayname"); - JmmNode valueNode = jmmNode.getJmmChild(1); JmmNode indexNode = jmmNode.getJmmChild(0); + JmmNode valueNode = jmmNode.getJmmChild(1); Type varType = getIdentifierType(this.currentMethodName, varName, this.symbolTable); Type indexType = expressionAnalysis.visit(indexNode); Type valueType = expressionAnalysis.visit(valueNode); From 38456a89aaaa6405f0fbf2b23b6abdb295eb835b Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 20 Apr 2023 18:30:47 +0100 Subject: [PATCH 067/253] Updated priority of ArraySubscript and LengthFieldAccess and MethodCall --- src/main/antlr/comp2023/grammar/Javamm.g4 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index 6787d82..16ed215 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -57,16 +57,16 @@ statement ; expression - : '(' expression ')' #ParenthesesExpr + : expression '[' expression ']' #ArraySubscript + | expression '.' field='length' #LengthFieldAccess + | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall + | '(' expression ')' #ParenthesesExpr | '!' expression #NegationExpr | expression op=('*' | '/') expression #ArithmeticExpr | expression op=('+' | '-') expression #ArithmeticExpr | expression op=('<' | '>') expression #ComparisonExpr | expression op='&&' expression #LogicalExpr | expression op='||' expression #LogicalExpr - | expression '[' expression ']' #ArraySubscript - | expression '.' field='length' #LengthFieldAccess - | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall | 'new' 'int' '[' expression ']' #ArrayCreation | 'new' classname=ID '(' ')' #ObjectCreation | value=INT #Integer From 7bdee4862817b5862ce6c2e622944d6c5ed3771c Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sat, 22 Apr 2023 20:20:32 +0100 Subject: [PATCH 068/253] ollir methods, class, imports --- config.properties | 2 +- src/main/pt/up/fe/comp2023/Launcher.java | 2 + src/main/pt/up/fe/comp2023/OllirUtils.java | 26 ++ src/main/pt/up/fe/comp2023/Optimization.java | 263 +++++++++++++++++++ 4 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 src/main/pt/up/fe/comp2023/OllirUtils.java create mode 100644 src/main/pt/up/fe/comp2023/Optimization.java diff --git a/config.properties b/config.properties index dce78ce..5eee1e0 100644 --- a/config.properties +++ b/config.properties @@ -5,7 +5,7 @@ ParserClass = pt.up.fe.comp2023.SimpleParser AnalysisClass = pt.up.fe.comp2023.Analysis # The fully qualified name of your class that implements the interface JmmOptimization -OptimizationClass = +OptimizationClass = pt.up.fe.comp2023.Optimization # The fully qualified name of your class that implements the interface JasminBackend BackendClass = pt.up.fe.comp2023.jasmin.JasminGenerator diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 2d8a8e1..cfdc125 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -69,6 +69,8 @@ public static void main(String[] args) { TestUtils.noErrors(semanticsResult.getReports()); // TODO: Add Ollir + Optimization optimization = new Optimization(); + OllirResult ollirResult = optimization.toOllir(semanticsResult); JasminGenerator jasminGenerator = new JasminGenerator(); // JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); diff --git a/src/main/pt/up/fe/comp2023/OllirUtils.java b/src/main/pt/up/fe/comp2023/OllirUtils.java new file mode 100644 index 0000000..1b9427b --- /dev/null +++ b/src/main/pt/up/fe/comp2023/OllirUtils.java @@ -0,0 +1,26 @@ +package pt.up.fe.comp2023; + +import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.analysis.table.Type; + +public class OllirUtils { + + public static String ollirTypes(Type type){ + String typeS = ""; // array needs to be checked first + + if (type.isArray()) + typeS = ".array"; + + if (type.getName().equals("boolean")) + typeS += ".bool"; + else if (type.getName().equals("int")) + typeS += ".i32"; + else if (type.getName().equals("void")) + typeS += ".V"; + else + typeS += "." + type.getName(); + + return typeS; + } + +} diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java new file mode 100644 index 0000000..62f87d0 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -0,0 +1,263 @@ +package pt.up.fe.comp2023; + +import org.specs.comp.ollir.Ollir; +import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.analysis.table.Symbol; +import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.ast.PostorderJmmVisitor; +import pt.up.fe.comp.jmm.ast.PreorderJmmVisitor; +import pt.up.fe.comp.jmm.ollir.JmmOptimization; +import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; + +import java.util.ArrayList; +import java.util.List; + + +public class Optimization extends AJmmVisitor implements JmmOptimization { + String code = ""; + List reports = new ArrayList<>(); + private SymbolTable table; + + // private class PostOrdOptm extends PostorderJmmVisitor{} + + @Override + public OllirResult toOllir(JmmSemanticsResult semanticsResult) { + table = semanticsResult.getSymbolTable(); + visit(semanticsResult.getRootNode()); + code += "} \n"; + System.out.println(code); + return new OllirResult(semanticsResult, code, reports); + } + + @Override + protected void buildVisitor() { + setDefaultVisit(this::visitAllChildren); + addVisit("ClassDecl", this::dealWithClass); // Dealing with imports in here + addVisit("MethodDecl", this::dealWithMethod); + addVisit("VoidMethodDecl", this::dealWithMethod); + addVisit("MainMethodDecl", this::dealWithMainMethod); + addVisit("MethodDeclParameters", this::dealWithParamDecl); + addVisit("MethodParameters", this::dealWithMethodCallParam); + addVisit("VarDecl", this::dealWithVarDecl); + addVisit("CodeBlock", this::dealWithCodeBlock); + // addVisit("Condition", this::dealWithCondition); // not for checkpoint 2 + // addVisit("Cycle", this::dealWithCycle); // not for checkpoint 2 + addVisit("Expr", this::dealWithExpr); + addVisit("Assignment", this::dealWithAssignment); + addVisit("ArrayAssignment", this::dealWithArrayAssignment); + addVisit("ParenthesesExpr", this::dealWithParenthesesExpr); + addVisit("NegationExpr", this::dealWithNegationExpr); + addVisit("ArithmeticExpr", this::dealWithArithmetic); + addVisit("ComparisonExpr", this::dealWithComparison); + addVisit("LogicalExpr", this::dealWithLogicalExpr); + addVisit("ArraySubscript", this::dealWithArraySubscript); + addVisit("LengthFieldAccess", this::dealWithLenFieldAccess); + addVisit("MethodCall", this::dealWithMethodCall); + addVisit("ArrayCreation", this::dealWithArrayCreation); + addVisit("ObjectCreation", this::dealWithObjectCreation); + addVisit("Integer", this::dealWithInteger); + addVisit("Boolean", this::dealWithBoolean); + addVisit("This", this::dealWithThis); + addVisit("Identifier", this::dealWithIdentifier); + } + + private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + return null; + } + + private Void dealWithThis(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithBoolean(JmmNode jmmNode, Void unused) { + code += jmmNode.get("value") + ".bool"; + return null; + } + + private Void dealWithInteger(JmmNode jmmNode, Void unused) { + code += jmmNode.get("value") + ".i32"; + return null; + } + + private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + return null; + } + + private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { + List fieldsOnClass = table.getFields(); + for (Symbol currField: fieldsOnClass){ + code += "\t.field private " + currField.getName() + OllirUtils.ollirTypes(currField.getType()) + ";\n"; + } + return null; + } + + private Void dealWithArraySubscript(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithComparison(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithNegationExpr(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithParenthesesExpr(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithAssignment(JmmNode jmmNode, Void unused) { + String left = jmmNode.get("varname"); + JmmNode right = jmmNode.getChildren().get(0); + code += "//" + OllirUtils.ollirTypes(jmmNode.)+ left + " := "; + visit(right); + code += ";\n"; + return null; + } + + private Void dealWithExpr(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithCodeBlock(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithVarDecl(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithMethodCallParam(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + + private Void dealWithParamDecl(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) + visit(child); + + return null; + } + private Void dealWithMethod(JmmNode jmmNode, Void unused) { + code += "\t.method public " + jmmNode.get("methodname") + "("; + + // Params + List parameters = table.getParameters(jmmNode.get("methodname")); + for (int i = 0; i< parameters.size(); i++){ + Symbol parameter = parameters.get(i); + code += parameter.getName() + OllirUtils.ollirTypes(parameter.getType()); + if ( i + 1 < parameters.size()) + code += ", "; + } + code += ")"; + // Return Type of Method + code += OllirUtils.ollirTypes(table.getReturnType(jmmNode.get("methodname"))) + " {\n"; + + for (var child : jmmNode.getChildren()) + visit(child); + + code += "\t}\n"; + + return null; + } + + + private Void dealWithMainMethod(JmmNode jmmNode, Void unused) { + code += "\t.method public static main(" + jmmNode.get("parametername") + ".array.String).V{\n"; + for (var child : jmmNode.getChildren()) + visit(child); + code += "\t}\n"; + return null; + } + private Void dealWithClass(JmmNode jmmNode, Void unused) { + // Imports + List imports = table.getImports(); + for (String currImport : imports) + code += "import " + currImport + ";\n"; + + // Verifies the existence of a superclass + String superClass = table.getSuper(); + if (superClass == null) + code += table.getClassName() + " {\n"; + else + code += table.getClassName() + " extends " + superClass + "{\n"; + dealWithLenFieldAccess(jmmNode, unused); + + // Constructor + code += "\t.construct " + table.getClassName() + "().V {\n" + "\t\tinvokespecial(this, \"\").V;\n\t}\n"; + + for (var child : jmmNode.getChildren()) // Visit methods, etc.. + visit(child); + + return null; + } +} From f4144f09f2c6965cb13f208c6d59cbb9b798a049 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sun, 23 Apr 2023 12:50:01 +0100 Subject: [PATCH 069/253] assignments (expression like i = 32) --- src/main/pt/up/fe/comp2023/Optimization.java | 47 +++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 62f87d0..e935a3b 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -165,9 +165,54 @@ private Void dealWithParenthesesExpr(JmmNode jmmNode, Void unused) { } private Void dealWithAssignment(JmmNode jmmNode, Void unused) { + Symbol var = null; + boolean isField = false; + + /* + Grammar distributes method declarations into 3 categories: + - main method; + - void method; + - method with return type + + Because of that, it's needed to check if the parent of the assignment function corresponds + to any of these types of methods to check if it is either a local variable or a parameter. + */ + + // Main Method + if (jmmNode.getJmmParent().getKind().equals("MainMethodDecl")){ + // Local Var + for (Symbol v : table.getLocalVariables("main")) + if (v.getName().equals(jmmNode.get("varname"))) + var = v; + + } + // Void Method OR Method with Return Type + else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.getJmmParent().getKind().equals("MethodDecl")) { + // Local Var + for (Symbol v : table.getLocalVariables(jmmNode.getJmmParent().get("methodname"))) + if (v.getName().equals(jmmNode.get("varname"))) + var = v; + // Parameter + if (var == null) + for (Symbol v : table.getParameters(jmmNode.getJmmParent().get("methodname"))) + if (v.getName().equals(jmmNode.get("varname"))) + var = v; + } + // Field + if (var == null) + for (Symbol s : this.table.getFields()) + if (s.getName().equals(jmmNode.get("varname"))) { + var = s; + isField = true; + } + // Throw error + if (var == null) + throw new NullPointerException("Variable 'var' is not a LOCAL VAR or a PARAMETER or a FIELD "); + + String left = jmmNode.get("varname"); JmmNode right = jmmNode.getChildren().get(0); - code += "//" + OllirUtils.ollirTypes(jmmNode.)+ left + " := "; + code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " := "; visit(right); code += ";\n"; return null; From cad6452008e7bb981070e4a14cac42edbde73208 Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Sun, 23 Apr 2023 23:06:15 +0100 Subject: [PATCH 070/253] Adds public tests for Final Checkpoint --- test/pt/up/fe/comp/CpUtils.java | 548 ++++++++++++++++++ .../1_parser_and_tree/AddMultConstants.jmm | 8 + .../import/ImportSuper.jmm | 4 + .../lookup/VarLookup_Field.jmm | 17 + .../lookup/VarLookup_Field_Main_Fail.jmm | 8 + .../lookup/VarLookup_Local.jmm | 12 + .../symboltable/MethodsAndFields.jmm | 28 + .../symboltable/Parameters.jmm | 7 + .../cpf/3_ollir/arithmetic/Arithmetic_and.jmm | 16 + .../3_ollir/arithmetic/Arithmetic_less.jmm | 15 + .../comp/cpf/3_ollir/arrays/ArrayAccess.jmm | 23 + .../fe/comp/cpf/3_ollir/arrays/ArrayInit.jmm | 9 + .../cpf/3_ollir/arrays/ComplexArrayAccess.jmm | 27 + .../cpf/3_ollir/basic/BasicMethodsArray.jmm | 13 + .../3_ollir/control_flow/SimpleIfElseStat.jmm | 17 + .../3_ollir/control_flow/SimpleWhileStat.jmm | 17 + .../cpf/3_ollir/control_flow/SwitchStat.jmm | 37 ++ .../4_jasmin/arithmetic/Arithmetic_and.jmm | 16 + .../4_jasmin/arithmetic/Arithmetic_and.ollir | 21 + .../4_jasmin/arithmetic/Arithmetic_less.jmm | 15 + .../4_jasmin/arithmetic/Arithmetic_less.ollir | 21 + .../4_jasmin/arithmetic/ByteCodeIndexes1.jmm | 7 + .../arithmetic/ByteCodeIndexes1.ollir | 11 + .../4_jasmin/arithmetic/ByteCodeIndexes2.jmm | 9 + .../arithmetic/ByteCodeIndexes2.ollir | 12 + .../comp/cpf/4_jasmin/arrays/ArrayAccess.jmm | 20 + .../cpf/4_jasmin/arrays/ArrayAccess.ollir | 40 ++ .../comp/cpf/4_jasmin/arrays/ArrayAsArg.jmm | 32 + .../comp/cpf/4_jasmin/arrays/ArrayAsArg.ollir | 29 + .../cpf/4_jasmin/arrays/ArrayAsArgCode.jmm | 17 + .../cpf/4_jasmin/arrays/ArrayAsArgCode.ollir | 17 + .../fe/comp/cpf/4_jasmin/arrays/ArrayInit.jmm | 9 + .../comp/cpf/4_jasmin/arrays/ArrayInit.ollir | 17 + .../4_jasmin/arrays/ComplexArrayAccess.jmm | 27 + .../4_jasmin/arrays/ComplexArrayAccess.ollir | 48 ++ .../cpf/4_jasmin/basic/BasicMethodsArray.jmm | 13 + .../4_jasmin/basic/BasicMethodsArray.ollir | 14 + .../4_jasmin/calls/ConditionArgsFuncCall.jmm | 22 + .../calls/ConditionArgsFuncCall.ollir | 29 + .../4_jasmin/control_flow/IfWhileNested.jmm | 32 + .../4_jasmin/control_flow/IfWhileNested.ollir | 35 ++ .../4_jasmin/control_flow/SimpleIfElseNot.jmm | 19 + .../control_flow/SimpleIfElseNot.ollir | 27 + .../control_flow/SimpleIfElseStat.jmm | 28 + .../control_flow/SimpleIfElseStat.ollir | 31 + .../4_jasmin/control_flow/SimpleWhileStat.jmm | 18 + .../control_flow/SimpleWhileStat.ollir | 22 + .../cpf/4_jasmin/control_flow/SwitchStat.jmm | 46 ++ .../4_jasmin/control_flow/SwitchStat.ollir | 62 ++ .../comp/cpf/4_jasmin/limits/LocalLimits.jmm | 10 + .../cpf/4_jasmin/limits/LocalLimits.ollir | 16 + .../5_optimizations/const_prop/PropSimple.jmm | 10 + .../const_prop/PropWithLoop.jmm | 16 + .../inst_selection/InstSelection_bipush_6.jmm | 7 + .../inst_selection/InstSelection_iconst_0.jmm | 7 + .../inst_selection/InstSelection_if_lt.jmm | 12 + .../inst_selection/InstSelection_iinc.jmm | 7 + .../InstSelection_ldc_32768.jmm | 7 + .../inst_selection/InstSelection_load_1.jmm | 5 + .../InstSelection_sipush_32767.jmm | 7 + .../inst_selection/InstSelection_store_1.jmm | 6 + .../5_optimizations/reg_alloc/regalloc.jmm | 16 + .../pt/up/fe/comp/cpf/Cpf1_ParserAndTree.java | 37 ++ .../up/fe/comp/cpf/Cpf2_SemanticAnalysis.java | 127 ++++ test/pt/up/fe/comp/cpf/Cpf3_Ollir.java | 176 ++++++ test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 240 ++++++++ .../pt/up/fe/comp/cpf/Cpf5_Optimizations.java | 196 +++++++ 67 files changed, 2474 insertions(+) create mode 100644 test/pt/up/fe/comp/CpUtils.java create mode 100644 test/pt/up/fe/comp/cpf/1_parser_and_tree/AddMultConstants.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/import/ImportSuper.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field_Main_Fail.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Local.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/MethodsAndFields.jmm create mode 100644 test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/Parameters.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_and.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_less.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayInit.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/arrays/ComplexArrayAccess.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/basic/BasicMethodsArray.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleIfElseStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleWhileStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/3_ollir/control_flow/SwitchStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.ollir create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropSimple.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropWithLoop.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_bipush_6.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iconst_0.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_if_lt.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_ldc_32768.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_load_1.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_sipush_32767.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_store_1.jmm create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/reg_alloc/regalloc.jmm create mode 100644 test/pt/up/fe/comp/cpf/Cpf1_ParserAndTree.java create mode 100644 test/pt/up/fe/comp/cpf/Cpf2_SemanticAnalysis.java create mode 100644 test/pt/up/fe/comp/cpf/Cpf3_Ollir.java create mode 100644 test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java create mode 100644 test/pt/up/fe/comp/cpf/Cpf5_Optimizations.java diff --git a/test/pt/up/fe/comp/CpUtils.java b/test/pt/up/fe/comp/CpUtils.java new file mode 100644 index 0000000..b19cbea --- /dev/null +++ b/test/pt/up/fe/comp/CpUtils.java @@ -0,0 +1,548 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp; + +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.hamcrest.Matcher; +import org.junit.Assert; +import org.specs.comp.ollir.ArrayType; +import org.specs.comp.ollir.AssignInstruction; +import org.specs.comp.ollir.BinaryOpInstruction; +import org.specs.comp.ollir.CallInstruction; +import org.specs.comp.ollir.ClassType; +import org.specs.comp.ollir.ClassUnit; +import org.specs.comp.ollir.Element; +import org.specs.comp.ollir.ElementType; +import org.specs.comp.ollir.Instruction; +import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.Node; +import org.specs.comp.ollir.OpInstruction; +import org.specs.comp.ollir.OperationType; +import org.specs.comp.ollir.ReturnInstruction; +import org.specs.comp.ollir.SingleOpInstruction; +import org.specs.comp.ollir.Type; + +import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.jasmin.JasminResult; +import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.specs.util.SpecsCollections; +import pt.up.fe.specs.util.SpecsIo; +import pt.up.fe.specs.util.SpecsStrings; +import pt.up.fe.specs.util.exceptions.NotImplementedException; +import pt.up.fe.specs.util.utilities.LineStream; + +/** + * Utility methods used in checkpoint tests. + * + * @author Joao Bispo + * + */ +public class CpUtils { + + // (if((\w\w)|_icmp\w+)\s+\w+) + // (if_icmpeq | if_icmpne | if_icmplt | if_icmpge | if_icmpgt | if_icmple | ifeq | ifne | iflt | ifge | ifgt | ifle) + public static final String IF_REGEX = "((if_icmpeq|if_icmpne|if_icmplt|if_icmpge|if_icmpgt|if_icmple|ifeq|ifne|iflt|ifge|ifgt|ifle)\\s+\\w+)"; + public static final String GOTO_REGEX = "(goto\\s+\\w+)"; + + static final String FIELD_PREFIX = "\\.field\\s+((public|private)\\s+)?(')?"; + static final String FIELD_SUFFIX = "(')?\\s+"; + + public static String toMessage(String message, OllirResult result) { + var finalMessage = new StringBuilder(); + + finalMessage.append(message).append("\n"); + + finalMessage.append("\nOLLIR code:\n").append(result.getOllirCode()).append("\n"); + + var numReports = result.getReports().size(); + if (numReports == 0) { + finalMessage.append("\nNo reports\n"); + } else { + finalMessage.append("\nReports (" + result.getReports().size() + "):\n"); + result.getReports().forEach(report -> finalMessage.append(report.toString() + "\n")); + } + finalMessage.append("\n"); + + return finalMessage.toString(); + // return message + "\n\nOLLIR:\n" + ollir.getOllirCode(); + } + + public static String toMessage(String message, JasminResult result) { + var finalMessage = new StringBuilder(); + + finalMessage.append(message).append("\n"); + + finalMessage.append("\nJasmin code:\n").append(result.getJasminCode()).append("\n"); + + var numReports = result.getReports().size(); + if (numReports == 0) { + finalMessage.append("\nNo reports\n"); + } else { + finalMessage.append("\nReports (" + result.getReports().size() + "):\n"); + result.getReports().forEach(report -> finalMessage.append(report.toString() + "\n")); + } + finalMessage.append("\n"); + + return finalMessage.toString(); + // return message + "\n\nJasmin:\n" + result.getJasminCode(); + } + + public static String toMessage(String message, SymbolTable result) { + var finalMessage = new StringBuilder(); + + if (message != null && !message.isBlank()) { + finalMessage.append(message).append("\n"); + } + + finalMessage.append("\nSymbol table:\n").append(result.print()).append("\n"); + + finalMessage.append("\n"); + + return finalMessage.toString(); + // return message + "\n\nJasmin:\n" + result.getJasminCode(); + } + + public static void testOllirToJasmin(String resource, String expectedOutput) { + // If AstToJasmin pipeline, do not execute test + if (TestUtils.hasAstToJasminClass()) { + return; + } + + var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); + + var result = TestUtils.backend(ollirResult); + + var testName = new File(resource).getName(); + System.out.println(testName + ":\n" + result.getJasminCode()); + var runOutput = result.runWithFullOutput(); + Assert.assertEquals("Error while running compiled Jasmin: " + runOutput.getOutput() + "\n\nJasmin code:\n" + + result.getJasminCode(), 0, runOutput.getReturnValue()); + System.out.println("\n Result: " + runOutput.getOutput()); + + if (expectedOutput != null) { + Assert.assertEquals("Output different from what was expected.\n\nJasmin code:\n" + result.getJasminCode(), + expectedOutput, runOutput.getOutput()); + } + } + + public static void testOllirToJasmin(String resource) { + testOllirToJasmin(resource, null); + } + + public static void testJmmCompilation(String resource, Consumer ollirTester, String executionOutput) { + + // If AstToJasmin pipeline, generate Jasmin + if (TestUtils.hasAstToJasminClass()) { + + var result = TestUtils.backend(SpecsIo.getResource(resource)); + + var testName = new File(resource).getName(); + System.out.println(testName + ":\n" + result.getJasminCode()); + var runOutput = result.runWithFullOutput(); + Assert.assertEquals("Error while running compiled Jasmin: " + runOutput.getOutput() + "\n\nJasmin code:\n" + + result.getJasminCode(), 0, + runOutput.getReturnValue()); + System.out.println("\n Result: " + runOutput.getOutput()); + + if (executionOutput != null) { + Assert.assertEquals( + "Output different from what was expected.\n\nJasmin code:\n" + result.getJasminCode(), + executionOutput, runOutput.getOutput()); + } + + return; + } + + var result = TestUtils.optimize(SpecsIo.getResource(resource)); + var testName = new File(resource).getName(); + System.out.println(testName + ":\n" + result.getOllirCode()); + + if (ollirTester != null) { + ollirTester.accept(result); + } + } + + public static void testJmmCompilation(String resource) { + CpUtils.testJmmCompilation(resource, null); + } + + public static void testJmmCompilation(String resource, Consumer ollirTester) { + testJmmCompilation(resource, ollirTester, null); + } + + public static void assertEquals(String message, Object expected, Object actual, OllirResult ollir) { + Assert.assertEquals(toMessage(message, ollir), expected, + actual); + } + + public static void assertEquals(String message, int expected, int actual, OllirResult ollir) { + Assert.assertEquals(toMessage(message, ollir), expected, + actual); + } + + public static void assertEquals(String message, long expected, long actual, OllirResult ollir) { + Assert.assertEquals(toMessage(message, ollir), expected, + actual); + } + + static public void assertTrue(String message, boolean condition, OllirResult ollir) { + Assert.assertTrue(toMessage(message, ollir), condition); + } + + public static void assertThat(String reason, T actual, Matcher matcher, OllirResult ollir) { + Assert.assertThat(toMessage(reason, ollir), actual, matcher); + } + + public static void assertEquals(String message, Object expected, Object actual, JasminResult result) { + Assert.assertEquals(toMessage(message, result), expected, actual); + } + + public static void assertEquals(String message, int expected, int actual, JasminResult result) { + Assert.assertEquals(toMessage(message, result), expected, actual); + } + + public static void assertNotEquals(String message, Object expected, Object actual, JasminResult jasminResult) { + Assert.assertNotEquals(toMessage(message, jasminResult), expected, actual); + } + + public static void assertNotNull(String message, Object obj, JasminResult jasminResult) { + Assert.assertNotNull(toMessage(message, jasminResult), obj); + } + + static public void assertTrue(String message, boolean condition, JasminResult result) { + Assert.assertTrue(toMessage(message, result), condition); + } + + public static void assertEquals(String message, int expected, int actual, SymbolTable results) { + Assert.assertEquals(toMessage(message, results), expected, actual); + } + + public static void assertEquals(String message, Object expected, Object actual, SymbolTable result) { + Assert.assertEquals(toMessage(message, result), expected, actual); + } + + public static org.specs.comp.ollir.Method getMethod(OllirResult result, String methodName) { + ClassUnit classUnit = result.getOllirClass(); + + for (var method : classUnit.getMethods()) { + if (method.getMethodName().equals(methodName)) { + return method; + } + } + + throw new RuntimeException(toMessage("Could not find OLLIR method with name '" + methodName + "'", result)); + } + + public static String toString(Type ollirType) { + return toString(ollirType.getTypeOfElement(), ollirType); + } + + public static String toString(ElementType elementType, Type ollirType) { + // var elementType = ollirType.getTypeOfElement(); + switch (elementType) { + case BOOLEAN: + return "bool"; + case INT32: + return "int"; + case STRING: + return "String"; + case VOID: + return "void"; + case OBJECTREF: + var objectRef = (ClassType) ollirType; + return objectRef.getName(); + case ARRAYREF: + var arrayType = (ArrayType) ollirType; + return toString(arrayType.getTypeOfElements(), null) + + SpecsStrings.buildLine("[]", arrayType.getNumDimensions()); + default: + throw new NotImplementedException(elementType); + } + } + + /** + * Tests if there an intruction of type c in the RHS of an assign. + * + * @param c + * @param method + */ + public static void assertAssignRhs(Class c, Method method, OllirResult ollir) { + + var inst = method.getInstructions().stream() + .filter(i -> i instanceof AssignInstruction) + .map(instr -> (AssignInstruction) instr) + .filter(assign -> c.isInstance(assign.getRhs())) + .findFirst(); + + assertTrue("Could not find a " + c.getName() + " in method " + method.getMethodName(), + inst.isPresent(), ollir); + } + + /** + * Tests if there an intruction of type c in the list of instructions. + * + * @param c + * @param method + */ + public static List assertInstExists(Class c, Method method, OllirResult ollir) { + + var inst = method.getInstructions().stream() + // Unfold instruction inside AssignInstrucion + .flatMap( + i -> i instanceof AssignInstruction ? Stream.of(i, ((AssignInstruction) i).getRhs()) + : Stream.of(i)) + .filter(i -> c.isInstance(i)) + .map(c::cast) + .collect(Collectors.toList()); + + assertTrue("Could not find a " + c.getName() + " in method " + method.getMethodName(), !inst.isEmpty(), + ollir); + + return inst; + } + + public static Method assertMethodExists(String methodName, OllirResult ollir) { + Method method = ollir.getOllirClass().getMethods().stream() + .filter(m -> m.getMethodName().equals(methodName)) + .findFirst() + .orElse(null); + + Assert.assertNotNull("Could not find method " + methodName + "\n\nOLLIR code:\n" + ollir.getOllirCode(), + method); + + return method; + } + + public static void assertReturnExists(Method method, OllirResult ollir) { + + var retInst = method.getInstructions().stream() + .filter(inst -> inst instanceof ReturnInstruction) + .findFirst(); + + assertTrue("Could not find a return instruction in method " + method.getMethodName() + + ollir.getOllirCode(), retInst.isPresent(), ollir); + } + + public static void assertHasOperation(OperationType opType, Method method, OllirResult ollirResult) { + + var binOps = CpUtils.assertInstExists(BinaryOpInstruction.class, method, ollirResult); + + var binOpsOfOperation = binOps.stream() + .filter(binOp -> binOp.getOperation().getOpType() == opType) + .collect(Collectors.toList()); + + CpUtils.assertTrue( + "Could not find binary operation of type " + opType.name() + " in method " + method.getMethodName(), + !binOpsOfOperation.isEmpty(), + ollirResult); + } + + public static List getOllirNodes(ClassUnit classUnit, Predicate filter) { + var nodes = new ArrayList(); + + for (var method : classUnit.getMethods()) { + getOllirNodes(method, filter, nodes); + } + // assertTrue(filterMessage, !nodes.isEmpty()); + // if (nodes.isEmpty()) { + // throw new RuntimeException(); + // } + + return nodes; + } + + public static List getOllirNodes(Method method, Predicate filter) { + var nodes = new ArrayList(); + getOllirNodes(method, filter, nodes); + return nodes; + } + + private static void getOllirNodes(Method method, Predicate filter, List filteredNodes) { + for (var inst : method.getInstructions()) { + getOllirNodes(inst, filter, filteredNodes); + } + + } + + private static void getOllirNodes(Node currentNode, Predicate filter, List filteredNodes) { + // Check if node passes the filter + if (filter.test(currentNode)) { + filteredNodes.add(currentNode); + } + + // Special cases + if (currentNode instanceof AssignInstruction) { + var assign = (AssignInstruction) currentNode; + getOllirNodes(assign.getRhs(), filter, filteredNodes); + } + } + + public static List getElements(Instruction inst) { + if (inst instanceof SingleOpInstruction) { + return Arrays.asList(((SingleOpInstruction) inst).getSingleOperand()); + } + + if (inst instanceof OpInstruction) { + return ((OpInstruction) inst).getOperands(); + } + + if (inst instanceof AssignInstruction) { + var assign = (AssignInstruction) inst; + return SpecsCollections.concat(assign.getDest(), getElements(assign.getRhs())); + } + + if (inst instanceof CallInstruction) { + var call = (CallInstruction) inst; + var operands = call.getListOfOperands(); + return operands != null ? operands : Collections.emptyList(); + } + + throw new NotImplementedException(inst.getClass()); + } + + /** + * Verifies if the given code matches (contains) the given regex + * + * @param code + * @param regex + */ + public static void matches(JasminResult result, String regex) { + matches(result, Pattern.compile(regex)); + } + + public static void matches(JasminResult result, Pattern regex) { + var matches = SpecsStrings.matches(result.getJasminCode(), regex); + assertTrue("Expected code to match /" + regex + "/", matches, result); + } + + public static void matches(String jasminCode, String regex) { + matches(jasminCode, Pattern.compile(regex)); + } + + public static void matches(String jasminCode, Pattern regex) { + var matches = SpecsStrings.matches(jasminCode, regex); + Assert.assertTrue("Expected code to match /" + regex + "/ in the following code:\n\n" + jasminCode, matches); + } + + public static void jasminHasField(JasminResult jasminResult, String fieldName, String fieldType) { + var regex = FIELD_PREFIX + fieldName + FIELD_SUFFIX + fieldType; + matches(jasminResult, regex); + } + + public static void jasminHasField(JasminResult jasminResult, String fieldType) { + var regex = FIELD_PREFIX + "\\w+" + FIELD_SUFFIX + fieldType; + matches(jasminResult, regex); + } + + public static String getJasminMethod(JasminResult jasminResult, String methodName) { + var code = jasminResult.getJasminCode(); + + if (methodName == null) { + methodName = "\\w+"; + } + + var regex = "\\.method\\s+((public|private)\\s)?+" + methodName + "((.)+?)\\.end\\s+method"; + // var regex = "\\.method\\s+((public|private)\\s+)?" + methodName + "((.|\\s)+?)\\.end\\s+method"; + + var results = SpecsStrings.getRegex(code, regex); + + assertTrue("Could not find method '" + methodName + "'", !results.isEmpty(), jasminResult); + + return results.get(2); + } + + public static String getJasminMethod(JasminResult jasminResult) { + return getJasminMethod(jasminResult, null); + } + + public static Integer getBytecodeIndex(String instructionPrefix, String jasminCode) { + try (var lines = LineStream.newInstance(jasminCode)) { + + while (lines.hasNextLine()) { + var line = lines.nextLine().strip(); + + if (!line.startsWith(instructionPrefix)) { + continue; + } + + var substring = line.substring(instructionPrefix.length()).strip(); + + if (substring.startsWith("_")) { + substring = substring.substring(1); + } + + return Integer.parseInt(substring); + } + + throw new RuntimeException("Could not find instruction with prefix " + instructionPrefix); + // fail("Could not find instruction with prefix " + instructionPrefix + " in code:\n\n" + jasminCode); + } catch (Exception e) { + fail("getBytecodeIndex('" + instructionPrefix + "'): " + e.getMessage() + "\n\n" + jasminCode); + // throw new RuntimeException( + // "Exception while looking for instruction " + instructionPrefix + " in code:\n\n" + jasminCode); + } + + return null; + } + + public static void runJasmin(JasminResult jasminResult, String expected) { + try { + var output = SpecsStrings.normalizeFileContents(jasminResult.run(), true); + assertEquals("Jasmin output", expected, output, jasminResult); + } catch(Exception e) { + throw new RuntimeException("Problems while running Jasmin code:\n" + jasminResult.getJasminCode(), e); + } + } + + private static final Pattern LIMIT_LOCALS = Pattern.compile("\\.limit\\s+locals\\s+([0-9]+)\\s+"); + + private static final Pattern LIMIT_STACK = Pattern.compile("\\.limit\\s+stack\\s+([0-9]+)\\s+"); + + public static Pattern getLimitLocalsRegex() { + return LIMIT_LOCALS; + } + + public static Pattern getLimitStackRegex() { + return LIMIT_STACK; + } + + public static String getLocalsRegex(int numLocals) { + return "(a|i)(store|load)(_|\\s+)" + (numLocals - 1); + } + + public static int countOccurences(JasminResult jasminResult, String word) { + String code = jasminResult.getJasminCode(); + return (code.length() - code.replace(word, "").length()) / word.length(); + } + + public static int countOccurrencesRegex(JasminResult jasminResult, String regexString) { + + String jasminCode = jasminResult.getJasminCode(); + var matches = SpecsStrings.getRegexGroups(jasminCode, regexString,0); + + return matches.size(); + } +} diff --git a/test/pt/up/fe/comp/cpf/1_parser_and_tree/AddMultConstants.jmm b/test/pt/up/fe/comp/cpf/1_parser_and_tree/AddMultConstants.jmm new file mode 100644 index 0000000..186933b --- /dev/null +++ b/test/pt/up/fe/comp/cpf/1_parser_and_tree/AddMultConstants.jmm @@ -0,0 +1,8 @@ +import io; +class AddMultConstants { + public static void main(String[] args) { + io.println(1+2*3); + io.println(1+2*3+5); + io.println(1+2*3+6/3); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/import/ImportSuper.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/import/ImportSuper.jmm new file mode 100644 index 0000000..80df8b2 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/import/ImportSuper.jmm @@ -0,0 +1,4 @@ +import Sup; + +class Simple extends Sup { +} diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field.jmm new file mode 100644 index 0000000..4de5096 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field.jmm @@ -0,0 +1,17 @@ +import io; + +class A { + int a; + + public int x(){ + a = 10; + io.print(a); + return a; + } + + public static void main(String[] args){ + A a; + a = new A(); + a.x(); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field_Main_Fail.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field_Main_Fail.jmm new file mode 100644 index 0000000..9f39ad7 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Field_Main_Fail.jmm @@ -0,0 +1,8 @@ + +class A { + int a; + + public static void main(String[] args){ + a = 10; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Local.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Local.jmm new file mode 100644 index 0000000..a6819e1 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/lookup/VarLookup_Local.jmm @@ -0,0 +1,12 @@ +import io; + +class A { + + int a; + + public static void main(String[] args){ + int a; + a = 10; + io.print(10); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/MethodsAndFields.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/MethodsAndFields.jmm new file mode 100644 index 0000000..247b8c7 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/MethodsAndFields.jmm @@ -0,0 +1,28 @@ + +class MethodsAndFields{ + int field1; + boolean field2; + MethodsAndFields field3; + + public int getField1(){ + return field1; + } + + public boolean getField2(){ + return field2; + } + + public MethodsAndFields getField3(){ + return field3; + } + + public int[] all(int a, boolean b, MethodsAndFields maf){ + int[] c; + c = new int[1]; + return c; + } + + public static void main(String[] args){ + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/Parameters.jmm b/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/Parameters.jmm new file mode 100644 index 0000000..d67d183 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/2_semantic_analysis/symboltable/Parameters.jmm @@ -0,0 +1,7 @@ + +class Parameters{ + + public int all(int a, boolean b, Parameters maf){ + return 0; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_and.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_and.jmm new file mode 100644 index 0000000..deb17fa --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_and.jmm @@ -0,0 +1,16 @@ +import io; + +class Arithmetic_and { + public static void main(String[] args) { + boolean a; + + a = true && false; + + if(a) { + io.print(1); + } else { + io.print(0); + } + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_less.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_less.jmm new file mode 100644 index 0000000..636daba --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/arithmetic/Arithmetic_less.jmm @@ -0,0 +1,15 @@ +import io; + +class Arithmetic_less { + public static void main(String[] args) { + boolean a; + + a = 10 < 20; + + if(a) { + io.print(1); + } else { + io.print(0); + } + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm new file mode 100644 index 0000000..73036dc --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm @@ -0,0 +1,23 @@ +import ioPlus; +class ArrayAccess { + + public int foo(int[] a) { + int result; + + result = a[0]; + result = a[1] + a[2]; + result = result + a[3]; + result = 1 + a[4]; + + a[0] = 1; + a[1] = 2; + a[2] = 3; + a[3] = 4; + a[4] = 5; + + + return result; + } + + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayInit.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayInit.jmm new file mode 100644 index 0000000..bbb1d60 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayInit.jmm @@ -0,0 +1,9 @@ +import ioPlus; +class ArrayInit { + + public static void main(String[] args) { + int[] a; + a = new int[5]; + ioPlus.printResult(a.length); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arrays/ComplexArrayAccess.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ComplexArrayAccess.jmm new file mode 100644 index 0000000..080eb32 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ComplexArrayAccess.jmm @@ -0,0 +1,27 @@ +import ioPlus; +class ComplexArrayAccess { + + public int func(int a) { + return a; + } + + public static void main(String[] args) { + int[] a; + int i; + ComplexArrayAccess d; + d = new ComplexArrayAccess(); + a = new int[5]; + a[0] = 1; + a[1] = 2; + a[2] = 3; + a[3] = 4; + a[4] = 5; + i = 1; + ioPlus.printResult(a[d.func(0)]); + ioPlus.printResult(a[i]); + ioPlus.printResult(a[4/2]); + ioPlus.printResult(a[a[2]]); + ioPlus.printResult(a[a.length -1 ]); + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/basic/BasicMethodsArray.jmm b/test/pt/up/fe/comp/cpf/3_ollir/basic/BasicMethodsArray.jmm new file mode 100644 index 0000000..7277605 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/basic/BasicMethodsArray.jmm @@ -0,0 +1,13 @@ + +import Other; +// import Person; + +class BasicMethods extends Other { + + public int[] func4(){ + int[] k; + k = new int[1]; + return k; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleIfElseStat.jmm b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleIfElseStat.jmm new file mode 100644 index 0000000..f089a9e --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleIfElseStat.jmm @@ -0,0 +1,17 @@ +import ioPlus; +class SimpleIfElseStat { + + + public int func(int a, int b){ + int result; + + if(a < b){ + result = a; + } else { + result = b; + } + + return result; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleWhileStat.jmm b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleWhileStat.jmm new file mode 100644 index 0000000..aec4c79 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SimpleWhileStat.jmm @@ -0,0 +1,17 @@ +import ioPlus; +class SimpleWhileStat { + + + public int func(int a){ + int c; + int i; + i = 0; + + while (i < a) { + i = i + 1; + } + + return i; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SwitchStat.jmm b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SwitchStat.jmm new file mode 100644 index 0000000..d0de4e3 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/3_ollir/control_flow/SwitchStat.jmm @@ -0,0 +1,37 @@ +import ioPlus; +class SwitchStat { + + + public int func(int a){ + int result; + + if(a < 1){ + result =1; + } else { + if(a < 2){ + result = 2; + } else { + if(a < 3){ + result = 3; + } else { + if(a < 4){ + result = 4; + } else { + if(a < 5){ + result = 5; + } else { + if(a < 6){ + result = 6; + } else { + result = 7; + } + } + } + } + } + } + + return result; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.jmm new file mode 100644 index 0000000..deb17fa --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.jmm @@ -0,0 +1,16 @@ +import io; + +class Arithmetic_and { + public static void main(String[] args) { + boolean a; + + a = true && false; + + if(a) { + io.print(1); + } else { + io.print(0); + } + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir new file mode 100644 index 0000000..6d000c1 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir @@ -0,0 +1,21 @@ +import io; +Arithmetic_and { + + .construct Arithmetic_and().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +a.bool :=.bool true.bool &&.bool false.bool; + +if (a.bool) goto ifbody_0; + invokestatic(io, "print", 0.i32).V; +goto endif_0; +ifbody_0: + invokestatic(io, "print", 1.i32).V; +endif_0: + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.jmm new file mode 100644 index 0000000..636daba --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.jmm @@ -0,0 +1,15 @@ +import io; + +class Arithmetic_less { + public static void main(String[] args) { + boolean a; + + a = 10 < 20; + + if(a) { + io.print(1); + } else { + io.print(0); + } + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir new file mode 100644 index 0000000..bad39cf --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir @@ -0,0 +1,21 @@ +import io; +Arithmetic_less { + + .construct Arithmetic_less().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +a.bool :=.bool 10.i32 <.bool 20.i32; + +if (a.bool) goto ifbody_0; + invokestatic(io, "print", 0.i32).V; +goto endif_0; +ifbody_0: + invokestatic(io, "print", 1.i32).V; +endif_0: + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.jmm new file mode 100644 index 0000000..59410b3 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.jmm @@ -0,0 +1,7 @@ +class ByteCodeIndexes1 { + + public int func(int a) + { + return a; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir new file mode 100644 index 0000000..5aaf352 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir @@ -0,0 +1,11 @@ +ByteCodeIndexes1 { + + .construct ByteCodeIndexes1().V { + invokespecial(this, "").V; + } + + .method public func(a.i32).i32 { +ret.i32 a.i32; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.jmm new file mode 100644 index 0000000..5408811 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.jmm @@ -0,0 +1,9 @@ +class ByteCodeIndexes2 { + + public int func(int a) + { + int b; + b = 11; + return b; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir new file mode 100644 index 0000000..c8609b0 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir @@ -0,0 +1,12 @@ +ByteCodeIndexes2 { + + .construct ByteCodeIndexes2().V { + invokespecial(this, "").V; + } + + .method public func(a.i32).i32 { +b.i32 :=.i32 11.i32; +ret.i32 b.i32; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.jmm new file mode 100644 index 0000000..83b9e11 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.jmm @@ -0,0 +1,20 @@ +import ioPlus; +class ArrayAccess { + + public static void main(String[] args) { + int[] a; + a = new int[5]; + a[0] = 1; + a[1] = 2; + a[2] = 3; + a[3] = 4; + a[4] = 5; + + ioPlus.printResult(a[0]); + ioPlus.printResult(a[1]); + ioPlus.printResult(a[2]); + ioPlus.printResult(a[3]); + ioPlus.printResult(a[4]); + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.ollir new file mode 100644 index 0000000..78df91e --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAccess.ollir @@ -0,0 +1,40 @@ +import ioPlus; +ArrayAccess { + + .construct ArrayAccess().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +temp0.i32 :=.i32 5.i32; +a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +temp1.i32 :=.i32 0.i32; +a[temp1.i32].i32 :=.i32 1.i32; +temp2.i32 :=.i32 1.i32; +a[temp2.i32].i32 :=.i32 2.i32; +temp3.i32 :=.i32 2.i32; +a[temp3.i32].i32 :=.i32 3.i32; +temp4.i32 :=.i32 3.i32; +a[temp4.i32].i32 :=.i32 4.i32; +temp5.i32 :=.i32 4.i32; +a[temp5.i32].i32 :=.i32 5.i32; +temp8.i32 :=.i32 0.i32; +temp7.i32 :=.i32 a[temp8.i32].i32; +invokestatic(ioPlus, "printResult", temp7.i32).V; +temp11.i32 :=.i32 1.i32; +temp10.i32 :=.i32 a[temp11.i32].i32; +invokestatic(ioPlus, "printResult", temp10.i32).V; +temp14.i32 :=.i32 2.i32; +temp13.i32 :=.i32 a[temp14.i32].i32; +invokestatic(ioPlus, "printResult", temp13.i32).V; +temp17.i32 :=.i32 3.i32; +temp16.i32 :=.i32 a[temp17.i32].i32; +invokestatic(ioPlus, "printResult", temp16.i32).V; +temp20.i32 :=.i32 4.i32; +temp19.i32 :=.i32 a[temp20.i32].i32; +invokestatic(ioPlus, "printResult", temp19.i32).V; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.jmm new file mode 100644 index 0000000..eeb9a56 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.jmm @@ -0,0 +1,32 @@ +import ioPlus; +class ArrayAsArg { + + public int func(int[] a) + { + int b; + b = a.length; + return b; + } + + public int func2() + { + int x; + int[] a; + ArrayAsArg c; + c = new ArrayAsArg(); + a = new int[2]; + x = c.func(a); + return x; + } + + public static void main(String[] args) + { + int x; + ArrayAsArg c; + c = new ArrayAsArg(); + x = c.func2(); + ioPlus.printResult(x); + } + + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.ollir new file mode 100644 index 0000000..ed40a7e --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArg.ollir @@ -0,0 +1,29 @@ +import ioPlus; +ArrayAsArg { + + .construct ArrayAsArg().V { + invokespecial(this, "").V; + } + + .method public func(a.array.i32).i32 { +b.i32 :=.i32 arraylength(a.array.i32).i32; +ret.i32 b.i32; + } + .method public func2().i32 { +c.ArrayAsArg :=.ArrayAsArg new(ArrayAsArg).ArrayAsArg; +invokespecial(c.ArrayAsArg,"").V; +temp0.i32 :=.i32 2.i32; +a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +x.i32 :=.i32 invokevirtual(c.ArrayAsArg, "func", a.array.i32).i32; +ret.i32 x.i32; + } + .method public static main(args.array.String).V { +c.ArrayAsArg :=.ArrayAsArg new(ArrayAsArg).ArrayAsArg; +invokespecial(c.ArrayAsArg,"").V; +x.i32 :=.i32 invokevirtual(c.ArrayAsArg, "func2").i32; +invokestatic(ioPlus, "printResult", x.i32).V; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.jmm new file mode 100644 index 0000000..99de593 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.jmm @@ -0,0 +1,17 @@ +import ioPlus; +class ArrayAsArg { + + public int func(int[] a) + { + int x; + int[] arr; + ArrayAsArg c; + + c = new ArrayAsArg(); + arr = new int[2]; + x = c.func(arr); + return x; + } + + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.ollir new file mode 100644 index 0000000..1fd8ba9 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayAsArgCode.ollir @@ -0,0 +1,17 @@ +import ioPlus; +ArrayAsArg { + + .construct ArrayAsArg().V { + invokespecial(this, "").V; + } + + .method public func(a.array.i32).i32 { +c.ArrayAsArg :=.ArrayAsArg new(ArrayAsArg).ArrayAsArg; +invokespecial(c.ArrayAsArg,"").V; +temp0.i32 :=.i32 2.i32; +arr.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +x.i32 :=.i32 invokevirtual(c.ArrayAsArg, "func", arr.array.i32).i32; +ret.i32 x.i32; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.jmm new file mode 100644 index 0000000..bbb1d60 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.jmm @@ -0,0 +1,9 @@ +import ioPlus; +class ArrayInit { + + public static void main(String[] args) { + int[] a; + a = new int[5]; + ioPlus.printResult(a.length); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir new file mode 100644 index 0000000..6eb7622 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir @@ -0,0 +1,17 @@ +import ioPlus; +ArrayInit { + + .construct ArrayInit().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +temp0.i32 :=.i32 5.i32; +a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +temp1.i32 :=.i32 arraylength(a.array.i32).i32.i32; +invokestatic(ioPlus, "printResult", temp1.i32).V; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.jmm new file mode 100644 index 0000000..080eb32 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.jmm @@ -0,0 +1,27 @@ +import ioPlus; +class ComplexArrayAccess { + + public int func(int a) { + return a; + } + + public static void main(String[] args) { + int[] a; + int i; + ComplexArrayAccess d; + d = new ComplexArrayAccess(); + a = new int[5]; + a[0] = 1; + a[1] = 2; + a[2] = 3; + a[3] = 4; + a[4] = 5; + i = 1; + ioPlus.printResult(a[d.func(0)]); + ioPlus.printResult(a[i]); + ioPlus.printResult(a[4/2]); + ioPlus.printResult(a[a[2]]); + ioPlus.printResult(a[a.length -1 ]); + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.ollir new file mode 100644 index 0000000..ccf0d32 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ComplexArrayAccess.ollir @@ -0,0 +1,48 @@ +import ioPlus; +ComplexArrayAccess { + + .construct ComplexArrayAccess().V { + invokespecial(this, "").V; + } + + .method public func(a.i32).i32 { +ret.i32 a.i32; + } + .method public static main(args.array.String).V { +d.ComplexArrayAccess :=.ComplexArrayAccess new(ComplexArrayAccess).ComplexArrayAccess; +invokespecial(d.ComplexArrayAccess,"").V; +temp0.i32 :=.i32 5.i32; +a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +temp1.i32 :=.i32 0.i32; +a[temp1.i32].i32 :=.i32 1.i32; +temp2.i32 :=.i32 1.i32; +a[temp2.i32].i32 :=.i32 2.i32; +temp3.i32 :=.i32 2.i32; +a[temp3.i32].i32 :=.i32 3.i32; +temp4.i32 :=.i32 3.i32; +a[temp4.i32].i32 :=.i32 4.i32; +temp5.i32 :=.i32 4.i32; +a[temp5.i32].i32 :=.i32 5.i32; +i.i32 :=.i32 1.i32; +temp8.i32 :=.i32 invokevirtual(d.ComplexArrayAccess, "func", 0.i32).i32.i32; +temp7.i32 :=.i32 a[temp8.i32].i32; +invokestatic(ioPlus, "printResult", temp7.i32).V; +temp11.i32 :=.i32 i.i32; +temp10.i32 :=.i32 a[temp11.i32].i32; +invokestatic(ioPlus, "printResult", temp10.i32).V; +temp14.i32 :=.i32 4.i32 /.i32 2.i32; +temp13.i32 :=.i32 a[temp14.i32].i32; +invokestatic(ioPlus, "printResult", temp13.i32).V; +temp21.i32 :=.i32 2.i32; +temp20.i32 :=.i32 a[temp21.i32].i32; +temp18.i32 :=.i32 a[temp20.i32].i32; +invokestatic(ioPlus, "printResult", temp18.i32).V; +temp28.i32 :=.i32 arraylength(a.array.i32).i32.i32.i32; +temp27.i32 :=.i32 temp28.i32 -.i32 1.i32; +temp25.i32 :=.i32 a[temp27.i32].i32; +invokestatic(ioPlus, "printResult", temp25.i32).V; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.jmm new file mode 100644 index 0000000..7277605 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.jmm @@ -0,0 +1,13 @@ + +import Other; +// import Person; + +class BasicMethods extends Other { + + public int[] func4(){ + int[] k; + k = new int[1]; + return k; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir new file mode 100644 index 0000000..f4d2711 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir @@ -0,0 +1,14 @@ +import Other; +BasicMethods extends Other { + + .construct BasicMethods().V { + invokespecial(this, "").V; + } + + .method public func4().array.i32 { +temp0.i32 :=.i32 1.i32; +k.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; +ret.array.i32 k.array.i32; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.jmm new file mode 100644 index 0000000..4e7e3c2 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.jmm @@ -0,0 +1,22 @@ +import ioPlus; +class ConditionArgsFuncCall { + + public int func(boolean a, boolean b, boolean c, boolean d){ + ioPlus.printResult(10); + return 1; + } + + public static void main(String[] args) { + int a; + int b; + boolean i; + boolean j; + ConditionArgsFuncCall d; + d = new ConditionArgsFuncCall(); + a = 10; + b = 5; + i = true; + j = false; + a = d.func(a < b, i && j , a < b && i, !i); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir new file mode 100644 index 0000000..afdd4f0 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir @@ -0,0 +1,29 @@ +import ioPlus; +ConditionArgsFuncCall { + + .construct ConditionArgsFuncCall().V { + invokespecial(this, "").V; + } + + .method public func(a.bool, b.bool, c.bool, d.bool).i32 { +invokestatic(ioPlus, "printResult", 10.i32).V; +ret.i32 1.i32; + } + .method public static main(args.array.String).V { +d.ConditionArgsFuncCall :=.ConditionArgsFuncCall new(ConditionArgsFuncCall).ConditionArgsFuncCall; +invokespecial(d.ConditionArgsFuncCall,"").V; +a.i32 :=.i32 10.i32; +b.i32 :=.i32 5.i32; +i.bool :=.bool true.bool; +j.bool :=.bool false.bool; +temp0.bool :=.bool a.i32 <.bool b.i32; +temp1.bool :=.bool i.bool &&.bool j.bool; +temp4.bool :=.bool a.i32 <.bool b.i32; +temp3.bool :=.bool temp4.bool &&.bool i.bool; +temp5.bool :=.bool !.bool i.bool; +a.i32 :=.i32 invokevirtual(d.ConditionArgsFuncCall, "func", temp0.bool, temp1.bool, temp3.bool, temp5.bool).i32; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.jmm new file mode 100644 index 0000000..2b14458 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.jmm @@ -0,0 +1,32 @@ +import ioPlus; + +class IfWhileNested { + + + public int func(int a){ + int i; + boolean flag; + + flag = true; + i = 0; + while (i < a) { + if(flag){ + ioPlus.printResult(1); + } else { + ioPlus.printResult(2); + } + + flag = !flag; + i = i + 1; + } + + return 1; + } + + public static void main(String[] args) { + IfWhileNested d; + int a; + d = new IfWhileNested(); + a = d.func(3); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir new file mode 100644 index 0000000..64dfe7b --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir @@ -0,0 +1,35 @@ +import ioPlus; +IfWhileNested { + + .construct IfWhileNested().V { + invokespecial(this, "").V; + } + + .method public func(a.i32).i32 { +flag.bool :=.bool true.bool; +i.i32 :=.i32 0.i32; +if (i.i32 <.bool a.i32) goto whilebody_1; +goto endwhile_1; +whilebody_1: + +if (flag.bool) goto ifbody_0; + invokestatic(ioPlus, "printResult", 2.i32).V; +goto endif_0; +ifbody_0: + invokestatic(ioPlus, "printResult", 1.i32).V; +endif_0: +flag.bool :=.bool !.bool flag.bool; +i.i32 :=.i32 i.i32 +.i32 1.i32; +if (i.i32 <.bool a.i32) goto whilebody_1; +endwhile_1: +ret.i32 1.i32; + } + .method public static main(args.array.String).V { +d.IfWhileNested :=.IfWhileNested new(IfWhileNested).IfWhileNested; +invokespecial(d.IfWhileNested,"").V; +a.i32 :=.i32 invokevirtual(d.IfWhileNested, "func", 3.i32).i32; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.jmm new file mode 100644 index 0000000..40b64a3 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.jmm @@ -0,0 +1,19 @@ +import io; + +class SimpleIfElseNot { + + + public static void main(String[] args) { + + if(true) + io.println(10); + else + io.println(20); + + if(false) + io.print(100); + else + io.print(200); + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir new file mode 100644 index 0000000..0386dcb --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir @@ -0,0 +1,27 @@ +import io; +SimpleIfElseNot { + + .construct SimpleIfElseNot().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { + +if (true.bool) goto ifbody_0; + invokestatic(io, "println", 20.i32).V; +goto endif_0; +ifbody_0: + invokestatic(io, "println", 10.i32).V; +endif_0: + +if (false.bool) goto ifbody_1; + invokestatic(io, "print", 200.i32).V; +goto endif_1; +ifbody_1: + invokestatic(io, "print", 100.i32).V; +endif_1: + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.jmm new file mode 100644 index 0000000..43ec9af --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.jmm @@ -0,0 +1,28 @@ +import ioPlus; +class SimpleIfElseStat { + + + public static void main(String[] args) { + int a; + int b; + + a = 5; + b = 10; + + if(a < b){ + ioPlus.printResult(a); + } else { + ioPlus.printResult(b); + } + + a = 10; + b = 8; + + if(a < b){ + ioPlus.printResult(a); + } else { + ioPlus.printResult(b); + } + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir new file mode 100644 index 0000000..79b8c8b --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir @@ -0,0 +1,31 @@ +import ioPlus; +SimpleIfElseStat { + + .construct SimpleIfElseStat().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +a.i32 :=.i32 5.i32; +b.i32 :=.i32 10.i32; + +if (a.i32 <.bool b.i32) goto ifbody_0; + invokestatic(ioPlus, "printResult", b.i32).V; +goto endif_0; +ifbody_0: + invokestatic(ioPlus, "printResult", a.i32).V; +endif_0: +a.i32 :=.i32 10.i32; +b.i32 :=.i32 8.i32; + +if (a.i32 <.bool b.i32) goto ifbody_1; + invokestatic(ioPlus, "printResult", b.i32).V; +goto endif_1; +ifbody_1: + invokestatic(ioPlus, "printResult", a.i32).V; +endif_1: + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.jmm new file mode 100644 index 0000000..9e5fc0f --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.jmm @@ -0,0 +1,18 @@ +import ioPlus; +class SimpleWhileStat { + + + public static void main(String[] args) { + int a; + int i; + + a = 3; + i = 0; + + while (i < a) { + ioPlus.printResult(i); + i = i + 1; + } + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir new file mode 100644 index 0000000..6573e29 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir @@ -0,0 +1,22 @@ +import ioPlus; +SimpleWhileStat { + + .construct SimpleWhileStat().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { +a.i32 :=.i32 3.i32; +i.i32 :=.i32 0.i32; +if (i.i32 <.bool a.i32) goto whilebody_0; +goto endwhile_0; +whilebody_0: +invokestatic(ioPlus, "printResult", i.i32).V; +i.i32 :=.i32 i.i32 +.i32 1.i32; +if (i.i32 <.bool a.i32) goto whilebody_0; +endwhile_0: + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.jmm new file mode 100644 index 0000000..fb7194a --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.jmm @@ -0,0 +1,46 @@ +import ioPlus; +class SwitchStat { + + + public int func(int a){ + if(a < 1){ + ioPlus.printResult(1); + } else { + if(a < 2){ + ioPlus.printResult(2); + } else { + if(a < 3){ + ioPlus.printResult(3); + } else { + if(a < 4){ + ioPlus.printResult(4); + } else { + if(a < 5){ + ioPlus.printResult(5); + } else { + if(a < 6){ + ioPlus.printResult(6); + } else { + ioPlus.printResult(7); + } + } + } + } + } + } + return 1; + } + + public static void main(String[] args) { + SwitchStat d; + int a; + d = new SwitchStat(); + a = d.func(0); + a = d.func(1); + a= d.func(2); + a= d.func(3); + a= d.func(4); + a= d.func(5); + a= d.func(6); + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir new file mode 100644 index 0000000..26a8dae --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir @@ -0,0 +1,62 @@ +import ioPlus; +SwitchStat { + + .construct SwitchStat().V { + invokespecial(this, "").V; + } + + .method public func(a.i32).i32 { + +if (a.i32 <.bool 1.i32) goto ifbody_5; + +if (a.i32 <.bool 2.i32) goto ifbody_4; + +if (a.i32 <.bool 3.i32) goto ifbody_3; + +if (a.i32 <.bool 4.i32) goto ifbody_2; + +if (a.i32 <.bool 5.i32) goto ifbody_1; + +if (a.i32 <.bool 6.i32) goto ifbody_0; + invokestatic(ioPlus, "printResult", 7.i32).V; +goto endif_0; +ifbody_0: + invokestatic(ioPlus, "printResult", 6.i32).V; +endif_0: +goto endif_1; +ifbody_1: + invokestatic(ioPlus, "printResult", 5.i32).V; +endif_1: +goto endif_2; +ifbody_2: + invokestatic(ioPlus, "printResult", 4.i32).V; +endif_2: +goto endif_3; +ifbody_3: + invokestatic(ioPlus, "printResult", 3.i32).V; +endif_3: +goto endif_4; +ifbody_4: + invokestatic(ioPlus, "printResult", 2.i32).V; +endif_4: +goto endif_5; +ifbody_5: + invokestatic(ioPlus, "printResult", 1.i32).V; +endif_5: +ret.i32 1.i32; + } + .method public static main(args.array.String).V { +d.SwitchStat :=.SwitchStat new(SwitchStat).SwitchStat; +invokespecial(d.SwitchStat,"").V; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 0.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 1.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 2.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 3.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 4.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 5.i32).i32; +a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 6.i32).i32; + +ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.jmm new file mode 100644 index 0000000..dab4682 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.jmm @@ -0,0 +1,10 @@ +class LocalLimits{ + + public int func(int a, int b){ + int j; + + a = b + 10 * (3 + this.func(3,4)); + j = this.func(3,4); + return 1; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.ollir new file mode 100644 index 0000000..f5bd655 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/limits/LocalLimits.ollir @@ -0,0 +1,16 @@ +LocalLimits { + + .construct LocalLimits().V { + invokespecial(this, "").V; + } + + .method public func(a.i32, b.i32).i32 { +temp6.i32 :=.i32 invokevirtual(this, "func", 3.i32, 4.i32).i32.i32.i32; +temp5.i32 :=.i32 3.i32 +.i32 temp6.i32; +temp3.i32 :=.i32 10.i32 *.i32 temp5.i32; +a.i32 :=.i32 b.i32 +.i32 temp3.i32; +j.i32 :=.i32 invokevirtual(this, "func", 3.i32, 4.i32).i32; +ret.i32 1.i32; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropSimple.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropSimple.jmm new file mode 100644 index 0000000..c5edb0b --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropSimple.jmm @@ -0,0 +1,10 @@ +class PropSimple { + public int foo(){ + int a; + a = 10; + return a; + } + public static void main(String[] args) { + + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropWithLoop.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropWithLoop.jmm new file mode 100644 index 0000000..e7e2382 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/const_prop/PropWithLoop.jmm @@ -0,0 +1,16 @@ +class PropWithLoop { + public int foo(){ + int a; + int i; + int res; + a = 10; + i = 0; + while (i < a){ + i=i+1; + } + res = i*a; + return res; + } + public static void main(String[] args) { + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_bipush_6.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_bipush_6.jmm new file mode 100644 index 0000000..47bceb6 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_bipush_6.jmm @@ -0,0 +1,7 @@ +class InstSelection_bipush_6 { + public int foo() { + int a; + a = 6; + return a; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iconst_0.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iconst_0.jmm new file mode 100644 index 0000000..ef594de --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iconst_0.jmm @@ -0,0 +1,7 @@ +class InstSelection_iconst_0 { + public int foo() { + int a; + a = 0; + return a; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_if_lt.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_if_lt.jmm new file mode 100644 index 0000000..e8e6e12 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_if_lt.jmm @@ -0,0 +1,12 @@ +class InstSelection_if_lt { + public static void main(String[] args) { + int a; + a = 0; + + if(a < 0) { + a = 1; + } else { + a = 2; + } + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.jmm new file mode 100644 index 0000000..8baccf1 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.jmm @@ -0,0 +1,7 @@ +class InstSelection_iinc { + public static void main(String[] args) { + int i; + i = 2; + i = i+1; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_ldc_32768.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_ldc_32768.jmm new file mode 100644 index 0000000..400bcfc --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_ldc_32768.jmm @@ -0,0 +1,7 @@ +class InstSelection_ldc_32768 { + public int foo() { + int a; + a = 32768; + return a; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_load_1.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_load_1.jmm new file mode 100644 index 0000000..8bc276c --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_load_1.jmm @@ -0,0 +1,5 @@ +class InstSelection_load_1 { + public int foo(int a) { + return a; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_sipush_32767.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_sipush_32767.jmm new file mode 100644 index 0000000..66849f4 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_sipush_32767.jmm @@ -0,0 +1,7 @@ +class InstSelection_sipush_32767 { + public int foo() { + int a; + a = 32767; + return a; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_store_1.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_store_1.jmm new file mode 100644 index 0000000..8a93d17 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_store_1.jmm @@ -0,0 +1,6 @@ +class InstSelection_store_1 { + public int foo(int a) { + a = 2; + return 0; + } +} diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/reg_alloc/regalloc.jmm b/test/pt/up/fe/comp/cpf/5_optimizations/reg_alloc/regalloc.jmm new file mode 100644 index 0000000..c21050c --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/reg_alloc/regalloc.jmm @@ -0,0 +1,16 @@ +class RegAlloc { + public int soManyRegisters(int arg){ + int a; + int b; + int c; + int d; + a = 0; + b = a; + c = b; + d = c; + return d; + } + + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/Cpf1_ParserAndTree.java b/test/pt/up/fe/comp/cpf/Cpf1_ParserAndTree.java new file mode 100644 index 0000000..ebd1728 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/Cpf1_ParserAndTree.java @@ -0,0 +1,37 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp.cpf; + +import org.junit.Test; +import pt.up.fe.comp.CpUtils; +import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.jasmin.JasminResult; +import pt.up.fe.specs.util.SpecsIo; +import pt.up.fe.specs.util.SpecsStrings; + +public class Cpf1_ParserAndTree { + + static JasminResult getJmmResult(String filename) { + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/1_parser_and_tree/" + filename)); + } + + @Test + public void section1_OpPrecedence_1_AddMultConstants() { + var result = getJmmResult("AddMultConstants.jmm"); + TestUtils.noErrors(result.getReports()); + CpUtils.assertEquals("Wrong results", "7\n12\n9", SpecsStrings.normalizeFileContents(result.run(), true), + result); + } + +} diff --git a/test/pt/up/fe/comp/cpf/Cpf2_SemanticAnalysis.java b/test/pt/up/fe/comp/cpf/Cpf2_SemanticAnalysis.java new file mode 100644 index 0000000..b008444 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/Cpf2_SemanticAnalysis.java @@ -0,0 +1,127 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp.cpf; + +import org.junit.Test; +import pt.up.fe.comp.CpUtils; +import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.jasmin.JasminResult; +import pt.up.fe.specs.util.SpecsIo; + +import static org.junit.Assert.assertEquals; + +public class Cpf2_SemanticAnalysis { + + static JasminResult getJasminResult(String filename) { + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/2_semantic_analysis/" + filename)); + } + + static JmmSemanticsResult getSemanticsResult(String filename) { + return TestUtils.analyse(SpecsIo.getResource("pt/up/fe/comp/cpf/2_semantic_analysis/" + filename)); + } + + static JmmSemanticsResult test(String filename, boolean fail) { + var semantics = getSemanticsResult(filename); + if (fail) { + TestUtils.mustFail(semantics.getReports()); + } else { + TestUtils.noErrors(semantics.getReports()); + } + return semantics; + } + + @Test + public void section1_SymbolTable_Fields() { + var semantics = test("symboltable/MethodsAndFields.jmm", false); + var st = semantics.getSymbolTable(); + var fields = st.getFields(); + assertEquals(3, fields.size()); + var checkInt = 0; + var checkBool = 0; + var checkObj = 0; + System.out.println("FIELDS: " + fields); + for (var f : fields) { + switch (f.getType().getName()) { + case "MethodsAndFields": + checkObj++; + break; + case "boolean": + checkBool++; + break; + case "int": + checkInt++; + break; + } + } + ; + CpUtils.assertEquals("Field of type int", 1, checkInt, st); + CpUtils.assertEquals("Field of type boolean", 1, checkBool, st); + CpUtils.assertEquals("Field of type object", 1, checkObj, st); + + } + + @Test + public void section1_SymbolTable_Parameters() { + var semantics = test("symboltable/Parameters.jmm", false); + var st = semantics.getSymbolTable(); + var methods = st.getMethods(); + CpUtils.assertEquals("Number of methods", 1, methods.size(), st); + + var parameters = st.getParameters(methods.get(0)); + CpUtils.assertEquals("Number of parameters", 3, parameters.size(), st); + CpUtils.assertEquals("Parameter 1", "int", parameters.get(0).getType().getName(), st); + CpUtils.assertEquals("Parameter 2", "boolean", parameters.get(1).getType().getName(), st); + CpUtils.assertEquals("Parameter 3", "Parameters", parameters.get(2).getType().getName(), st); + } + + /** + * Test if fields are not being accessed from static methods. + */ + @Test + public void section2_Lookup_SuperWithImport() { + var semantics = test("import/ImportSuper.jmm", false); + CpUtils.assertEquals("Super", "Sup", semantics.getSymbolTable().getSuper(), semantics.getSymbolTable()); + } + + /** + * Test if fields are not being accessed from static methods. + */ + @Test + public void section2_Lookup_VarLookup_Field_Main_Fail() { + test("lookup/VarLookup_Field_Main_Fail.jmm", true); + } + + /** + * Test if the code can correctly lookup a local variable, even if there is a field with the same name. + */ + @Test + public void section2_Lookup_VarLookup_Local() { + var jasminResult = getJasminResult("lookup/VarLookup_Local.jmm"); + + assertEquals("10", jasminResult.run().trim()); + } + + /** + * Test if the code can correctly lookup a field. + */ + @Test + public void section2_Lookup_VarLookup_Field() { + var jasminResult = getJasminResult("lookup/VarLookup_Field.jmm"); + + CpUtils.assertEquals("Lookup of field", "10", jasminResult.run().trim(), jasminResult); + } + + +} diff --git a/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java b/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java new file mode 100644 index 0000000..bd4dd08 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java @@ -0,0 +1,176 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp.cpf; + +import org.junit.Test; +import org.specs.comp.ollir.*; +import pt.up.fe.comp.CpUtils; +import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.specs.util.SpecsIo; + +import java.util.stream.Collectors; + +public class Cpf3_Ollir { + + static OllirResult getOllirResult(String filename) { + return TestUtils.optimize(SpecsIo.getResource("pt/up/fe/comp/cpf/3_ollir/" + filename)); + } + + + /*checks if method declaration is correct (array)*/ + @Test + public void section1_Basic_Method_Declaration_Array() { + var result = getOllirResult("basic/BasicMethodsArray.jmm"); + + var method = CpUtils.getMethod(result, "func4"); + + CpUtils.assertEquals("Method return type", "int[]", CpUtils.toString(method.getReturnType()), result); + } + + + @Test + public void section2_Arithmetic_Simple_and() { + var ollirResult = getOllirResult("arithmetic/Arithmetic_and.jmm"); + + var method = CpUtils.getMethod(ollirResult, "main"); + + CpUtils.assertHasOperation(OperationType.ANDB, method, ollirResult); + } + + @Test + public void section2_Arithmetic_Simple_less() { + var ollirResult = getOllirResult("arithmetic/Arithmetic_less.jmm"); + + var method = CpUtils.getMethod(ollirResult, "main"); + + CpUtils.assertHasOperation(OperationType.LTH, method, ollirResult); + + } + + @Test + public void section3_ControlFlow_If_Simple_Single_goto() { + + var result = getOllirResult("control_flow/SimpleIfElseStat.jmm"); + + var method = CpUtils.getMethod(result, "func"); + + var branches = CpUtils.assertInstExists(CondBranchInstruction.class, method, result); + CpUtils.assertEquals("Number of branches", 1, branches.size(), result); + + var gotos = CpUtils.assertInstExists(GotoInstruction.class, method, result); + CpUtils.assertTrue("Has at least 1 goto", gotos.size() >= 1, result); + } + + @Test + public void section3_ControlFlow_If_Switch() { + + var result = getOllirResult("control_flow/SwitchStat.jmm"); + + var method = CpUtils.getMethod(result, "func"); + + var branches = CpUtils.assertInstExists(CondBranchInstruction.class, method, result); + CpUtils.assertEquals("Number of branches", 6, branches.size(), result); + + var gotos = CpUtils.assertInstExists(GotoInstruction.class, method, result); + CpUtils.assertTrue("Has at least 6 gotos", gotos.size() >= 6, result); + } + + @Test + public void section3_ControlFlow_While_Simple() { + + var result = getOllirResult("control_flow/SimpleWhileStat.jmm"); + + var method = CpUtils.getMethod(result, "func"); + + var branches = CpUtils.assertInstExists(CondBranchInstruction.class, method, result); + + CpUtils.assertTrue("Number of branches between 1 and 2", branches.size() > 0 && branches.size() < 3, result); + } + + /*checks if dynamic invocations work properly*/ + @Test + public void section4_Calls_Invoke_Virtual() { + var result = getOllirResult("calls/NoArgsFuncCall.jmm"); + + var method = CpUtils.getMethod(result, "bar"); + + var calls = CpUtils.assertInstExists(CallInstruction.class, method, result); + + CpUtils.assertEquals("Number of calls", 1, calls.size(), result); + + CpUtils.assertEquals("Invocation type of call", CallType.invokevirtual, calls.get(0).getInvocationType(), + result); + } + + /*checks if an array is correctly initialized*/ + @Test + public void section5_Arrays_Init_Array() { + var result = getOllirResult("arrays/ArrayInit.jmm"); + + var method = CpUtils.getMethod(result, "main"); + + var calls = CpUtils.assertInstExists(CallInstruction.class, method, result); + + CpUtils.assertEquals("Number of calls", 3, calls.size(), result); + + // Get new + var newCalls = calls.stream().filter(call -> call.getInvocationType() == CallType.NEW) + .collect(Collectors.toList()); + + CpUtils.assertEquals("Number of 'new' calls", 1, newCalls.size(), result); + + // Get length + var lengthCalls = calls.stream().filter(call -> call.getInvocationType() == CallType.arraylength) + .collect(Collectors.toList()); + + CpUtils.assertEquals("Number of 'arraylenght' calls", 1, lengthCalls.size(), result); + } + + /*checks if the access to the elements of array is correct*/ + @Test + public void section5_Arrays_Access_Array() { + var result = getOllirResult("arrays/ArrayAccess.jmm"); + + var method = CpUtils.getMethod(result, "foo"); + + var assigns = CpUtils.assertInstExists(AssignInstruction.class, method, result); + var numArrayStores = assigns.stream().filter(assign -> assign.getDest() instanceof ArrayOperand).count(); + CpUtils.assertEquals("Number of array stores", 5, numArrayStores, result); + + var numArrayReads = assigns.stream() + .flatMap(assign -> CpUtils.getElements(assign.getRhs()).stream()) + .filter(element -> element instanceof ArrayOperand).count(); + CpUtils.assertEquals("Number of array reads", 5, numArrayReads, result); + } + + /*checks multiple expressions as indexes to access the elements of an array*/ + @Test + public void section5_Arrays_Load_ComplexArrayAccess() { + // Just parse + var result = getOllirResult("arrays/ComplexArrayAccess.jmm"); + + var method = CpUtils.getMethod(result, "main"); + + var assigns = CpUtils.assertInstExists(AssignInstruction.class, method, result); + var numArrayStores = assigns.stream().filter(assign -> assign.getDest() instanceof ArrayOperand).count(); + CpUtils.assertEquals("Number of array stores", 5, numArrayStores, result); + + var numArrayReads = assigns.stream() + .flatMap(assign -> CpUtils.getElements(assign.getRhs()).stream()) + .filter(element -> element instanceof ArrayOperand).count(); + CpUtils.assertEquals("Number of array reads", 6, numArrayReads, result); + } + +} diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java new file mode 100644 index 0000000..b994674 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -0,0 +1,240 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp.cpf; + +import org.junit.Test; +import pt.up.fe.comp.CpUtils; +import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.jasmin.JasminResult; +import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.specs.util.SpecsIo; +import pt.up.fe.specs.util.SpecsStrings; + +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class Cpf4_Jasmin { + + private static boolean USE_OLLIR_EXPERIMENTAL = false; + + public static void enableOllirInputs() { + USE_OLLIR_EXPERIMENTAL = true; + } + + public static boolean useOllirInputs() { + return USE_OLLIR_EXPERIMENTAL; + } + + static JasminResult getJasminResult(String filename) { + if (USE_OLLIR_EXPERIMENTAL) { + filename = SpecsIo.removeExtension(filename) + ".ollir"; + return TestUtils.backend(new OllirResult(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename), + Collections.emptyMap())); + } + + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename)); + } + + + private static final String JASMIN_METHOD_REGEX_PREFIX = "\\.method\\s+((public|private)\\s+)?(\\w+)\\(\\)"; + + /*checks if method declaration is correct (array)*/ + @Test + public void section1_Basic_Method_Declaration_Array() { + JasminResult jasminResult = getJasminResult("basic/BasicMethodsArray.jmm"); + CpUtils.matches(jasminResult, JASMIN_METHOD_REGEX_PREFIX + "\\[I"); + } + + /*checks if the index for loading a argument is correct (should be 1) */ + @Test + public void section2_Arithmetic_BytecodeIndex_IloadArg() { + var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes1.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + + int iloadIndex = CpUtils.getBytecodeIndex("iload", methodCode); + assertEquals(1, iloadIndex); + } + + /*checks if the index for storing a var is correct (should be > 1) */ + @Test + public void section2_Arithmetic_BytecodeIndex_IstoreVar() { + var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes2.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + + int istoreIndex = CpUtils.getBytecodeIndex("istore", methodCode); + assertTrue("Expected index to be greater than one, is " + istoreIndex, istoreIndex > 1); + } + + @Test + public void section2_Arithmetic_Simple_and() { + CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_and.jmm"), "0"); + } + + @Test + public void section2_Arithmetic_Simple_less() { + CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_less.jmm"), "1"); + } + + + /*checks if an addition is correct (more than 2 values)*/ + @Test + public void section3_ControlFlow_If_Simple() { + CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseStat.jmm"), "Result: 5\nResult: 8"); + } + + /*checks if an addition is correct (more than 2 values)*/ + @Test + public void section3_ControlFlow_If_Not_Simple() { + CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseNot.jmm"), "10\n200"); + } + + /*checks if the code of a simple WHILE statement is well executed */ + @Test + public void section3_ControlFlow_While_Simple() { + CpUtils.runJasmin(getJasminResult("control_flow/SimpleWhileStat.jmm"), "Result: 0\nResult: 1\nResult: 2"); + } + + /*checks if the code of a more complex IF ELSE statement (similar a switch statement) is well executed */ + @Test + public void section3_ControlFlow_Mixed_Switch() { + CpUtils.runJasmin(getJasminResult("control_flow/SwitchStat.jmm"), + "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5\nResult: 6\nResult: 7"); + } + + /*checks if the code of a more complex IF ELSE statement (similar a switch statement) is well executed */ + @Test + public void section3_ControlFlow_Mixed_Nested() { + CpUtils.runJasmin(getJasminResult("control_flow/IfWhileNested.jmm"), "Result: 1\nResult: 2\nResult: 1"); + } + + /*checks if the code of a call to a function with multiple arguments (using boolean expressions in the call) is + well executed*/ + @Test + public void section4_Calls_Misc_ConditionArgs() { + CpUtils.runJasmin(getJasminResult("calls/ConditionArgsFuncCall.jmm"), "Result: 10"); + + } + + + /*checks if an array is correctly initialized*/ + @Test + public void section5_Arrays_Init_Array() { + CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.jmm"), "Result: 5"); + + } + + /*checks if the access to the elements of array is correct*/ + @Test + public void section5_Arrays_Store_Array() { + CpUtils.runJasmin(getJasminResult("arrays/ArrayAccess.jmm"), + "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); + + } + + /*checks multiple expressions as indexes to access the elements of an array*/ + @Test + public void section5_Arrays_Load_ComplexArrayAccess() { + CpUtils.runJasmin(getJasminResult("arrays/ComplexArrayAccess.jmm"), + "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); + + } + + /*checks if array has correct signature ?*/ + @Test + public void section5_Arrays_Signature_ArrayAsArg() { + var jasminResult = getJasminResult("arrays/ArrayAsArgCode.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + + CpUtils.matches(methodCode, "invokevirtual\\s+ArrayAsArg(/|\\.)(\\w+)\\(\\[I\\)I"); + } + + /*checks if array is being passed correctly as an argument to a function*/ + @Test + public void section5_Arrays_As_Arg_Simple() { + CpUtils.runJasmin(getJasminResult("arrays/ArrayAsArg.jmm"), "Result: 2"); + } + + /*checks if array is being passed correctly as an argument to a function (index of aload > 1)*/ + @Test + public void section5_Arrays_As_Arg_Aload() { + var jasminResult = getJasminResult("arrays/ArrayAsArgCode.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + + int aloadIndex = CpUtils.getBytecodeIndex("aload", methodCode); + assertTrue("Expected aload index to be greater than 1, is " + aloadIndex + ":\n" + methodCode, aloadIndex > 1); + } + + /*checks if the .limits locals is not a const 99 value */ + @Test + public void section6_Limits_Locals_Not_99() { + var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + var numLocals = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitLocalsRegex(), 1)); + assertTrue("limit locals should be less than 99:\n" + methodCode, numLocals >= 0 && numLocals < 99); + + // Make sure the code compiles + jasminResult.compile(); + } + + /*checks if the .limits locals is the expected value (with a tolerance of 2) */ + @Test + public void section6_Limits_Locals_Simple() { + + var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + var numLocals = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitLocalsRegex(), 1)); + + // Find store or load with numLocals - 1 + var regex = CpUtils.getLocalsRegex(numLocals); + CpUtils.matches(methodCode, regex); + + // Makes sure the code compiles + jasminResult.compile(); + } + + /*checks if the .limits stack is not a const 99 value */ + @Test + public void section6_Limits_Stack_Not_99() { + var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + var numStack = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitStackRegex(), 1)); + assertTrue("limit stack should be less than 99:\n" + methodCode, numStack >= 0 && numStack < 99); + + // Make sure the code compiles + jasminResult.compile(); + } + + /*checks if the .limits stack is the expected value (with a tolerance of 2) */ + @Test + public void section6_Limits_Stack_Simple() { + + var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var methodCode = CpUtils.getJasminMethod(jasminResult); + var numStack = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitStackRegex(), 1)); + + int expectedLimit = 3; + int errorMargin = 2; + int upperLimit = expectedLimit + errorMargin; + + assertTrue( + "limit stack should be = " + expectedLimit + " (accepted if <= " + upperLimit + + "), but is " + numStack + ":\n" + methodCode, + numStack <= upperLimit && numStack >= expectedLimit); + + // Make sure the code compiles + jasminResult.compile(); + } +} diff --git a/test/pt/up/fe/comp/cpf/Cpf5_Optimizations.java b/test/pt/up/fe/comp/cpf/Cpf5_Optimizations.java new file mode 100644 index 0000000..1067551 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/Cpf5_Optimizations.java @@ -0,0 +1,196 @@ +/** + * Copyright 2022 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. under the License. + */ + +package pt.up.fe.comp.cpf; + +import org.junit.Test; +import pt.up.fe.comp.CpUtils; +import pt.up.fe.comp.TestUtils; +import pt.up.fe.comp.jmm.jasmin.JasminResult; +import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.specs.util.SpecsIo; +import pt.up.fe.specs.util.SpecsStrings; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Cpf5_Optimizations { + + static OllirResult getOllirResult(String filename) { + return TestUtils.optimize(SpecsIo.getResource("pt/up/fe/comp/cpf/5_optimizations/" + filename)); + } + + static JasminResult getJasminResult(String filename) { + String resource = SpecsIo.getResource("pt/up/fe/comp/cpf/5_optimizations/" + filename); + return TestUtils.backend(resource); + } + + static JasminResult getJasminResultOpt(String filename) { + Map config = new HashMap<>(); + config.put("optimize", "true"); + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/5_optimizations/" + filename), config); + } + + static JasminResult getJasminResultReg(String filename, int numReg) { + Map config = new HashMap<>(); + config.put("registerAllocation", String.valueOf(numReg)); + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/5_optimizations/" + filename), config); + } + + /** + * Test if small integers are loaded with iconst + */ + @Test + public void section1_InstSelection_iconst_0() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_iconst_0.jmm"); + CpUtils.matches(jasminResult, "iconst_0"); + + } + + + /** + * Test if integer 6 is loaded with bipush + */ + @Test + public void section1_InstSelection_bipush_6() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_bipush_6.jmm"); + CpUtils.matches(jasminResult, "bipush\\s6"); + } + + + /** + * Test if integer 32767 is loaded with sipush + */ + @Test + public void section1_InstSelection_sipush_32767() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_sipush_32767.jmm"); + CpUtils.matches(jasminResult, "sipush\\s32767"); + } + + /** + * Test if integer 32768 is loaded with ldc + */ + @Test + public void section1_InstSelection_ldc_32768() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_ldc_32768.jmm"); + CpUtils.matches(jasminResult, "ldc\\s32768"); + } + + @Test + public void section1_InstSelection_IfLt() { + var jasminResult = getJasminResult("inst_selection/InstSelection_if_lt.jmm"); + CpUtils.matches(jasminResult, "(iflt|ifge)"); + } + + /** + * Test if iinc is used when incrementing a variable + */ + @Test + public void section1_InstSelection_iinc() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_iinc.jmm"); + CpUtils.matches(jasminResult, "iinc\\s+\\w+\\s+1"); + + } + + /** + * Test if iload_1 is used. + */ + @Test + public void section1_InstSelection_iload_1() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_load_1.jmm"); + CpUtils.matches(jasminResult, "iload_1"); + } + + + /** + * Test if istore_1 is used. + */ + @Test + public void section1_InstSelection_istore_1() { + JasminResult jasminResult = getJasminResult("inst_selection/InstSelection_store_1.jmm"); + CpUtils.matches(jasminResult, "istore_1"); + + } + + + @Test + public void section2_RegAlloc_AtMostRequestedNumber() { + + String filename = "reg_alloc/regalloc.jmm"; + int expectedNumReg = 3; + + JasminResult original = getJasminResult(filename); + JasminResult optimized = getJasminResultReg(filename, expectedNumReg); + + CpUtils.assertNotEquals("Expected code to change with -r flag\n\nOriginal code:\n" + original.getJasminCode(), + original.getJasminCode(), optimized.getJasminCode(), + optimized); + + String method = CpUtils.getJasminMethod(optimized, "soManyRegisters"); + Pattern pattern = Pattern.compile("\\.limit\\s+locals\\s+(\\d+)\\s+"); + Matcher matcher = pattern.matcher(method); + CpUtils.assertTrue("Expected to find correct .limit locals directive", + matcher.find(), + optimized); + + String captured = matcher.group(1); + CpUtils.assertNotNull("Expected to find correct .limit locals directive", + captured, + optimized); + + Integer actualNumReg = SpecsStrings.decodeInteger(captured); + CpUtils.assertNotNull("Could not convert locals limit to integer", + actualNumReg, + optimized); + + CpUtils.assertTrue("Expected number of locals in 'soManyRegisters' to be <= than " + expectedNumReg, + actualNumReg <= expectedNumReg, + optimized); + } + + + @Test + public void section3_ConstProp_Simple() { + + String filename = "const_prop/PropSimple.jmm"; + + JasminResult original = getJasminResult(filename); + JasminResult optimized = getJasminResultOpt(filename); + + CpUtils.assertNotEquals("Expected code to change with -o flag\n\nOriginal code:\n" + original.getJasminCode(), + original.getJasminCode(), optimized.getJasminCode(), + optimized); + + CpUtils.matches(optimized, "(bipush|sipush|ldc) 10\\s+ireturn"); + } + + + @Test + public void section3_ConstProp_WithLoop() { + + String filename = "const_prop/PropWithLoop.jmm"; + + JasminResult original = getJasminResult(filename); + JasminResult optimized = getJasminResultOpt(filename); + + CpUtils.assertNotEquals("Expected code to change with -o flag\n\nOriginal code:\n" + original.getJasminCode(), + original.getJasminCode(), optimized.getJasminCode(), + optimized); + + CpUtils.matches(optimized, "(bipush|sipush|ldc) 10\\s+imul"); + } + + +} From 8a322d373aef5ddcf6f1b98de23042061f81341a Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sun, 23 Apr 2023 23:23:38 +0100 Subject: [PATCH 071/253] return statements --- src/main/pt/up/fe/comp2023/Optimization.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index e935a3b..44a1bf9 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -254,8 +254,7 @@ private Void dealWithParamDecl(JmmNode jmmNode, Void unused) { } private Void dealWithMethod(JmmNode jmmNode, Void unused) { code += "\t.method public " + jmmNode.get("methodname") + "("; - - // Params + // Parameters List parameters = table.getParameters(jmmNode.get("methodname")); for (int i = 0; i< parameters.size(); i++){ Symbol parameter = parameters.get(i); @@ -265,13 +264,18 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { } code += ")"; // Return Type of Method - code += OllirUtils.ollirTypes(table.getReturnType(jmmNode.get("methodname"))) + " {\n"; + String returnType = OllirUtils.ollirTypes(table.getReturnType(jmmNode.get("methodname"))); + code += returnType + " {\n"; - for (var child : jmmNode.getChildren()) - visit(child); + for (int i = 0; i < jmmNode.getChildren().size() - 1; i++ ) + visit(jmmNode.getChildren().get(i)); - code += "\t}\n"; + // Return + int indexReturn = jmmNode.getChildren().size() - 1; + code += "\t\tret" + returnType + " "; + visit(jmmNode.getChildren().get(indexReturn)); // Visit the expression after "return" keyword + code += ";\n\t}\n"; return null; } @@ -283,6 +287,7 @@ private Void dealWithMainMethod(JmmNode jmmNode, Void unused) { code += "\t}\n"; return null; } + private Void dealWithClass(JmmNode jmmNode, Void unused) { // Imports List imports = table.getImports(); From a3d24d783b310e52954cc54f2d7564ba48118323 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 24 Apr 2023 11:18:28 +0100 Subject: [PATCH 072/253] id ollir implementation --- src/main/pt/up/fe/comp2023/Optimization.java | 33 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 44a1bf9..6866745 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -65,8 +65,37 @@ protected void buildVisitor() { } private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); + var method = jmmNode.getAncestor("MethodDecl"); + Symbol var = null; + + if (method.isPresent()) { + List localVarClass = table.getLocalVariables(method.get().get("methodname")); + List paramsOnClass = table.getParameters(method.get().get("methodname")); + + // If it's not any of the above, then consider it's in an import + // Check if local var + for (Symbol lv : localVarClass) + if (lv.getName().equals(jmmNode.get("value"))) + var = lv; + + // If not local var, then check if param + if (var == null) + for (Symbol p : paramsOnClass) + if (p.getName().equals(jmmNode.get("value"))) + var = p; + + + } + + List fields = table.getFields(); + // If not local nor param, check if field + if (var == null) + for (Symbol f : fields) + if (f.getName().equals(jmmNode.get("value"))) + var = f; + if (var != null) + code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + return null; } From 3dff92d040970659129eef959247d963d4f2344b Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 24 Apr 2023 11:24:16 +0100 Subject: [PATCH 073/253] assignment ollir hotfix --- src/main/pt/up/fe/comp2023/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 6866745..be1c782 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -241,7 +241,7 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge String left = jmmNode.get("varname"); JmmNode right = jmmNode.getChildren().get(0); - code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " := "; + code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; visit(right); code += ";\n"; return null; From 19454fc2d0dcf434e4c5803678fc88b50f8767ab Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Mon, 24 Apr 2023 12:19:25 +0100 Subject: [PATCH 074/253] Jasmin CPF tests now read a .ollir instead of .jmm, removes OLLIR test --- test/pt/up/fe/comp/cpf/Cpf3_Ollir.java | 20 +---- test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 102 ++++++++++++++++++------ 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java b/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java index bd4dd08..d9f4951 100644 --- a/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java +++ b/test/pt/up/fe/comp/cpf/Cpf3_Ollir.java @@ -99,24 +99,10 @@ public void section3_ControlFlow_While_Simple() { CpUtils.assertTrue("Number of branches between 1 and 2", branches.size() > 0 && branches.size() < 3, result); } - /*checks if dynamic invocations work properly*/ - @Test - public void section4_Calls_Invoke_Virtual() { - var result = getOllirResult("calls/NoArgsFuncCall.jmm"); - - var method = CpUtils.getMethod(result, "bar"); - - var calls = CpUtils.assertInstExists(CallInstruction.class, method, result); - - CpUtils.assertEquals("Number of calls", 1, calls.size(), result); - - CpUtils.assertEquals("Invocation type of call", CallType.invokevirtual, calls.get(0).getInvocationType(), - result); - } /*checks if an array is correctly initialized*/ @Test - public void section5_Arrays_Init_Array() { + public void section4_Arrays_Init_Array() { var result = getOllirResult("arrays/ArrayInit.jmm"); var method = CpUtils.getMethod(result, "main"); @@ -140,7 +126,7 @@ public void section5_Arrays_Init_Array() { /*checks if the access to the elements of array is correct*/ @Test - public void section5_Arrays_Access_Array() { + public void section4_Arrays_Access_Array() { var result = getOllirResult("arrays/ArrayAccess.jmm"); var method = CpUtils.getMethod(result, "foo"); @@ -157,7 +143,7 @@ public void section5_Arrays_Access_Array() { /*checks multiple expressions as indexes to access the elements of an array*/ @Test - public void section5_Arrays_Load_ComplexArrayAccess() { + public void section4_Arrays_Load_ComplexArrayAccess() { // Just parse var result = getOllirResult("arrays/ComplexArrayAccess.jmm"); diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java index b994674..f4295f3 100644 --- a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -18,8 +18,10 @@ import pt.up.fe.comp.TestUtils; import pt.up.fe.comp.jmm.jasmin.JasminResult; import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.specs.util.SpecsCheck; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsStrings; +import utils.ProjectTestUtils; import java.util.Collections; @@ -28,8 +30,8 @@ public class Cpf4_Jasmin { - private static boolean USE_OLLIR_EXPERIMENTAL = false; - + // private static boolean USE_OLLIR_EXPERIMENTAL = false; +/* public static void enableOllirInputs() { USE_OLLIR_EXPERIMENTAL = true; } @@ -37,8 +39,9 @@ public static void enableOllirInputs() { public static boolean useOllirInputs() { return USE_OLLIR_EXPERIMENTAL; } - +*/ static JasminResult getJasminResult(String filename) { + /* if (USE_OLLIR_EXPERIMENTAL) { filename = SpecsIo.removeExtension(filename) + ".ollir"; return TestUtils.backend(new OllirResult(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename), @@ -46,6 +49,57 @@ static JasminResult getJasminResult(String filename) { } return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename)); +*/ + + var resource = "pt/up/fe/comp/cpf/4_jasmin/" + filename; + + SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); + + // If AstToJasmin pipeline, change name of the resource and execute other test + if (TestUtils.hasAstToJasminClass()) { + + // Rename resource + var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; + + // Test Jmm resource + var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); + + return result; + } + + var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); + + var result = TestUtils.backend(ollirResult); + + return result; + + } + + public static void testOllirToJasmin(String resource, String expectedOutput) { + SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); + + // If AstToJasmin pipeline, change name of the resource and execute other test + if (TestUtils.hasAstToJasminClass()) { + + // Rename resource + var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; + + // Test Jmm resource + var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); + ProjectTestUtils.runJasmin(result, expectedOutput); + + return; + } + + var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); + + var result = TestUtils.backend(ollirResult); + + ProjectTestUtils.runJasmin(result, null); + } + + public static void testOllirToJasmin(String resource) { + testOllirToJasmin(resource, null); } @@ -54,14 +108,14 @@ static JasminResult getJasminResult(String filename) { /*checks if method declaration is correct (array)*/ @Test public void section1_Basic_Method_Declaration_Array() { - JasminResult jasminResult = getJasminResult("basic/BasicMethodsArray.jmm"); + JasminResult jasminResult = getJasminResult("basic/BasicMethodsArray.ollir"); CpUtils.matches(jasminResult, JASMIN_METHOD_REGEX_PREFIX + "\\[I"); } /*checks if the index for loading a argument is correct (should be 1) */ @Test public void section2_Arithmetic_BytecodeIndex_IloadArg() { - var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes1.jmm"); + var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes1.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); int iloadIndex = CpUtils.getBytecodeIndex("iload", methodCode); @@ -71,7 +125,7 @@ public void section2_Arithmetic_BytecodeIndex_IloadArg() { /*checks if the index for storing a var is correct (should be > 1) */ @Test public void section2_Arithmetic_BytecodeIndex_IstoreVar() { - var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes2.jmm"); + var jasminResult = getJasminResult("arithmetic/ByteCodeIndexes2.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); int istoreIndex = CpUtils.getBytecodeIndex("istore", methodCode); @@ -80,51 +134,51 @@ public void section2_Arithmetic_BytecodeIndex_IstoreVar() { @Test public void section2_Arithmetic_Simple_and() { - CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_and.jmm"), "0"); + CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_and.ollir"), "0"); } @Test public void section2_Arithmetic_Simple_less() { - CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_less.jmm"), "1"); + CpUtils.runJasmin(getJasminResult("arithmetic/Arithmetic_less.ollir"), "1"); } /*checks if an addition is correct (more than 2 values)*/ @Test public void section3_ControlFlow_If_Simple() { - CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseStat.jmm"), "Result: 5\nResult: 8"); + CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseStat.ollir"), "Result: 5\nResult: 8"); } /*checks if an addition is correct (more than 2 values)*/ @Test public void section3_ControlFlow_If_Not_Simple() { - CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseNot.jmm"), "10\n200"); + CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseNot.ollir"), "10\n200"); } /*checks if the code of a simple WHILE statement is well executed */ @Test public void section3_ControlFlow_While_Simple() { - CpUtils.runJasmin(getJasminResult("control_flow/SimpleWhileStat.jmm"), "Result: 0\nResult: 1\nResult: 2"); + CpUtils.runJasmin(getJasminResult("control_flow/SimpleWhileStat.ollir"), "Result: 0\nResult: 1\nResult: 2"); } /*checks if the code of a more complex IF ELSE statement (similar a switch statement) is well executed */ @Test public void section3_ControlFlow_Mixed_Switch() { - CpUtils.runJasmin(getJasminResult("control_flow/SwitchStat.jmm"), + CpUtils.runJasmin(getJasminResult("control_flow/SwitchStat.ollir"), "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5\nResult: 6\nResult: 7"); } /*checks if the code of a more complex IF ELSE statement (similar a switch statement) is well executed */ @Test public void section3_ControlFlow_Mixed_Nested() { - CpUtils.runJasmin(getJasminResult("control_flow/IfWhileNested.jmm"), "Result: 1\nResult: 2\nResult: 1"); + CpUtils.runJasmin(getJasminResult("control_flow/IfWhileNested.ollir"), "Result: 1\nResult: 2\nResult: 1"); } /*checks if the code of a call to a function with multiple arguments (using boolean expressions in the call) is well executed*/ @Test public void section4_Calls_Misc_ConditionArgs() { - CpUtils.runJasmin(getJasminResult("calls/ConditionArgsFuncCall.jmm"), "Result: 10"); + CpUtils.runJasmin(getJasminResult("calls/ConditionArgsFuncCall.ollir"), "Result: 10"); } @@ -132,14 +186,14 @@ public void section4_Calls_Misc_ConditionArgs() { /*checks if an array is correctly initialized*/ @Test public void section5_Arrays_Init_Array() { - CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.jmm"), "Result: 5"); + CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); } /*checks if the access to the elements of array is correct*/ @Test public void section5_Arrays_Store_Array() { - CpUtils.runJasmin(getJasminResult("arrays/ArrayAccess.jmm"), + CpUtils.runJasmin(getJasminResult("arrays/ArrayAccess.ollir"), "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); } @@ -147,7 +201,7 @@ public void section5_Arrays_Store_Array() { /*checks multiple expressions as indexes to access the elements of an array*/ @Test public void section5_Arrays_Load_ComplexArrayAccess() { - CpUtils.runJasmin(getJasminResult("arrays/ComplexArrayAccess.jmm"), + CpUtils.runJasmin(getJasminResult("arrays/ComplexArrayAccess.ollir"), "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); } @@ -155,7 +209,7 @@ public void section5_Arrays_Load_ComplexArrayAccess() { /*checks if array has correct signature ?*/ @Test public void section5_Arrays_Signature_ArrayAsArg() { - var jasminResult = getJasminResult("arrays/ArrayAsArgCode.jmm"); + var jasminResult = getJasminResult("arrays/ArrayAsArgCode.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); CpUtils.matches(methodCode, "invokevirtual\\s+ArrayAsArg(/|\\.)(\\w+)\\(\\[I\\)I"); @@ -164,13 +218,13 @@ public void section5_Arrays_Signature_ArrayAsArg() { /*checks if array is being passed correctly as an argument to a function*/ @Test public void section5_Arrays_As_Arg_Simple() { - CpUtils.runJasmin(getJasminResult("arrays/ArrayAsArg.jmm"), "Result: 2"); + CpUtils.runJasmin(getJasminResult("arrays/ArrayAsArg.ollir"), "Result: 2"); } /*checks if array is being passed correctly as an argument to a function (index of aload > 1)*/ @Test public void section5_Arrays_As_Arg_Aload() { - var jasminResult = getJasminResult("arrays/ArrayAsArgCode.jmm"); + var jasminResult = getJasminResult("arrays/ArrayAsArgCode.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); int aloadIndex = CpUtils.getBytecodeIndex("aload", methodCode); @@ -180,7 +234,7 @@ public void section5_Arrays_As_Arg_Aload() { /*checks if the .limits locals is not a const 99 value */ @Test public void section6_Limits_Locals_Not_99() { - var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var jasminResult = getJasminResult("limits/LocalLimits.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); var numLocals = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitLocalsRegex(), 1)); assertTrue("limit locals should be less than 99:\n" + methodCode, numLocals >= 0 && numLocals < 99); @@ -193,7 +247,7 @@ public void section6_Limits_Locals_Not_99() { @Test public void section6_Limits_Locals_Simple() { - var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var jasminResult = getJasminResult("limits/LocalLimits.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); var numLocals = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitLocalsRegex(), 1)); @@ -208,7 +262,7 @@ public void section6_Limits_Locals_Simple() { /*checks if the .limits stack is not a const 99 value */ @Test public void section6_Limits_Stack_Not_99() { - var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var jasminResult = getJasminResult("limits/LocalLimits.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); var numStack = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitStackRegex(), 1)); assertTrue("limit stack should be less than 99:\n" + methodCode, numStack >= 0 && numStack < 99); @@ -221,7 +275,7 @@ public void section6_Limits_Stack_Not_99() { @Test public void section6_Limits_Stack_Simple() { - var jasminResult = getJasminResult("limits/LocalLimits.jmm"); + var jasminResult = getJasminResult("limits/LocalLimits.ollir"); var methodCode = CpUtils.getJasminMethod(jasminResult); var numStack = Integer.parseInt(SpecsStrings.getRegexGroup(methodCode, CpUtils.getLimitStackRegex(), 1)); From 2cb6916b16eecbda0642b388770fcada270ac0ba Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 25 Apr 2023 20:25:56 +0100 Subject: [PATCH 075/253] method call --- src/main/pt/up/fe/comp2023/Launcher.java | 9 ++-- src/main/pt/up/fe/comp2023/Optimization.java | 50 ++++++++++++++++--- .../cp2/ollir/CompileMethodInvocation.jmm | 1 + 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index cfdc125..4582fb3 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -68,13 +68,12 @@ public static void main(String[] args) { // Check if there are semantic errors TestUtils.noErrors(semanticsResult.getReports()); - // TODO: Add Ollir - Optimization optimization = new Optimization(); - OllirResult ollirResult = optimization.toOllir(semanticsResult); + Optimization optimization = new Optimization(); + OllirResult ollirResult = optimization.toOllir(semanticsResult); JasminGenerator jasminGenerator = new JasminGenerator(); - // JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); - // System.out.println(jasminResult.getJasminCode()); + JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); + System.out.println(jasminResult.getJasminCode()); // TestUtils.runJasmin(jasminResult.getJasminCode()); diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index be1c782..049038f 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -72,7 +72,6 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { List localVarClass = table.getLocalVariables(method.get().get("methodname")); List paramsOnClass = table.getParameters(method.get().get("methodname")); - // If it's not any of the above, then consider it's in an import // Check if local var for (Symbol lv : localVarClass) if (lv.getName().equals(jmmNode.get("value"))) @@ -93,16 +92,17 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { for (Symbol f : fields) if (f.getName().equals(jmmNode.get("value"))) var = f; + // If found, send it with its type if (var != null) code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); - + // If it's not any of the above, then consider it's in an import + else + code += jmmNode.get("value"); return null; } private Void dealWithThis(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); - + code += "this"; return null; } @@ -130,8 +130,43 @@ private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { } private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) + JmmNode left = jmmNode.getJmmChild(0); + String methodName = jmmNode.get("methodcall"); + String returnType = ".V"; + + if (table.getMethods().contains(methodName)) + for (String m : table.getMethods()) + if (m == methodName) + returnType = OllirUtils.ollirTypes(table.getReturnType(m)); + else + returnType = ".V"; + + if (left.getKind().equals("This")){ + code += "\t\tinvokevirtual("; + + } + else { + if (table.getImports().contains(left.get("value"))) + code += "\t\tinvokestatic(" ; + else + code += "\t\tinvokevirtual(" ; + } + + // The first arg is the object that calls the method and the second is the name of the method called + code += left.get("value") + " , \"" + methodName +"\""; + + // The following arguments can exist or not they are the arguments of the method called + JmmNode params = jmmNode.getJmmChild(1); + for (var child : params.getChildren()) { + code += " , "; visit(child); + } + + code += ")\n"; + + // Type of method + code += returnType + ";"; + return null; } @@ -236,7 +271,7 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge } // Throw error if (var == null) - throw new NullPointerException("Variable 'var' is not a LOCAL VAR or a PARAMETER or a FIELD "); + throw new NullPointerException("Variable 'var' is not a LOCAL VAR or a PARAMETER or a FIELD"); String left = jmmNode.get("varname"); @@ -269,6 +304,7 @@ private Void dealWithVarDecl(JmmNode jmmNode, Void unused) { } private Void dealWithMethodCallParam(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) visit(child); diff --git a/test/pt/up/fe/comp/cp2/ollir/CompileMethodInvocation.jmm b/test/pt/up/fe/comp/cp2/ollir/CompileMethodInvocation.jmm index a5aced4..80a0f61 100644 --- a/test/pt/up/fe/comp/cp2/ollir/CompileMethodInvocation.jmm +++ b/test/pt/up/fe/comp/cp2/ollir/CompileMethodInvocation.jmm @@ -16,3 +16,4 @@ class CompileMethodInvocation { return 0; } } + From b44f511c913d6132edcd3c7cf66a64c5abfd0f9f Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:19:59 +0100 Subject: [PATCH 076/253] hotfix before trying to see if test only passes if i check ancestor's type --- src/main/pt/up/fe/comp2023/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 049038f..aabafba 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -136,7 +136,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { if (table.getMethods().contains(methodName)) for (String m : table.getMethods()) - if (m == methodName) + if (m.equals(methodName)) returnType = OllirUtils.ollirTypes(table.getReturnType(m)); else returnType = ".V"; From 4006b014cd225d19132f5d21c7cdc367592624d9 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:00:40 +0100 Subject: [PATCH 077/253] hotfix method call when not class name --- src/main/pt/up/fe/comp2023/Optimization.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index aabafba..66cbba0 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -4,6 +4,7 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.PostorderJmmVisitor; import pt.up.fe.comp.jmm.ast.PreorderJmmVisitor; @@ -133,6 +134,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { JmmNode left = jmmNode.getJmmChild(0); String methodName = jmmNode.get("methodcall"); String returnType = ".V"; + boolean isStatic = false; if (table.getMethods().contains(methodName)) for (String m : table.getMethods()) @@ -146,14 +148,18 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { } else { - if (table.getImports().contains(left.get("value"))) - code += "\t\tinvokestatic(" ; + if (table.getImports().contains(left.get("value"))) { + code += "\t\tinvokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called + isStatic = true; + } else code += "\t\tinvokevirtual(" ; } - // The first arg is the object that calls the method and the second is the name of the method called - code += left.get("value") + " , \"" + methodName +"\""; + // Case the invocation is not static + if (!isStatic){ + code += left.get("value") + OllirUtils.ollirTypes(new Type(left.get("typename"), false))+ " , \"" + methodName + "\""; + } // The following arguments can exist or not they are the arguments of the method called JmmNode params = jmmNode.getJmmChild(1); @@ -162,10 +168,10 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { visit(child); } - code += ")\n"; + code += ")"; // Type of method - code += returnType + ";"; + code += returnType + ";\n"; return null; @@ -304,7 +310,6 @@ private Void dealWithVarDecl(JmmNode jmmNode, Void unused) { } private Void dealWithMethodCallParam(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) visit(child); From 79ca2cd221fa3761aef17117e65e7edc43812284 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:20:20 +0100 Subject: [PATCH 078/253] object ollir --- src/main/pt/up/fe/comp2023/Optimization.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 66cbba0..7106b6a 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -118,6 +118,18 @@ private Void dealWithInteger(JmmNode jmmNode, Void unused) { } private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { + JmmNode father = jmmNode.getJmmParent(); // see the father to see the whole expression + String leftString = "", rightString = ""; + + if (father.getKind().equals("Assignment")){ // or ARRAY ASSIGNMENT (LATER IMPLEMENT) + leftString = father.get("varname"); + rightString = jmmNode.get("classname"); + } + + code += "new(" + rightString + ")." + rightString + ";\n"; + code += "\t\tinvokespecial(" + leftString + "." + rightString + ",\"\").V"; + + for (var child : jmmNode.getChildren()) visit(child); return null; From 6ab6348b40b6d415a7f1e84518c3194aeb233408 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:09:26 +0100 Subject: [PATCH 079/253] hotfix params identifier --- src/main/pt/up/fe/comp2023/Optimization.java | 32 +++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 7106b6a..403edb1 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -68,6 +68,8 @@ protected void buildVisitor() { private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { var method = jmmNode.getAncestor("MethodDecl"); Symbol var = null; + boolean isLocal = false, isParam = false, isField = false; + int idParam = 0; if (method.isPresent()) { List localVarClass = table.getLocalVariables(method.get().get("methodname")); @@ -75,27 +77,40 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { // Check if local var for (Symbol lv : localVarClass) - if (lv.getName().equals(jmmNode.get("value"))) + if (lv.getName().equals(jmmNode.get("value"))) { var = lv; + isLocal = true; + } // If not local var, then check if param if (var == null) - for (Symbol p : paramsOnClass) - if (p.getName().equals(jmmNode.get("value"))) - var = p; - - + for (int p = 0; p < paramsOnClass.size(); p++) + if (paramsOnClass.get(p).getName().equals(jmmNode.get("value"))) { + var = paramsOnClass.get(p); + isParam = true; + idParam = p + 1; + } } List fields = table.getFields(); + // If not local nor param, check if field if (var == null) for (Symbol f : fields) - if (f.getName().equals(jmmNode.get("value"))) + if (f.getName().equals(jmmNode.get("value"))) { var = f; + isField = true; + } + // If found, send it with its type if (var != null) - code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + if (isLocal) + code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + else if (isParam) + code += "$" + idParam + "." + jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + else if (isField) + code += code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + // If it's not any of the above, then consider it's in an import else code += jmmNode.get("value"); @@ -219,6 +234,7 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { } private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) visit(child); From 102f673b8124bff607d53525f4bc0ba01a59cc05 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:21:06 +0100 Subject: [PATCH 080/253] hotfix assignment --- src/main/pt/up/fe/comp2023/Optimization.java | 31 +++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 403edb1..1d131e3 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -265,6 +265,10 @@ private Void dealWithParenthesesExpr(JmmNode jmmNode, Void unused) { private Void dealWithAssignment(JmmNode jmmNode, Void unused) { Symbol var = null; boolean isField = false; + boolean isParam = false; + boolean isLocal = false; + int idParam = 0; + List t = table.getParameters(jmmNode.getJmmParent().get("methodname")); /* Grammar distributes method declarations into 3 categories: @@ -288,13 +292,26 @@ private Void dealWithAssignment(JmmNode jmmNode, Void unused) { else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.getJmmParent().getKind().equals("MethodDecl")) { // Local Var for (Symbol v : table.getLocalVariables(jmmNode.getJmmParent().get("methodname"))) - if (v.getName().equals(jmmNode.get("varname"))) + if (v.getName().equals(jmmNode.get("varname"))) { var = v; + isLocal = true; + } // Parameter if (var == null) for (Symbol v : table.getParameters(jmmNode.getJmmParent().get("methodname"))) - if (v.getName().equals(jmmNode.get("varname"))) + if (v.getName().equals(jmmNode.get("varname"))){ var = v; + isParam = true; + } + + // Parameter + if (var == null) + for (int i = 0; i < t.size(); i++) + if (t.get(i).getName().equals(jmmNode.get("varname"))){ + var = t.get(i); + isParam = true; + idParam = 1 + i; + } } // Field if (var == null) @@ -310,9 +327,15 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge String left = jmmNode.get("varname"); JmmNode right = jmmNode.getChildren().get(0); - code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + if (isLocal) + code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + else if (isParam) + code += "\t\t$" + idParam + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + else if (isField) + code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; + visit(right); - code += ";\n"; + code += isField ? ");\n" : ";\n"; return null; } From 6877b9f98bd71b666ac18dcf15e35fdc5d26c2d0 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 11:42:24 +0100 Subject: [PATCH 081/253] BUGGED but hotfix in putfield --- src/main/pt/up/fe/comp2023/Optimization.java | 39 ++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 1d131e3..b4dea99 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -38,7 +38,7 @@ protected void buildVisitor() { setDefaultVisit(this::visitAllChildren); addVisit("ClassDecl", this::dealWithClass); // Dealing with imports in here addVisit("MethodDecl", this::dealWithMethod); - addVisit("VoidMethodDecl", this::dealWithMethod); + addVisit("VoidMethodDecl", this::dealWithVoidMethod); addVisit("MainMethodDecl", this::dealWithMainMethod); addVisit("MethodDeclParameters", this::dealWithParamDecl); addVisit("MethodParameters", this::dealWithMethodCallParam); @@ -67,13 +67,16 @@ protected void buildVisitor() { private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { var method = jmmNode.getAncestor("MethodDecl"); + var voidMethod = jmmNode.getAncestor("VoidMethodDecl"); + var mainMethod = jmmNode.getAncestor("MainMethodDecl"); Symbol var = null; boolean isLocal = false, isParam = false, isField = false; int idParam = 0; - if (method.isPresent()) { - List localVarClass = table.getLocalVariables(method.get().get("methodname")); - List paramsOnClass = table.getParameters(method.get().get("methodname")); + if (method.isPresent() || voidMethod.isPresent() || mainMethod.isPresent()) { + var methodName = mainMethod.isPresent() ? "main" : method.orElseGet(voidMethod::get).get("methodname"); + List localVarClass = table.getLocalVariables(methodName); + List paramsOnClass = table.getParameters(methodName); // Check if local var for (Symbol lv : localVarClass) @@ -109,7 +112,7 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { else if (isParam) code += "$" + idParam + "." + jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); else if (isField) - code += code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); // If it's not any of the above, then consider it's in an import else @@ -141,7 +144,7 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { rightString = jmmNode.get("classname"); } - code += "new(" + rightString + ")." + rightString + ";\n"; + code += "\t\tnew(" + rightString + ")." + rightString + ";\n"; code += "\t\tinvokespecial(" + leftString + "." + rightString + ",\"\").V"; @@ -200,7 +203,6 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { // Type of method code += returnType + ";\n"; - return null; } @@ -373,6 +375,7 @@ private Void dealWithParamDecl(JmmNode jmmNode, Void unused) { return null; } + private Void dealWithMethod(JmmNode jmmNode, Void unused) { code += "\t.method public " + jmmNode.get("methodname") + "("; // Parameters @@ -384,6 +387,7 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { code += ", "; } code += ")"; + // Return Type of Method String returnType = OllirUtils.ollirTypes(table.getReturnType(jmmNode.get("methodname"))); code += returnType + " {\n"; @@ -400,6 +404,27 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { return null; } + private Void dealWithVoidMethod(JmmNode jmmNode, Void unused) { + code += "\t.method public " + jmmNode.get("methodname") + "("; + // Parameters + List parameters = table.getParameters(jmmNode.get("methodname")); + for (int i = 0; i< parameters.size(); i++){ + Symbol parameter = parameters.get(i); + code += parameter.getName() + OllirUtils.ollirTypes(parameter.getType()); + if ( i + 1 < parameters.size()) + code += ", "; + } + code += ")"; + + code += ".V{\n"; + + for (int i = 0; i < jmmNode.getChildren().size() ; i++ ) + visit(jmmNode.getChildren().get(i)); + + code += ";\n\t}\n"; + return null; + } + private Void dealWithMainMethod(JmmNode jmmNode, Void unused) { code += "\t.method public static main(" + jmmNode.get("parametername") + ".array.String).V{\n"; From 14c0c5b6c80ea0ee9456ca54aa6555abc013b7d3 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 11:50:35 +0100 Subject: [PATCH 082/253] fix double semicollon and changes in void method --- src/main/pt/up/fe/comp2023/Optimization.java | 21 ++++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index b4dea99..487e39a 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -22,8 +22,6 @@ public class Optimization extends AJmmVisitor implements JmmOptimiza List reports = new ArrayList<>(); private SymbolTable table; - // private class PostOrdOptm extends PostorderJmmVisitor{} - @Override public OllirResult toOllir(JmmSemanticsResult semanticsResult) { table = semanticsResult.getSymbolTable(); @@ -144,7 +142,7 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { rightString = jmmNode.get("classname"); } - code += "\t\tnew(" + rightString + ")." + rightString + ";\n"; + code += "new(" + rightString + ")." + rightString + ";\n"; code += "\t\tinvokespecial(" + leftString + "." + rightString + ",\"\").V"; @@ -174,16 +172,16 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { returnType = ".V"; if (left.getKind().equals("This")){ - code += "\t\tinvokevirtual("; + code += "invokevirtual("; } else { if (table.getImports().contains(left.get("value"))) { - code += "\t\tinvokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called + code += "invokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called isStatic = true; } else - code += "\t\tinvokevirtual(" ; + code += "invokevirtual(" ; } // Case the invocation is not static @@ -201,7 +199,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { code += ")"; // Type of method - code += returnType + ";\n"; + code += returnType; return null; } @@ -337,14 +335,15 @@ else if (isField) code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; visit(right); - code += isField ? ");\n" : ";\n"; + code += isField ? ").V;\n" : ";\n"; return null; } private Void dealWithExpr(JmmNode jmmNode, Void unused) { + code += "\t\t"; for (var child : jmmNode.getChildren()) visit(child); - + code += ";\n"; return null; } @@ -421,7 +420,7 @@ private Void dealWithVoidMethod(JmmNode jmmNode, Void unused) { for (int i = 0; i < jmmNode.getChildren().size() ; i++ ) visit(jmmNode.getChildren().get(i)); - code += ";\n\t}\n"; + code += "\t\tret.V;\n\t}\n"; return null; } @@ -430,7 +429,7 @@ private Void dealWithMainMethod(JmmNode jmmNode, Void unused) { code += "\t.method public static main(" + jmmNode.get("parametername") + ".array.String).V{\n"; for (var child : jmmNode.getChildren()) visit(child); - code += "\t}\n"; + code += "\t\tret.V;\n\t}\n"; return null; } From 9ced369e4fc03a6371759d8d43d229fec52008ac Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 13:55:43 +0100 Subject: [PATCH 083/253] expressions - i am so confused --- src/main/pt/up/fe/comp2023/Optimization.java | 50 +++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 487e39a..181fab2 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -21,6 +21,7 @@ public class Optimization extends AJmmVisitor implements JmmOptimiza String code = ""; List reports = new ArrayList<>(); private SymbolTable table; + int tempVarId = 0; @Override public OllirResult toOllir(JmmSemanticsResult semanticsResult) { @@ -104,32 +105,36 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { } // If found, send it with its type - if (var != null) + if (var != null) { + String ttype = OllirUtils.ollirTypes(var.getType()); if (isLocal) - code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); + jmmNode.put("valueOl", jmmNode.get("value") + ttype); else if (isParam) - code += "$" + idParam + "." + jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); - else if (isField) - code += jmmNode.get("value") + OllirUtils.ollirTypes(var.getType()); - + jmmNode.put("valueOl", "$" + idParam + "." + jmmNode.get("value") + ttype); + else if (isField) { + String temp = "t" + tempVarId++ + ttype; + jmmNode.put("valueOl", temp); + code += temp + " :=" + ttype + " getfield(this , " + jmmNode.get("value") + ttype + ")" + ttype + ";"; + } + } // If it's not any of the above, then consider it's in an import else - code += jmmNode.get("value"); + jmmNode.put("valueOl", jmmNode.get("value")); return null; } private Void dealWithThis(JmmNode jmmNode, Void unused) { - code += "this"; + jmmNode.put("valueOl", "this"); return null; } private Void dealWithBoolean(JmmNode jmmNode, Void unused) { - code += jmmNode.get("value") + ".bool"; + jmmNode.put("valueOl", jmmNode.get("value") + ".bool"); return null; } private Void dealWithInteger(JmmNode jmmNode, Void unused) { - code += jmmNode.get("value") + ".i32"; + jmmNode.put("valueOl", jmmNode.get("value") + ".i32" ); return null; } @@ -234,9 +239,18 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { } private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { + JmmNode leftSon = jmmNode.getJmmChild(0); + JmmNode rightSon = jmmNode.getJmmChild(1); - for (var child : jmmNode.getChildren()) - visit(child); + visit(leftSon); + visit(rightSon); + + String left = leftSon.get("valueOl"); + String right = rightSon.get("valueOl"); + String temp = "t" + tempVarId++ + ".i32"; + + code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + jmmNode.put("valueOl", temp); return null; } @@ -324,9 +338,10 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge if (var == null) throw new NullPointerException("Variable 'var' is not a LOCAL VAR or a PARAMETER or a FIELD"); + JmmNode right = jmmNode.getChildren().get(0); + visit(right); String left = jmmNode.get("varname"); - JmmNode right = jmmNode.getChildren().get(0); if (isLocal) code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isParam) @@ -334,7 +349,7 @@ else if (isParam) else if (isField) code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; - visit(right); + code += right.get("valueOl"); code += isField ? ").V;\n" : ";\n"; return null; } @@ -395,11 +410,10 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { visit(jmmNode.getChildren().get(i)); // Return - int indexReturn = jmmNode.getChildren().size() - 1; + JmmNode returnNode = jmmNode.getJmmChild(jmmNode.getNumChildren() - 1); - code += "\t\tret" + returnType + " "; - visit(jmmNode.getChildren().get(indexReturn)); // Visit the expression after "return" keyword - code += ";\n\t}\n"; + visit(returnNode); // Visit the expression after "return" keyword + code += "\t\tret" + returnType + " " + returnNode.get("valueOl") + ";\n\t}\n"; return null; } From b56939762ec0482db87ff43323fa920949c68ed8 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:01:45 +0100 Subject: [PATCH 084/253] logical expressions --- src/main/pt/up/fe/comp2023/Optimization.java | 28 +++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 181fab2..6d98fe6 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -225,15 +225,35 @@ private Void dealWithArraySubscript(JmmNode jmmNode, Void unused) { } private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); + JmmNode leftSon = jmmNode.getJmmChild(0); + JmmNode rightSon = jmmNode.getJmmChild(1); + + visit(leftSon); + visit(rightSon); + + String left = leftSon.get("valueOl"); + String right = rightSon.get("valueOl"); + String temp = "t" + tempVarId++ + ".bool"; + + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; + jmmNode.put("valueOl", temp); return null; } private Void dealWithComparison(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); + JmmNode leftSon = jmmNode.getJmmChild(0); + JmmNode rightSon = jmmNode.getJmmChild(1); + + visit(leftSon); + visit(rightSon); + + String left = leftSon.get("valueOl"); + String right = rightSon.get("valueOl"); + String temp = "t" + tempVarId++ + ".bool"; + + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + jmmNode.put("valueOl", temp); return null; } From 9fa0e52957d171f28e9593c74481849eb5fcc095 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:11:42 +0100 Subject: [PATCH 085/253] fix in method params --- src/main/pt/up/fe/comp2023/Optimization.java | 75 +++++++++++--------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 6d98fe6..317f2c7 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -43,8 +43,8 @@ protected void buildVisitor() { addVisit("MethodParameters", this::dealWithMethodCallParam); addVisit("VarDecl", this::dealWithVarDecl); addVisit("CodeBlock", this::dealWithCodeBlock); - // addVisit("Condition", this::dealWithCondition); // not for checkpoint 2 - // addVisit("Cycle", this::dealWithCycle); // not for checkpoint 2 + // addVisit("Condition", this::dealWithCondition); // not for checkpoint 2 + // addVisit("Cycle", this::dealWithCycle); // not for checkpoint 2 addVisit("Expr", this::dealWithExpr); addVisit("Assignment", this::dealWithAssignment); addVisit("ArrayAssignment", this::dealWithArrayAssignment); @@ -134,7 +134,7 @@ private Void dealWithBoolean(JmmNode jmmNode, Void unused) { } private Void dealWithInteger(JmmNode jmmNode, Void unused) { - jmmNode.put("valueOl", jmmNode.get("value") + ".i32" ); + jmmNode.put("valueOl", jmmNode.get("value") + ".i32"); return null; } @@ -142,7 +142,7 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { JmmNode father = jmmNode.getJmmParent(); // see the father to see the whole expression String leftString = "", rightString = ""; - if (father.getKind().equals("Assignment")){ // or ARRAY ASSIGNMENT (LATER IMPLEMENT) + if (father.getKind().equals("Assignment")) { // or ARRAY ASSIGNMENT (LATER IMPLEMENT) leftString = father.get("varname"); rightString = jmmNode.get("classname"); } @@ -164,7 +164,7 @@ private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { } private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { - JmmNode left = jmmNode.getJmmChild(0); + JmmNode left = jmmNode.getJmmChild(0); String methodName = jmmNode.get("methodcall"); String returnType = ".V"; boolean isStatic = false; @@ -176,29 +176,33 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { else returnType = ".V"; - if (left.getKind().equals("This")){ - code += "invokevirtual("; + JmmNode params = jmmNode.getJmmChild(1); + for (var child : params.getChildren()) { + visit(child); + } - } - else { + String temp = "t" + tempVarId++ + returnType; + if (!returnType.equals(".V")) + code += temp + " :=" + returnType + " "; + + if (left.getKind().equals("This")) { + code += "invokevirtual("; + } else { if (table.getImports().contains(left.get("value"))) { code += "invokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called isStatic = true; - } - else - code += "invokevirtual(" ; + } else + code += "invokevirtual("; } // Case the invocation is not static - if (!isStatic){ - code += left.get("value") + OllirUtils.ollirTypes(new Type(left.get("typename"), false))+ " , \"" + methodName + "\""; + if (!isStatic) { + code += left.get("value") + OllirUtils.ollirTypes(new Type(left.get("typename"), false)) + " , \"" + methodName + "\""; } // The following arguments can exist or not they are the arguments of the method called - JmmNode params = jmmNode.getJmmChild(1); for (var child : params.getChildren()) { - code += " , "; - visit(child); + code += " , " + child.get("valueOl"); } code += ")"; @@ -206,12 +210,17 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { // Type of method code += returnType; + if (!returnType.equals(".V")) + code += ";\n"; + + jmmNode.put("valueOl", temp); + return null; } private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { List fieldsOnClass = table.getFields(); - for (Symbol currField: fieldsOnClass){ + for (Symbol currField : fieldsOnClass) { code += "\t.field private " + currField.getName() + OllirUtils.ollirTypes(currField.getType()) + ";\n"; } return null; @@ -235,7 +244,7 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); String temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; jmmNode.put("valueOl", temp); return null; @@ -252,7 +261,7 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); String temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; jmmNode.put("valueOl", temp); return null; @@ -269,7 +278,7 @@ private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); String temp = "t" + tempVarId++ + ".i32"; - code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; jmmNode.put("valueOl", temp); return null; @@ -315,7 +324,7 @@ private Void dealWithAssignment(JmmNode jmmNode, Void unused) { */ // Main Method - if (jmmNode.getJmmParent().getKind().equals("MainMethodDecl")){ + if (jmmNode.getJmmParent().getKind().equals("MainMethodDecl")) { // Local Var for (Symbol v : table.getLocalVariables("main")) if (v.getName().equals(jmmNode.get("varname"))) @@ -333,7 +342,7 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge // Parameter if (var == null) for (Symbol v : table.getParameters(jmmNode.getJmmParent().get("methodname"))) - if (v.getName().equals(jmmNode.get("varname"))){ + if (v.getName().equals(jmmNode.get("varname"))) { var = v; isParam = true; } @@ -341,7 +350,7 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge // Parameter if (var == null) for (int i = 0; i < t.size(); i++) - if (t.get(i).getName().equals(jmmNode.get("varname"))){ + if (t.get(i).getName().equals(jmmNode.get("varname"))) { var = t.get(i); isParam = true; idParam = 1 + i; @@ -365,7 +374,7 @@ else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.ge if (isLocal) code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isParam) - code += "\t\t$" + idParam + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + code += "\t\t$" + idParam + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isField) code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; @@ -414,10 +423,10 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { code += "\t.method public " + jmmNode.get("methodname") + "("; // Parameters List parameters = table.getParameters(jmmNode.get("methodname")); - for (int i = 0; i< parameters.size(); i++){ + for (int i = 0; i < parameters.size(); i++) { Symbol parameter = parameters.get(i); code += parameter.getName() + OllirUtils.ollirTypes(parameter.getType()); - if ( i + 1 < parameters.size()) + if (i + 1 < parameters.size()) code += ", "; } code += ")"; @@ -426,7 +435,7 @@ private Void dealWithMethod(JmmNode jmmNode, Void unused) { String returnType = OllirUtils.ollirTypes(table.getReturnType(jmmNode.get("methodname"))); code += returnType + " {\n"; - for (int i = 0; i < jmmNode.getChildren().size() - 1; i++ ) + for (int i = 0; i < jmmNode.getChildren().size() - 1; i++) visit(jmmNode.getChildren().get(i)); // Return @@ -441,17 +450,17 @@ private Void dealWithVoidMethod(JmmNode jmmNode, Void unused) { code += "\t.method public " + jmmNode.get("methodname") + "("; // Parameters List parameters = table.getParameters(jmmNode.get("methodname")); - for (int i = 0; i< parameters.size(); i++){ + for (int i = 0; i < parameters.size(); i++) { Symbol parameter = parameters.get(i); code += parameter.getName() + OllirUtils.ollirTypes(parameter.getType()); - if ( i + 1 < parameters.size()) + if (i + 1 < parameters.size()) code += ", "; } code += ")"; code += ".V{\n"; - for (int i = 0; i < jmmNode.getChildren().size() ; i++ ) + for (int i = 0; i < jmmNode.getChildren().size(); i++) visit(jmmNode.getChildren().get(i)); code += "\t\tret.V;\n\t}\n"; @@ -471,14 +480,14 @@ private Void dealWithClass(JmmNode jmmNode, Void unused) { // Imports List imports = table.getImports(); for (String currImport : imports) - code += "import " + currImport + ";\n"; + code += "import " + currImport + ";\n"; // Verifies the existence of a superclass String superClass = table.getSuper(); if (superClass == null) code += table.getClassName() + " {\n"; else - code += table.getClassName() + " extends " + superClass + "{\n"; + code += table.getClassName() + " extends " + superClass + "{\n"; dealWithLenFieldAccess(jmmNode, unused); // Constructor From 50688657af9e8d4944adbf898c4a0d15cf7cb308 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:36:07 +0100 Subject: [PATCH 086/253] huge refactor ollir --- src/main/pt/up/fe/comp2023/Optimization.java | 90 +++++++------------- 1 file changed, 32 insertions(+), 58 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 317f2c7..93f5bcb 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -139,20 +139,15 @@ private Void dealWithInteger(JmmNode jmmNode, Void unused) { } private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { - JmmNode father = jmmNode.getJmmParent(); // see the father to see the whole expression - String leftString = "", rightString = ""; + String rightString = jmmNode.get("classname"); - if (father.getKind().equals("Assignment")) { // or ARRAY ASSIGNMENT (LATER IMPLEMENT) - leftString = father.get("varname"); - rightString = jmmNode.get("classname"); - } + String temp = "t" + tempVarId++ + "." + rightString; - code += "new(" + rightString + ")." + rightString + ";\n"; - code += "\t\tinvokespecial(" + leftString + "." + rightString + ",\"\").V"; + code += temp + " :=." + rightString + " new(" + rightString + ")." + rightString + ";\n"; + code += "\t\tinvokespecial(" + temp + ",\"\").V;\n"; + jmmNode.put("valueOl", temp); - for (var child : jmmNode.getChildren()) - visit(child); return null; } @@ -165,6 +160,7 @@ private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { JmmNode left = jmmNode.getJmmChild(0); + visit(left); String methodName = jmmNode.get("methodcall"); String returnType = ".V"; boolean isStatic = false; @@ -197,7 +193,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { // Case the invocation is not static if (!isStatic) { - code += left.get("value") + OllirUtils.ollirTypes(new Type(left.get("typename"), false)) + " , \"" + methodName + "\""; + code += left.get("valueOl") + " , \"" + methodName + "\""; } // The following arguments can exist or not they are the arguments of the method called @@ -306,71 +302,49 @@ private Void dealWithParenthesesExpr(JmmNode jmmNode, Void unused) { } private Void dealWithAssignment(JmmNode jmmNode, Void unused) { + var method = jmmNode.getAncestor("MethodDecl"); + var voidMethod = jmmNode.getAncestor("VoidMethodDecl"); + var mainMethod = jmmNode.getAncestor("MainMethodDecl"); Symbol var = null; - boolean isField = false; - boolean isParam = false; - boolean isLocal = false; + boolean isLocal = false, isParam = false, isField = false; int idParam = 0; - List t = table.getParameters(jmmNode.getJmmParent().get("methodname")); - - /* - Grammar distributes method declarations into 3 categories: - - main method; - - void method; - - method with return type - - Because of that, it's needed to check if the parent of the assignment function corresponds - to any of these types of methods to check if it is either a local variable or a parameter. - */ + String left = jmmNode.get("varname"); - // Main Method - if (jmmNode.getJmmParent().getKind().equals("MainMethodDecl")) { - // Local Var - for (Symbol v : table.getLocalVariables("main")) - if (v.getName().equals(jmmNode.get("varname"))) - var = v; + if (method.isPresent() || voidMethod.isPresent() || mainMethod.isPresent()) { + var methodName = mainMethod.isPresent() ? "main" : method.orElseGet(voidMethod::get).get("methodname"); + List localVarClass = table.getLocalVariables(methodName); + List paramsOnClass = table.getParameters(methodName); - } - // Void Method OR Method with Return Type - else if (jmmNode.getJmmParent().getKind().equals("VoidMethodDecl") || jmmNode.getJmmParent().getKind().equals("MethodDecl")) { - // Local Var - for (Symbol v : table.getLocalVariables(jmmNode.getJmmParent().get("methodname"))) - if (v.getName().equals(jmmNode.get("varname"))) { - var = v; + // Check if local var + for (Symbol lv : localVarClass) + if (lv.getName().equals(left)) { + var = lv; isLocal = true; } - // Parameter - if (var == null) - for (Symbol v : table.getParameters(jmmNode.getJmmParent().get("methodname"))) - if (v.getName().equals(jmmNode.get("varname"))) { - var = v; - isParam = true; - } - // Parameter + // If not local var, then check if param if (var == null) - for (int i = 0; i < t.size(); i++) - if (t.get(i).getName().equals(jmmNode.get("varname"))) { - var = t.get(i); + for (int p = 0; p < paramsOnClass.size(); p++) + if (paramsOnClass.get(p).getName().equals(left)) { + var = paramsOnClass.get(p); isParam = true; - idParam = 1 + i; + idParam = p + 1; } } - // Field + + List fields = table.getFields(); + + // If not local nor param, check if field if (var == null) - for (Symbol s : this.table.getFields()) - if (s.getName().equals(jmmNode.get("varname"))) { - var = s; + for (Symbol f : fields) + if (f.getName().equals(left)) { + var = f; isField = true; } - // Throw error - if (var == null) - throw new NullPointerException("Variable 'var' is not a LOCAL VAR or a PARAMETER or a FIELD"); JmmNode right = jmmNode.getChildren().get(0); visit(right); - String left = jmmNode.get("varname"); if (isLocal) code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isParam) From 7057ebca25dee85f2a9e290b1cbaa0c811e61099 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:10:50 +0100 Subject: [PATCH 087/253] parentheses ollir --- src/main/pt/up/fe/comp2023/Optimization.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 93f5bcb..95f440b 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -295,9 +295,8 @@ private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { } private Void dealWithParenthesesExpr(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); - + visit(jmmNode.getJmmChild(0)); + jmmNode.put("valueOl", jmmNode.getJmmChild(0).get("valueOl")); return null; } From 1d505cc7fef7786d025fa792732f176cbc2c6b90 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:17:44 +0100 Subject: [PATCH 088/253] semicollon fix --- src/main/pt/up/fe/comp2023/Optimization.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index 95f440b..b43451d 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -164,6 +164,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { String methodName = jmmNode.get("methodcall"); String returnType = ".V"; boolean isStatic = false; + boolean makeTemp = !jmmNode.getJmmParent().getKind().equals("Expr"); if (table.getMethods().contains(methodName)) for (String m : table.getMethods()) @@ -178,7 +179,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { } String temp = "t" + tempVarId++ + returnType; - if (!returnType.equals(".V")) + if (makeTemp) code += temp + " :=" + returnType + " "; if (left.getKind().equals("This")) { @@ -206,7 +207,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { // Type of method code += returnType; - if (!returnType.equals(".V")) + if (makeTemp) code += ";\n"; jmmNode.put("valueOl", temp); From e0c897625e4a04f398244e65bf9f390e792db90b Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 27 Apr 2023 17:52:30 +0100 Subject: [PATCH 089/253] fix - else was making problems --- src/main/pt/up/fe/comp2023/Optimization.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index b43451d..de2ee11 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -166,12 +166,10 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { boolean isStatic = false; boolean makeTemp = !jmmNode.getJmmParent().getKind().equals("Expr"); - if (table.getMethods().contains(methodName)) - for (String m : table.getMethods()) - if (m.equals(methodName)) - returnType = OllirUtils.ollirTypes(table.getReturnType(m)); - else - returnType = ".V"; + for (String m : table.getMethods()) + if (m.equals(methodName)) + returnType = OllirUtils.ollirTypes(table.getReturnType(m)); + JmmNode params = jmmNode.getJmmChild(1); for (var child : params.getChildren()) { From 46cbd85fd7e0b01632fb691b5f55ad69e0ac86f8 Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Sat, 29 Apr 2023 18:32:17 +0100 Subject: [PATCH 090/253] Updates OLLIR library - Array accesses now support literals - All uses of `this` can now have type information (previous case where `this` did not have the type still supported) - Array variable in array accesses can now have type information (previous case still supported) - `new` can be used without arguments, since information about the class is in the return type (previous case still supported) - Class `FieldInstruction` has new methods `.getOperands()`, `.getInstanceOperand()` and `getField()`. Subclass `PutFieldInstruction` has new method `getValue()` - Method .show() in classes Intruction, Element and Type now show more information --- libs/comp2023-ollir-sources.jar | Bin 0 -> 55711 bytes libs/comp2023-ollir.jar | Bin 0 -> 91342 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 libs/comp2023-ollir-sources.jar create mode 100644 libs/comp2023-ollir.jar diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..269d6304f88555edefa31a50d7169f0e2b489646 GIT binary patch literal 55711 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�Hz5TKWKh}2?B0Ecr9wX`KnMFRR@&Uj*g@awpIRz-a=-GWt;GB);Cn5tJixU7$NbTi#sCt1zop6; zJDJ)3XS*6tXjZ;m;Y0BOSaKRLNB_{a`ZE>!9SHpcP1e@P_&?g{4>MY*$`?ZbOy~)C zko*Y(JQw;Ei2WDVZ|(PkXQiXGe-FrS3E=&ZcKS0F`W=e@BhTi4&BhF3PO9q)N{_UF zInoI*bN<{l=_LPw{6~zH|G4Zs%|vD7wvGp7Ko$A^qYEX<{x{ek3l2Z;ul%(OwLaoJ zI{~n-fV%!XAu|KK|65=GUWf5l@Ee;`^nO5{djMeKKkW*5F7!KB{6{dLW!n5_EBfK7 zU!~yxBo_MJDF1idZ=L@;@$~? z3-A8{{HJCjAY_rz|1!z1B8-3GR}B9L{(qr=RrmV~y=MFm=-)PnALeEGMU3t*mWSy- zu>L`s?(g>f(ZhaK8~clVZT=7BpR~vR&ikFf*1vc^zGf*{{sZsdo4Ni@`mxsftK8OK zHH-Qmq`!r&`j3J22l>|!Sbvd~06IRu9RmJc$G?$(4v6(@<$sMR^H&k3asS^%{6~D5 zUrYIQ*Zp6ml$HMXQhu`s|5y008}a^vU)B6~_;0u6{fhtf7u~<`&~5)6|JU!kzcPPa kp8ty(+x`E+{AsaXUJ4v=OZ+278Y>Vf;I_zQ@W+4u4>Zb=82|tP literal 0 HcmV?d00001 diff --git a/libs/comp2023-ollir.jar b/libs/comp2023-ollir.jar new file mode 100644 index 0000000000000000000000000000000000000000..bf3c853f5feca9405de77cd654ba0af5bba1abc5 GIT binary patch literal 91342 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

Dd_ylp8pl^ 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 PxJRNmT%Qw+vbcW%7+9GP literal 0 HcmV?d00001 From 6535addc25aaa7901c6a90b9df9d682bc1bf68ba Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Sun, 30 Apr 2023 10:53:07 +0100 Subject: [PATCH 091/253] [Fix] Creates ArrayOperand instances in OLLIR --- libs/comp2023-ollir-sources.jar | Bin 55711 -> 55713 bytes libs/comp2023-ollir.jar | Bin 91342 -> 91373 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar index 269d6304f88555edefa31a50d7169f0e2b489646..0cb7c4b60027c7c4f44fdcbf5c63cba87078c681 100644 GIT binary patch delta 8320 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 O{{O|yNDia_8TcQ<3;fvt delta 8324 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 diff --git a/libs/comp2023-ollir.jar b/libs/comp2023-ollir.jar index bf3c853f5feca9405de77cd654ba0af5bba1abc5..3fd5037497c18bc877685c7fe44e76340ffa2199 100644 GIT binary patch delta 19497 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 Date: Sun, 30 Apr 2023 11:34:37 +0100 Subject: [PATCH 092/253] [Fix] 'new' syntax without operands now assumes a first operand based on the return type --- libs/comp2023-ollir-sources.jar | Bin 55713 -> 56061 bytes libs/comp2023-ollir.jar | Bin 91373 -> 91912 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar index 0cb7c4b60027c7c4f44fdcbf5c63cba87078c681..f89ca72dcdd87b73417fbc8407b4cec3cfab1f13 100644 GIT binary patch delta 10610 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 a^$}Vo2A%f)W5#+g!O_d;u>He-v;05%Lktf9 delta 10265 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

|_Zazrr&@9&UU$dZ!lOoIrbwRI&`7sQ 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 J!EPGqe*pRvR>lAT delta 23512 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�`>egq;a|ZK$OeN>0ErMp+Il%`QJLAxnUJ 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 Date: Mon, 1 May 2023 17:53:34 +0100 Subject: [PATCH 093/253] Refactor: added separate packages for different compiler stages --- config.properties | 4 ++-- src/main/pt/up/fe/comp2023/Launcher.java | 5 +++-- src/main/pt/up/fe/comp2023/{ => ollir}/OllirUtils.java | 4 +--- src/main/pt/up/fe/comp2023/{ => ollir}/Optimization.java | 8 ++------ src/main/pt/up/fe/comp2023/{ => semantic}/Analysis.java | 2 +- .../up/fe/comp2023/{ => semantic}/ExpressionAnalysis.java | 5 +++-- .../pt/up/fe/comp2023/{ => semantic}/MethodTable.java | 5 ++--- .../pt/up/fe/comp2023/{ => semantic}/MySymbolTable.java | 2 +- .../up/fe/comp2023/{ => semantic}/SemanticAnalysis.java | 4 ++-- .../pt/up/fe/comp2023/{ => semantic}/SemanticUtils.java | 2 +- 10 files changed, 18 insertions(+), 23 deletions(-) rename src/main/pt/up/fe/comp2023/{ => ollir}/OllirUtils.java (89%) rename src/main/pt/up/fe/comp2023/{ => ollir}/Optimization.java (98%) rename src/main/pt/up/fe/comp2023/{ => semantic}/Analysis.java (96%) rename src/main/pt/up/fe/comp2023/{ => semantic}/ExpressionAnalysis.java (98%) rename src/main/pt/up/fe/comp2023/{ => semantic}/MethodTable.java (93%) rename src/main/pt/up/fe/comp2023/{ => semantic}/MySymbolTable.java (99%) rename src/main/pt/up/fe/comp2023/{ => semantic}/SemanticAnalysis.java (98%) rename src/main/pt/up/fe/comp2023/{ => semantic}/SemanticUtils.java (98%) diff --git a/config.properties b/config.properties index 5eee1e0..0c3cd06 100644 --- a/config.properties +++ b/config.properties @@ -2,10 +2,10 @@ ParserClass = pt.up.fe.comp2023.SimpleParser # The fully qualified name of your class that implements the interface JmmAnalysis -AnalysisClass = pt.up.fe.comp2023.Analysis +AnalysisClass = pt.up.fe.comp2023.semantic.Analysis # The fully qualified name of your class that implements the interface JmmOptimization -OptimizationClass = pt.up.fe.comp2023.Optimization +OptimizationClass = pt.up.fe.comp2023.ollir.Optimization # The fully qualified name of your class that implements the interface JasminBackend BackendClass = pt.up.fe.comp2023.jasmin.JasminGenerator diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 4582fb3..0ca11e8 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -12,6 +12,9 @@ import pt.up.fe.comp2023.jasmin.JasminGenerator; import pt.up.fe.comp.jmm.jasmin.JasminResult; import pt.up.fe.comp.jmm.report.Report; +import pt.up.fe.comp2023.ollir.Optimization; +import pt.up.fe.comp2023.semantic.Analysis; +import pt.up.fe.comp2023.semantic.MySymbolTable; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsLogs; import pt.up.fe.specs.util.SpecsSystem; @@ -76,8 +79,6 @@ public static void main(String[] args) { System.out.println(jasminResult.getJasminCode()); // TestUtils.runJasmin(jasminResult.getJasminCode()); - - // ... add remaining stages } private static Map parseArgs(String[] args) { diff --git a/src/main/pt/up/fe/comp2023/OllirUtils.java b/src/main/pt/up/fe/comp2023/ollir/OllirUtils.java similarity index 89% rename from src/main/pt/up/fe/comp2023/OllirUtils.java rename to src/main/pt/up/fe/comp2023/ollir/OllirUtils.java index 1b9427b..87548be 100644 --- a/src/main/pt/up/fe/comp2023/OllirUtils.java +++ b/src/main/pt/up/fe/comp2023/ollir/OllirUtils.java @@ -1,6 +1,5 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.ollir; -import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.analysis.table.Type; public class OllirUtils { @@ -22,5 +21,4 @@ else if (type.getName().equals("void")) return typeS; } - } diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java similarity index 98% rename from src/main/pt/up/fe/comp2023/Optimization.java rename to src/main/pt/up/fe/comp2023/ollir/Optimization.java index de2ee11..564b122 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -1,22 +1,18 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.ollir; -import org.specs.comp.ollir.Ollir; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; -import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.JmmNode; -import pt.up.fe.comp.jmm.ast.PostorderJmmVisitor; -import pt.up.fe.comp.jmm.ast.PreorderJmmVisitor; import pt.up.fe.comp.jmm.ollir.JmmOptimization; import pt.up.fe.comp.jmm.ollir.OllirResult; import pt.up.fe.comp.jmm.report.Report; import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp2023.ollir.OllirUtils; import java.util.ArrayList; import java.util.List; - public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; List reports = new ArrayList<>(); diff --git a/src/main/pt/up/fe/comp2023/Analysis.java b/src/main/pt/up/fe/comp2023/semantic/Analysis.java similarity index 96% rename from src/main/pt/up/fe/comp2023/Analysis.java rename to src/main/pt/up/fe/comp2023/semantic/Analysis.java index 01d4dff..c563b1d 100644 --- a/src/main/pt/up/fe/comp2023/Analysis.java +++ b/src/main/pt/up/fe/comp2023/semantic/Analysis.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.JmmAnalysis; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; diff --git a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java similarity index 98% rename from src/main/pt/up/fe/comp2023/ExpressionAnalysis.java rename to src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java index 3452627..0e5cc40 100644 --- a/src/main/pt/up/fe/comp2023/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; @@ -6,11 +6,12 @@ import pt.up.fe.comp.jmm.report.Report; import pt.up.fe.comp.jmm.report.ReportType; import pt.up.fe.comp.jmm.report.Stage; +import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.List; import java.util.Objects; -import static pt.up.fe.comp2023.SemanticUtils.*; +import static pt.up.fe.comp2023.semantic.SemanticUtils.*; public class ExpressionAnalysis extends AJmmVisitor { private String methodName; diff --git a/src/main/pt/up/fe/comp2023/MethodTable.java b/src/main/pt/up/fe/comp2023/semantic/MethodTable.java similarity index 93% rename from src/main/pt/up/fe/comp2023/MethodTable.java rename to src/main/pt/up/fe/comp2023/semantic/MethodTable.java index 4b82ac7..c268b2d 100644 --- a/src/main/pt/up/fe/comp2023/MethodTable.java +++ b/src/main/pt/up/fe/comp2023/semantic/MethodTable.java @@ -1,11 +1,11 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.Type; -import java.util.ArrayList; import java.util.List; public class MethodTable { + private final String name; private final List parameters; private final List localVariables; @@ -33,5 +33,4 @@ public List getLocalVariables() { public Type getReturnType() { return returnType; } - } diff --git a/src/main/pt/up/fe/comp2023/MySymbolTable.java b/src/main/pt/up/fe/comp2023/semantic/MySymbolTable.java similarity index 99% rename from src/main/pt/up/fe/comp2023/MySymbolTable.java rename to src/main/pt/up/fe/comp2023/semantic/MySymbolTable.java index 9a51220..de64c04 100644 --- a/src/main/pt/up/fe/comp2023/MySymbolTable.java +++ b/src/main/pt/up/fe/comp2023/semantic/MySymbolTable.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; diff --git a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java b/src/main/pt/up/fe/comp2023/semantic/SemanticAnalysis.java similarity index 98% rename from src/main/pt/up/fe/comp2023/SemanticAnalysis.java rename to src/main/pt/up/fe/comp2023/semantic/SemanticAnalysis.java index f242c9c..3b43ef9 100644 --- a/src/main/pt/up/fe/comp2023/SemanticAnalysis.java +++ b/src/main/pt/up/fe/comp2023/semantic/SemanticAnalysis.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; @@ -10,7 +10,7 @@ import java.util.List; import java.util.Objects; -import static pt.up.fe.comp2023.SemanticUtils.*; +import static pt.up.fe.comp2023.semantic.SemanticUtils.*; public class SemanticAnalysis extends AJmmVisitor { private final MySymbolTable symbolTable; diff --git a/src/main/pt/up/fe/comp2023/SemanticUtils.java b/src/main/pt/up/fe/comp2023/semantic/SemanticUtils.java similarity index 98% rename from src/main/pt/up/fe/comp2023/SemanticUtils.java rename to src/main/pt/up/fe/comp2023/semantic/SemanticUtils.java index ee8033c..40d2c28 100644 --- a/src/main/pt/up/fe/comp2023/SemanticUtils.java +++ b/src/main/pt/up/fe/comp2023/semantic/SemanticUtils.java @@ -1,4 +1,4 @@ -package pt.up.fe.comp2023; +package pt.up.fe.comp2023.semantic; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.Type; From 738d8881561004d89cebe602deee85e06ab0e61a Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 1 May 2023 18:07:51 +0100 Subject: [PATCH 094/253] Uncomented line to run jasmin code --- src/main/pt/up/fe/comp2023/Launcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 0ca11e8..762e0a2 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -78,7 +78,7 @@ public static void main(String[] args) { JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); System.out.println(jasminResult.getJasminCode()); - // TestUtils.runJasmin(jasminResult.getJasminCode()); + TestUtils.runJasmin(jasminResult.getJasminCode()); } private static Map parseArgs(String[] args) { From 3eb582c57c0ee83e125dc8b692f04c7e6477daba Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 1 May 2023 19:14:31 +0100 Subject: [PATCH 095/253] fix boolean values --- src/main/pt/up/fe/comp2023/Optimization.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/Optimization.java b/src/main/pt/up/fe/comp2023/Optimization.java index de2ee11..6f290ac 100644 --- a/src/main/pt/up/fe/comp2023/Optimization.java +++ b/src/main/pt/up/fe/comp2023/Optimization.java @@ -129,7 +129,10 @@ private Void dealWithThis(JmmNode jmmNode, Void unused) { } private Void dealWithBoolean(JmmNode jmmNode, Void unused) { - jmmNode.put("valueOl", jmmNode.get("value") + ".bool"); + if (jmmNode.get("value").equals("true")) + jmmNode.put("valueOl", 1 + ".bool"); + else + jmmNode.put("valueOl", 0 + ".bool"); return null; } From 79b60a0f521dd8c96c969cbfde7c1470efa01b21 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 1 May 2023 19:21:02 +0100 Subject: [PATCH 096/253] more ellegant fix of last commit --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 5a66689..396619b 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -125,10 +125,7 @@ private Void dealWithThis(JmmNode jmmNode, Void unused) { } private Void dealWithBoolean(JmmNode jmmNode, Void unused) { - if (jmmNode.get("value").equals("true")) - jmmNode.put("valueOl", 1 + ".bool"); - else - jmmNode.put("valueOl", 0 + ".bool"); + jmmNode.put("valueOl", jmmNode.get("value").equals("true") ? "1.bool" : "0.bool"); return null; } From a6c190caf5cfd43f4ba1d8210405bf819d54b1c0 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 1 May 2023 20:18:05 +0100 Subject: [PATCH 097/253] Created method to handle branch instruction --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 9 +++++++++ src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index e9588ad..75004f3 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -224,6 +224,15 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha return statementList; } + public static String createBranchStatement(CondBranchInstruction instruction, HashMap varTable) { + String statementList = ""; + if (instruction instanceof OpCondInstruction) + System.out.println("OpCondInstruction"); + if (instruction instanceof SingleOpCondInstruction) + System.out.println("SingleOpCondInstruction"); + return statementList; + } + public static String createReturnStatement(ReturnInstruction instruction, HashMap varTable) { ElementType returnType = instruction.getElementType(); Element returnElement = instruction.getOperand(); diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 06c9274..0969bca 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -94,6 +94,8 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { + instruction.show(); + String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -113,6 +115,10 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Mon, 1 May 2023 20:37:20 +0100 Subject: [PATCH 098/253] Created separate method to handle single and op condition instructions --- .../comp2023/jasmin/JVMInstructionUtils.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 75004f3..8284577 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -224,15 +224,24 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha return statementList; } - public static String createBranchStatement(CondBranchInstruction instruction, HashMap varTable) { + public static String createSingleOpConditionStatement(SingleOpCondInstruction instruction, HashMap varTable) { + String statementList = ""; + return statementList; + } + + public static String createOpConditionStatement(OpCondInstruction instruction, HashMap varTable) { String statementList = ""; - if (instruction instanceof OpCondInstruction) - System.out.println("OpCondInstruction"); - if (instruction instanceof SingleOpCondInstruction) - System.out.println("SingleOpCondInstruction"); return statementList; } + public static String createBranchStatement(CondBranchInstruction instruction, HashMap varTable) { + if (instruction instanceof SingleOpCondInstruction) + return createSingleOpConditionStatement((SingleOpCondInstruction)instruction, varTable); + if (instruction instanceof OpCondInstruction) + return createOpConditionStatement((OpCondInstruction)instruction, varTable); + return ""; + } + public static String createReturnStatement(ReturnInstruction instruction, HashMap varTable) { ElementType returnType = instruction.getElementType(); Element returnElement = instruction.getOperand(); From 08ae1ecf15af546a54d8ad6f5a66036b7b4e374c Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 1 May 2023 20:52:29 +0100 Subject: [PATCH 099/253] Implemented jasmin single op condition --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 8284577..d9cf80d 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -226,6 +226,8 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha public static String createSingleOpConditionStatement(SingleOpCondInstruction instruction, HashMap varTable) { String statementList = ""; + statementList += createInstructionRhs(instruction.getCondition(), varTable); + statementList += "\tifeq " + instruction.getLabel() + "\n"; return statementList; } From 3a34495023a5456db22a31c30a51344b9590ac80 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 2 May 2023 12:07:51 +0100 Subject: [PATCH 100/253] Implemented jasmin binary comparison operations instruction --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index d9cf80d..c67c1a6 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -154,8 +154,10 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, statementList += "\tior\n"; break; case LTH: + statementList += "\tif_icmplt "; break; case GTH: + statementList += "\tif_icmpgt "; break; } return statementList; From 733feeb4b13da3c533d4d78e6669151b3f557414 Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Wed, 3 May 2023 20:08:20 +0100 Subject: [PATCH 101/253] Replaces occurences of true/false.bool with 1/0.bool in OLLIR files of CPF --- .../up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir | 2 +- .../up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir | 4 ++-- .../up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir | 2 +- .../fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir index 6d000c1..337eeac 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir @@ -6,7 +6,7 @@ Arithmetic_and { } .method public static main(args.array.String).V { -a.bool :=.bool true.bool &&.bool false.bool; +a.bool :=.bool 1.bool &&.bool 0.bool; if (a.bool) goto ifbody_0; invokestatic(io, "print", 0.i32).V; diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir index afdd4f0..fd07958 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/calls/ConditionArgsFuncCall.ollir @@ -14,8 +14,8 @@ d.ConditionArgsFuncCall :=.ConditionArgsFuncCall new(ConditionArgsFuncCall).Cond invokespecial(d.ConditionArgsFuncCall,"").V; a.i32 :=.i32 10.i32; b.i32 :=.i32 5.i32; -i.bool :=.bool true.bool; -j.bool :=.bool false.bool; +i.bool :=.bool 1.bool; +j.bool :=.bool 0.bool; temp0.bool :=.bool a.i32 <.bool b.i32; temp1.bool :=.bool i.bool &&.bool j.bool; temp4.bool :=.bool a.i32 <.bool b.i32; diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir index 64dfe7b..201def7 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir @@ -6,7 +6,7 @@ IfWhileNested { } .method public func(a.i32).i32 { -flag.bool :=.bool true.bool; +flag.bool :=.bool 1.bool; i.i32 :=.i32 0.i32; if (i.i32 <.bool a.i32) goto whilebody_1; goto endwhile_1; diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir index 0386dcb..f090cc2 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir @@ -7,14 +7,14 @@ SimpleIfElseNot { .method public static main(args.array.String).V { -if (true.bool) goto ifbody_0; +if (1.bool) goto ifbody_0; invokestatic(io, "println", 20.i32).V; goto endif_0; ifbody_0: invokestatic(io, "println", 10.i32).V; endif_0: -if (false.bool) goto ifbody_1; +if (0.bool) goto ifbody_1; invokestatic(io, "print", 200.i32).V; goto endif_1; ifbody_1: From 7c66d0c1c268da8de2344ea56d8edb2b0e610bf3 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 5 May 2023 13:24:49 +0100 Subject: [PATCH 102/253] Implemented jasmin binary and unary op conditions --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index c67c1a6..33d6a23 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -169,11 +169,10 @@ public static String createInstructionRhs(SingleOpInstruction instruction, HashM public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); - String statementList = ""; + String statementList = ""; statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); statementList += getStoreInstruction(assignElement, varTable); - return statementList; } @@ -235,6 +234,11 @@ public static String createSingleOpConditionStatement(SingleOpCondInstruction in public static String createOpConditionStatement(OpCondInstruction instruction, HashMap varTable) { String statementList = ""; + if (instruction.getCondition() instanceof BinaryOpInstruction) + statementList += createBinaryOpInstruction((BinaryOpInstruction)instruction.getCondition(), varTable); + else + statementList += createUnaryOpStatement((UnaryOpInstruction)instruction.getCondition(), varTable); + statementList += instruction.getLabel() + "\n"; return statementList; } From 8ce4cbef2b4f003a703d96b41ac925fef16e90b5 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 5 May 2023 13:48:33 +0100 Subject: [PATCH 103/253] Added labels to correct positions of jasmin code --- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 0969bca..32288ee 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -94,8 +94,6 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { - instruction.show(); - String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -162,8 +160,13 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Fri, 5 May 2023 13:57:34 +0100 Subject: [PATCH 104/253] Inverted comparison instructions used in conditions in order to match goto labels --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 33d6a23..a20b68d 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -154,10 +154,10 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, statementList += "\tior\n"; break; case LTH: - statementList += "\tif_icmplt "; + statementList += "\tif_icmpgt "; break; case GTH: - statementList += "\tif_icmpgt "; + statementList += "\tif_icmplt "; break; } return statementList; @@ -228,7 +228,7 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha public static String createSingleOpConditionStatement(SingleOpCondInstruction instruction, HashMap varTable) { String statementList = ""; statementList += createInstructionRhs(instruction.getCondition(), varTable); - statementList += "\tifeq " + instruction.getLabel() + "\n"; + statementList += "\tifneq " + instruction.getLabel() + "\n"; return statementList; } From cb0d803bc9d58b2cc3b3a1cff1e61c39df17793d Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 5 May 2023 14:47:11 +0100 Subject: [PATCH 105/253] Implemented jasmin goto instruction --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++++ src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index a20b68d..5d8079c 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -250,6 +250,10 @@ public static String createBranchStatement(CondBranchInstruction instruction, Ha return ""; } + public static String createGotoStatement(GotoInstruction instruction, HashMap varTable) { + return "\tgoto " + instruction.getLabel() + "\n"; + } + public static String createReturnStatement(ReturnInstruction instruction, HashMap varTable) { ElementType returnType = instruction.getElementType(); Element returnElement = instruction.getOperand(); diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 32288ee..64b6100 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -111,6 +111,10 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Fri, 5 May 2023 17:55:41 +0100 Subject: [PATCH 106/253] Fixed syntax error in jasmin zero comparison --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 +- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 5d8079c..19e2792 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -228,7 +228,7 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha public static String createSingleOpConditionStatement(SingleOpCondInstruction instruction, HashMap varTable) { String statementList = ""; statementList += createInstructionRhs(instruction.getCondition(), varTable); - statementList += "\tifneq " + instruction.getLabel() + "\n"; + statementList += "\tifne " + instruction.getLabel() + "\n"; return statementList; } diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 64b6100..b5b8443 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -166,9 +166,7 @@ public static String handleMethodStatements(Method method) { String statementList = ""; for (Instruction instruction: method.getInstructions()) { for (String label: method.getLabels(instruction)) - statementList += label + ": "; - if (!method.getLabels(instruction).isEmpty()) - statementList += "\n"; + statementList += "\t" + label + ":\n"; statementList += handleInstruction(instruction, method.getVarTable(), false); } return statementList; From 91cbb3f7d708b3c4f09f1b63582407c0b2c2f704 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sat, 6 May 2023 23:16:13 +0100 Subject: [PATCH 107/253] if statements --- .../pt/up/fe/comp2023/ollir/Optimization.java | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 396619b..9137850 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -15,6 +15,7 @@ public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; + String temp; List reports = new ArrayList<>(); private SymbolTable table; int tempVarId = 0; @@ -39,7 +40,7 @@ protected void buildVisitor() { addVisit("MethodParameters", this::dealWithMethodCallParam); addVisit("VarDecl", this::dealWithVarDecl); addVisit("CodeBlock", this::dealWithCodeBlock); - // addVisit("Condition", this::dealWithCondition); // not for checkpoint 2 + addVisit("Condition", this::dealWithCondition); // addVisit("Cycle", this::dealWithCycle); // not for checkpoint 2 addVisit("Expr", this::dealWithExpr); addVisit("Assignment", this::dealWithAssignment); @@ -60,6 +61,26 @@ protected void buildVisitor() { addVisit("Identifier", this::dealWithIdentifier); } + private Void dealWithCondition(JmmNode jmmNode, Void unused) { + code += "\t"; visit(jmmNode.getJmmChild(0)); code += ";\n"; + + // Condition statement + code += "\t\tif (" + temp + ") goto ifz;\n"; + + // What occurs if the condition isn't met + code += "\t\t\t"; visit(jmmNode.getJmmChild(2)); + code += "\t\t\tgoto endif;\n"; + + // What occurs if the condition is met + code += "\t\tifz:\n\t"; visit(jmmNode.getJmmChild(1)); + + // End of If + code +="\t\tendif:\n\t"; + + + return null; + } + private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { var method = jmmNode.getAncestor("MethodDecl"); var voidMethod = jmmNode.getAncestor("VoidMethodDecl"); @@ -108,7 +129,7 @@ private Void dealWithIdentifier(JmmNode jmmNode, Void unused) { else if (isParam) jmmNode.put("valueOl", "$" + idParam + "." + jmmNode.get("value") + ttype); else if (isField) { - String temp = "t" + tempVarId++ + ttype; + temp = "t" + tempVarId++ + ttype; jmmNode.put("valueOl", temp); code += temp + " :=" + ttype + " getfield(this , " + jmmNode.get("value") + ttype + ")" + ttype + ";"; } @@ -137,7 +158,7 @@ private Void dealWithInteger(JmmNode jmmNode, Void unused) { private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { String rightString = jmmNode.get("classname"); - String temp = "t" + tempVarId++ + "." + rightString; + temp = "t" + tempVarId++ + "." + rightString; code += temp + " :=." + rightString + " new(" + rightString + ")." + rightString + ";\n"; code += "\t\tinvokespecial(" + temp + ",\"\").V;\n"; @@ -172,7 +193,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { visit(child); } - String temp = "t" + tempVarId++ + returnType; + temp = "t" + tempVarId++ + returnType; if (makeTemp) code += temp + " :=" + returnType + " "; @@ -233,7 +254,7 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { String left = leftSon.get("valueOl"); String right = rightSon.get("valueOl"); - String temp = "t" + tempVarId++ + ".bool"; + temp = "t" + tempVarId++ + ".bool"; code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; jmmNode.put("valueOl", temp); @@ -244,15 +265,18 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { private Void dealWithComparison(JmmNode jmmNode, Void unused) { JmmNode leftSon = jmmNode.getJmmChild(0); JmmNode rightSon = jmmNode.getJmmChild(1); + var condition = jmmNode.getAncestor("Condition"); visit(leftSon); visit(rightSon); String left = leftSon.get("valueOl"); String right = rightSon.get("valueOl"); - String temp = "t" + tempVarId++ + ".bool"; + temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right; + if (condition.isEmpty()) + code += ";\n"; jmmNode.put("valueOl", temp); return null; @@ -267,7 +291,7 @@ private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { String left = leftSon.get("valueOl"); String right = rightSon.get("valueOl"); - String temp = "t" + tempVarId++ + ".i32"; + temp = "t" + tempVarId++ + ".i32"; code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; jmmNode.put("valueOl", temp); @@ -355,6 +379,7 @@ private Void dealWithExpr(JmmNode jmmNode, Void unused) { code += "\t\t"; for (var child : jmmNode.getChildren()) visit(child); + code += ";\n"; return null; } From eb3149d4407edfbb158710973b49a2f977fe0c26 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 7 May 2023 01:40:53 +0100 Subject: [PATCH 108/253] Added comparison expressions and control flow tests --- src/main/pt/up/fe/comp2023/Launcher.java | 25 ++- .../4_jasmin/arithmetic/Arithmetic_and.ollir | 17 +- .../4_jasmin/arithmetic/Arithmetic_less.ollir | 17 +- .../arithmetic/ByteCodeIndexes1.ollir | 3 +- .../arithmetic/ByteCodeIndexes2.ollir | 5 +- .../4_jasmin/basic/BasicMethodsArray.ollir | 7 +- .../4_jasmin/control_flow/IfWhileNested.ollir | 42 ++-- .../SimpleIfElseArithmetic_and.ollir | 29 +++ .../control_flow/SimpleIfElseNot.ollir | 28 ++- .../control_flow/SimpleIfElseStat.ollir | 35 ++-- .../control_flow/SimpleWhileStat.ollir | 21 +- .../4_jasmin/control_flow/SwitchStat.ollir | 97 +++++---- test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 189 +++++++++++------- 13 files changed, 295 insertions(+), 220 deletions(-) create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseArithmetic_and.ollir diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 762e0a2..0f7053c 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -71,8 +71,29 @@ public static void main(String[] args) { // Check if there are semantic errors TestUtils.noErrors(semanticsResult.getReports()); - Optimization optimization = new Optimization(); - OllirResult ollirResult = optimization.toOllir(semanticsResult); + // Optimization optimization = new Optimization(); + // OllirResult ollirResult = optimization.toOllir(semanticsResult); + String ollirCode = "import io;\n" + + "Arithmetic_and {\n" + + "\n" + + " .construct Arithmetic_and().V {\n" + + " invokespecial(this, \"\").V;\n" + + " }\n" + + "\n" + + " .method public static main(args.array.String).V {\n" + + " a.bool :=.bool true.bool &&.bool false.bool;\n" + + "\n" + + " if (a.bool) goto ifbody_0;\n" + + " invokestatic(io, \"print\", 0.i32).V;\n" + + " goto endif_0;\n" + + " ifbody_0:\n" + + " invokestatic(io, \"print\", 1.i32).V;\n" + + " endif_0:\n" + + "\n" + + " ret.V;\n" + + " }\n" + + "}"; + OllirResult ollirResult = new OllirResult(ollirCode, new HashMap<>()); JasminGenerator jasminGenerator = new JasminGenerator(); JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir index 337eeac..81a0da7 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir @@ -6,16 +6,15 @@ Arithmetic_and { } .method public static main(args.array.String).V { -a.bool :=.bool 1.bool &&.bool 0.bool; + a.bool :=.bool 1.bool &&.bool 0.bool; -if (a.bool) goto ifbody_0; - invokestatic(io, "print", 0.i32).V; -goto endif_0; -ifbody_0: - invokestatic(io, "print", 1.i32).V; -endif_0: + if (a.bool) goto ifbody_0; + invokestatic(io, "print", 0.i32).V; + goto endif_0; + ifbody_0: + invokestatic(io, "print", 1.i32).V; + endif_0: -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir index bad39cf..a638c7d 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir @@ -6,16 +6,15 @@ Arithmetic_less { } .method public static main(args.array.String).V { -a.bool :=.bool 10.i32 <.bool 20.i32; + a.bool :=.bool 10.i32 <.bool 20.i32; -if (a.bool) goto ifbody_0; - invokestatic(io, "print", 0.i32).V; -goto endif_0; -ifbody_0: - invokestatic(io, "print", 1.i32).V; -endif_0: + if (a.bool) goto ifbody_0; + invokestatic(io, "print", 0.i32).V; + goto endif_0; + ifbody_0: + invokestatic(io, "print", 1.i32).V; + endif_0: -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir index 5aaf352..ce8bb81 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes1.ollir @@ -5,7 +5,6 @@ ByteCodeIndexes1 { } .method public func(a.i32).i32 { -ret.i32 a.i32; + ret.i32 a.i32; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir index c8609b0..f06a713 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arithmetic/ByteCodeIndexes2.ollir @@ -5,8 +5,7 @@ ByteCodeIndexes2 { } .method public func(a.i32).i32 { -b.i32 :=.i32 11.i32; -ret.i32 b.i32; + b.i32 :=.i32 11.i32; + ret.i32 b.i32; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir index f4d2711..1a94a87 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/basic/BasicMethodsArray.ollir @@ -6,9 +6,8 @@ BasicMethods extends Other { } .method public func4().array.i32 { -temp0.i32 :=.i32 1.i32; -k.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; -ret.array.i32 k.array.i32; + temp0.i32 :=.i32 1.i32; + k.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; + ret.array.i32 k.array.i32; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir index 201def7..52ddf93 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir @@ -6,30 +6,30 @@ IfWhileNested { } .method public func(a.i32).i32 { -flag.bool :=.bool 1.bool; -i.i32 :=.i32 0.i32; -if (i.i32 <.bool a.i32) goto whilebody_1; -goto endwhile_1; -whilebody_1: + flag.bool :=.bool 1.bool; + i.i32 :=.i32 0.i32; + if (i.i32 <.bool a.i32) goto whilebody_1; + goto endwhile_1; + whilebody_1: -if (flag.bool) goto ifbody_0; - invokestatic(ioPlus, "printResult", 2.i32).V; -goto endif_0; -ifbody_0: - invokestatic(ioPlus, "printResult", 1.i32).V; -endif_0: -flag.bool :=.bool !.bool flag.bool; -i.i32 :=.i32 i.i32 +.i32 1.i32; -if (i.i32 <.bool a.i32) goto whilebody_1; -endwhile_1: -ret.i32 1.i32; + if (flag.bool) goto ifbody_0; + invokestatic(ioPlus, "printResult", 2.i32).V; + goto endif_0; + ifbody_0: + invokestatic(ioPlus, "printResult", 1.i32).V; + endif_0: + flag.bool :=.bool !.bool flag.bool; + i.i32 :=.i32 i.i32 +.i32 1.i32; + if (i.i32 <.bool a.i32) goto whilebody_1; + endwhile_1: + ret.i32 1.i32; } + .method public static main(args.array.String).V { -d.IfWhileNested :=.IfWhileNested new(IfWhileNested).IfWhileNested; -invokespecial(d.IfWhileNested,"").V; -a.i32 :=.i32 invokevirtual(d.IfWhileNested, "func", 3.i32).i32; + d.IfWhileNested :=.IfWhileNested new(IfWhileNested).IfWhileNested; + invokespecial(d.IfWhileNested,"").V; + a.i32 :=.i32 invokevirtual(d.IfWhileNested, "func", 3.i32).i32; -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseArithmetic_and.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseArithmetic_and.ollir new file mode 100644 index 0000000..fb826c3 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseArithmetic_and.ollir @@ -0,0 +1,29 @@ +import io; +Arithmetic_and { + + .construct Arithmetic_and().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { + a.bool :=.bool 1.bool &&.bool 0.bool; + var1.i32 :=.i32 1.i32; + var2.i32 :=.i32 2.i32; + + if (a.bool) goto ifbody_0; + invokestatic(io, "print", 0.i32).V; + goto endif_0; + ifbody_0: + invokestatic(io, "print", 1.i32).V; + endif_0: + + if (var1.i32 <.bool var2.i32) goto ifbody_1; + invokestatic(io, "print", 0.i32).V; + goto endif_1; + ifbody_1: + invokestatic(io, "print", 1.i32).V; + endif_1: + + ret.V; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir index f090cc2..54cf5c4 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir @@ -6,22 +6,20 @@ SimpleIfElseNot { } .method public static main(args.array.String).V { + if (1.bool) goto ifbody_0; + invokestatic(io, "println", 20.i32).V; + goto endif_0; + ifbody_0: + invokestatic(io, "println", 10.i32).V; + endif_0: -if (1.bool) goto ifbody_0; - invokestatic(io, "println", 20.i32).V; -goto endif_0; -ifbody_0: - invokestatic(io, "println", 10.i32).V; -endif_0: + if (0.bool) goto ifbody_1; + invokestatic(io, "print", 200.i32).V; + goto endif_1; + ifbody_1: + invokestatic(io, "print", 100.i32).V; + endif_1: -if (0.bool) goto ifbody_1; - invokestatic(io, "print", 200.i32).V; -goto endif_1; -ifbody_1: - invokestatic(io, "print", 100.i32).V; -endif_1: - -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir index 79b8c8b..eeea6ab 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir @@ -6,26 +6,25 @@ SimpleIfElseStat { } .method public static main(args.array.String).V { -a.i32 :=.i32 5.i32; -b.i32 :=.i32 10.i32; + a.i32 :=.i32 5.i32; + b.i32 :=.i32 10.i32; -if (a.i32 <.bool b.i32) goto ifbody_0; - invokestatic(ioPlus, "printResult", b.i32).V; -goto endif_0; -ifbody_0: - invokestatic(ioPlus, "printResult", a.i32).V; -endif_0: -a.i32 :=.i32 10.i32; -b.i32 :=.i32 8.i32; + if (a.i32 <.bool b.i32) goto ifbody_0; + invokestatic(ioPlus, "printResult", b.i32).V; + goto endif_0; + ifbody_0: + invokestatic(ioPlus, "printResult", a.i32).V; + endif_0: + a.i32 :=.i32 10.i32; + b.i32 :=.i32 8.i32; -if (a.i32 <.bool b.i32) goto ifbody_1; - invokestatic(ioPlus, "printResult", b.i32).V; -goto endif_1; -ifbody_1: - invokestatic(ioPlus, "printResult", a.i32).V; -endif_1: + if (a.i32 <.bool b.i32) goto ifbody_1; + invokestatic(ioPlus, "printResult", b.i32).V; + goto endif_1; + ifbody_1: + invokestatic(ioPlus, "printResult", a.i32).V; + endif_1: -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir index 6573e29..dabac04 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir @@ -6,17 +6,16 @@ SimpleWhileStat { } .method public static main(args.array.String).V { -a.i32 :=.i32 3.i32; -i.i32 :=.i32 0.i32; -if (i.i32 <.bool a.i32) goto whilebody_0; -goto endwhile_0; -whilebody_0: -invokestatic(ioPlus, "printResult", i.i32).V; -i.i32 :=.i32 i.i32 +.i32 1.i32; -if (i.i32 <.bool a.i32) goto whilebody_0; -endwhile_0: + a.i32 :=.i32 3.i32; + i.i32 :=.i32 0.i32; + if (i.i32 <.bool a.i32) goto whilebody_0; + goto endwhile_0; + whilebody_0: + invokestatic(ioPlus, "printResult", i.i32).V; + i.i32 :=.i32 i.i32 +.i32 1.i32; + if (i.i32 <.bool a.i32) goto whilebody_0; + endwhile_0: -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir index 26a8dae..b8344f9 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir @@ -6,57 +6,56 @@ SwitchStat { } .method public func(a.i32).i32 { + if (a.i32 <.bool 1.i32) goto ifbody_5; -if (a.i32 <.bool 1.i32) goto ifbody_5; - -if (a.i32 <.bool 2.i32) goto ifbody_4; - -if (a.i32 <.bool 3.i32) goto ifbody_3; - -if (a.i32 <.bool 4.i32) goto ifbody_2; - -if (a.i32 <.bool 5.i32) goto ifbody_1; - -if (a.i32 <.bool 6.i32) goto ifbody_0; - invokestatic(ioPlus, "printResult", 7.i32).V; -goto endif_0; -ifbody_0: - invokestatic(ioPlus, "printResult", 6.i32).V; -endif_0: -goto endif_1; -ifbody_1: - invokestatic(ioPlus, "printResult", 5.i32).V; -endif_1: -goto endif_2; -ifbody_2: - invokestatic(ioPlus, "printResult", 4.i32).V; -endif_2: -goto endif_3; -ifbody_3: - invokestatic(ioPlus, "printResult", 3.i32).V; -endif_3: -goto endif_4; -ifbody_4: - invokestatic(ioPlus, "printResult", 2.i32).V; -endif_4: -goto endif_5; -ifbody_5: - invokestatic(ioPlus, "printResult", 1.i32).V; -endif_5: -ret.i32 1.i32; + if (a.i32 <.bool 2.i32) goto ifbody_4; + + if (a.i32 <.bool 3.i32) goto ifbody_3; + + if (a.i32 <.bool 4.i32) goto ifbody_2; + + if (a.i32 <.bool 5.i32) goto ifbody_1; + + if (a.i32 <.bool 6.i32) goto ifbody_0; + invokestatic(ioPlus, "printResult", 7.i32).V; + goto endif_0; + ifbody_0: + invokestatic(ioPlus, "printResult", 6.i32).V; + endif_0: + goto endif_1; + ifbody_1: + invokestatic(ioPlus, "printResult", 5.i32).V; + endif_1: + goto endif_2; + ifbody_2: + invokestatic(ioPlus, "printResult", 4.i32).V; + endif_2: + goto endif_3; + ifbody_3: + invokestatic(ioPlus, "printResult", 3.i32).V; + endif_3: + goto endif_4; + ifbody_4: + invokestatic(ioPlus, "printResult", 2.i32).V; + endif_4: + goto endif_5; + ifbody_5: + invokestatic(ioPlus, "printResult", 1.i32).V; + endif_5: + ret.i32 1.i32; } + .method public static main(args.array.String).V { -d.SwitchStat :=.SwitchStat new(SwitchStat).SwitchStat; -invokespecial(d.SwitchStat,"").V; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 0.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 1.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 2.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 3.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 4.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 5.i32).i32; -a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 6.i32).i32; - -ret.V; - } + d.SwitchStat :=.SwitchStat new(SwitchStat).SwitchStat; + invokespecial(d.SwitchStat,"").V; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 0.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 1.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 2.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 3.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 4.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 5.i32).i32; + a.i32 :=.i32 invokevirtual(d.SwitchStat, "func", 6.i32).i32; + ret.V; + } } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java index f4295f3..1af62fa 100644 --- a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -18,6 +18,7 @@ import pt.up.fe.comp.TestUtils; import pt.up.fe.comp.jmm.jasmin.JasminResult; import pt.up.fe.comp.jmm.ollir.OllirResult; +import pt.up.fe.comp2023.jasmin.JasminGenerator; import pt.up.fe.specs.util.SpecsCheck; import pt.up.fe.specs.util.SpecsIo; import pt.up.fe.specs.util.SpecsStrings; @@ -30,79 +31,6 @@ public class Cpf4_Jasmin { - // private static boolean USE_OLLIR_EXPERIMENTAL = false; -/* - public static void enableOllirInputs() { - USE_OLLIR_EXPERIMENTAL = true; - } - - public static boolean useOllirInputs() { - return USE_OLLIR_EXPERIMENTAL; - } -*/ - static JasminResult getJasminResult(String filename) { - /* - if (USE_OLLIR_EXPERIMENTAL) { - filename = SpecsIo.removeExtension(filename) + ".ollir"; - return TestUtils.backend(new OllirResult(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename), - Collections.emptyMap())); - } - - return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename)); -*/ - - var resource = "pt/up/fe/comp/cpf/4_jasmin/" + filename; - - SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); - - // If AstToJasmin pipeline, change name of the resource and execute other test - if (TestUtils.hasAstToJasminClass()) { - - // Rename resource - var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; - - // Test Jmm resource - var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); - - return result; - } - - var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); - - var result = TestUtils.backend(ollirResult); - - return result; - - } - - public static void testOllirToJasmin(String resource, String expectedOutput) { - SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); - - // If AstToJasmin pipeline, change name of the resource and execute other test - if (TestUtils.hasAstToJasminClass()) { - - // Rename resource - var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; - - // Test Jmm resource - var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); - ProjectTestUtils.runJasmin(result, expectedOutput); - - return; - } - - var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); - - var result = TestUtils.backend(ollirResult); - - ProjectTestUtils.runJasmin(result, null); - } - - public static void testOllirToJasmin(String resource) { - testOllirToJasmin(resource, null); - } - - private static final String JASMIN_METHOD_REGEX_PREFIX = "\\.method\\s+((public|private)\\s+)?(\\w+)\\(\\)"; /*checks if method declaration is correct (array)*/ @@ -179,7 +107,6 @@ public void section3_ControlFlow_Mixed_Nested() { @Test public void section4_Calls_Misc_ConditionArgs() { CpUtils.runJasmin(getJasminResult("calls/ConditionArgsFuncCall.ollir"), "Result: 10"); - } @@ -187,7 +114,6 @@ public void section4_Calls_Misc_ConditionArgs() { @Test public void section5_Arrays_Init_Array() { CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); - } /*checks if the access to the elements of array is correct*/ @@ -195,7 +121,6 @@ public void section5_Arrays_Init_Array() { public void section5_Arrays_Store_Array() { CpUtils.runJasmin(getJasminResult("arrays/ArrayAccess.ollir"), "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); - } /*checks multiple expressions as indexes to access the elements of an array*/ @@ -203,7 +128,6 @@ public void section5_Arrays_Store_Array() { public void section5_Arrays_Load_ComplexArrayAccess() { CpUtils.runJasmin(getJasminResult("arrays/ComplexArrayAccess.ollir"), "Result: 1\nResult: 2\nResult: 3\nResult: 4\nResult: 5"); - } /*checks if array has correct signature ?*/ @@ -291,4 +215,115 @@ public void section6_Limits_Stack_Simple() { // Make sure the code compiles jasminResult.compile(); } + + @Test + public void ollirToJasminArithmeticAnd() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_and.ollir"); + } + + @Test + public void ollirToJasminArithmeticLess() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arithmetic/Arithmetic_less.ollir"); + } + + @Test + public void ollirToJasminIfElseArithmeticAnd() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseArithmetic_and.ollir"); + } + + @Test + public void ollirToJasminSimpleIfElseNot() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseNot.ollir"); + } + + @Test + public void ollirToJasminSimpleIfElseStat() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleIfElseStat.ollir"); + } + + @Test + public void ollirToJasminSwitchStat() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/SwitchStat.ollir"); + } + + @Test + public void ollirToJasminSimpleWhileStat() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleWhileStat.ollir"); + } + + @Test + public void ollirToJasminIfWhileNested() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir"); + } + + // private static boolean USE_OLLIR_EXPERIMENTAL = false; + /* + public static void enableOllirInputs() { + USE_OLLIR_EXPERIMENTAL = true; + } + + public static boolean useOllirInputs() { + return USE_OLLIR_EXPERIMENTAL; + } + */ + static JasminResult getJasminResult(String filename) { + /* + if (USE_OLLIR_EXPERIMENTAL) { + filename = SpecsIo.removeExtension(filename) + ".ollir"; + return TestUtils.backend(new OllirResult(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename), + Collections.emptyMap())); + } + + return TestUtils.backend(SpecsIo.getResource("pt/up/fe/comp/cpf/4_jasmin/" + filename)); + */ + + var resource = "pt/up/fe/comp/cpf/4_jasmin/" + filename; + SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); + + // If AstToJasmin pipeline, change name of the resource and execute other test + if (TestUtils.hasAstToJasminClass()) { + + // Rename resource + var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; + + // Test Jmm resource + var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); + + return result; + } + + var ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); + + var result = TestUtils.backend(ollirResult); + + return result; + + } + + public static void testOllirToJasmin(String resource, String expectedOutput) { + SpecsCheck.checkArgument(resource.endsWith(".ollir"), () -> "Expected resource to end with .ollir: " + resource); + + // If AstToJasmin pipeline, change name of the resource and execute other test + if (TestUtils.hasAstToJasminClass()) { + + // Rename resource + var jmmResource = SpecsIo.removeExtension(resource) + ".jmm"; + + // Test Jmm resource + var result = TestUtils.backend(SpecsIo.getResource(jmmResource)); + ProjectTestUtils.runJasmin(result, expectedOutput); + + return; + } + + OllirResult ollirResult = new OllirResult(SpecsIo.getResource(resource), Collections.emptyMap()); + JasminGenerator jasminGenerator = new JasminGenerator(); + JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); + System.out.println(jasminResult.getJasminCode()); + TestUtils.runJasmin(jasminResult.getJasminCode()); + } + + public static void testOllirToJasmin(String resource) { + testOllirToJasmin(resource, null); + } } From 1b1c809e9eb77115f969eea999b1f9cf75489057 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 8 May 2023 17:13:58 +0100 Subject: [PATCH 109/253] Jasmin static methods refactor and added field to count label id --- src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java | 6 +++--- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java b/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java index 121c228..c1ab0e2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminGenerator.java @@ -24,19 +24,19 @@ private String generateJasminCode(ClassUnit classUnit) { + createMethodDefinitions(classUnit); } - private String createHeader(ClassUnit classUnit) { + public static String createHeader(ClassUnit classUnit) { return JasminUtils.createClassDirective(classUnit) + JasminUtils.createSuperDirective(classUnit); } - private String createFieldDefinitions(ClassUnit classUnit) { + public static String createFieldDefinitions(ClassUnit classUnit) { String fieldDefinitions = ""; for (Field field: classUnit.getFields()) fieldDefinitions += JasminUtils.createFieldDirective(field); return fieldDefinitions; } - private String createMethodDefinitions(ClassUnit classUnit) { + public static String createMethodDefinitions(ClassUnit classUnit) { String methodDefinitions = ""; for (Method method: classUnit.getMethods()) if (method.isConstructMethod()) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index b5b8443..06108b2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -7,6 +7,8 @@ public class JasminUtils { + public static int customLabelCounter = 0; + public static String getTypeDescriptor(Type type, boolean isDeclaration) { ElementType elementType = type.getTypeOfElement(); if (elementType.equals(ElementType.INT32)) From 20bf8597df4c4797991b021f60c2d4ffa1db436c Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 8 May 2023 17:21:47 +0100 Subject: [PATCH 110/253] Refactor: changed noper instruction handler name --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++-- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 19e2792..53b6b3a 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -163,7 +163,7 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, return statementList; } - public static String createInstructionRhs(SingleOpInstruction instruction, HashMap varTable) { + public static String createNoperInstruction(SingleOpInstruction instruction, HashMap varTable) { return getLoadInstruction(instruction.getSingleOperand(), varTable); } @@ -227,7 +227,7 @@ public static String createPutfieldStatement(PutFieldInstruction instruction, Ha public static String createSingleOpConditionStatement(SingleOpCondInstruction instruction, HashMap varTable) { String statementList = ""; - statementList += createInstructionRhs(instruction.getCondition(), varTable); + statementList += createNoperInstruction(instruction.getCondition(), varTable); statementList += "\tifne " + instruction.getLabel() + "\n"; return statementList; } diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 06108b2..c7a9ad4 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -155,7 +155,7 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Mon, 8 May 2023 17:53:32 +0100 Subject: [PATCH 111/253] Added custom branching to comparison operations outside if-elses --- .../comp2023/jasmin/JVMInstructionUtils.java | 27 +++++++++++++++++-- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 3 ++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 53b6b3a..c328e84 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -129,7 +129,7 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash return statementList; } - public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable) { + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { String statementList = ""; statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); statementList += getLoadInstruction(instruction.getRightOperand(), varTable); @@ -155,9 +155,13 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, break; case LTH: statementList += "\tif_icmpgt "; + if (!isBranchCond) + statementList += createAuxBranchStatement(); break; case GTH: statementList += "\tif_icmplt "; + if (!isBranchCond) + statementList += createAuxBranchStatement(); break; } return statementList; @@ -235,7 +239,7 @@ public static String createSingleOpConditionStatement(SingleOpCondInstruction in public static String createOpConditionStatement(OpCondInstruction instruction, HashMap varTable) { String statementList = ""; if (instruction.getCondition() instanceof BinaryOpInstruction) - statementList += createBinaryOpInstruction((BinaryOpInstruction)instruction.getCondition(), varTable); + statementList += createBinaryOpInstruction((BinaryOpInstruction)instruction.getCondition(), varTable, true); else statementList += createUnaryOpStatement((UnaryOpInstruction)instruction.getCondition(), varTable); statementList += instruction.getLabel() + "\n"; @@ -254,6 +258,25 @@ public static String createGotoStatement(GotoInstruction instruction, HashMap varTable) { ElementType returnType = instruction.getElementType(); Element returnElement = instruction.getOperand(); diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index c7a9ad4..e9a5367 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -151,7 +151,8 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Mon, 8 May 2023 17:56:54 +0100 Subject: [PATCH 112/253] Adjusted instructions used in comparison to also include equals comparison --- src/main/pt/up/fe/comp2023/Launcher.java | 2 +- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 0f7053c..dfd5e1c 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -81,7 +81,7 @@ public static void main(String[] args) { " }\n" + "\n" + " .method public static main(args.array.String).V {\n" + - " a.bool :=.bool true.bool &&.bool false.bool;\n" + + " a.bool :=.bool 1.bool &&.bool 0.bool;\n" + "\n" + " if (a.bool) goto ifbody_0;\n" + " invokestatic(io, \"print\", 0.i32).V;\n" + diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index c328e84..46f3612 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -154,12 +154,12 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, statementList += "\tior\n"; break; case LTH: - statementList += "\tif_icmpgt "; + statementList += "\tif_icmpge "; if (!isBranchCond) statementList += createAuxBranchStatement(); break; case GTH: - statementList += "\tif_icmplt "; + statementList += "\tif_icmple "; if (!isBranchCond) statementList += createAuxBranchStatement(); break; From 841aa42669f0c84a4fc21b567ddaf5ac762acd5b Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 8 May 2023 18:19:36 +0100 Subject: [PATCH 113/253] Fixed instructions used in comparisons --- .../comp2023/jasmin/JVMInstructionUtils.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 46f3612..1d48315 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -154,12 +154,12 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, statementList += "\tior\n"; break; case LTH: - statementList += "\tif_icmpge "; + statementList += "\tif_icmplt "; if (!isBranchCond) statementList += createAuxBranchStatement(); break; case GTH: - statementList += "\tif_icmple "; + statementList += "\tif_icmpgt "; if (!isBranchCond) statementList += createAuxBranchStatement(); break; @@ -260,20 +260,20 @@ public static String createGotoStatement(GotoInstruction instruction, HashMap Date: Mon, 8 May 2023 19:04:05 +0100 Subject: [PATCH 114/253] Fixed not operator implementation --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 1d48315..1e482b2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -123,7 +123,8 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash switch (instruction.getOperation().getOpType()) { case NOT: case NOTB: - statementList += "\tineg\n"; + statementList += "\tifeq "; + statementList += createAuxBranchStatement(); break; } return statementList; From d29b7d3f15afdee360275315c2d5f45e8769f5c8 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 9 May 2023 12:35:11 +0100 Subject: [PATCH 115/253] Improve parseArgs() to handle -o option --- src/main/pt/up/fe/comp2023/Launcher.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 762e0a2..d2dd141 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -71,6 +71,11 @@ public static void main(String[] args) { // Check if there are semantic errors TestUtils.noErrors(semanticsResult.getReports()); + if(Boolean.parseBoolean(config.get("optimize"))){ + System.out.println("Applying optimizations..."); + //TODO: apply optimizations (constant propagation and constant folding) + } + Optimization optimization = new Optimization(); OllirResult ollirResult = optimization.toOllir(semanticsResult); @@ -85,17 +90,21 @@ private static Map parseArgs(String[] args) { SpecsLogs.info("Executing with args: " + Arrays.toString(args)); // Check if there is at least one argument - if (args.length != 1) { - throw new RuntimeException("Expected a single argument, a path to an existing input file."); + if (args.length < 1) { + throw new RuntimeException("Usage: ./jmm [-o]"); } // Create config Map config = new HashMap<>(); config.put("inputFile", args[0]); - config.put("optimize", "false"); config.put("registerAllocation", "-1"); config.put("debug", "false"); + if (Arrays.asList(args).contains("-o")) + config.put("optimize", "true"); + else + config.put("optimize", "false"); + return config; } } From 3290bb5de749921e0f4f7d76f8525ec158ef4022 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 9 May 2023 13:26:43 +0100 Subject: [PATCH 116/253] Add constructor of Optimization class --- src/main/pt/up/fe/comp2023/Launcher.java | 2 +- .../pt/up/fe/comp2023/ollir/Optimization.java | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index d2dd141..fccc669 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -76,7 +76,7 @@ public static void main(String[] args) { //TODO: apply optimizations (constant propagation and constant folding) } - Optimization optimization = new Optimization(); + Optimization optimization = new Optimization(semanticsResult); OllirResult ollirResult = optimization.toOllir(semanticsResult); JasminGenerator jasminGenerator = new JasminGenerator(); diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 396619b..2df19de 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -9,6 +9,7 @@ import pt.up.fe.comp.jmm.report.Report; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp2023.ollir.OllirUtils; +import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.ArrayList; import java.util.List; @@ -16,18 +17,28 @@ public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; List reports = new ArrayList<>(); - private SymbolTable table; + private final SymbolTable table; int tempVarId = 0; + + public Optimization(JmmSemanticsResult semanticsResult){ + this.table = semanticsResult.getSymbolTable(); + } + @Override public OllirResult toOllir(JmmSemanticsResult semanticsResult) { - table = semanticsResult.getSymbolTable(); visit(semanticsResult.getRootNode()); code += "} \n"; System.out.println(code); return new OllirResult(semanticsResult, code, reports); } + @Override + public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { + //TODO + return JmmOptimization.super.optimize(semanticsResult); + } + @Override protected void buildVisitor() { setDefaultVisit(this::visitAllChildren); From 185c25de007efda0232010e9b23694eb510e2dc1 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 9 May 2023 13:31:24 +0100 Subject: [PATCH 117/253] Add basic structure of ConstantPropagation and ConstantFolding classes --- .../pt/up/fe/comp2023/ollir/Optimization.java | 7 ++++++- .../optimization/ConstantFolding.java | 19 +++++++++++++++++++ .../optimization/ConstantPropagation.java | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java create mode 100644 src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 2df19de..94371c7 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -9,6 +9,8 @@ import pt.up.fe.comp.jmm.report.Report; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp2023.ollir.OllirUtils; +import pt.up.fe.comp2023.optimization.ConstantFolding; +import pt.up.fe.comp2023.optimization.ConstantPropagation; import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.ArrayList; @@ -35,8 +37,11 @@ public OllirResult toOllir(JmmSemanticsResult semanticsResult) { @Override public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { + ConstantPropagation constantPropagation = new ConstantPropagation(semanticsResult); + ConstantFolding constantFolding = new ConstantFolding(semanticsResult); + //TODO - return JmmOptimization.super.optimize(semanticsResult); + return semanticsResult; } @Override diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java new file mode 100644 index 0000000..539da68 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -0,0 +1,19 @@ +package pt.up.fe.comp2023.optimization; + +import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp2023.semantic.MySymbolTable; + +public class ConstantFolding extends AJmmVisitor { + private SymbolTable symbolTable; + private String currentMethodName; + public ConstantFolding (JmmSemanticsResult semanticsResult){ + this.symbolTable = semanticsResult.getSymbolTable(); + } + + @Override + protected void buildVisitor() { + + } +} diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java new file mode 100644 index 0000000..7255b08 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -0,0 +1,19 @@ +package pt.up.fe.comp2023.optimization; + +import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; + +public class ConstantPropagation extends AJmmVisitor { + private SymbolTable symbolTable; + private String currentMethodName; + + public ConstantPropagation (JmmSemanticsResult semanticsResult){ + this.symbolTable = semanticsResult.getSymbolTable(); + } + + @Override + protected void buildVisitor() { + + } +} From 0693c98b949e9ca2ee9a4a6aa3851bea77ae9bb8 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 9 May 2023 18:13:38 +0100 Subject: [PATCH 118/253] fix grammar mistake --- src/main/antlr/comp2023/grammar/Javamm.g4 | 4 ++-- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index 16ed215..ebfd873 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -57,10 +57,10 @@ statement ; expression - : expression '[' expression ']' #ArraySubscript + : '(' expression ')' #ParenthesesExpr + | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall - | '(' expression ')' #ParenthesesExpr | '!' expression #NegationExpr | expression op=('*' | '/') expression #ArithmeticExpr | expression op=('+' | '-') expression #ArithmeticExpr diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 9137850..d79a024 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -62,7 +62,7 @@ protected void buildVisitor() { } private Void dealWithCondition(JmmNode jmmNode, Void unused) { - code += "\t"; visit(jmmNode.getJmmChild(0)); code += ";\n"; + code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += ";\n"; // Condition statement code += "\t\tif (" + temp + ") goto ifz;\n"; @@ -239,6 +239,7 @@ private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { } private Void dealWithArraySubscript(JmmNode jmmNode, Void unused) { + for (var child : jmmNode.getChildren()) visit(child); From bb8d979446a157d8d835466f1b953e5b8b567306 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 9 May 2023 18:48:34 +0100 Subject: [PATCH 119/253] labels of ifs fixed --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index d79a024..45b80b6 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -63,19 +63,20 @@ protected void buildVisitor() { private Void dealWithCondition(JmmNode jmmNode, Void unused) { code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += ";\n"; + var ifId = tempVarId++; // Condition statement - code += "\t\tif (" + temp + ") goto ifz;\n"; + code += "\t\tif (" + temp + ") goto if" + ifId + ";\n"; // What occurs if the condition isn't met code += "\t\t\t"; visit(jmmNode.getJmmChild(2)); - code += "\t\t\tgoto endif;\n"; + code += "\t\t\tgoto endif" + ifId + ";\n"; // What occurs if the condition is met - code += "\t\tifz:\n\t"; visit(jmmNode.getJmmChild(1)); + code += "\t\tif" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); // End of If - code +="\t\tendif:\n\t"; + code +="\t\tendif" + ifId + ":\n\t"; return null; From 721e37a42365d9d469f94bac0877653315eb9222 Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Tue, 9 May 2023 19:48:22 +0100 Subject: [PATCH 120/253] Removes old, duplicated version of OLLIR library --- libs/ollir-javadoc.jar | Bin 280988 -> 0 bytes libs/ollir-sources.jar | Bin 56142 -> 0 bytes libs/ollir.jar | Bin 91651 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 libs/ollir-javadoc.jar delete mode 100644 libs/ollir-sources.jar delete mode 100644 libs/ollir.jar diff --git a/libs/ollir-javadoc.jar b/libs/ollir-javadoc.jar deleted file mode 100644 index d098d56adf30ae192b13b03554099dab67c8319a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280988 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%0A6DVR;>;&-0_1VM<7SGlG+Pp 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 diff --git a/libs/ollir-sources.jar b/libs/ollir-sources.jar deleted file mode 100644 index d4eefccaba1b3c9a202bc1f44a77f89fa30ec5a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56142 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 diff --git a/libs/ollir.jar b/libs/ollir.jar deleted file mode 100644 index 8e856bfe6b07606fb1ba1747c80518da04a17479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91651 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

5R|*h-n^d0AEZ=IgiZ@Sr&d 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 Date: Tue, 9 May 2023 20:04:54 +0100 Subject: [PATCH 121/253] Updates comp2023-lib, OLLIR tests should now ignore semantic errors --- libs/comp2023-lib-sources.jar | Bin 45222 -> 45267 bytes libs/comp2023-lib.jar | Bin 79779 -> 79945 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-lib-sources.jar b/libs/comp2023-lib-sources.jar index 1d99b41750d0b7398d60fef11556c003a1e5f6b8..da2192c1de512987f688a3d2cade89e5807c1e9d 100644 GIT binary patch delta 3499 zcmV;c4OH@`;R4g)0u4}00|W{H00;;GH=wDJ4dnwQqm{Ass6qqr1(CC$LlR96B%_s9 z{(KAd9t{8hTtt(h85EP$kRE>$g>Lhh*uG1BPS2e*_SovZw4EtTK@wvAQ3=qAug!PA zT>u0D5+W%@&h?HniA4g~UF`mLu?vD5n%vP9BO4i4n|R6Mq{ucezx?9MFL<^oO6fPm z@3JhWIZYn~7xDL5_R9QzIkNu^%V;inBCeUJQrSC9$mj2<$ao&V5^{fDe6N1@jWE4+ z$8TX`EMJW7KP*s@ro6;STy7-K_`j*-MXx-1z$N}aOnpO3!4&x`^=p^D!_-TL4e_=5 zGrHsaVZ%mrzL9{StulxWOGI2rp2j!$^K8wMyAk~^iV>Y|9)x6>i`RGbp2ob0FD}nN zBy8i`sBXNGCC^vaj4pp%MXOdt`-!5sscuuAkR+u-kU10bM`#n|cWfhYZAyMmB_l!t z6cV!J0CaLy78_Pd&ICETeEa(1J95&DjnjfInjX<4De@&>#T)x*GJR>uYxah^L$^gl zPX^ehET1ALu5sdOWCLGXk`abwl0ZlxQe=LR<2ha0yUZF=?Mh4OZJzEaUAn zHHw5yH%;&)vNV5VF1}4^eg}5h#pSOGA^0u$ zHE@SN8R5C{^G-PZYGx;{qdC@UXq**`C#^`+vAR{rNOZP<{1fcKuuHOVN?{XUA+@!w8e{)j^S8-u!0 zmZ&A0&)9IfkjkbXKrs@GrmQ5_%$qbUL^-)-03}d10FGi$6s)Kuq2;Q|ST2Q6+E_2L zrkJ{-qMv|nge7GS0r(0rlDC#+=!yAJNV3Z8!zRk|Q~A>9c$fLVf}%tW;tv`o6! znph|Q29EXZK>%rKhap+l6hokV<@O81@)LmRNzs93N5-AN=__C#c)Av?#-zU z^bQ;jg!9{?fHXfRYbu<5M#Uxy6`6r5XwrWkIGK{aoRA!#bLtB#f zRkpgXTc6-B@^ik)lf*UdzybPqc;!#%PJn!n|`d7{y5qky_I}V%|56mC%m^J zdb`t-^mjb*$_us4ZxC-tU_90DsYK+xaA;Z89n)*VK)`WVP$%frNw+eOwUw%A-n_ZE zRu`xMLX86$ZZKG$aKaB8&!-cF* zw9U-c0SUgjs1;=5ODB|dJ)pCOG*QgU%k_(qdc0lSn?C9d$&d_QP;3daH7GquKN6%w!JOUj%W2IZeMob zP#l>YV4y7WdsfO`)4GJMd3y)au@I`cQa>0)fi-!U;^Go!(_gsKHWtE#G0aY-fC}AzM1vMS2SRHCZ1#3N}*7~#+&?=P_ zXek{`DEx!uMxTh&XET3AOy;-=h?}AHKB4W8TTznW85dZFb4Ijmq=5E^4bybuUew+f ze9=tx4HxoQ6FIHDp?unp5$3g2UUlsQKKn2IU&vI)cE}R z`tmwVC||thrI0~3e0fze!E)(v`n}r^FLZ=Ph-L?M8go$-={kRfd-c5ud0kYP^}1$Y zj{RN`++)?hx9q37S6EKC?YdEYeQa-^A6V)T-;e$ID=hnXl2dQn(*(I<&^E4frB7p( z+jn|RhaHgXoM5)YJ(D&YP&N0EFOT-pK^GOiOPiiMyJl7i`I_={*fr}FBrnXYAoTr- z+*O=oveC*u(KCOoynDWXM82?AJ$NQ*AK3d7K-F4u5URH4IH>x((n231eOqPqkPvic zj!hLJLuuNf;G^gV1}6}NWHf$4<5wvqzORMA#0{AH`8Vfs-|$;~Iteq5sGXG=rW478 zJX-P(aL2?^3S*A+fl{`ZbTfttc6bK)W~WoXIFSCBVySa7BNvr5=K1JYG?%Sv1>wHT^~qvVb~JUhLoX~jrJH%@amKp$^T?eFt=72{%q za^TYZ(*%DAeKVPniK3-`!IS6q$@9rCGc!wE4UpIGdd!Q?m=|`;$8D3$j#k#~XXCRajVu6Lwl>C)E$H4q`AR~oV2;-CU`shX1BKB0pjI3Y*R%Zwt z+E2;kg?-rB6#7vh4BznljxGL4#TsUcroCef%vpafS{(ekPD9Fk?&OhZE6WRJc(6a> zxg;Ehe*F^u9J>PJgQq9tc_;sjpA4E(ALREWzulv7-98UYbO`r>v zZIgc$N9^g-Dm)kX5eGg_)|9J039SSZes4=8CKtiymajU>VGhcG?z=pjAb<@{dM^b_ zmoelLx)l$KVSs^5zi$dI<0V#LTTOR7KW#tiyko0RN1b`3$JqIJ4ud5_rK`#Xk#$Pu z#49^(3&AyC9r2o<`b<3#H2ssRECHC!!KQx`!n`=3KlY0{{mhZOjwfQB;4y}J!k)Wo zQwf*y2BJQd1Zv;z_*T8!sjmamYd=ya#Sog&P;?kRVyLPIbp+yHth_C@d>)AB2{T%D zK3hc9Ic-fLc7U^H>ZBN;+|Y+?BW3pEs~OqokFORCN;G(mC(`OoS^c#wOVt(xKD&Qq zE1u_SOILf1ae26bd|H*$1s?NbA6Qa>{kDIRg$qSl@BOt;sA!eBx^l=go$Y2p8Q%8W zzS_Pmpyo(ZcVGdJfNeD0zSz#yR>6Cw_X^yN7>Gc(6|4k61ezB5eFHGCpSID(!XE(6 z1>uI;PwUonvtf|bwhnuunozaPanXOdxr=U?jEiM7aWOaXmN|2bwWwsg0rbffDsmjI zmVHYV5`mxd$w(-Y}dv!Cn!$R7QWic-qiv|V%Ie%7P4%^|+G_Agx z(!pkBe3cg^!_}{KaK{{{1!Bn^ktI#M4>sZ99G{(o;UJv+^o#E3K2zte*7$$1c5H%< zzSFye4T;|xxj?DN z9qBQ_G7?=Vs*qB-n%8>MqzvdLlhCTrbZLSW`Qr~qr!k~d5)uI6^bNn&P|}t^X!%b9 z+Wg5C`Inc$K(E@KK5aF6GjTWhpdEg&je`q7L+2Bg0dMkNCmr#c(B^-5insq@OA6kD z(XdtUe*6zmO928D0}22D2nYZ-psACo%aJIqm{Gwo{Izj*uHapPS2er_SovZ zB%LWtK@wvAQ3242ug!PAT>u0D5)vgv&h?HniA7?uyV(8hVgZ6nn%&VkBTJRm%XG%l ztSXi-zW(a#uXwSngd*?hJxzI)UR<7k%-B-#s(jIFyitOe^J_+@Omu%*YsK^QR0#SY zV=ZS@p0g~%wbL5y{EC-%Z2C_s7q96uP9Rn6`3mwYQ7xHJoJFPGFy$L2uvq%OC{kL| z{6TV={!|pF_V2Fv;OT{yJ&19XcwcVt8_MXaum+7fgljR zG5xSY;3O_^5SIXtg8zS;hVER|;S&EJ=DwstGR^)<|JsIjn7d%ukY4LQ8xu|*mTUv! z8wH`YQU|$YnY7TtpJxk}-EBa3QEfnU^B@%~G+vkWZO${2duWN|)f;r-3bS^|C$cF`p)`me-wC2=S zA>WM16K5azIr@KQbO2&}Ma<7naocyog6L>z?4DIqc3_Qy9Y8Kvr_RG+GzQQ;O&6c` zfOr`@WyMlGK&nlg9rvo(0Ri4erlBD?AqI+p(vH1hEC4EVrrgt{#cFqmB3(UFE9f&v zHe}t$vgd&5_HVpZ<_eRK)e$6|VY+%Ls^Uy{Y_zvA@eqI5?eLKN$dt`+7#wX=GiYpj zgJE-Q^H~ZqY_fPr9M@nlz*gsE!e>O=zHNdhiQ}1a`9n_2JMhakA%9g#$!{U9K|1^? z2rq4%_tNP%2X5dd3p973wC2LpK)5tYr{pSURBAEze98zVvpUZo$Zs{x`HZuvXE-v0 zETk3`j0t~p8PD}pj?S60bkxZ-J+C{1Y>3VdkV4#fvltp;E@%PMX*s20dQozf^jw7q zuza;5Jq#F7o_R=!z-)BYQjJ0xkx3{3-UqH0q@cVEX*8>&zn%E<5rz0S1#_b=Nk_L( zu$6S7v`;^RVH7w`dr2)=Fld;FN^;8pN?>dN97TUhRII8Mp<-SatW+{&ZM~N`SB!mC zF;2iXQi(cK6}Tw{G+$`;8S8k#&4atnf@f8oPf1xRe*hj}X5c70P!k3nm+mwtHl@0S zV{^L~Ksw%WNH!~gAyA(Bba7aI1~3CHdeH3YxD_}<1MC7%-$RWqpk(4bABRI2hHM1> zv|WF&JwBY>fVzP017asg`wKA(YyZ(+pdHAF!@DvhYzW>ytH*(Oph*wnJw3OAxYeG0 z7Q_QV@oi_FL>Xw>aE8k4^qlM+@7>nnP%A7b0P{Zcax?P$KPmg)_1 z-{n+CK)<4jD7#%z<=K1Z(DRvi8e#BxP2=8hcB`&}jq3e{U_5MA1g1aYUf~r3(9VCM zdHC(Ow((nXS;AU7qj@g1?|${lzhBMDnyAVae$2S{W|F$@?#JI@u|o^Hl_@bH z-QLruPxZDIh?rVaw`)dx=4-7@F42GHb5=5ez(A6f4mgz(!bdw#FpS5tvYT18&?#xP zuih7sb*5}zZnC+~a*ZYRhSHL3ynXoJw(+3h%wuEr$1&%|yUF*|ZiO0lGI%j!c03)+ zaMKg7veG;K7W0+`rd0D{NhZNNhmKqQK5Km#$vOTc>gAoL?$-Ws&eF@8SFe9AuC>co z`$>kT-O4lG>p!PO5^+~YMn4~|TRO$ozCmv4aEC5Fhtw(7)goYmkf^-jbeO10k99qd zHT|6u9!)gER>2$9KShim;6o?3>#dal+ys34OA=8ienxuegQ}O9*JOrH@1f+d4x;}T z0Qk}~@CImz&ApEFb0*(j;`V>nl3v<&c4}4uYa_+W3)@Ye-T{zi;hF^I@e)$-#&yNA zzQ6s_%cJjona53E$f0&YIg|t6hlf`Fw{5-Qbm-eJT*`G<DUOGQrFV=f9};22Ix4ds8ASq^My!!Kr- zjSf0^koC6*mQ*cpD-F*lRDyS3{YN+1dixgZOM%$2i00b57Kk`~ML7^S+K&7Z;rxM1 z&_~pzoqN#)8&Cg6AV(GAn->F}jfo+8>t8@JZJq@V?^HcBpvZ^vEzdY2 zLl@$e&UmhvNDL);+VDZs;kmxIbrpuh@T!^RKv`aN7@<=K9p# zdfl_uF}a`Cmw_;M;weD0m62g-2|TgPTmOZAfSd^k3nS14s=M+I5#PZY269B1rK4TquW^xg6070QKa=^=1Q z_q5la0jtiHgIIrcl$&8Sl$BTJ2;!T%Xu8C(bKp5uLo!x^?F&Def24B;X-FlT4`}mw zN~<4QAu@1_=JoR1Q=PB)tvTC*)kV^+z^u@bVp1K>_(!;7@-T-!hvqmUn~wT5!w3nU zLiN}qTCWb2I(E&`RMMuJ>lV|kVi-t%#hG|LQec-vDw=;*N=v-svEE_54~TYbQ|D4K zm%9!{_uX_jNc@O{+OUQn9-1pt18?oq+>fTL?~nK#YgXL&T8^-L2CVDimI<6MjT(AM zM#&v}czSYA^O})@F1_YRhCW)JxZmgLJjLk-6~W2*?Fcx1KRO^I%}oD-C(qoIXQN*Z z>@aaYKw*Esn?BEbeV)5MpH|KjD0r*IVayY%vgZKS2TJ=vPMYEWr}iDXc0($0*)t}8 zCC@N5e;27rp%oJO=)8G#-}i}oD}O-dFbC^*&>rt6Wc1uU?Cq}nED?yo=WpoTJI27F zV%m`quHp=+?B_B8i>|SPbcP4R6J9F9q3d@q;Lm@NuP{D%a!j7}N|5F(du?rpl{g=p zlwodQkl&A2E>D}Y<(kbP{!7lv41mqlqOui*C+eMoq3R^X&-cU zsE*WpHJMV0STzY?Z3cJ=b({%*S43C3;wE#B;4{Y^cq#EK0DPP+DAzO@ttFEowPTW! zi|BuICs!W@uqQ3R_~NZ{p~q33OHrt*)0Zh^-ScA;IF)wGf>5^&z3jNhmZxK}(<2LI5<|qcO*X z1)0EnE|&D@?4hk*EaGAz5Dbe7cXFr8CBA>4w-^n%WUvD6_wTHFd#mio@VbxmStG<| zGL#>N52@)DgnonmFD7oQ6(5-4iL`=>-iL2!Iel%eCL2H z&F4E)2J196k1U|cEb6%Eum)3-hjd{3%np&@^D?BL1KC-L^|E+)i zrU$1A(d_kg4>%Z;`L^=dw8U=5K*TryR?oL@Dp+^qx!dGXeKmmd*Es;pXp;e3;f(SwMoa^nZ3f6MgNuAWWja)Tg#f_XLJ~4F!6t~kGe!^ zz7fSZlZ=XNVU8Lim0y+MD-(UB6F60+r#+TfR-+5e6^bg~^2Tn4l?B~s6q^-Vk~Ue9 zKmPD+nnF>fpaPH{ZTu~U)>gbW`X5KE`PNtYmlx4QuiKtH=`;o-@#UZ&Uc1J@383Zk z8Ph;8_<+b{yf(FkpDyC@0de{RdD>0Rj{Q3IG5I2mqvGgtHHx5&;A0 tnpv|XpNj|s8JK~yvZu`m4zhb&R$)ojUGWS60A)jyjj%ul)13eS002@jx%~hD diff --git a/libs/comp2023-lib.jar b/libs/comp2023-lib.jar index bf2de1269c283023c2044151fb4d65913b7a7253..41cf62d79dccb62f129b77a3f201c958a1949daf 100644 GIT binary patch delta 7940 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 From 69284122d1cc2f514585d08082de971b6e37a512 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 9 May 2023 23:33:39 +0100 Subject: [PATCH 122/253] Added basic structure of semanticsResult optimization method --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 94371c7..7100505 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -39,8 +39,12 @@ public OllirResult toOllir(JmmSemanticsResult semanticsResult) { public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { ConstantPropagation constantPropagation = new ConstantPropagation(semanticsResult); ConstantFolding constantFolding = new ConstantFolding(semanticsResult); + boolean codeModified = constantFolding.apply(); //TODO: change to constantPropagation.aplly() || constantFolding.apply() + + while(codeModified){ + codeModified = constantFolding.apply(); //TODO: change to constantPropagation.aplly() || constantFolding.apply() + } - //TODO return semanticsResult; } From 0799f2de37d29e401b177f38aa90b28e539c67cd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 9 May 2023 23:34:20 +0100 Subject: [PATCH 123/253] Add default visitor of ConstantFolding class --- .../optimization/ConstantFolding.java | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 539da68..ce8d875 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -3,17 +3,62 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; -import pt.up.fe.comp2023.semantic.MySymbolTable; +import pt.up.fe.comp.jmm.ast.JmmNode; public class ConstantFolding extends AJmmVisitor { + private JmmSemanticsResult semanticsResult; private SymbolTable symbolTable; private String currentMethodName; + private boolean codeModified; public ConstantFolding (JmmSemanticsResult semanticsResult){ + this.semanticsResult = semanticsResult; this.symbolTable = semanticsResult.getSymbolTable(); } + public boolean apply(){ + this.codeModified = false; + visit(semanticsResult.getRootNode()); + return this.codeModified; + } + @Override protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); + addVisit("ParenthesesExpr", this::computeParenthesesExprResult); + addVisit("NegationExpr", this::negateBooleanExpr); + addVisit("ArithmeticExpr", this::computeArithmeticExprResult); + addVisit("ComparisonExpr", this::computeComparisonResult); + addVisit("LogicalExpr", this::computeLogicalExprResult); + } + + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; + } + + private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { + //TODO + return null; + } + + private Void negateBooleanExpr(JmmNode jmmNode, Void unused) { + //TODO + return null; + } + + private Void computeArithmeticExprResult(JmmNode jmmNode, Void unused) { + //TODO + return null; + } + + private Void computeComparisonResult(JmmNode jmmNode, Void unused) { + //TODO + return null; + } + private Void computeLogicalExprResult(JmmNode jmmNode, Void unused) { + //TODO + return null; } } From db765ea91c5d7d3eab03b5f1c39ed5364a22883c Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 00:09:52 +0100 Subject: [PATCH 124/253] Add method to compute the result of a paretheses expr --- src/main/pt/up/fe/comp2023/Launcher.java | 9 +++++++-- .../pt/up/fe/comp2023/ollir/Optimization.java | 9 ++------- .../fe/comp2023/optimization/ConstantFolding.java | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index fccc669..7ed0f20 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -71,12 +71,17 @@ public static void main(String[] args) { // Check if there are semantic errors TestUtils.noErrors(semanticsResult.getReports()); + Optimization optimization = new Optimization(); + if(Boolean.parseBoolean(config.get("optimize"))){ System.out.println("Applying optimizations..."); - //TODO: apply optimizations (constant propagation and constant folding) + + optimization.optimize(semanticsResult); + + // Output AST after optimizations + System.out.println(semanticsResult.getRootNode().toTree()); } - Optimization optimization = new Optimization(semanticsResult); OllirResult ollirResult = optimization.toOllir(semanticsResult); JasminGenerator jasminGenerator = new JasminGenerator(); diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 7100505..33a168b 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -19,16 +19,12 @@ public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; List reports = new ArrayList<>(); - private final SymbolTable table; + private SymbolTable table; int tempVarId = 0; - - public Optimization(JmmSemanticsResult semanticsResult){ - this.table = semanticsResult.getSymbolTable(); - } - @Override public OllirResult toOllir(JmmSemanticsResult semanticsResult) { + this.table = semanticsResult.getSymbolTable(); visit(semanticsResult.getRootNode()); code += "} \n"; System.out.println(code); @@ -44,7 +40,6 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { while(codeModified){ codeModified = constantFolding.apply(); //TODO: change to constantPropagation.aplly() || constantFolding.apply() } - return semanticsResult; } diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index ce8d875..99ae954 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -38,7 +38,20 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { - //TODO + System.out.println("Parentheses Expr"); + visit(jmmNode.getJmmChild(0)); + JmmNode exprNode = jmmNode.getJmmChild(0); + + if(exprNode.getKind().equals("Integer")){ + this.codeModified = true; + jmmNode.replace(exprNode); + } + + else if(exprNode.getKind().equals("Boolean")){ + this.codeModified = true; + jmmNode.replace(exprNode); + } + return null; } From 6763d9f0001889dd736e1dbe75504ca4465d215d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 00:10:45 +0100 Subject: [PATCH 125/253] Refactor computeParenthesesExprResult() --- .../pt/up/fe/comp2023/optimization/ConstantFolding.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 99ae954..2e54be5 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -42,12 +42,7 @@ private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { visit(jmmNode.getJmmChild(0)); JmmNode exprNode = jmmNode.getJmmChild(0); - if(exprNode.getKind().equals("Integer")){ - this.codeModified = true; - jmmNode.replace(exprNode); - } - - else if(exprNode.getKind().equals("Boolean")){ + if(exprNode.getKind().equals("Integer") || exprNode.getKind().equals("Boolean")){ this.codeModified = true; jmmNode.replace(exprNode); } From b3b6cb2efde2719507eff1cd038884b5aa4d1611 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 00:30:16 +0100 Subject: [PATCH 126/253] Add method to compute the value of a negation expr --- src/main/antlr/comp2023/grammar/Javamm.g4 | 8 ++++---- .../fe/comp2023/optimization/ConstantFolding.java | 13 +++++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index 16ed215..dd9009c 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -49,11 +49,11 @@ type locals[boolean isArray = false] statement : '{' statement* '}' #CodeBlock - | 'if' '(' condition=expression ')' iftrue=statement 'else' iffalse=statement #Condition - | 'while' '(' condition=expression ')' whiletrue=statement #Cycle + | 'if' '(' expression ')' statement 'else' statement #Condition + | 'while' '(' expression ')' statement #Cycle | expression ';' #Expr - | varname=ID '=' value=expression ';' #Assignment - | arrayname=ID '[' index=expression ']' '=' value=expression ';' #ArrayAssignment + | varname=ID '=' expression ';' #Assignment + | arrayname=ID '[' expression ']' '=' expression ';' #ArrayAssignment ; expression diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 2e54be5..2883769 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -6,7 +6,7 @@ import pt.up.fe.comp.jmm.ast.JmmNode; public class ConstantFolding extends AJmmVisitor { - private JmmSemanticsResult semanticsResult; + private final JmmSemanticsResult semanticsResult; private SymbolTable symbolTable; private String currentMethodName; private boolean codeModified; @@ -51,7 +51,16 @@ private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { } private Void negateBooleanExpr(JmmNode jmmNode, Void unused) { - //TODO + visit(jmmNode.getJmmChild(0)); + JmmNode exprNode = jmmNode.getJmmChild(0); + + if (exprNode.getKind().equals("Boolean")) { + this.codeModified = true; + boolean exprValue = Boolean.parseBoolean(exprNode.get("value")); + exprNode.put("value", String.valueOf(!exprValue)); + jmmNode.replace(exprNode); + } + return null; } From 366ea7173e2bafb47c74e4ce399a4be4551b4f82 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 00:59:00 +0100 Subject: [PATCH 127/253] Add method to compute the value of a logical expression --- .../comp2023/optimization/ConstantFolding.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 2883769..059fa5f 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -75,7 +75,23 @@ private Void computeComparisonResult(JmmNode jmmNode, Void unused) { } private Void computeLogicalExprResult(JmmNode jmmNode, Void unused) { - //TODO + visit(jmmNode.getJmmChild(0)); + visit(jmmNode.getJmmChild(1)); + JmmNode leftExpr = jmmNode.getJmmChild(0); + JmmNode rightExpr = jmmNode.getJmmChild(1); + String operator = jmmNode.get("op"); + + if (leftExpr.getKind().equals("Boolean") && rightExpr.getKind().equals("Boolean")){ + this.codeModified = true; + boolean leftValue = Boolean.parseBoolean(leftExpr.get("value")); + boolean rightValue = Boolean.parseBoolean(rightExpr.get("value")); + + if (operator.equals("&&")) + leftExpr.put("value", String.valueOf(leftValue && rightValue)); + else + leftExpr.put("value", String.valueOf(leftValue || rightValue)); + jmmNode.replace(leftExpr); + } return null; } } From 7f606d1361ced59517feb1606f49d836dfec8b53 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 01:28:29 +0100 Subject: [PATCH 128/253] Add method to compute the value of a comparison expression --- .../optimization/ConstantFolding.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 059fa5f..233f5b5 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -70,7 +70,25 @@ private Void computeArithmeticExprResult(JmmNode jmmNode, Void unused) { } private Void computeComparisonResult(JmmNode jmmNode, Void unused) { - //TODO + visit(jmmNode.getJmmChild(0)); + visit(jmmNode.getJmmChild(1)); + JmmNode leftExpr = jmmNode.getJmmChild(0); + JmmNode rightExpr = jmmNode.getJmmChild(1); + String operator = jmmNode.get("op"); + + if (leftExpr.getKind().equals("Integer") && rightExpr.getKind().equals("Integer")){ + this.codeModified = true; + int leftValue = Integer.parseInt(leftExpr.get("value")); + int rightValue = Integer.parseInt(rightExpr.get("value")); + + if (operator.equals("<")) + leftExpr.put("value", String.valueOf(leftValue < rightValue)); + else + leftExpr.put("value", String.valueOf(leftValue > rightValue)); + + //TODO: Change kind of leftExpr to a boolean + jmmNode.replace(leftExpr); + } return null; } From 515e89de1165914c41d4a0cec2a18db8bfedcbb4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 01:38:37 +0100 Subject: [PATCH 129/253] Add method to compute the value of a arithmetic expression --- .../optimization/ConstantFolding.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 233f5b5..5457aa9 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -38,7 +38,6 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { - System.out.println("Parentheses Expr"); visit(jmmNode.getJmmChild(0)); JmmNode exprNode = jmmNode.getJmmChild(0); @@ -46,7 +45,6 @@ private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { this.codeModified = true; jmmNode.replace(exprNode); } - return null; } @@ -60,12 +58,29 @@ private Void negateBooleanExpr(JmmNode jmmNode, Void unused) { exprNode.put("value", String.valueOf(!exprValue)); jmmNode.replace(exprNode); } - return null; } private Void computeArithmeticExprResult(JmmNode jmmNode, Void unused) { - //TODO + visit(jmmNode.getJmmChild(0)); + visit(jmmNode.getJmmChild(1)); + JmmNode leftExpr = jmmNode.getJmmChild(0); + JmmNode rightExpr = jmmNode.getJmmChild(1); + String operator = jmmNode.get("op"); + + if (leftExpr.getKind().equals("Integer") && rightExpr.getKind().equals("Integer")){ + this.codeModified = true; + int leftValue = Integer.parseInt(leftExpr.get("value")); + int rightValue = Integer.parseInt(rightExpr.get("value")); + + switch (operator) { + case "+" -> leftExpr.put("value", String.valueOf(leftValue + rightValue)); + case "-" -> leftExpr.put("value", String.valueOf(leftValue - rightValue)); + case "*" -> leftExpr.put("value", String.valueOf(leftValue * rightValue)); + case "/" -> leftExpr.put("value", String.valueOf(leftValue / rightValue)); + } + jmmNode.replace(leftExpr); + } return null; } @@ -85,7 +100,7 @@ private Void computeComparisonResult(JmmNode jmmNode, Void unused) { leftExpr.put("value", String.valueOf(leftValue < rightValue)); else leftExpr.put("value", String.valueOf(leftValue > rightValue)); - + //TODO: Change kind of leftExpr to a boolean jmmNode.replace(leftExpr); } From 7162c02d4d7f16d334dbcdebdb0ebff6ce82e718 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 01:41:12 +0100 Subject: [PATCH 130/253] Refactor ConstantFolding to remove unnecessary fields --- src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 5457aa9..ac54d54 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -1,18 +1,14 @@ package pt.up.fe.comp2023.optimization; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; -import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; public class ConstantFolding extends AJmmVisitor { private final JmmSemanticsResult semanticsResult; - private SymbolTable symbolTable; - private String currentMethodName; private boolean codeModified; public ConstantFolding (JmmSemanticsResult semanticsResult){ this.semanticsResult = semanticsResult; - this.symbolTable = semanticsResult.getSymbolTable(); } public boolean apply(){ From 4a1fba6e8c6cedbaed794ae2d0fc12419567cdc1 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 01:49:13 +0100 Subject: [PATCH 131/253] Add default visitor of ConstantPropagation --- .../optimization/ConstantPropagation.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 7255b08..5b9f97d 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -3,17 +3,32 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; +import pt.up.fe.comp.jmm.ast.JmmNode; public class ConstantPropagation extends AJmmVisitor { private SymbolTable symbolTable; - private String currentMethodName; + private final JmmSemanticsResult semanticsResult; + private boolean codeModified; public ConstantPropagation (JmmSemanticsResult semanticsResult){ this.symbolTable = semanticsResult.getSymbolTable(); + this.semanticsResult = semanticsResult; + } + + public boolean apply(){ + this.codeModified = false; + visit(semanticsResult.getRootNode()); + return this.codeModified; } @Override protected void buildVisitor() { + setDefaultVisit(this::setDefaultVisit); + } + private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + for (JmmNode child: jmmNode.getChildren()) + visit(child); + return null; } } From eb8d5d4578cebadcac20a9223d58abaa4547c216 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 01:50:54 +0100 Subject: [PATCH 132/253] Apply constantPropagation during semanticsResult optimization --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 33a168b..efd21db 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -35,10 +35,10 @@ public OllirResult toOllir(JmmSemanticsResult semanticsResult) { public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { ConstantPropagation constantPropagation = new ConstantPropagation(semanticsResult); ConstantFolding constantFolding = new ConstantFolding(semanticsResult); - boolean codeModified = constantFolding.apply(); //TODO: change to constantPropagation.aplly() || constantFolding.apply() + boolean codeModified = constantPropagation.apply() || constantFolding.apply(); while(codeModified){ - codeModified = constantFolding.apply(); //TODO: change to constantPropagation.aplly() || constantFolding.apply() + codeModified = constantPropagation.apply() || constantFolding.apply(); } return semanticsResult; } From fd3cbc7d4f1fd3ab7b1571c6ef00c52ebf160960 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 10 May 2023 19:35:11 +0100 Subject: [PATCH 133/253] Improved computeComparisonResul() --- src/main/pt/up/fe/comp2023/Launcher.java | 1 + .../pt/up/fe/comp2023/optimization/ConstantFolding.java | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 7ed0f20..40521f4 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -73,6 +73,7 @@ public static void main(String[] args) { Optimization optimization = new Optimization(); + //Apply Constant Propagation and Constant Folding optimizations if(Boolean.parseBoolean(config.get("optimize"))){ System.out.println("Applying optimizations..."); diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index ac54d54..6849cd7 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -3,6 +3,7 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.ast.JmmNodeImpl; public class ConstantFolding extends AJmmVisitor { private final JmmSemanticsResult semanticsResult; @@ -91,14 +92,14 @@ private Void computeComparisonResult(JmmNode jmmNode, Void unused) { this.codeModified = true; int leftValue = Integer.parseInt(leftExpr.get("value")); int rightValue = Integer.parseInt(rightExpr.get("value")); + JmmNodeImpl newNode = new JmmNodeImpl("Boolean"); if (operator.equals("<")) - leftExpr.put("value", String.valueOf(leftValue < rightValue)); + newNode.put("value", String.valueOf(leftValue < rightValue)); else - leftExpr.put("value", String.valueOf(leftValue > rightValue)); + newNode.put("value", String.valueOf(leftValue > rightValue)); - //TODO: Change kind of leftExpr to a boolean - jmmNode.replace(leftExpr); + jmmNode.replace(newNode); } return null; } From 13a046f5e4318a8a0232289d8fc0899d88dc8c83 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 11 May 2023 18:45:15 +0100 Subject: [PATCH 134/253] initial version while cycles --- .../pt/up/fe/comp2023/ollir/Optimization.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 45b80b6..a23f911 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -41,7 +41,7 @@ protected void buildVisitor() { addVisit("VarDecl", this::dealWithVarDecl); addVisit("CodeBlock", this::dealWithCodeBlock); addVisit("Condition", this::dealWithCondition); - // addVisit("Cycle", this::dealWithCycle); // not for checkpoint 2 + addVisit("Cycle", this::dealWithCycle); addVisit("Expr", this::dealWithExpr); addVisit("Assignment", this::dealWithAssignment); addVisit("ArrayAssignment", this::dealWithArrayAssignment); @@ -61,8 +61,27 @@ protected void buildVisitor() { addVisit("Identifier", this::dealWithIdentifier); } + private Void dealWithCycle(JmmNode jmmNode, Void unused) { + code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += "\n"; + var ifId = tempVarId++; + + // Condition statement - negation + code += "\t\tif (!.bool " + temp + ") goto end_loop" + ifId + ";\n"; + + // What occurs if the condition is met + code += "\t\tloop" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); + code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += "\n"; + code += "\t\t if( " + temp + ") goto loop" + ifId + ";\n"; + + // End of If + code +="\t\tend_loop" + ifId + ":\n\t"; + + + return null; + } + private Void dealWithCondition(JmmNode jmmNode, Void unused) { - code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += ";\n"; + code += "\t\t"; visit(jmmNode.getJmmChild(0)); var ifId = tempVarId++; // Condition statement @@ -268,6 +287,8 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { JmmNode leftSon = jmmNode.getJmmChild(0); JmmNode rightSon = jmmNode.getJmmChild(1); var condition = jmmNode.getAncestor("Condition"); + var cycle = jmmNode.getAncestor("Cycle"); + visit(leftSon); visit(rightSon); @@ -277,7 +298,7 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { temp = "t" + tempVarId++ + ".bool"; code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right; - if (condition.isEmpty()) + if (condition.isEmpty() || cycle.isEmpty()) code += ";\n"; jmmNode.put("valueOl", temp); @@ -378,11 +399,14 @@ else if (isField) } private Void dealWithExpr(JmmNode jmmNode, Void unused) { + var cycle = jmmNode.getAncestor("Cycle"); code += "\t\t"; for (var child : jmmNode.getChildren()) visit(child); - code += ";\n"; + if (cycle.isEmpty()) + code += ";\n"; + System.out.println(jmmNode.getKind()); return null; } From 1ea684feead5bd2f66a19405d03420c3874dc87d Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 11 May 2023 23:22:02 +0100 Subject: [PATCH 135/253] hotfix operator type --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index a23f911..ffa0c4c 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -297,7 +297,7 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".i32 " + right; + code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; if (condition.isEmpty() || cycle.isEmpty()) code += ";\n"; jmmNode.put("valueOl", temp); From 752ce748da1efaa5c68522e41aae72308302d218 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 02:48:13 +0100 Subject: [PATCH 136/253] Refactor ConstantFolding methods --- .../comp2023/optimization/ConstantFolding.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 6849cd7..1a1f376 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -35,8 +35,8 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { } private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { - visit(jmmNode.getJmmChild(0)); JmmNode exprNode = jmmNode.getJmmChild(0); + visit(exprNode); if(exprNode.getKind().equals("Integer") || exprNode.getKind().equals("Boolean")){ this.codeModified = true; @@ -46,8 +46,8 @@ private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { } private Void negateBooleanExpr(JmmNode jmmNode, Void unused) { - visit(jmmNode.getJmmChild(0)); JmmNode exprNode = jmmNode.getJmmChild(0); + visit(exprNode); if (exprNode.getKind().equals("Boolean")) { this.codeModified = true; @@ -59,11 +59,11 @@ private Void negateBooleanExpr(JmmNode jmmNode, Void unused) { } private Void computeArithmeticExprResult(JmmNode jmmNode, Void unused) { - visit(jmmNode.getJmmChild(0)); - visit(jmmNode.getJmmChild(1)); JmmNode leftExpr = jmmNode.getJmmChild(0); JmmNode rightExpr = jmmNode.getJmmChild(1); String operator = jmmNode.get("op"); + visit(leftExpr); + visit(rightExpr); if (leftExpr.getKind().equals("Integer") && rightExpr.getKind().equals("Integer")){ this.codeModified = true; @@ -82,11 +82,11 @@ private Void computeArithmeticExprResult(JmmNode jmmNode, Void unused) { } private Void computeComparisonResult(JmmNode jmmNode, Void unused) { - visit(jmmNode.getJmmChild(0)); - visit(jmmNode.getJmmChild(1)); JmmNode leftExpr = jmmNode.getJmmChild(0); JmmNode rightExpr = jmmNode.getJmmChild(1); String operator = jmmNode.get("op"); + visit(leftExpr); + visit(rightExpr); if (leftExpr.getKind().equals("Integer") && rightExpr.getKind().equals("Integer")){ this.codeModified = true; @@ -105,11 +105,11 @@ private Void computeComparisonResult(JmmNode jmmNode, Void unused) { } private Void computeLogicalExprResult(JmmNode jmmNode, Void unused) { - visit(jmmNode.getJmmChild(0)); - visit(jmmNode.getJmmChild(1)); JmmNode leftExpr = jmmNode.getJmmChild(0); JmmNode rightExpr = jmmNode.getJmmChild(1); String operator = jmmNode.get("op"); + visit(leftExpr); + visit(rightExpr); if (leftExpr.getKind().equals("Boolean") && rightExpr.getKind().equals("Boolean")){ this.codeModified = true; From da25fc5bb1ce77b9dc98758731ba42b98ed2cfdc Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 02:50:38 +0100 Subject: [PATCH 137/253] Improved ConstantPropagation in order to store constants --- .../optimization/ConstantPropagation.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 5b9f97d..da8d904 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -1,34 +1,52 @@ package pt.up.fe.comp2023.optimization; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; -import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; -public class ConstantPropagation extends AJmmVisitor { - private SymbolTable symbolTable; +import java.util.HashMap; +import java.util.Map; + +public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; private boolean codeModified; public ConstantPropagation (JmmSemanticsResult semanticsResult){ - this.symbolTable = semanticsResult.getSymbolTable(); this.semanticsResult = semanticsResult; } public boolean apply(){ this.codeModified = false; - visit(semanticsResult.getRootNode()); + Map constants = new HashMap<>(); + + visit(semanticsResult.getRootNode(), constants); return this.codeModified; } @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); + addVisit("Assignment", this::dealWithAssignment); + addVisit("Identifier", this::dealWithIdentifier); } - private Void setDefaultVisit(JmmNode jmmNode, Void unused) { + private Void setDefaultVisit(JmmNode jmmNode, Map constants) { for (JmmNode child: jmmNode.getChildren()) - visit(child); + visit(child, constants); + return null; + } + + private Void dealWithAssignment(JmmNode jmmNode, Map stringStringMap) { + String varName = jmmNode.get("varname"); + //TODO return null; } + + private Void dealWithIdentifier(JmmNode jmmNode, Map stringStringMap) { + //TODO + + return null; + } + + } From 31a9bfe9686af1ec095fa08b4a0157a5daf41a92 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 02:56:29 +0100 Subject: [PATCH 138/253] Implemented dealWithAssignment() in ConstantPropagation --- .../comp2023/optimization/ConstantPropagation.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index da8d904..c4d3752 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -36,13 +36,19 @@ private Void setDefaultVisit(JmmNode jmmNode, Map constants) { return null; } - private Void dealWithAssignment(JmmNode jmmNode, Map stringStringMap) { + private Void dealWithAssignment(JmmNode jmmNode, Map constants) { String varName = jmmNode.get("varname"); - //TODO + JmmNode exprNode = jmmNode.getJmmChild(0); + visit(exprNode); + + if (exprNode.getKind().equals("Integer") || exprNode.getKind().equals("Boolean")) + constants.put(varName, exprNode.get("value")); + else //Unknown Value + constants.remove(varName); return null; } - private Void dealWithIdentifier(JmmNode jmmNode, Map stringStringMap) { + private Void dealWithIdentifier(JmmNode jmmNode, Map constants) { //TODO return null; From aeb9638ae894299386b0d427a482f10afa480093 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 03:15:53 +0100 Subject: [PATCH 139/253] Add visitor for a method declaration in ConstantPropagation --- .../optimization/ConstantPropagation.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index c4d3752..4cf9886 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -1,6 +1,7 @@ package pt.up.fe.comp2023.optimization; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; +import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; @@ -9,10 +10,13 @@ public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; + private final SymbolTable symbolTable; + private String currentMethodName; private boolean codeModified; public ConstantPropagation (JmmSemanticsResult semanticsResult){ this.semanticsResult = semanticsResult; + this.symbolTable = semanticsResult.getSymbolTable(); } public boolean apply(){ @@ -26,6 +30,9 @@ public boolean apply(){ @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); + addVisit("MethodDecl", this::changeCurrentMethodName); + addVisit("VoidMethodDecl", this::changeCurrentMethodName); + addVisit("MainMethodDecl", this::changeCurrentMethodName); addVisit("Assignment", this::dealWithAssignment); addVisit("Identifier", this::dealWithIdentifier); } @@ -36,10 +43,19 @@ private Void setDefaultVisit(JmmNode jmmNode, Map constants) { return null; } + private Void changeCurrentMethodName(JmmNode jmmNode, Map constants) { + this.currentMethodName = jmmNode.get("methodname"); + constants.clear(); + + for (JmmNode child: jmmNode.getChildren()) + visit(child, constants); + return null; + } + private Void dealWithAssignment(JmmNode jmmNode, Map constants) { String varName = jmmNode.get("varname"); JmmNode exprNode = jmmNode.getJmmChild(0); - visit(exprNode); + visit(exprNode, constants); if (exprNode.getKind().equals("Integer") || exprNode.getKind().equals("Boolean")) constants.put(varName, exprNode.get("value")); @@ -49,7 +65,7 @@ private Void dealWithAssignment(JmmNode jmmNode, Map constants) } private Void dealWithIdentifier(JmmNode jmmNode, Map constants) { - //TODO + String identifierName = jmmNode.get("value"); return null; } From fde2a63af2d1c90015a2b273d97a35ac9be09104 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 04:08:54 +0100 Subject: [PATCH 140/253] Add visitor for Identifier in ConstantPropagation --- .../optimization/ConstantPropagation.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 4cf9886..e5a7c50 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -2,12 +2,17 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; +import pt.up.fe.comp.jmm.ast.JmmNodeImpl; +import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.HashMap; import java.util.Map; +import static pt.up.fe.comp2023.semantic.SemanticUtils.getIdentifierType; + public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; private final SymbolTable symbolTable; @@ -48,7 +53,7 @@ private Void changeCurrentMethodName(JmmNode jmmNode, Map consta constants.clear(); for (JmmNode child: jmmNode.getChildren()) - visit(child, constants); + visit(child, constants); //each statement modifies the map return null; } @@ -66,7 +71,20 @@ private Void dealWithAssignment(JmmNode jmmNode, Map constants) private Void dealWithIdentifier(JmmNode jmmNode, Map constants) { String identifierName = jmmNode.get("value"); - + String constant = constants.get(identifierName); + + if(constant != null) { + if(constant.equals("true") || constant.equals("false")) { //Boolean constant + JmmNode newNode = new JmmNodeImpl("Boolean"); + jmmNode.replace(newNode); + this.codeModified = true; + } + else { //Integer constant + JmmNode newNode = new JmmNodeImpl("Integer"); + jmmNode.replace(newNode); + this.codeModified = true; + } + } return null; } From 6bf279c1cf92b6a0dcd9220fd94965ed254e864e Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 04:09:59 +0100 Subject: [PATCH 141/253] Refactor Identifier visitor in ConstantPropagation --- .../optimization/ConstantPropagation.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index e5a7c50..9185668 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -74,16 +74,13 @@ private Void dealWithIdentifier(JmmNode jmmNode, Map constants) String constant = constants.get(identifierName); if(constant != null) { - if(constant.equals("true") || constant.equals("false")) { //Boolean constant - JmmNode newNode = new JmmNodeImpl("Boolean"); - jmmNode.replace(newNode); - this.codeModified = true; - } - else { //Integer constant - JmmNode newNode = new JmmNodeImpl("Integer"); - jmmNode.replace(newNode); - this.codeModified = true; - } + JmmNode newNode; + if(constant.equals("true") || constant.equals("false")) //Boolean constant + newNode = new JmmNodeImpl("Boolean"); + else //Integer constant + newNode = new JmmNodeImpl("Integer"); + jmmNode.replace(newNode); + this.codeModified = true; } return null; } From f046dd4156944ad281930fa2b13d5fcea0ac4c91 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 04:21:08 +0100 Subject: [PATCH 142/253] Fix dealWithIdentifier() to set the value attribute of the new node --- .../pt/up/fe/comp2023/optimization/ConstantPropagation.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 9185668..3f86873 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -75,15 +75,14 @@ private Void dealWithIdentifier(JmmNode jmmNode, Map constants) if(constant != null) { JmmNode newNode; - if(constant.equals("true") || constant.equals("false")) //Boolean constant + if(constant.equals("true") || constant.equals("false")) //Boolean constant newNode = new JmmNodeImpl("Boolean"); else //Integer constant newNode = new JmmNodeImpl("Integer"); + newNode.put("value", constant); jmmNode.replace(newNode); this.codeModified = true; } return null; } - - } From da121b7d5545915df4303aad80fdd38ed4a1c54a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 04:42:35 +0100 Subject: [PATCH 143/253] Add visitor to Cycle node in ConstantPropagation --- .../optimization/ConstantPropagation.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 3f86873..b6e0999 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -38,6 +38,7 @@ protected void buildVisitor() { addVisit("MethodDecl", this::changeCurrentMethodName); addVisit("VoidMethodDecl", this::changeCurrentMethodName); addVisit("MainMethodDecl", this::changeCurrentMethodName); + addVisit("Cycle", this::dealWithCycle); addVisit("Assignment", this::dealWithAssignment); addVisit("Identifier", this::dealWithIdentifier); } @@ -57,6 +58,20 @@ private Void changeCurrentMethodName(JmmNode jmmNode, Map consta return null; } + private Void dealWithCycle(JmmNode jmmNode, Map constants) { + JmmNode conditionNode = jmmNode.getJmmChild(0); + visit(conditionNode, constants); + + if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) //Dead code + jmmNode.getJmmParent().removeJmmChild(jmmNode); + else { + //TODO: check which variables are modified and remove them from the map + for (JmmNode child: jmmNode.getChildren()) + visit(child, constants); //each statement modifies the map + } + return null; + } + private Void dealWithAssignment(JmmNode jmmNode, Map constants) { String varName = jmmNode.get("varname"); JmmNode exprNode = jmmNode.getJmmChild(0); From ba6d766d7f66e865fee2309f33c1409194dce950 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 13:21:37 +0100 Subject: [PATCH 144/253] Add method to check the value of a cycle condition in ConstantFolding --- .../comp2023/optimization/ConstantFolding.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 1a1f376..04342a4 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -21,11 +21,14 @@ public boolean apply(){ @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); + addVisit("Cycle", this::checkCycleCondition); + //TODO: add visit to "Condition" and check the value of the condition addVisit("ParenthesesExpr", this::computeParenthesesExprResult); addVisit("NegationExpr", this::negateBooleanExpr); addVisit("ArithmeticExpr", this::computeArithmeticExprResult); addVisit("ComparisonExpr", this::computeComparisonResult); addVisit("LogicalExpr", this::computeLogicalExprResult); + } private Void setDefaultVisit(JmmNode jmmNode, Void unused) { @@ -34,6 +37,20 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { return null; } + private Void checkCycleCondition(JmmNode jmmNode, Void unused) { + JmmNode conditionNode = jmmNode.getJmmChild(0); + visit(conditionNode); + + if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { //Dead code + jmmNode.getJmmParent().removeJmmChild(jmmNode); + } + else { //Condition value is 'true' or undefined + for (JmmNode child : jmmNode.getChildren()) + visit(child); + } + return null; + } + private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { JmmNode exprNode = jmmNode.getJmmChild(0); visit(exprNode); From 1e3be57dea913f09e50d1b9f114d049f08091bd7 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 15:14:28 +0100 Subject: [PATCH 145/253] Add method to check value of IfElse statement in ConstantFolding --- .../optimization/ConstantFolding.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 04342a4..2b5d84b 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -22,6 +22,7 @@ public boolean apply(){ protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); addVisit("Cycle", this::checkCycleCondition); + addVisit("Condition", this::checkIfElseCondition); //TODO: add visit to "Condition" and check the value of the condition addVisit("ParenthesesExpr", this::computeParenthesesExprResult); addVisit("NegationExpr", this::negateBooleanExpr); @@ -37,6 +38,43 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { return null; } + private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { + JmmNode conditionNode = jmmNode.getJmmChild(0); + JmmNode ifTrue = jmmNode.getJmmChild(1); + JmmNode ifFalse = jmmNode.getJmmChild(2); + int ifElseIndex = jmmNode.getIndexOfSelf(); + visit(conditionNode); + + //'else' block code is never reached (condition value == 'true') + if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("true")) { + if (ifTrue.getKind().equals("CodeBlock")){ + for(JmmNode child : ifTrue.getChildren()) + jmmNode.getJmmParent().setChild(child, child.getIndexOfSelf() + ifElseIndex); + } + else + jmmNode.getJmmParent().setChild(ifTrue, ifElseIndex); + jmmNode.delete(); + } + + //'if' block code is never executed (condition value == 'false') + else if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { + if (ifFalse.getKind().equals("CodeBlock")){ + for(JmmNode child : ifFalse.getChildren()) + jmmNode.getJmmParent().setChild(child, child.getIndexOfSelf() + ifElseIndex); + } + else + jmmNode.getJmmParent().setChild(ifFalse, ifElseIndex); + jmmNode.delete(); + } + + //condition value is undefined + else { + visit(ifTrue); + visit(ifFalse); + } + return null; + } + private Void checkCycleCondition(JmmNode jmmNode, Void unused) { JmmNode conditionNode = jmmNode.getJmmChild(0); visit(conditionNode); From aec32a636fc37840701380e9a37bb3503a14ab16 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 15:25:18 +0100 Subject: [PATCH 146/253] Fix checkIfElseCondition() to use 'add' method instead of 'setChild' --- .../up/fe/comp2023/optimization/ConstantFolding.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 2b5d84b..ddcc80e 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -45,25 +45,25 @@ private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { int ifElseIndex = jmmNode.getIndexOfSelf(); visit(conditionNode); - //'else' block code is never reached (condition value == 'true') + //'else' block code is never reached (condition value is 'true') if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("true")) { if (ifTrue.getKind().equals("CodeBlock")){ for(JmmNode child : ifTrue.getChildren()) - jmmNode.getJmmParent().setChild(child, child.getIndexOfSelf() + ifElseIndex); + jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); } else - jmmNode.getJmmParent().setChild(ifTrue, ifElseIndex); + jmmNode.getJmmParent().add(ifTrue, ifElseIndex); jmmNode.delete(); } - //'if' block code is never executed (condition value == 'false') + //'if' block code is never executed (condition value is 'false') else if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { if (ifFalse.getKind().equals("CodeBlock")){ for(JmmNode child : ifFalse.getChildren()) - jmmNode.getJmmParent().setChild(child, child.getIndexOfSelf() + ifElseIndex); + jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); } else - jmmNode.getJmmParent().setChild(ifFalse, ifElseIndex); + jmmNode.getJmmParent().add(ifFalse, ifElseIndex); jmmNode.delete(); } From 08342cad4c1415adbc0ed50db4e46463304f3c6d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 15:36:06 +0100 Subject: [PATCH 147/253] Refactor method that deals with IfElse in ConstantFolding --- .../optimization/ConstantFolding.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index ddcc80e..edb55b8 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -45,25 +45,17 @@ private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { int ifElseIndex = jmmNode.getIndexOfSelf(); visit(conditionNode); - //'else' block code is never reached (condition value is 'true') - if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("true")) { - if (ifTrue.getKind().equals("CodeBlock")){ - for(JmmNode child : ifTrue.getChildren()) - jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); - } - else - jmmNode.getJmmParent().add(ifTrue, ifElseIndex); - jmmNode.delete(); - } + if (conditionNode.getKind().equals("Boolean")) { + // if condition value is true, the code inside the 'ifTrue' node will be executed + // else, the code inside the 'ifFalse' node will be executed. + JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifTrue : ifFalse; - //'if' block code is never executed (condition value is 'false') - else if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { - if (ifFalse.getKind().equals("CodeBlock")){ - for(JmmNode child : ifFalse.getChildren()) + if (reachedCode.getKind().equals("CodeBlock")){ + for(JmmNode child : reachedCode.getChildren()) jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); } else - jmmNode.getJmmParent().add(ifFalse, ifElseIndex); + jmmNode.getJmmParent().add(reachedCode, ifElseIndex); jmmNode.delete(); } From eebc8d92806feed5b9ba3c96b33bb64e8c0e1e59 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Fri, 12 May 2023 15:48:30 +0100 Subject: [PATCH 148/253] hotfix ollir cpf of --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index ffa0c4c..318164b 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -298,7 +298,7 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { temp = "t" + tempVarId++ + ".bool"; code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; - if (condition.isEmpty() || cycle.isEmpty()) + //if (condition.isEmpty() || cycle.isEmpty()) code += ";\n"; jmmNode.put("valueOl", temp); From a9dd759602f2a90f5efee82956e10e275106bb2f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 17:22:19 +0100 Subject: [PATCH 149/253] Create OptimizationUtils class and add intersectMaps method --- .../optimization/OptimizationUtils.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java new file mode 100644 index 0000000..80ee0ca --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -0,0 +1,19 @@ +package pt.up.fe.comp2023.optimization; + +import java.util.HashMap; +import java.util.Map; + +public class OptimizationUtils { + public static Map intersectMaps (Map map1, Map map2){ + Map result = new HashMap<>(); + + for (Map.Entry entry : map1.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + + if (map2.containsKey(key) && map2.get(key).equals(value)) + result.put(key, value); + } + return result; + } +} From b6cc1fb83e6d1703d93fc7d211bb68dfab50206c Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 17:25:52 +0100 Subject: [PATCH 150/253] Add method that deals with Condition node in ConstantPropagation --- .../optimization/ConstantFolding.java | 1 + .../optimization/ConstantPropagation.java | 42 +++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index edb55b8..a08e0ab 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -57,6 +57,7 @@ private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { else jmmNode.getJmmParent().add(reachedCode, ifElseIndex); jmmNode.delete(); + this.codeModified = true; } //condition value is undefined diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index b6e0999..34c66fa 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -11,12 +11,13 @@ import java.util.HashMap; import java.util.Map; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.intersectMaps; import static pt.up.fe.comp2023.semantic.SemanticUtils.getIdentifierType; public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; - private final SymbolTable symbolTable; - private String currentMethodName; + private final SymbolTable symbolTable; //TODO: remove + private String currentMethodName; //TODO: remove private boolean codeModified; public ConstantPropagation (JmmSemanticsResult semanticsResult){ @@ -38,6 +39,7 @@ protected void buildVisitor() { addVisit("MethodDecl", this::changeCurrentMethodName); addVisit("VoidMethodDecl", this::changeCurrentMethodName); addVisit("MainMethodDecl", this::changeCurrentMethodName); + addVisit("Condition", this::checkIfElseCondition); addVisit("Cycle", this::dealWithCycle); addVisit("Assignment", this::dealWithAssignment); addVisit("Identifier", this::dealWithIdentifier); @@ -50,7 +52,7 @@ private Void setDefaultVisit(JmmNode jmmNode, Map constants) { } private Void changeCurrentMethodName(JmmNode jmmNode, Map constants) { - this.currentMethodName = jmmNode.get("methodname"); + this.currentMethodName = jmmNode.get("methodname"); //TODO: remove constants.clear(); for (JmmNode child: jmmNode.getChildren()) @@ -58,6 +60,40 @@ private Void changeCurrentMethodName(JmmNode jmmNode, Map consta return null; } + private Void checkIfElseCondition(JmmNode jmmNode, Map constants) { + JmmNode conditionNode = jmmNode.getJmmChild(0); + JmmNode ifTrue = jmmNode.getJmmChild(1); + JmmNode ifFalse = jmmNode.getJmmChild(2); + int ifElseIndex = jmmNode.getIndexOfSelf(); + visit(conditionNode, constants); + + //TODO: [refactor] create a method to execute this changes + if (conditionNode.getKind().equals("Boolean")) { + // if condition value is true, the code inside the 'ifTrue' node will be executed + // else, the code inside the 'ifFalse' node will be executed. + JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifTrue : ifFalse; + + if (reachedCode.getKind().equals("CodeBlock")){ + for(JmmNode child : reachedCode.getChildren()) + jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); + } + else + jmmNode.getJmmParent().add(reachedCode, ifElseIndex); + jmmNode.delete(); + this.codeModified = true; + } + + else { //Condition value is undefined + Map ifTrueConstants = new HashMap<>(constants); + Map ifFalseConstants = new HashMap<>(constants); + + visit(ifTrue, ifTrueConstants); + visit(ifFalse, ifFalseConstants); + constants = intersectMaps(ifTrueConstants, ifFalseConstants); + } + return null; + } + private Void dealWithCycle(JmmNode jmmNode, Map constants) { JmmNode conditionNode = jmmNode.getJmmChild(0); visit(conditionNode, constants); From 3ab68cf87800b93d615c95159a262ff16343f529 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 17:36:33 +0100 Subject: [PATCH 151/253] Add method to replace the #Codition node with the reached code --- .../comp2023/optimization/OptimizationUtils.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 80ee0ca..8018492 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,9 +1,23 @@ package pt.up.fe.comp2023.optimization; +import pt.up.fe.comp.jmm.ast.JmmNode; + import java.util.HashMap; import java.util.Map; public class OptimizationUtils { + public static void replaceIfElseWithReachedCode(JmmNode jmmNode, JmmNode reachedCode){ + int ifElseIndex = jmmNode.getIndexOfSelf(); + + if (reachedCode.getKind().equals("CodeBlock")){ + for(JmmNode child : reachedCode.getChildren()) + jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); + } + else + jmmNode.getJmmParent().add(reachedCode, ifElseIndex); + jmmNode.delete(); + } + public static Map intersectMaps (Map map1, Map map2){ Map result = new HashMap<>(); From 7b1a82c6e6efc8e978cae474120b3e67d044adce Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 12 May 2023 17:38:39 +0100 Subject: [PATCH 152/253] Refactor methods that deal with IfElse in order to use the new method Refactor methods that deal with IfElse in order to use the new method replaceIfElseWithReachedCode() --- .../optimization/ConstantFolding.java | 25 ++++++-------- .../optimization/ConstantPropagation.java | 33 +++++++------------ 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index a08e0ab..988e15c 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -5,6 +5,8 @@ import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.JmmNodeImpl; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; + public class ConstantFolding extends AJmmVisitor { private final JmmSemanticsResult semanticsResult; private boolean codeModified; @@ -40,30 +42,23 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { JmmNode conditionNode = jmmNode.getJmmChild(0); - JmmNode ifTrue = jmmNode.getJmmChild(1); - JmmNode ifFalse = jmmNode.getJmmChild(2); - int ifElseIndex = jmmNode.getIndexOfSelf(); + JmmNode ifCode = jmmNode.getJmmChild(1); + JmmNode elseCode = jmmNode.getJmmChild(2); visit(conditionNode); if (conditionNode.getKind().equals("Boolean")) { - // if condition value is true, the code inside the 'ifTrue' node will be executed - // else, the code inside the 'ifFalse' node will be executed. - JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifTrue : ifFalse; + // if condition value is true, the code inside the 'ifCode' is executed + // else, the code inside the 'elseCode' is executed. + JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; - if (reachedCode.getKind().equals("CodeBlock")){ - for(JmmNode child : reachedCode.getChildren()) - jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); - } - else - jmmNode.getJmmParent().add(reachedCode, ifElseIndex); - jmmNode.delete(); + replaceIfElseWithReachedCode(jmmNode, reachedCode); this.codeModified = true; } //condition value is undefined else { - visit(ifTrue); - visit(ifFalse); + visit(ifCode); + visit(elseCode); } return null; } diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 34c66fa..f460e63 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -2,17 +2,14 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; -import pt.up.fe.comp.jmm.analysis.table.Type; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.JmmNodeImpl; -import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.HashMap; import java.util.Map; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.intersectMaps; -import static pt.up.fe.comp2023.semantic.SemanticUtils.getIdentifierType; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; @@ -62,34 +59,26 @@ private Void changeCurrentMethodName(JmmNode jmmNode, Map consta private Void checkIfElseCondition(JmmNode jmmNode, Map constants) { JmmNode conditionNode = jmmNode.getJmmChild(0); - JmmNode ifTrue = jmmNode.getJmmChild(1); - JmmNode ifFalse = jmmNode.getJmmChild(2); - int ifElseIndex = jmmNode.getIndexOfSelf(); + JmmNode ifCode = jmmNode.getJmmChild(1); + JmmNode elseCode = jmmNode.getJmmChild(2); visit(conditionNode, constants); - //TODO: [refactor] create a method to execute this changes if (conditionNode.getKind().equals("Boolean")) { // if condition value is true, the code inside the 'ifTrue' node will be executed // else, the code inside the 'ifFalse' node will be executed. - JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifTrue : ifFalse; - - if (reachedCode.getKind().equals("CodeBlock")){ - for(JmmNode child : reachedCode.getChildren()) - jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); - } - else - jmmNode.getJmmParent().add(reachedCode, ifElseIndex); - jmmNode.delete(); + JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; + + replaceIfElseWithReachedCode(jmmNode, reachedCode); this.codeModified = true; } else { //Condition value is undefined - Map ifTrueConstants = new HashMap<>(constants); - Map ifFalseConstants = new HashMap<>(constants); + Map ifConstants = new HashMap<>(constants); + Map elseConstants = new HashMap<>(constants); - visit(ifTrue, ifTrueConstants); - visit(ifFalse, ifFalseConstants); - constants = intersectMaps(ifTrueConstants, ifFalseConstants); + visit(ifCode, ifConstants); + visit(elseCode, elseConstants); + constants = intersectMaps(ifConstants, elseConstants); } return null; } From 0ce1a26432f91dccf2069c26faf73914ea17808e Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 13 May 2023 00:02:57 +0100 Subject: [PATCH 153/253] [fix] Visit reached code after replacing #Condition node --- .../pt/up/fe/comp2023/optimization/ConstantFolding.java | 7 ++++--- .../up/fe/comp2023/optimization/ConstantPropagation.java | 9 ++++++--- .../up/fe/comp2023/optimization/OptimizationUtils.java | 5 ++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 988e15c..f4aa84d 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -25,7 +25,6 @@ protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); addVisit("Cycle", this::checkCycleCondition); addVisit("Condition", this::checkIfElseCondition); - //TODO: add visit to "Condition" and check the value of the condition addVisit("ParenthesesExpr", this::computeParenthesesExprResult); addVisit("NegationExpr", this::negateBooleanExpr); addVisit("ArithmeticExpr", this::computeArithmeticExprResult); @@ -50,8 +49,10 @@ private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { // if condition value is true, the code inside the 'ifCode' is executed // else, the code inside the 'elseCode' is executed. JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; - replaceIfElseWithReachedCode(jmmNode, reachedCode); + + for(JmmNode child : reachedCode.getChildren()) + visit(child); this.codeModified = true; } @@ -68,7 +69,7 @@ private Void checkCycleCondition(JmmNode jmmNode, Void unused) { visit(conditionNode); if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { //Dead code - jmmNode.getJmmParent().removeJmmChild(jmmNode); + jmmNode.delete(); } else { //Condition value is 'true' or undefined for (JmmNode child : jmmNode.getChildren()) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index f460e63..791ab56 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -7,6 +7,7 @@ import pt.up.fe.comp.jmm.ast.JmmNodeImpl; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; @@ -67,8 +68,10 @@ private Void checkIfElseCondition(JmmNode jmmNode, Map constants // if condition value is true, the code inside the 'ifTrue' node will be executed // else, the code inside the 'ifFalse' node will be executed. JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; - replaceIfElseWithReachedCode(jmmNode, reachedCode); + + for(JmmNode child : reachedCode.getChildren()) + visit(child, constants); this.codeModified = true; } @@ -78,7 +81,7 @@ private Void checkIfElseCondition(JmmNode jmmNode, Map constants visit(ifCode, ifConstants); visit(elseCode, elseConstants); - constants = intersectMaps(ifConstants, elseConstants); + intersectMaps(ifConstants, elseConstants, constants); } return null; } @@ -88,7 +91,7 @@ private Void dealWithCycle(JmmNode jmmNode, Map constants) { visit(conditionNode, constants); if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) //Dead code - jmmNode.getJmmParent().removeJmmChild(jmmNode); + jmmNode.delete(); else { //TODO: check which variables are modified and remove them from the map for (JmmNode child: jmmNode.getChildren()) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 8018492..4e760ea 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -18,8 +18,8 @@ public static void replaceIfElseWithReachedCode(JmmNode jmmNode, JmmNode reached jmmNode.delete(); } - public static Map intersectMaps (Map map1, Map map2){ - Map result = new HashMap<>(); + public static void intersectMaps (Map map1, Map map2, Map result){ + result.clear(); for (Map.Entry entry : map1.entrySet()) { String key = entry.getKey(); @@ -28,6 +28,5 @@ public static Map intersectMaps (Map map1, Map Date: Sat, 13 May 2023 17:26:31 +0100 Subject: [PATCH 154/253] Adds public CPF Jasmin test, section3_ControlFlow_Inverted --- .../control_flow/SimpleControlFlow.jmm | 19 ++++++++++++++++++ .../control_flow/SimpleControlFlow.ollir | 20 +++++++++++++++++++ test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 6 ++++++ 3 files changed, 45 insertions(+) create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.jmm create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.jmm b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.jmm new file mode 100644 index 0000000..d7d96c9 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.jmm @@ -0,0 +1,19 @@ +import ioPlus; +class SimpleControlFlow { + + + public static void main(String[] args) { + int a; + int b; + + a = 2; + b = 3; + + if(b < a){ + ioPlus.printResult(a); + } else { + ioPlus.printResult(b); + } + + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir new file mode 100644 index 0000000..4e5914c --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir @@ -0,0 +1,20 @@ +import ioPlus; +SimpleControlFlow { + .construct SimpleControlFlow().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { + + a.i32 :=.i32 2.i32; + b.i32 :=.i32 3.i32; + if (b.i32 >=.bool a.i32) goto ELSE_0; + invokestatic(ioPlus, "printResult", a.i32).V; + goto ENDIF_1; + ELSE_0: + invokestatic(ioPlus, "printResult", b.i32).V; + ENDIF_1: + ret.V; + } + +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java index f4295f3..0008e47 100644 --- a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -151,6 +151,12 @@ public void section3_ControlFlow_If_Simple() { /*checks if an addition is correct (more than 2 values)*/ @Test + public void section3_ControlFlow_Inverted() { + CpUtils.runJasmin(getJasminResult("control_flow/SimpleControlFlow.ollir"), "Result: 3"); + } + + /*checks OLLIR code that uses >= for an inverted condition */ + @Test public void section3_ControlFlow_If_Not_Simple() { CpUtils.runJasmin(getJasminResult("control_flow/SimpleIfElseNot.ollir"), "10\n200"); } From 8c8739effa19fc5183858ea660ab91b5bd43a345 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 13 May 2023 18:08:50 +0100 Subject: [PATCH 155/253] Change dealWithCycle in ConstantPropagation to not remove #Cycle node --- .../optimization/ConstantFolding.java | 1 + .../optimization/ConstantPropagation.java | 19 +++++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index f4aa84d..806362f 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -70,6 +70,7 @@ private Void checkCycleCondition(JmmNode jmmNode, Void unused) { if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { //Dead code jmmNode.delete(); + this.codeModified = true; } else { //Condition value is 'true' or undefined for (JmmNode child : jmmNode.getChildren()) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 791ab56..7a81740 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -6,9 +6,7 @@ import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.JmmNodeImpl; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.util.*; import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; @@ -87,16 +85,13 @@ private Void checkIfElseCondition(JmmNode jmmNode, Map constants } private Void dealWithCycle(JmmNode jmmNode, Map constants) { - JmmNode conditionNode = jmmNode.getJmmChild(0); - visit(conditionNode, constants); + Map oldConstants = new HashMap<>(constants); + Map cycleConstants = new HashMap<>(constants); - if(conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) //Dead code - jmmNode.delete(); - else { - //TODO: check which variables are modified and remove them from the map - for (JmmNode child: jmmNode.getChildren()) - visit(child, constants); //each statement modifies the map - } + for (JmmNode child: jmmNode.getChildren()) + visit(child, cycleConstants); + + intersectMaps(cycleConstants, oldConstants, constants); return null; } From 5d40c8f56073e4597c6b0f7fff360c5dfaed128d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 13 May 2023 18:12:17 +0100 Subject: [PATCH 156/253] Change checkIfElseCondition() to not replace #Condition node --- .../optimization/ConstantPropagation.java | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 7a81740..0e13594 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -60,27 +60,13 @@ private Void checkIfElseCondition(JmmNode jmmNode, Map constants JmmNode conditionNode = jmmNode.getJmmChild(0); JmmNode ifCode = jmmNode.getJmmChild(1); JmmNode elseCode = jmmNode.getJmmChild(2); - visit(conditionNode, constants); - - if (conditionNode.getKind().equals("Boolean")) { - // if condition value is true, the code inside the 'ifTrue' node will be executed - // else, the code inside the 'ifFalse' node will be executed. - JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; - replaceIfElseWithReachedCode(jmmNode, reachedCode); - - for(JmmNode child : reachedCode.getChildren()) - visit(child, constants); - this.codeModified = true; - } - - else { //Condition value is undefined - Map ifConstants = new HashMap<>(constants); - Map elseConstants = new HashMap<>(constants); + Map ifConstants = new HashMap<>(constants); + Map elseConstants = new HashMap<>(constants); - visit(ifCode, ifConstants); - visit(elseCode, elseConstants); - intersectMaps(ifConstants, elseConstants, constants); - } + visit(conditionNode, constants); + visit(ifCode, ifConstants); + visit(elseCode, elseConstants); + intersectMaps(ifConstants, elseConstants, constants); return null; } From 402bd5827cc32876d8d057b5da70bb35a69ac08a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 13 May 2023 18:14:53 +0100 Subject: [PATCH 157/253] Refactor ConstantPropagation: remove some fields/rename methods --- .../optimization/ConstantPropagation.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 0e13594..d3137a2 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -12,13 +12,10 @@ public class ConstantPropagation extends AJmmVisitor, Void> { private final JmmSemanticsResult semanticsResult; - private final SymbolTable symbolTable; //TODO: remove - private String currentMethodName; //TODO: remove private boolean codeModified; public ConstantPropagation (JmmSemanticsResult semanticsResult){ this.semanticsResult = semanticsResult; - this.symbolTable = semanticsResult.getSymbolTable(); } public boolean apply(){ @@ -32,10 +29,10 @@ public boolean apply(){ @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); - addVisit("MethodDecl", this::changeCurrentMethodName); - addVisit("VoidMethodDecl", this::changeCurrentMethodName); - addVisit("MainMethodDecl", this::changeCurrentMethodName); - addVisit("Condition", this::checkIfElseCondition); + addVisit("MethodDecl", this::clearConstants); + addVisit("VoidMethodDecl", this::clearConstants); + addVisit("MainMethodDecl", this::clearConstants); + addVisit("Condition", this::dealWithCondition); addVisit("Cycle", this::dealWithCycle); addVisit("Assignment", this::dealWithAssignment); addVisit("Identifier", this::dealWithIdentifier); @@ -47,8 +44,7 @@ private Void setDefaultVisit(JmmNode jmmNode, Map constants) { return null; } - private Void changeCurrentMethodName(JmmNode jmmNode, Map constants) { - this.currentMethodName = jmmNode.get("methodname"); //TODO: remove + private Void clearConstants(JmmNode jmmNode, Map constants) { constants.clear(); for (JmmNode child: jmmNode.getChildren()) @@ -56,7 +52,7 @@ private Void changeCurrentMethodName(JmmNode jmmNode, Map consta return null; } - private Void checkIfElseCondition(JmmNode jmmNode, Map constants) { + private Void dealWithCondition(JmmNode jmmNode, Map constants) { JmmNode conditionNode = jmmNode.getJmmChild(0); JmmNode ifCode = jmmNode.getJmmChild(1); JmmNode elseCode = jmmNode.getJmmChild(2); From e1f4805d9f5dd2995936dff3a3f77b37e85726cf Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 13 May 2023 18:19:45 +0100 Subject: [PATCH 158/253] Remove methods for #Condition and #Cycle in ConstantFolding --- .../optimization/ConstantFolding.java | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 806362f..0ca5c8b 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -23,8 +23,6 @@ public boolean apply(){ @Override protected void buildVisitor() { setDefaultVisit(this::setDefaultVisit); - addVisit("Cycle", this::checkCycleCondition); - addVisit("Condition", this::checkIfElseCondition); addVisit("ParenthesesExpr", this::computeParenthesesExprResult); addVisit("NegationExpr", this::negateBooleanExpr); addVisit("ArithmeticExpr", this::computeArithmeticExprResult); @@ -39,46 +37,6 @@ private Void setDefaultVisit(JmmNode jmmNode, Void unused) { return null; } - private Void checkIfElseCondition(JmmNode jmmNode, Void unused) { - JmmNode conditionNode = jmmNode.getJmmChild(0); - JmmNode ifCode = jmmNode.getJmmChild(1); - JmmNode elseCode = jmmNode.getJmmChild(2); - visit(conditionNode); - - if (conditionNode.getKind().equals("Boolean")) { - // if condition value is true, the code inside the 'ifCode' is executed - // else, the code inside the 'elseCode' is executed. - JmmNode reachedCode = conditionNode.get("value").equals("true") ? ifCode : elseCode; - replaceIfElseWithReachedCode(jmmNode, reachedCode); - - for(JmmNode child : reachedCode.getChildren()) - visit(child); - this.codeModified = true; - } - - //condition value is undefined - else { - visit(ifCode); - visit(elseCode); - } - return null; - } - - private Void checkCycleCondition(JmmNode jmmNode, Void unused) { - JmmNode conditionNode = jmmNode.getJmmChild(0); - visit(conditionNode); - - if (conditionNode.getKind().equals("Boolean") && conditionNode.get("value").equals("false")) { //Dead code - jmmNode.delete(); - this.codeModified = true; - } - else { //Condition value is 'true' or undefined - for (JmmNode child : jmmNode.getChildren()) - visit(child); - } - return null; - } - private Void computeParenthesesExprResult(JmmNode jmmNode, Void unused) { JmmNode exprNode = jmmNode.getJmmChild(0); visit(exprNode); From 09abf1b005d87f07ea568ee61db3603ff4883d28 Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Mon, 15 May 2023 10:19:10 +0100 Subject: [PATCH 159/253] Fixes OLLIR file in CPF Jasmin test, section3_ControlFlow_Inverted --- .../fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir index 4e5914c..62dd2c5 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir @@ -1,7 +1,7 @@ import ioPlus; SimpleControlFlow { .construct SimpleControlFlow().V { - invokespecial(this, "").V; + invokespecial(this, "init").V; } .method public static main(args.array.String).V { From 51bb5824167a56b86680b67f8756c1a1b80f10dd Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Mon, 15 May 2023 19:39:32 +0100 Subject: [PATCH 160/253] Fixes Type.toString() in OLLIR when elementType is null --- libs/comp2023-ollir-sources.jar | Bin 56061 -> 56192 bytes libs/comp2023-ollir.jar | Bin 91912 -> 91980 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar index f89ca72dcdd87b73417fbc8407b4cec3cfab1f13..7841631f482cad36b4be784084ae396e31a27b9a 100644 GIT binary patch delta 2628 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 CZczsS delta 4998 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�EQue zhXf#nKu&u=LX5fvzvyqcJwzf9U2F)10^;{yP4X-s#1tgS@}t2ddw?C*&$EXl*3mGa zBg_v2unhje{QVJVQ|d$ST#~<45H-nU2`U@JoC1Vl=3XM%V+mqfGa(RCbj-WbFf-^B zfPs@`LI%SN8Q6L6U*{~Fxv@Av}ys@3w<-}hqKR9 zoh$f%o$%L%0Nh6&kE6pY(AjCnfq(+ekg>Vu6PNi z-*f{+;Wm!CK`D=wg6>Z>i`( zse~Z9DjjvDoT@4dQrvf|LY_1GA_!4OpwBTnYH}q^CCyg~{=Y{<5PfB?Y5?tW5(06U zF6v7aHA)MfN2LcekH{rj#wF+7;H+{I4LCBp?8yy>|PUF7b9NA8HIA zv=0x`1tntt3t|WTymt3~f)`YTjp~1pFgOHB!S&5hA$x5a#OV!4!xN;t(9k8Q!_lbF z1xFGV$oGZ><_&1x!+!w#f3MJWDx_}sAH)LY7y>-MPoCd5AOu2`E(?nZEeN_43BXw{ q`9M Date: Tue, 16 May 2023 11:37:48 +0100 Subject: [PATCH 161/253] Fixes resource of CPF Jasmin test section3_ControlFlow_Inverted --- .../fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir index 62dd2c5..15de9fb 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/control_flow/SimpleControlFlow.ollir @@ -1,7 +1,7 @@ import ioPlus; SimpleControlFlow { .construct SimpleControlFlow().V { - invokespecial(this, "init").V; + invokespecial(this, "").V; } .method public static main(args.array.String).V { From 3a154bccdcf8390ffb2b7108cf0b42440f4e42fc Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 16 May 2023 11:48:15 +0100 Subject: [PATCH 162/253] Added argument loading before jasmin new instruction --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 1e482b2..7896d8c 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -110,9 +110,10 @@ public static String getInvokeSpecialInstruction(CallInstruction instruction, Ha return "\tinvokespecial " + createInvokeInstructionArgument(instruction, false); } - public static String getNewInstruction(Operand firstArg) { + public static String getNewInstruction(CallInstruction instruction, HashMap varTable) { String statementList = ""; - statementList += "\tnew " + firstArg.getName() + '\n'; + statementList += loadInvokeArguments(instruction.getListOfOperands(), varTable); + statementList += "\tnew " + ((Operand)instruction.getFirstArg()).getName() + '\n'; statementList += "\tdup\n"; return statementList; } @@ -186,7 +187,7 @@ public static String createCallStatement(CallInstruction instruction, HashMap Date: Tue, 16 May 2023 12:16:03 +0100 Subject: [PATCH 163/253] Implemented instruction to create basic new array --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 13 ++++++++++++- .../comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir | 0 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 7896d8c..f4d2c82 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Objects; import static java.lang.Integer.parseInt; import static java.lang.Math.abs; @@ -118,6 +119,13 @@ public static String getNewInstruction(CallInstruction instruction, HashMap varTable) { + String statementList = ""; + statementList += loadInvokeArguments(instruction.getListOfOperands(), varTable); + statementList += "\tnewarray int\n"; // TODO: change array type + return statementList; + } + public static String createUnaryOpStatement(UnaryOpInstruction instruction, HashMap varTable) { String statementList = ""; statementList += getLoadInstruction(instruction.getOperand(), varTable); @@ -187,7 +195,10 @@ public static String createCallStatement(CallInstruction instruction, HashMap Date: Tue, 16 May 2023 12:17:43 +0100 Subject: [PATCH 164/253] Added array initialization tests --- src/main/pt/up/fe/comp2023/Launcher.java | 16 +++++---------- .../comp/cpf/4_jasmin/arrays/ArrayInit.ollir | 11 +++++----- .../4_jasmin/arrays/ArrayInitComplex.ollir | 20 +++++++++++++++++++ .../cpf/4_jasmin/arrays/ArrayInitSimple.ollir | 14 +++++++++++++ test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 20 +++++++++++++++++++ 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitSimple.ollir diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index dfd5e1c..be22292 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -73,22 +73,16 @@ public static void main(String[] args) { // Optimization optimization = new Optimization(); // OllirResult ollirResult = optimization.toOllir(semanticsResult); - String ollirCode = "import io;\n" + - "Arithmetic_and {\n" + + String ollirCode = "import ioPlus;\n" + + "ArrayInit {\n" + "\n" + - " .construct Arithmetic_and().V {\n" + + " .construct ArrayInit().V {\n" + " invokespecial(this, \"\").V;\n" + " }\n" + "\n" + " .method public static main(args.array.String).V {\n" + - " a.bool :=.bool 1.bool &&.bool 0.bool;\n" + - "\n" + - " if (a.bool) goto ifbody_0;\n" + - " invokestatic(io, \"print\", 0.i32).V;\n" + - " goto endif_0;\n" + - " ifbody_0:\n" + - " invokestatic(io, \"print\", 1.i32).V;\n" + - " endif_0:\n" + + " temp0.i32 :=.i32 5.i32;\n" + + " a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32;\n" + "\n" + " ret.V;\n" + " }\n" + diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir index 6eb7622..35dd718 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir @@ -6,12 +6,11 @@ ArrayInit { } .method public static main(args.array.String).V { -temp0.i32 :=.i32 5.i32; -a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; -temp1.i32 :=.i32 arraylength(a.array.i32).i32.i32; -invokestatic(ioPlus, "printResult", temp1.i32).V; + temp0.i32 :=.i32 5.i32; + a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; + temp1.i32 :=.i32 arraylength(a.array.i32).i32.i32; + invokestatic(ioPlus, "printResult", temp1.i32).V; -ret.V; + ret.V; } - } \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir index e69de29..59556c5 100644 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir @@ -0,0 +1,20 @@ +import ioPlus; +ArrayInit { + + .construct ArrayInit().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { + temp0.i32 :=.i32 5.i32; + a1.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; + temp1.i32 :=.i32 arraylength(a1.array.i32).i32.i32; + invokestatic(ioPlus, "printResult", temp1.i32).V; + + a2.array.array.array.i32 :=.array.array.array.i32 new(array, 5.i32, 4.i32, 3.i32).array.array.array.i32; + temp2.i32 :=.i32 arraylength(a2.array.array.array.i32).i32.i32; + invokestatic(ioPlus, "printResult", tempp2.i32).V; + + ret.V; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitSimple.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitSimple.ollir new file mode 100644 index 0000000..56a3f6b --- /dev/null +++ b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitSimple.ollir @@ -0,0 +1,14 @@ +import ioPlus; +ArrayInit { + + .construct ArrayInit().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V { + temp0.i32 :=.i32 5.i32; + a.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; + + ret.V; + } +} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java index f3d530c..c3cb043 100644 --- a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -122,6 +122,11 @@ public void section5_Arrays_Init_Array() { CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); } + @Test + public void section5_Arrays_Init_Array_Complex() { + CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); + } + /*checks if the access to the elements of array is correct*/ @Test public void section5_Arrays_Store_Array() { @@ -262,6 +267,21 @@ public void ollirToJasminIfWhileNested() { testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/control_flow/IfWhileNested.ollir"); } + @Test + public void OllirToJasminArrayInitSimple() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitSimple.ollir"); + } + + @Test + public void OllirToJasminArrayInit() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir"); + } + + @Test + public void OllirToJasminArrayInitComplex() { + testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir"); + } + // private static boolean USE_OLLIR_EXPERIMENTAL = false; /* public static void enableOllirInputs() { From 35cd76a673680e4bbebecf5e9ad43184663e7d6b Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 16 May 2023 13:30:48 +0100 Subject: [PATCH 165/253] Fix optimize() to check semanticsResult's config before optimizing --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index efd21db..e5652b9 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -33,12 +33,14 @@ public OllirResult toOllir(JmmSemanticsResult semanticsResult) { @Override public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { - ConstantPropagation constantPropagation = new ConstantPropagation(semanticsResult); - ConstantFolding constantFolding = new ConstantFolding(semanticsResult); - boolean codeModified = constantPropagation.apply() || constantFolding.apply(); + if (Boolean.parseBoolean(semanticsResult.getConfig().get("optimize"))) { + ConstantPropagation constantPropagation = new ConstantPropagation(semanticsResult); + ConstantFolding constantFolding = new ConstantFolding(semanticsResult); - while(codeModified){ - codeModified = constantPropagation.apply() || constantFolding.apply(); + boolean codeModified = constantPropagation.apply() || constantFolding.apply(); + while (codeModified) { + codeModified = constantPropagation.apply() || constantFolding.apply(); + } } return semanticsResult; } From 140f2b383ffddb2b92457e154d06fd662d072483 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 16 May 2023 20:59:38 +0100 Subject: [PATCH 166/253] Removed tests not in scope of java-- --- .../4_jasmin/arrays/ArrayInitComplex.ollir | 20 ------------------- test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java | 10 ---------- 2 files changed, 30 deletions(-) delete mode 100644 test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir diff --git a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir b/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir deleted file mode 100644 index 59556c5..0000000 --- a/test/pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir +++ /dev/null @@ -1,20 +0,0 @@ -import ioPlus; -ArrayInit { - - .construct ArrayInit().V { - invokespecial(this, "").V; - } - - .method public static main(args.array.String).V { - temp0.i32 :=.i32 5.i32; - a1.array.i32 :=.array.i32 new(array, temp0.i32).array.i32; - temp1.i32 :=.i32 arraylength(a1.array.i32).i32.i32; - invokestatic(ioPlus, "printResult", temp1.i32).V; - - a2.array.array.array.i32 :=.array.array.array.i32 new(array, 5.i32, 4.i32, 3.i32).array.array.array.i32; - temp2.i32 :=.i32 arraylength(a2.array.array.array.i32).i32.i32; - invokestatic(ioPlus, "printResult", tempp2.i32).V; - - ret.V; - } -} \ No newline at end of file diff --git a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java index c3cb043..4711083 100644 --- a/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java +++ b/test/pt/up/fe/comp/cpf/Cpf4_Jasmin.java @@ -122,11 +122,6 @@ public void section5_Arrays_Init_Array() { CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); } - @Test - public void section5_Arrays_Init_Array_Complex() { - CpUtils.runJasmin(getJasminResult("arrays/ArrayInit.ollir"), "Result: 5"); - } - /*checks if the access to the elements of array is correct*/ @Test public void section5_Arrays_Store_Array() { @@ -277,11 +272,6 @@ public void OllirToJasminArrayInit() { testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInit.ollir"); } - @Test - public void OllirToJasminArrayInitComplex() { - testOllirToJasmin("pt/up/fe/comp/cpf/4_jasmin/arrays/ArrayInitComplex.ollir"); - } - // private static boolean USE_OLLIR_EXPERIMENTAL = false; /* public static void enableOllirInputs() { From a4437ded54c339ddb02b289e904e98984f30395d Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 16 May 2023 21:16:41 +0100 Subject: [PATCH 167/253] Implemented jasmin arraylength instruction --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index f4d2c82..5ce2611 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -2,9 +2,7 @@ import org.specs.comp.ollir.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Objects; +import java.util.*; import static java.lang.Integer.parseInt; import static java.lang.Math.abs; @@ -77,7 +75,8 @@ public static String getStoreInstruction(Element element, HashMap listOfOperands, HashMap varTable) { String statementList = ""; for (Element argument: listOfOperands) { - statementList += getLoadInstruction(argument, varTable); } + statementList += getLoadInstruction(argument, varTable); + } return statementList; } @@ -122,7 +121,14 @@ public static String getNewInstruction(CallInstruction instruction, HashMap varTable) { String statementList = ""; statementList += loadInvokeArguments(instruction.getListOfOperands(), varTable); - statementList += "\tnewarray int\n"; // TODO: change array type + statementList += "\tnewarray int\n"; + return statementList; + } + + public static String getArrayLengthInstruction(CallInstruction instruction, HashMap varTable) { + String statementList = ""; + statementList += getLoadInstruction(instruction.getFirstArg(), varTable); + statementList += "\tarraylength\n"; return statementList; } @@ -210,6 +216,7 @@ public static String createCallStatement(CallInstruction instruction, HashMap Date: Wed, 17 May 2023 23:47:32 +0100 Subject: [PATCH 168/253] Refactor optimization: remove unused method and imports --- .../fe/comp2023/optimization/ConstantFolding.java | 2 -- .../optimization/ConstantPropagation.java | 1 - .../comp2023/optimization/OptimizationUtils.java | 15 --------------- 3 files changed, 18 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java index 0ca5c8b..dae09ae 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantFolding.java @@ -5,8 +5,6 @@ import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.JmmNodeImpl; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; - public class ConstantFolding extends AJmmVisitor { private final JmmSemanticsResult semanticsResult; private boolean codeModified; diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index d3137a2..1e46c23 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -1,7 +1,6 @@ package pt.up.fe.comp2023.optimization; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; -import pt.up.fe.comp.jmm.analysis.table.SymbolTable; import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ast.JmmNodeImpl; diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 4e760ea..648c113 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,23 +1,8 @@ package pt.up.fe.comp2023.optimization; -import pt.up.fe.comp.jmm.ast.JmmNode; - -import java.util.HashMap; import java.util.Map; public class OptimizationUtils { - public static void replaceIfElseWithReachedCode(JmmNode jmmNode, JmmNode reachedCode){ - int ifElseIndex = jmmNode.getIndexOfSelf(); - - if (reachedCode.getKind().equals("CodeBlock")){ - for(JmmNode child : reachedCode.getChildren()) - jmmNode.getJmmParent().add(child, child.getIndexOfSelf() + ifElseIndex); - } - else - jmmNode.getJmmParent().add(reachedCode, ifElseIndex); - jmmNode.delete(); - } - public static void intersectMaps (Map map1, Map map2, Map result){ result.clear(); From b67ea33aa3331774b7fdbdd87bdc7e5b79a886f8 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 18 May 2023 02:06:38 +0100 Subject: [PATCH 169/253] assign arrays param and local var --- .../pt/up/fe/comp2023/ollir/Optimization.java | 61 +++++++++++++++++-- .../comp/cpf/3_ollir/arrays/ArrayAccess.jmm | 2 +- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 318164b..be1369c 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -3,12 +3,11 @@ import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; +import pt.up.fe.comp.jmm.ast.AJmmVisitor; import pt.up.fe.comp.jmm.ast.JmmNode; import pt.up.fe.comp.jmm.ollir.JmmOptimization; import pt.up.fe.comp.jmm.ollir.OllirResult; import pt.up.fe.comp.jmm.report.Report; -import pt.up.fe.comp.jmm.ast.AJmmVisitor; -import pt.up.fe.comp2023.ollir.OllirUtils; import java.util.ArrayList; import java.util.List; @@ -330,8 +329,62 @@ private Void dealWithNegationExpr(JmmNode jmmNode, Void unused) { } private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); + var method = jmmNode.getAncestor("MethodDecl"); + var voidMethod = jmmNode.getAncestor("VoidMethodDecl"); + var mainMethod = jmmNode.getAncestor("MainMethodDecl"); + Symbol var = null; + boolean isLocal = false, isParam = false, isField = false; + int idParam = 0; + String left = jmmNode.get("arrayname"); + + if (method.isPresent() || voidMethod.isPresent() || mainMethod.isPresent()) { + var methodName = mainMethod.isPresent() ? "main" : method.orElseGet(voidMethod::get).get("methodname"); + List localVarClass = table.getLocalVariables(methodName); + List paramsOnClass = table.getParameters(methodName); + + // Check if local var + for (Symbol lv : localVarClass) + if (lv.getName().equals(left)) { + var = lv; + isLocal = true; + } + + // If not local var, then check if param + if (var == null) + for (int p = 0; p < paramsOnClass.size(); p++) + if (paramsOnClass.get(p).getName().equals(left)) { + var = paramsOnClass.get(p); + isParam = true; + idParam = p + 1; + } + } + + List fields = table.getFields(); + + // If not local nor param, check if field + if (var == null) + for (Symbol f : fields) + if (f.getName().equals(left)) { + var = f; + isField = true; + } + + JmmNode right = jmmNode.getChildren().get(0); + JmmNode last = jmmNode.getChildren().get(1); + visit(right); + + if (isLocal) + code += "\t\t" + left + "[" ; + else if (isParam) + code += "\t\t$" + idParam + '.' + left + "["; + else if (isField) + code += "\t\tputfield(this, " + left + "["; + + code += right.get("valueOl") + "].i32 :=.i32 "; + + visit(last); + + code += last.get("valueOl") +";\n"; return null; } diff --git a/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm index 73036dc..02436b9 100644 --- a/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm +++ b/test/pt/up/fe/comp/cpf/3_ollir/arrays/ArrayAccess.jmm @@ -3,7 +3,7 @@ class ArrayAccess { public int foo(int[] a) { int result; - + result = a[0]; result = a[1] + a[2]; result = result + a[3]; From 0106d76b29efebaf4168f8759772ba7345e02ca3 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 18 May 2023 14:56:17 +0100 Subject: [PATCH 170/253] field array assignment --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index be1369c..28665a2 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -374,13 +374,14 @@ private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { visit(right); if (isLocal) - code += "\t\t" + left + "[" ; + code += "\t\t" + left; else if (isParam) - code += "\t\t$" + idParam + '.' + left + "["; + code += "\t\t$" + idParam + '.' + left; else if (isField) - code += "\t\tputfield(this, " + left + "["; + code += "\t\tt" + tempVarId + ".array.i32 :=.array.i32 getfield(this, " + left + ".array.i32).array.i32;" + + "\n\t\tt" + tempVarId++; - code += right.get("valueOl") + "].i32 :=.i32 "; + code += "[" + right.get("valueOl") + "].i32 :=.i32 "; visit(last); From e1062bc966747ba7a909d402dbae7c8030b5db9c Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 18 May 2023 20:00:26 +0100 Subject: [PATCH 171/253] array access --- .../pt/up/fe/comp2023/ollir/Optimization.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 28665a2..4e89ec7 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -249,7 +249,7 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { return null; } - private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { + private Void dealWithFieldDeclaration(JmmNode jmmNode, Void unused) { List fieldsOnClass = table.getFields(); for (Symbol currField : fieldsOnClass) { code += "\t.field private " + currField.getName() + OllirUtils.ollirTypes(currField.getType()) + ";\n"; @@ -257,11 +257,24 @@ private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { return null; } - private Void dealWithArraySubscript(JmmNode jmmNode, Void unused) { - - for (var child : jmmNode.getChildren()) - visit(child); + private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { + JmmNode caller = jmmNode.getJmmChild(0); + visit(caller); + jmmNode.put("valueOl", "t" + tempVarId + ".i32"); + String caller_name = caller.get("valueOl"); + code += "t" + tempVarId++ + ".i32 :=.i32 arraylength(" + caller_name + ").i32;"; + return null; + } + private Void dealWithArraySubscript(JmmNode jmmNode, Void unused) { + JmmNode left = jmmNode.getJmmChild(0); + JmmNode right = jmmNode.getJmmChild(1); + visit(left); + visit(right); + String leftS = left.get("valueOl"); + String rightS = right.get("valueOl"); + code += "\t\tt" + tempVarId + ".i32 :=.i32 " + leftS + "[" + rightS + "].i32;\n"; + jmmNode.put("valueOl", "t" + tempVarId++ + ".i32"); return null; } @@ -561,7 +574,7 @@ private Void dealWithClass(JmmNode jmmNode, Void unused) { code += table.getClassName() + " {\n"; else code += table.getClassName() + " extends " + superClass + "{\n"; - dealWithLenFieldAccess(jmmNode, unused); + dealWithFieldDeclaration(jmmNode, unused); // Constructor code += "\t.construct " + table.getClassName() + "().V {\n" + "\t\tinvokespecial(this, \"\").V;\n\t}\n"; From 317ef5c374376006e1217ecc6667064557c732a4 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 19 May 2023 00:57:43 +0100 Subject: [PATCH 172/253] Changed jasmin element loading to support ArrayOperand elements --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 5ce2611..5ed718c 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -11,6 +11,7 @@ public class JVMInstructionUtils { public static String getLoadInstruction(Element element, HashMap varTable) { + System.out.println(element.getType()); if (element.isLiteral()) { int literal = parseInt(((LiteralElement)element).getLiteral()); if (literal >= 0 && literal <= 5) @@ -24,7 +25,11 @@ public static String getLoadInstruction(Element element, HashMap Date: Fri, 19 May 2023 00:58:33 +0100 Subject: [PATCH 173/253] Implemented jasmin array access --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 5ed718c..0b5e09f 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -11,7 +11,6 @@ public class JVMInstructionUtils { public static String getLoadInstruction(Element element, HashMap varTable) { - System.out.println(element.getType()); if (element.isLiteral()) { int literal = parseInt(((LiteralElement)element).getLiteral()); if (literal >= 0 && literal <= 5) @@ -194,10 +193,18 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); - String statementList = ""; + + if (assignElement instanceof ArrayOperand) { + statementList += getLoadInstruction(assignElement, varTable); + statementList += getLoadInstruction(((ArrayOperand)assignElement).getIndexOperands().get(0), varTable); + } + statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); - statementList += getStoreInstruction(assignElement, varTable); + if (assignElement instanceof ArrayOperand) + statementList += "\tiastore\n"; + else + statementList += getStoreInstruction(assignElement, varTable); return statementList; } From 1b9c44e59b388da94dbcb64a2ee5397b05c801d1 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 19 May 2023 11:47:18 +0100 Subject: [PATCH 174/253] Fixed jasmin new object instruction --- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index e9a5367..01543ac 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -109,7 +109,7 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Fri, 19 May 2023 13:28:45 +0100 Subject: [PATCH 175/253] Refactor: implemented new method to load array index --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 0b5e09f..8ccd916 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -47,6 +47,13 @@ public static String getLoadInstruction(Element element, HashMap varTable) { + String statementList = ""; + statementList += getLoadInstruction(array, varTable); + statementList += getLoadInstruction(array.getIndexOperands().get(0), varTable); + return statementList; + } + public static String getStoreInstruction(Element element, HashMap varTable) { int virtualReg = varTable.get(((Operand)element).getName()).getVirtualReg(); @@ -195,11 +202,8 @@ public static String createAssignStatement(AssignInstruction instruction, HashMa Element assignElement = instruction.getDest(); String statementList = ""; - if (assignElement instanceof ArrayOperand) { - statementList += getLoadInstruction(assignElement, varTable); - statementList += getLoadInstruction(((ArrayOperand)assignElement).getIndexOperands().get(0), varTable); - } - + if (assignElement instanceof ArrayOperand) + statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); if (assignElement instanceof ArrayOperand) statementList += "\tiastore\n"; From 0dcc7687ce1c7e427e341ba354dc5fc8f150e528 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 19 May 2023 13:33:31 +0100 Subject: [PATCH 176/253] Completed jasmin array access (non-initialization) --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 8ccd916..455f20a 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -195,7 +195,12 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, } public static String createNoperInstruction(SingleOpInstruction instruction, HashMap varTable) { - return getLoadInstruction(instruction.getSingleOperand(), varTable); + Element operand = instruction.getSingleOperand(); + if (operand instanceof ArrayOperand) { + return getArrayLoadInstruction((ArrayOperand)operand, varTable) + + "\tiaload\n"; + } + return getLoadInstruction(operand, varTable); } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { From 5978986591a86141f74371a65cba67a9b7725afd Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 19 May 2023 15:17:03 +0100 Subject: [PATCH 177/253] Added jasmin instructions for less/greater than or equals --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 455f20a..606ea13 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -185,11 +185,21 @@ public static String createBinaryOpInstruction(BinaryOpInstruction instruction, if (!isBranchCond) statementList += createAuxBranchStatement(); break; + case LTE: + statementList += "\tif_icmple "; + if (!isBranchCond) + statementList += createAuxBranchStatement(); + break; case GTH: statementList += "\tif_icmpgt "; if (!isBranchCond) statementList += createAuxBranchStatement(); break; + case GTE: + statementList += "\tif_icmpge "; + if (!isBranchCond) + statementList += createAuxBranchStatement(); + break; } return statementList; } From a110d7c2b2a3e8787fa5297faf0b1ded191b8ebb Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 20 May 2023 19:35:44 +0100 Subject: [PATCH 178/253] Created fields to keep track of locals and stack size --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 3 +++ src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 606ea13..217938d 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -10,6 +10,9 @@ public class JVMInstructionUtils { + public static int numLocals = 0; + public static int stackSize = 0; + public static String getLoadInstruction(Element element, HashMap varTable) { if (element.isLiteral()) { int literal = parseInt(((LiteralElement)element).getLiteral()); diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 01543ac..9c1c26b 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -196,11 +196,15 @@ public static String createConstructMethod(String superClassName) { } public static String createMethodDirective(Method method) { + JVMInstructionUtils.numLocals = 0; + JVMInstructionUtils.stackSize = 0; String methodDirective = ".method "; + String instructions = handleMethodStatements(method); + methodDirective += createMethodDeclaration(method); - methodDirective += "\t.limit stack 99\n"; - methodDirective += "\t.limit locals 99\n"; - methodDirective += handleMethodStatements(method); + methodDirective += "\t.limit stack " + JVMInstructionUtils.stackSize + "\n"; + methodDirective += "\t.limit locals " + JVMInstructionUtils.numLocals + "\n"; + methodDirective += instructions; return methodDirective + ".end method\n\n"; } } From afa84a8ed4f924f6ab317e1a48ca7dae2dec997a Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 20 May 2023 19:47:00 +0100 Subject: [PATCH 179/253] Implemented limit locals calculation --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 217938d..519e186 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -59,6 +59,8 @@ public static String getArrayLoadInstruction(ArrayOperand array, HashMap varTable) { int virtualReg = varTable.get(((Operand)element).getName()).getVirtualReg(); + if (virtualReg > JVMInstructionUtils.numLocals) + numLocals = virtualReg; if (element.isLiteral()) { int literal = parseInt(((LiteralElement)element).getLiteral()); From d3f0780e5613cfa61c5d4ae0c1125f090d98215a Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 21 May 2023 12:21:02 +0100 Subject: [PATCH 180/253] Added number of method arguments and this for instance methods in locals calculation --- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 9c1c26b..14601f2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -198,9 +198,12 @@ public static String createConstructMethod(String superClassName) { public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; JVMInstructionUtils.stackSize = 0; - String methodDirective = ".method "; String instructions = handleMethodStatements(method); + JVMInstructionUtils.numLocals += method.getParams().size(); + if (!method.isStaticMethod()) + JVMInstructionUtils.numLocals++; + String methodDirective = ".method "; methodDirective += createMethodDeclaration(method); methodDirective += "\t.limit stack " + JVMInstructionUtils.stackSize + "\n"; methodDirective += "\t.limit locals " + JVMInstructionUtils.numLocals + "\n"; From 0c069c9e69cfe59b3cc619b09b21e5d78cbbc846 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 21 May 2023 20:08:03 +0100 Subject: [PATCH 181/253] Fixed handling number of arguments in locals calculation --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 3 +++ src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 519e186..f619abb 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -33,6 +33,9 @@ public static String getLoadInstruction(Element element, HashMap JVMInstructionUtils.numLocals) + numLocals = virtualReg; + switch (elementType) { case THIS: return "\taload_0\n"; diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 14601f2..a3a927a 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -197,11 +197,15 @@ public static String createConstructMethod(String superClassName) { public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; - JVMInstructionUtils.stackSize = 0; + JVMInstructionUtils.stackSize = 99; String instructions = handleMethodStatements(method); - JVMInstructionUtils.numLocals += method.getParams().size(); - if (!method.isStaticMethod()) + if (method.isStaticMethod() && method.getParams().size() > 0) JVMInstructionUtils.numLocals++; + else if (!method.isStaticMethod()) { + if (JVMInstructionUtils.numLocals < method.getParams().size()) + JVMInstructionUtils.numLocals += method.getParams().size(); + JVMInstructionUtils.numLocals++; + } String methodDirective = ".method "; methodDirective += createMethodDeclaration(method); From a412922099cf5de27be1d908e5718deb2e150691 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 22 May 2023 09:29:28 +0100 Subject: [PATCH 182/253] Added new static field to track current stack size and methods to increase/decrease --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 17 +++++++++++++++-- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index f619abb..28e577d 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -12,6 +12,19 @@ public class JVMInstructionUtils { public static int numLocals = 0; public static int stackSize = 0; + public static int currStackSize = 0; + + public static void increaseStackSize(int n) { + currStackSize += n; + if (currStackSize > stackSize) + stackSize = currStackSize; + } + + public static void decreaseStackSize(int n) { + currStackSize -= n; + if (currStackSize > stackSize) + stackSize = currStackSize; + } public static String getLoadInstruction(Element element, HashMap varTable) { if (element.isLiteral()) { @@ -33,7 +46,7 @@ public static String getLoadInstruction(Element element, HashMap JVMInstructionUtils.numLocals) + if (virtualReg > numLocals) numLocals = virtualReg; switch (elementType) { @@ -62,7 +75,7 @@ public static String getArrayLoadInstruction(ArrayOperand array, HashMap varTable) { int virtualReg = varTable.get(((Operand)element).getName()).getVirtualReg(); - if (virtualReg > JVMInstructionUtils.numLocals) + if (virtualReg > numLocals) numLocals = virtualReg; if (element.isLiteral()) { diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index a3a927a..2b61952 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -197,7 +197,7 @@ public static String createConstructMethod(String superClassName) { public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; - JVMInstructionUtils.stackSize = 99; + JVMInstructionUtils.stackSize = 0; String instructions = handleMethodStatements(method); if (method.isStaticMethod() && method.getParams().size() > 0) JVMInstructionUtils.numLocals++; From 89e08ac1a3768cce967fb8aebb961cf84064dbf0 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 09:35:00 +0100 Subject: [PATCH 183/253] Add basic structure of RegisterAllocation class --- .../pt/up/fe/comp2023/ollir/Optimization.java | 15 +++++++ .../optimization/RegisterAllocation.java | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index e5652b9..94d773c 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -1,5 +1,9 @@ package pt.up.fe.comp2023.ollir; +import org.specs.comp.ollir.ClassUnit; +import org.specs.comp.ollir.Instruction; +import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.OllirErrorException; import pt.up.fe.comp.jmm.analysis.JmmSemanticsResult; import pt.up.fe.comp.jmm.analysis.table.Symbol; import pt.up.fe.comp.jmm.analysis.table.SymbolTable; @@ -11,10 +15,13 @@ import pt.up.fe.comp2023.ollir.OllirUtils; import pt.up.fe.comp2023.optimization.ConstantFolding; import pt.up.fe.comp2023.optimization.ConstantPropagation; +import pt.up.fe.comp2023.optimization.RegisterAllocation; import pt.up.fe.comp2023.semantic.MySymbolTable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class Optimization extends AJmmVisitor implements JmmOptimization { String code = ""; @@ -45,6 +52,14 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { return semanticsResult; } + public OllirResult optimize(OllirResult ollirResult) { + ClassUnit classUnit = ollirResult.getOllirClass(); + + for(Method method : classUnit.getMethods()) + new RegisterAllocation(method); + return ollirResult; + } + @Override protected void buildVisitor() { setDefaultVisit(this::visitAllChildren); diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java new file mode 100644 index 0000000..2269c4d --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -0,0 +1,41 @@ +package pt.up.fe.comp2023.optimization; + +import org.specs.comp.ollir.Element; +import org.specs.comp.ollir.Instruction; +import org.specs.comp.ollir.Method; + +import java.util.*; + +public class RegisterAllocation { + private Method method; + private Map> defs = new HashMap<>(); + private Map> uses = new HashMap<>(); + private Map> in = new HashMap<>(); + private Map> out = new HashMap<>(); + public RegisterAllocation(Method method) { + this.method = method; + method.buildCFG(); + + for (Instruction instruction : method.getInstructions()){ + this.defs.put(instruction, getDef(instruction)); + this.uses.put(instruction, getUse(instruction)); + } + + computeInOuts(); + } + + public Set getDef(Instruction instruction){ + //TODO + return new HashSet(); + + } + + public Set getUse(Instruction instruction){ + //TODO + return new HashSet(); + } + + public void computeInOuts() { + //TODO + } +} From 9d9e49fe3e9309b63b7aa11c9bc88a4b7d6f149b Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 22 May 2023 17:04:42 +0100 Subject: [PATCH 184/253] Reset current stack size for each method --- src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 2b61952..fbaca30 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -198,6 +198,7 @@ public static String createConstructMethod(String superClassName) { public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; JVMInstructionUtils.stackSize = 0; + JVMInstructionUtils.currStackSize = 0; String instructions = handleMethodStatements(method); if (method.isStaticMethod() && method.getParams().size() > 0) JVMInstructionUtils.numLocals++; From 2023588ed88408b0699faa6d0319d0942ea53684 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Mon, 22 May 2023 17:06:25 +0100 Subject: [PATCH 185/253] For each isntruction increase or decrease stack size accordingly --- .../comp2023/jasmin/JVMInstructionUtils.java | 40 ++++++++++++++++--- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 4 +- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 28e577d..cf4c280 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -27,6 +27,7 @@ public static void decreaseStackSize(int n) { } public static String getLoadInstruction(Element element, HashMap varTable) { + increaseStackSize(1); if (element.isLiteral()) { int literal = parseInt(((LiteralElement)element).getLiteral()); if (literal >= 0 && literal <= 5) @@ -74,6 +75,7 @@ public static String getArrayLoadInstruction(ArrayOperand array, HashMap varTable) { + decreaseStackSize(1); int virtualReg = varTable.get(((Operand)element).getName()).getVirtualReg(); if (virtualReg > numLocals) numLocals = virtualReg; @@ -128,6 +130,7 @@ public static String getInvokeVirtualInstruction(CallInstruction instruction, Ha statementList += getLoadInstruction(instruction.getFirstArg(), varTable); statementList += loadInvokeArguments(instruction.getListOfOperands(), varTable); statementList += "\tinvokevirtual " + createInvokeInstructionArgument(instruction, false); + decreaseStackSize(instruction.getListOfOperands().size() + 1); return statementList; } @@ -135,6 +138,7 @@ public static String getInvokeStaticInstruction(CallInstruction instruction, Has String statementList = ""; statementList += loadInvokeArguments(instruction.getListOfOperands(), varTable); statementList += "\tinvokestatic " + createInvokeInstructionArgument(instruction, true); + decreaseStackSize(instruction.getListOfOperands().size()); return statementList; } @@ -147,6 +151,7 @@ public static String getNewInstruction(CallInstruction instruction, HashMap varTable) { Element operand = instruction.getSingleOperand(); if (operand instanceof ArrayOperand) { - return getArrayLoadInstruction((ArrayOperand)operand, varTable) - + "\tiaload\n"; + String statementList = ""; + statementList += getArrayLoadInstruction((ArrayOperand)operand, varTable); + statementList += "\tiaload\n"; + decreaseStackSize(1); + return statementList; } return getLoadInstruction(operand, varTable); } @@ -241,8 +260,10 @@ public static String createAssignStatement(AssignInstruction instruction, HashMa if (assignElement instanceof ArrayOperand) statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); - if (assignElement instanceof ArrayOperand) + if (assignElement instanceof ArrayOperand) { statementList += "\tiastore\n"; + decreaseStackSize(3); + } else statementList += getStoreInstruction(assignElement, varTable); return statementList; @@ -272,6 +293,7 @@ public static String createCallStatement(CallInstruction instruction, HashMap varTable) { - ArrayList aux = new ArrayList<>(); - aux.add(instruction.getThirdOperand()); + ArrayList arguments = new ArrayList<>(); + arguments.add(instruction.getThirdOperand()); String statementList = ""; statementList += getLoadInstruction(instruction.getFirstOperand(), varTable); - statementList += loadInvokeArguments(aux, varTable); + statementList += loadInvokeArguments(arguments, varTable); statementList += "\tputfield " + JasminUtils.getTypeDescriptor(instruction.getFirstOperand().getType(), false) + '/' + ((Operand)instruction.getSecondOperand()).getName() + " " + JasminUtils.getTypeDescriptor(instruction.getThirdOperand().getType(), true) + '\n'; + decreaseStackSize(arguments.size() + 1); return statementList; } @@ -305,6 +328,7 @@ public static String createSingleOpConditionStatement(SingleOpCondInstruction in String statementList = ""; statementList += createNoperInstruction(instruction.getCondition(), varTable); statementList += "\tifne " + instruction.getLabel() + "\n"; + decreaseStackSize(1); return statementList; } @@ -337,6 +361,7 @@ public static String createAuxBranchStatement() { JasminUtils.customLabelCounter++; // if condition is false statementList += "\ticonst_0\n"; + increaseStackSize(1); // skip true section statementList += "\tgoto false_" + JasminUtils.customLabelCounter + "\n"; JasminUtils.customLabelCounter++; @@ -344,6 +369,7 @@ public static String createAuxBranchStatement() { statementList += "\ttrue_" + (JasminUtils.customLabelCounter - 2) + ":\n"; // if condition is true statementList += "\ticonst_1\n"; + increaseStackSize(1); // false section (for skipping true section) statementList += "\tfalse_" + (JasminUtils.customLabelCounter - 1) + ":\n"; return statementList; @@ -360,10 +386,12 @@ public static String createReturnStatement(ReturnInstruction instruction, HashMa case INT32: case BOOLEAN: statementList += getLoadInstruction(returnElement, varTable); statementList += "\tireturn\n"; + decreaseStackSize(1); break; case STRING: case OBJECTREF: case ARRAYREF: case THIS: statementList += getLoadInstruction(returnElement, varTable); statementList += "\tareturn\n"; + decreaseStackSize(1); } return statementList; } diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index fbaca30..d8e7bdc 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -109,8 +109,10 @@ public static String handleInstruction(Instruction instruction, HashMap Date: Mon, 22 May 2023 17:50:20 +0100 Subject: [PATCH 186/253] Add methods to compute def and use of each instruction --- .../optimization/RegisterAllocation.java | 72 +++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 2269c4d..70f7e94 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,13 +1,17 @@ package pt.up.fe.comp2023.optimization; -import org.specs.comp.ollir.Element; -import org.specs.comp.ollir.Instruction; -import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.*; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Map; + +import static org.specs.comp.ollir.InstructionType.ASSIGN; public class RegisterAllocation { - private Method method; + private final Method method; private Map> defs = new HashMap<>(); private Map> uses = new HashMap<>(); private Map> in = new HashMap<>(); @@ -16,23 +20,67 @@ public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); + //TODO: remove + System.out.println(method.getMethodName()); + System.out.println("------------------"); + for (Instruction instruction : method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); - this.uses.put(instruction, getUse(instruction)); - } + this.uses.put(instruction, getUse(instruction, new HashSet<>())); + //TODO: remove + instruction.show(); + System.out.println("Defs:" + defs.get(instruction)); + System.out.println("Uses:" + uses.get(instruction)); + } computeInOuts(); } public Set getDef(Instruction instruction){ - //TODO - return new HashSet(); + Set def = new HashSet<>(); + if(instruction.getInstType() == ASSIGN) { + AssignInstruction assignInst = (AssignInstruction)instruction; + def.add(assignInst.getDest()); + } + return def; } - public Set getUse(Instruction instruction){ - //TODO - return new HashSet(); + public Set getUse(Instruction instruction, Set result){ + switch (instruction.getInstType()) { + case ASSIGN -> { + AssignInstruction assignInst = (AssignInstruction) instruction; + return getUse(assignInst.getRhs(), result); + } + case CALL -> { + CallInstruction callInst = (CallInstruction) instruction; + List arguments = callInst.getListOfOperands(); + for (Element argument : arguments) { + if (!argument.isLiteral()) + result.add(argument); + } + } + case RETURN -> { + ReturnInstruction returnInst = (ReturnInstruction) instruction; + Element returnElement = returnInst.getOperand(); + if (returnElement != null && !returnElement.isLiteral()) + result.add(returnElement); + } + case BINARYOPER -> { + BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; + if (!binInst.getLeftOperand().isLiteral()) + result.add(binInst.getLeftOperand()); + if (!binInst.getRightOperand().isLiteral()) + result.add(binInst.getRightOperand()); + } + case NOPER -> { + SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; + Element operand = singleOpInstruction.getSingleOperand(); + if (!operand.isLiteral()) + result.add(operand); + } + } + return result; } public void computeInOuts() { From 91f2386ad28d440b49bb390c68b4077ae6b6cc97 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:54:09 +0100 Subject: [PATCH 187/253] change to grammar --- src/main/antlr/comp2023/grammar/Javamm.g4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index ebfd873..830cde8 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -58,6 +58,8 @@ statement expression : '(' expression ')' #ParenthesesExpr + | 'new' 'int' '[' expression ']' #ArrayCreation + | 'new' classname=ID '(' ')' #ObjectCreation | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall @@ -67,8 +69,6 @@ expression | expression op=('<' | '>') expression #ComparisonExpr | expression op='&&' expression #LogicalExpr | expression op='||' expression #LogicalExpr - | 'new' 'int' '[' expression ']' #ArrayCreation - | 'new' classname=ID '(' ')' #ObjectCreation | value=INT #Integer | value=('true' | 'false') #Boolean | 'this' #This From a1069cf110ea36af79da2c4010b4377a9389e478 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:55:14 +0100 Subject: [PATCH 188/253] aa --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 4e89ec7..81bdad0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -188,6 +188,8 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { } private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { + JmmNode size = jmmNode.getChildren().get(0); + String for (var child : jmmNode.getChildren()) visit(child); From db390b04a8c492eacaceef514908dfdea7d1b3f7 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Mon, 22 May 2023 17:56:28 +0100 Subject: [PATCH 189/253] hotfix grammar --- src/main/antlr/comp2023/grammar/Javamm.g4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/antlr/comp2023/grammar/Javamm.g4 b/src/main/antlr/comp2023/grammar/Javamm.g4 index f2425c7..68b3c62 100644 --- a/src/main/antlr/comp2023/grammar/Javamm.g4 +++ b/src/main/antlr/comp2023/grammar/Javamm.g4 @@ -58,6 +58,8 @@ statement expression : '(' expression ')' #ParenthesesExpr + | 'new' 'int' '[' expression ']' #ArrayCreation + | 'new' classname=ID '(' ')' #ObjectCreation | expression '[' expression ']' #ArraySubscript | expression '.' field='length' #LengthFieldAccess | expression '.' methodcall=ID '(' methodCallParameters ')' #MethodCall @@ -67,8 +69,6 @@ expression | expression op=('<' | '>') expression #ComparisonExpr | expression op='&&' expression #LogicalExpr | expression op='||' expression #LogicalExpr - | 'new' 'int' '[' expression ']' #ArrayCreation - | 'new' classname=ID '(' ')' #ObjectCreation | value=INT #Integer | value=('true' | 'false') #Boolean | 'this' #This From 5742fac288b0460d2e4adb114eb8ee69400095a7 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 22:50:40 +0100 Subject: [PATCH 190/253] Add utils methods compute union and difference of sets --- .../optimization/OptimizationUtils.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 648c113..b34e64a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,6 +1,10 @@ package pt.up.fe.comp2023.optimization; +import org.specs.comp.ollir.Element; + +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class OptimizationUtils { public static void intersectMaps (Map map1, Map map2, Map result){ @@ -14,4 +18,18 @@ public static void intersectMaps (Map map1, Map result.put(key, value); } } + + public static Set differenceSets (Set set1, Set set2){ + Set result = new HashSet<>(set1); + result.removeAll(set2); + + return result; + } + + public static Set unionSets (Set set1, Set set2){ + Set result = new HashSet<>(set1); + result.addAll(set2); + + return result; + } } From bdc427b92da87b8cc229ab06a8516004aa08bcd4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Mon, 22 May 2023 22:51:27 +0100 Subject: [PATCH 191/253] Implement method to compute liveIn and liveOut --- .../optimization/RegisterAllocation.java | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 70f7e94..4bcaeab 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -9,6 +9,8 @@ import java.util.Map; import static org.specs.comp.ollir.InstructionType.ASSIGN; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.differenceSets; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.unionSets; public class RegisterAllocation { private final Method method; @@ -33,7 +35,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeInOuts(); + computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -83,7 +85,36 @@ public Set getUse(Instruction instruction, Set result){ return result; } - public void computeInOuts() { - //TODO + public void computeLiveInOuts() { + for (Instruction instruction : method.getInstructions()){ + this.in.put(instruction, new HashSet<>()); + this.out.put(instruction, new HashSet<>()); + } + + boolean liveChanged; + do { + liveChanged = false; + for(Instruction instruction : method.getInstructions()){ + //Save current liveIn and liveOut + Set liveInAux = new HashSet<>(this.in.get(instruction)); + Set liveOutAux = new HashSet<>(this.out.get(instruction)); + + //Update liveIn + Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); + Set newLiveIn = unionSets(this.uses.get(instruction), difference); + + //Update liveOut + Set newLiveOut = new HashSet<>(); + for(Node node : instruction.getSuccessors()){ + Instruction successor = (Instruction) node; + newLiveOut.addAll(this.in.get(successor)); + } + this.out.put(instruction, newLiveOut); + + //Check if liveIn or liveOut changed + if(!liveOutAux.equals(newLiveOut) || !liveInAux.equals(newLiveIn)) + liveChanged = true; + } + } while(liveChanged); } } From 59331a894ab8c3dd8ad96f23fba3b128377defb8 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 11:03:56 +0100 Subject: [PATCH 192/253] fix if --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 81bdad0..75d0da0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -80,11 +80,11 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { } private Void dealWithCondition(JmmNode jmmNode, Void unused) { - code += "\t\t"; visit(jmmNode.getJmmChild(0)); + code += "\t\t"; visit(jmmNode.getJmmChild(0)); var ifId = tempVarId++; // Condition statement - code += "\t\tif (" + temp + ") goto if" + ifId + ";\n"; + code += "\t\tif (" + jmmNode.getJmmChild(0).get("valueOl") + ") goto if" + ifId + ";\n"; // What occurs if the condition isn't met code += "\t\t\t"; visit(jmmNode.getJmmChild(2)); @@ -189,7 +189,7 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { JmmNode size = jmmNode.getChildren().get(0); - String + for (var child : jmmNode.getChildren()) visit(child); From 5411ddf3cc83efdb8b3fad005ae4c116064dac35 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 11:18:01 +0100 Subject: [PATCH 193/253] while hotfix --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 75d0da0..29c22f2 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -65,7 +65,7 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { var ifId = tempVarId++; // Condition statement - negation - code += "\t\tif (!.bool " + temp + ") goto end_loop" + ifId + ";\n"; + code += "\t\tif (!.bool " + jmmNode.getJmmChild(0).get("valueOl") + ") goto end_loop" + ifId + ";\n"; // What occurs if the condition is met code += "\t\tloop" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); From 32a84631b065a51e08c09d3fc7cc132655f4ce2f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:05:34 +0100 Subject: [PATCH 194/253] Add method to check if an element is a local variable --- .../fe/comp2023/optimization/OptimizationUtils.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index b34e64a..3c1e77a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -1,7 +1,11 @@ package pt.up.fe.comp2023.optimization; +import org.specs.comp.ollir.Descriptor; import org.specs.comp.ollir.Element; +import org.specs.comp.ollir.Method; +import org.specs.comp.ollir.Operand; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -32,4 +36,13 @@ public static Set unionSets (Set set1, Set set2){ return result; } + + public static boolean isLocalVar(Element element, Method method) { + HashMap varTable = method.getVarTable(); + String varName = ((Operand)element).getName(); + int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + + return varTable.get(element.toString()).getVirtualReg() < firstLocalVarRegister) + } + } From 295a91423bc0282700c870c0fa4c441d056bdf57 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 12:07:03 +0100 Subject: [PATCH 195/253] Instruction selection: iinc --- .../comp2023/jasmin/JVMInstructionUtils.java | 24 ++++++++++++++++++- .../inst_selection/InstSelection_iinc.ollir | 11 +++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index cf4c280..3f9c66c 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -183,6 +183,23 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash return statementList; } + public static String checkInc(BinaryOpInstruction instruction, HashMap varTable) { + Element leftOperand = instruction.getLeftOperand(); + Element rightOperand = instruction.getRightOperand(); + + if (!(leftOperand instanceof LiteralElement) && + rightOperand instanceof LiteralElement && + parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) + return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; + + if (leftOperand instanceof LiteralElement && + !(rightOperand instanceof LiteralElement) && + parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) + return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; + + return ""; + } + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { String statementList = ""; statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); @@ -254,9 +271,14 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { - Element assignElement = instruction.getDest(); String statementList = ""; + if (instruction.getRhs() instanceof BinaryOpInstruction) { + statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), varTable); + if (!statementList.equals("")) + return statementList; + } + Element assignElement = instruction.getDest(); if (assignElement instanceof ArrayOperand) statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); diff --git a/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir new file mode 100644 index 0000000..750e2d5 --- /dev/null +++ b/test/pt/up/fe/comp/cpf/5_optimizations/inst_selection/InstSelection_iinc.ollir @@ -0,0 +1,11 @@ +InstSelection_iinc { + .construct InstSelection_iinc().V { + invokespecial(this, "").V; + } + + .method public static main(args.array.String).V{ + i.i32 :=.i32 2.i32; + i.i32:=.i32 i.i32 +.i32 1.i32; + ret.V; + } +} \ No newline at end of file From d57caafe9e890b54bf21bbcc66d4f57f7906c3d4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:08:18 +0100 Subject: [PATCH 196/253] Small correction to isLocalVar() --- src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 3c1e77a..70c3023 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -42,7 +42,7 @@ public static boolean isLocalVar(Element element, Method method) { String varName = ((Operand)element).getName(); int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(element.toString()).getVirtualReg() < firstLocalVarRegister) + return varTable.get(varName).getVirtualReg() < firstLocalVarRegister; } } From a0391f260489e8f2fee1e8b9320d57271b621bc6 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 12:16:33 +0100 Subject: [PATCH 197/253] Improved getUse() in order to check if element is a local variable --- .../optimization/RegisterAllocation.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 4bcaeab..560d539 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,16 +1,14 @@ package pt.up.fe.comp2023.optimization; import org.specs.comp.ollir.*; - import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Map; -import static org.specs.comp.ollir.InstructionType.ASSIGN; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.differenceSets; -import static pt.up.fe.comp2023.optimization.OptimizationUtils.unionSets; +import static org.specs.comp.ollir.InstructionType.*; +import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; public class RegisterAllocation { private final Method method; @@ -35,7 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeLiveInOuts(); + //computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -43,7 +41,8 @@ public Set getDef(Instruction instruction){ if(instruction.getInstType() == ASSIGN) { AssignInstruction assignInst = (AssignInstruction)instruction; - def.add(assignInst.getDest()); + if(isLocalVar(assignInst.getDest(), this.method)) + def.add(assignInst.getDest()); } return def; } @@ -58,27 +57,29 @@ public Set getUse(Instruction instruction, Set result){ CallInstruction callInst = (CallInstruction) instruction; List arguments = callInst.getListOfOperands(); for (Element argument : arguments) { - if (!argument.isLiteral()) + if (!argument.isLiteral() && isLocalVar(argument, this.method)) result.add(argument); } } case RETURN -> { ReturnInstruction returnInst = (ReturnInstruction) instruction; Element returnElement = returnInst.getOperand(); - if (returnElement != null && !returnElement.isLiteral()) + if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) result.add(returnElement); } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; - if (!binInst.getLeftOperand().isLiteral()) - result.add(binInst.getLeftOperand()); - if (!binInst.getRightOperand().isLiteral()) - result.add(binInst.getRightOperand()); + Element leftOperand = binInst.getLeftOperand(); + Element rightOperand = binInst.getRightOperand(); + if (!leftOperand.isLiteral() && isLocalVar(leftOperand, this.method)) + result.add(leftOperand); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; Element operand = singleOpInstruction.getSingleOperand(); - if (!operand.isLiteral()) + if (!operand.isLiteral() && isLocalVar(operand, this.method)) result.add(operand); } } From 46d9fc3fbc8e1c6a7233aa8a162323df0098f3b5 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 13:35:16 +0100 Subject: [PATCH 198/253] Improve getUse() to handle PUTFIELD instruction type --- .../fe/comp2023/optimization/OptimizationUtils.java | 2 +- .../comp2023/optimization/RegisterAllocation.java | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 70c3023..713fef0 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -42,7 +42,7 @@ public static boolean isLocalVar(Element element, Method method) { String varName = ((Operand)element).getName(); int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(varName).getVirtualReg() < firstLocalVarRegister; + return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; } } diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 560d539..b70d712 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -78,10 +78,17 @@ public Set getUse(Instruction instruction, Set result){ } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; - Element operand = singleOpInstruction.getSingleOperand(); - if (!operand.isLiteral() && isLocalVar(operand, this.method)) - result.add(operand); + Element rightOperand = singleOpInstruction.getSingleOperand(); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); + } + case PUTFIELD -> { + PutFieldInstruction putFieldInstruction = (PutFieldInstruction) instruction; + Element rightOperand = putFieldInstruction.getThirdOperand(); + if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) + result.add(rightOperand); } + //TODO: } return result; } From ae073f09cb5a59b3c046648c58bff35c7f219350 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Tue, 23 May 2023 13:47:04 +0100 Subject: [PATCH 199/253] Improve getUse() to handle UNARYOPER instruction type --- .../pt/up/fe/comp2023/optimization/RegisterAllocation.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index b70d712..1d3febd 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -67,6 +67,12 @@ public Set getUse(Instruction instruction, Set result){ if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) result.add(returnElement); } + case UNARYOPER -> { + UnaryOpInstruction unaryOpInstruction = (UnaryOpInstruction) instruction; + Element operand = unaryOpInstruction.getOperand(); + if (!operand.isLiteral() && isLocalVar(operand, this.method)) + result.add(operand); + } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; Element leftOperand = binInst.getLeftOperand(); @@ -88,7 +94,6 @@ public Set getUse(Instruction instruction, Set result){ if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) result.add(rightOperand); } - //TODO: } return result; } From 15763205b3d47fdaaa0bcdf23294506581892ade Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 15:27:21 +0100 Subject: [PATCH 200/253] array creation --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 29c22f2..afb0505 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -188,10 +188,10 @@ private Void dealWithObjectCreation(JmmNode jmmNode, Void unused) { } private Void dealWithArrayCreation(JmmNode jmmNode, Void unused) { - JmmNode size = jmmNode.getChildren().get(0); + visit(jmmNode.getJmmChild(0)); + code += "\t\tt" + tempVarId + ".array.i32 :=.array.i32 new(array, " + jmmNode.getJmmChild(0).get("valueOl") +").array.i32;\n"; - for (var child : jmmNode.getChildren()) - visit(child); + jmmNode.put("valueOl", "t" + tempVarId++ + ".array.i32" ); return null; } From 26cca1182539086b062b764dd6b6451ec62e6a31 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 12:21:59 +0100 Subject: [PATCH 201/253] Verified if binary operation is addition before doing iinc --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 3f9c66c..ff58645 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -187,12 +187,14 @@ public static String checkInc(BinaryOpInstruction instruction, HashMap Date: Tue, 23 May 2023 16:49:29 +0100 Subject: [PATCH 202/253] this changed to always display class name --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index afb0505..de41e82 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -160,7 +160,7 @@ else if (isField) { } private Void dealWithThis(JmmNode jmmNode, Void unused) { - jmmNode.put("valueOl", "this"); + jmmNode.put("valueOl", "this." + table.getClassName()); return null; } From 24ef437c5e4ca6620705f1c4c9f89cd3da67872b Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 16:50:55 +0100 Subject: [PATCH 203/253] Verified if the left and right side variables are the same before using iinc --- .../pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ff58645..ce8f784 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -183,19 +183,22 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash return statementList; } - public static String checkInc(BinaryOpInstruction instruction, HashMap varTable) { + public static String checkInc(BinaryOpInstruction instruction, Element dest, HashMap varTable) { Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); + String destName = ((Operand)dest).getName(); if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && + destName.equals(((Operand)leftOperand).getName()) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && + destName.equals(((Operand)rightOperand).getName()) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; @@ -273,14 +276,14 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { + Element assignElement = instruction.getDest(); String statementList = ""; if (instruction.getRhs() instanceof BinaryOpInstruction) { - statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), varTable); + statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) return statementList; } - Element assignElement = instruction.getDest(); if (assignElement instanceof ArrayOperand) statementList += getArrayLoadInstruction((ArrayOperand)assignElement, varTable); statementList += JasminUtils.handleInstruction(instruction.getRhs(), varTable, true); From 0269fe01988d920723d0f06414ee12d9b8eccb98 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 17:04:13 +0100 Subject: [PATCH 204/253] negation implemented --- .../pt/up/fe/comp2023/ollir/Optimization.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index de41e82..e3e492d 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -291,7 +291,7 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; + code += temp + " :=.bool " + left + " " + jmmNode.get("op") + ".bool " + right + ";\n"; jmmNode.put("valueOl", temp); return null; @@ -300,9 +300,6 @@ private Void dealWithLogicalExpr(JmmNode jmmNode, Void unused) { private Void dealWithComparison(JmmNode jmmNode, Void unused) { JmmNode leftSon = jmmNode.getJmmChild(0); JmmNode rightSon = jmmNode.getJmmChild(1); - var condition = jmmNode.getAncestor("Condition"); - var cycle = jmmNode.getAncestor("Cycle"); - visit(leftSon); visit(rightSon); @@ -311,9 +308,8 @@ private Void dealWithComparison(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".bool"; - code += temp + ":=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; - //if (condition.isEmpty() || cycle.isEmpty()) - code += ";\n"; + code += temp + " :=.bool " + left + " " + jmmNode.get("op") + ".bool " + right; + code += ";\n"; jmmNode.put("valueOl", temp); return null; @@ -330,16 +326,19 @@ private Void dealWithArithmetic(JmmNode jmmNode, Void unused) { String right = rightSon.get("valueOl"); temp = "t" + tempVarId++ + ".i32"; - code += temp + ":=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; + code += temp + " :=.i32 " + left + " " + jmmNode.get("op") + ".i32 " + right + ";\n"; jmmNode.put("valueOl", temp); return null; } private Void dealWithNegationExpr(JmmNode jmmNode, Void unused) { - for (var child : jmmNode.getChildren()) - visit(child); - + JmmNode son = jmmNode.getJmmChild(0); + visit(son); + String sonS = son.get("valueOl"); + temp = "t" + tempVarId++ + ".bool"; + code += temp + " :=.bool !.bool " + sonS + ";\n"; + jmmNode.put("valueOl", temp); return null; } From e8996bebe3e731359c1dd87dd8c82ca4f7a180af Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Tue, 23 May 2023 17:28:16 +0100 Subject: [PATCH 205/253] fix semicolon on cycles --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index e3e492d..a5a819f 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -467,13 +467,11 @@ else if (isField) } private Void dealWithExpr(JmmNode jmmNode, Void unused) { - var cycle = jmmNode.getAncestor("Cycle"); code += "\t\t"; for (var child : jmmNode.getChildren()) visit(child); - if (cycle.isEmpty()) - code += ";\n"; + code += ";\n"; System.out.println(jmmNode.getKind()); return null; } From f5a147ee838a8380dd1c84cb5b654ea69659d3b7 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Tue, 23 May 2023 17:51:26 +0100 Subject: [PATCH 206/253] Refactored binary operation instruction generation --- .../comp2023/jasmin/JVMInstructionUtils.java | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ce8f784..2b553e7 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -205,59 +205,66 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has return ""; } - public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { - String statementList = ""; - statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); - statementList += getLoadInstruction(instruction.getRightOperand(), varTable); + public static String createArithmeticInstruction(OperationType operationType) { + decreaseStackSize(1); - switch (instruction.getOperation().getOpType()) { + switch (operationType) { case ADD: - statementList += "\tiadd\n"; - decreaseStackSize(1); - break; + return "\tiadd\n"; case SUB: - statementList += "\tisub\n"; - decreaseStackSize(1); - break; + return "\tisub\n"; case MUL: - statementList += "\timul\n"; - decreaseStackSize(1); - break; + return "\timul\n"; case DIV: - statementList += "\tidiv\n"; - decreaseStackSize(1); - break; + return "\tidiv\n"; + } + return ""; + } + + public static String createLogicalInstruction(OperationType operationType) { + decreaseStackSize(1); + + switch (operationType) { case AND: case ANDB: - statementList += "\tiand\n"; - decreaseStackSize(1); - break; + return "\tiand\n"; case OR: case ORB: - statementList += "\tior\n"; - decreaseStackSize(1); - break; + return "\tior\n"; + } + return ""; + } + + public static String createComparisonInstruction(OperationType operationType, boolean isBranchCond) { + decreaseStackSize(2); + String statementList = ""; + + switch (operationType) { case LTH: - statementList += "\tif_icmplt "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmplt " : "\tif_icmplt " + createAuxBranchStatement(); case LTE: - statementList += "\tif_icmple "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmple " : "\tif_icmple " + createAuxBranchStatement(); case GTH: - statementList += "\tif_icmpgt "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); - break; + return isBranchCond ? "\tif_icmpgt " : "\tif_icmpgt " + createAuxBranchStatement(); case GTE: - statementList += "\tif_icmpge "; - if (!isBranchCond) - statementList += createAuxBranchStatement(); - decreaseStackSize(2); + return isBranchCond ? "\tif_icmpge " : "\tif_icmpge " + createAuxBranchStatement(); + } + return ""; + } + + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { + OperationType operationType = instruction.getOperation().getOpType(); + String statementList = ""; + statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); + statementList += getLoadInstruction(instruction.getRightOperand(), varTable); + + switch (operationType) { + case ADD: case SUB: case MUL: case DIV: + statementList += createArithmeticInstruction(operationType); + break; + case AND: case ANDB: case OR: case ORB: + statementList += createLogicalInstruction(operationType); + break; + case LTH: case LTE: case GTH: case GTE: + statementList += createComparisonInstruction(operationType, isBranchCond); break; } return statementList; From f168a5cb3f16129c6bbb1110deea76c478de5ec9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 09:21:42 +0100 Subject: [PATCH 207/253] Add utils method to get local vars from the varTable --- .../optimization/OptimizationUtils.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 713fef0..df7c5a9 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -32,7 +32,8 @@ public static Set differenceSets (Set set1, Set set2) public static Set unionSets (Set set1, Set set2){ Set result = new HashSet<>(set1); - result.addAll(set2); + if(set2 != null) + result.addAll(set2); return result; } @@ -45,4 +46,23 @@ public static boolean isLocalVar(Element element, Method method) { return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; } + public static boolean isLocalVar(String identifier, Method method) { + HashMap varTable = method.getVarTable(); + int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + + return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; + } + + public static Set getLocalVars(Method method) { + HashMap varTable = method.getVarTable(); + Set localsVars = new HashSet<>(); + + for(Map.Entry entry : varTable.entrySet()){ + String identifier = entry.getKey(); + if(isLocalVar(identifier, method)) + localsVars.add(identifier); + } + return localsVars; + } + } From ec2b377765c07cc134e0088de5525e8a019af1e4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:38:50 +0100 Subject: [PATCH 208/253] Fixed computeLiveInOuts() --- .../optimization/RegisterAllocation.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 1d3febd..0dc2edf 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -12,10 +12,10 @@ public class RegisterAllocation { private final Method method; - private Map> defs = new HashMap<>(); - private Map> uses = new HashMap<>(); - private Map> in = new HashMap<>(); - private Map> out = new HashMap<>(); + private final Map> defs = new HashMap<>(); + private final Map> uses = new HashMap<>(); + private final Map> in = new HashMap<>(); + private final Map> out = new HashMap<>(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -33,7 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - //computeLiveInOuts(); + computeLiveInOuts(); } public Set getDef(Instruction instruction){ @@ -115,17 +115,19 @@ public void computeLiveInOuts() { //Update liveIn Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); Set newLiveIn = unionSets(this.uses.get(instruction), difference); + this.in.put(instruction, newLiveIn); //Update liveOut Set newLiveOut = new HashSet<>(); - for(Node node : instruction.getSuccessors()){ - Instruction successor = (Instruction) node; - newLiveOut.addAll(this.in.get(successor)); + + for(Node successor : instruction.getSuccessors()){ + Set liveInSuccessor = this.in.get(successor); + newLiveOut = unionSets(newLiveOut, liveInSuccessor); } this.out.put(instruction, newLiveOut); //Check if liveIn or liveOut changed - if(!liveOutAux.equals(newLiveOut) || !liveInAux.equals(newLiveIn)) + if(!liveInAux.equals(newLiveIn) || !liveOutAux.equals(newLiveOut)) liveChanged = true; } } while(liveChanged); From abe58f1f9c7dc3e413e0deb63c567ac9d68246fd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:50:23 +0100 Subject: [PATCH 209/253] Create MyNode class and add basic methods --- .../interferenceGraph/MyNode.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java new file mode 100644 index 0000000..e3ea03b --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java @@ -0,0 +1,34 @@ +package pt.up.fe.comp2023.optimization.interferenceGraph; + +import org.specs.comp.ollir.Element; +import java.util.HashSet; +import java.util.Set; + +public class MyNode { + private final String varName; + private final Set adj = new HashSet<>(); + + public MyNode(String varName){ + this.varName = varName; + } + + public String getVariable() { + return this.varName; + } + + public Set getAdj() { + return adj; + } + + public void addAdj(String varName) { + this.adj.add(varName); + } + + public int getNodeDegree() { + return this.adj.size(); + } + + public void removeAdj(String varName){ + this.adj.remove(varName); + } +} From 23e2c93eb981a470c53c8e260bf3ff0c6e1cfb15 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 14:50:47 +0100 Subject: [PATCH 210/253] Create MyInterferenceGraph class and add basic methods --- .../MyInterferenceGraph.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java new file mode 100644 index 0000000..591c230 --- /dev/null +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -0,0 +1,35 @@ +package pt.up.fe.comp2023.optimization.interferenceGraph; + +import java.util.ArrayList; +import java.util.List; + +public class MyInterferenceGraph { + private final List nodes = new ArrayList<>(); + + public void addNode(String variable){ + MyNode newNode = new MyNode(variable); + this.nodes.add(newNode); + } + + public MyNode getNode(String varName){ + for(MyNode node : this.nodes){ + if(node.getVariable().equals(varName)) + return node; + } + return null; + } + public void addEdge(String src, String dest){ + getNode(src).getAdj().add(dest); + getNode(dest).getAdj().add(src); + } + + public void removeNode(String varName){ + MyNode node = getNode(varName); + + for(String adj : node.getAdj()){ + MyNode adjNode = getNode(adj); + adjNode.removeAdj(varName); + } + this.nodes.remove(node); + } +} From ec6f30eb87b99935fd3b84657210727f55ef7a48 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:36:28 +0100 Subject: [PATCH 211/253] Add method to get variable name of an Element --- .../fe/comp2023/optimization/OptimizationUtils.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index df7c5a9..5caf3cf 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -5,10 +5,7 @@ import org.specs.comp.ollir.Method; import org.specs.comp.ollir.Operand; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class OptimizationUtils { public static void intersectMaps (Map map1, Map map2, Map result){ @@ -53,9 +50,9 @@ public static boolean isLocalVar(String identifier, Method method) { return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; } - public static Set getLocalVars(Method method) { + public static List getLocalVars(Method method) { HashMap varTable = method.getVarTable(); - Set localsVars = new HashSet<>(); + List localsVars = new ArrayList<>(); for(Map.Entry entry : varTable.entrySet()){ String identifier = entry.getKey(); @@ -65,4 +62,8 @@ public static Set getLocalVars(Method method) { return localsVars; } + public static String toVarName(Element element){ + return ((Operand)element).getName(); + } + } From f8a487d393df2febb0a9a8d95e00d8fa8476e65f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:46:15 +0100 Subject: [PATCH 212/253] Refactor: define differenceSets and unionSets as generic methods --- .../fe/comp2023/optimization/OptimizationUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 5caf3cf..e80cdb2 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -20,15 +20,16 @@ public static void intersectMaps (Map map1, Map } } - public static Set differenceSets (Set set1, Set set2){ - Set result = new HashSet<>(set1); - result.removeAll(set2); + public static Set differenceSets(Set set1, Set set2) { + Set result = new HashSet<>(set1); + if(set2 != null) + result.removeAll(set2); return result; } - public static Set unionSets (Set set1, Set set2){ - Set result = new HashSet<>(set1); + public static Set unionSets(Set set1, Set set2) { + Set result = new HashSet<>(set1); if(set2 != null) result.addAll(set2); @@ -65,5 +66,4 @@ public static List getLocalVars(Method method) { public static String toVarName(Element element){ return ((Operand)element).getName(); } - } From f93fab32f949093f31cf415e75c9c102cf46b646 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 15:49:27 +0100 Subject: [PATCH 213/253] Change key type in maps of RegisterAllocation from Element to String --- .../optimization/RegisterAllocation.java | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 0dc2edf..331bb1e 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -1,6 +1,8 @@ package pt.up.fe.comp2023.optimization; import org.specs.comp.ollir.*; +import pt.up.fe.comp2023.optimization.interferenceGraph.MyInterferenceGraph; + import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -12,10 +14,10 @@ public class RegisterAllocation { private final Method method; - private final Map> defs = new HashMap<>(); - private final Map> uses = new HashMap<>(); - private final Map> in = new HashMap<>(); - private final Map> out = new HashMap<>(); + private final Map> defs = new HashMap<>(); + private final Map> uses = new HashMap<>(); + private final Map> in = new HashMap<>(); + private final Map> out = new HashMap<>(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -33,21 +35,23 @@ public RegisterAllocation(Method method) { System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); } - computeLiveInOuts(); + computeLiveInOut(); } - public Set getDef(Instruction instruction){ - Set def = new HashSet<>(); + public Set getDef(Instruction instruction){ + Set def = new HashSet<>(); if(instruction.getInstType() == ASSIGN) { AssignInstruction assignInst = (AssignInstruction)instruction; - if(isLocalVar(assignInst.getDest(), this.method)) - def.add(assignInst.getDest()); + if(isLocalVar(assignInst.getDest(), this.method)){ + Element dest = assignInst.getDest(); + def.add(toVarName(dest)); + } } return def; } - public Set getUse(Instruction instruction, Set result){ + public Set getUse(Instruction instruction, Set result){ switch (instruction.getInstType()) { case ASSIGN -> { AssignInstruction assignInst = (AssignInstruction) instruction; @@ -58,47 +62,47 @@ public Set getUse(Instruction instruction, Set result){ List arguments = callInst.getListOfOperands(); for (Element argument : arguments) { if (!argument.isLiteral() && isLocalVar(argument, this.method)) - result.add(argument); + result.add(toVarName(argument)); } } case RETURN -> { ReturnInstruction returnInst = (ReturnInstruction) instruction; Element returnElement = returnInst.getOperand(); if (returnElement != null && !returnElement.isLiteral() && isLocalVar(returnElement, this.method)) - result.add(returnElement); + result.add(toVarName(returnElement)); } case UNARYOPER -> { UnaryOpInstruction unaryOpInstruction = (UnaryOpInstruction) instruction; Element operand = unaryOpInstruction.getOperand(); if (!operand.isLiteral() && isLocalVar(operand, this.method)) - result.add(operand); + result.add(toVarName(operand)); } case BINARYOPER -> { BinaryOpInstruction binInst = (BinaryOpInstruction) instruction; Element leftOperand = binInst.getLeftOperand(); Element rightOperand = binInst.getRightOperand(); if (!leftOperand.isLiteral() && isLocalVar(leftOperand, this.method)) - result.add(leftOperand); + result.add(toVarName(leftOperand)); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } case NOPER -> { SingleOpInstruction singleOpInstruction = (SingleOpInstruction) instruction; Element rightOperand = singleOpInstruction.getSingleOperand(); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } case PUTFIELD -> { PutFieldInstruction putFieldInstruction = (PutFieldInstruction) instruction; Element rightOperand = putFieldInstruction.getThirdOperand(); if (!rightOperand.isLiteral() && isLocalVar(rightOperand, this.method)) - result.add(rightOperand); + result.add(toVarName(rightOperand)); } } return result; } - public void computeLiveInOuts() { + public void computeLiveInOut() { for (Instruction instruction : method.getInstructions()){ this.in.put(instruction, new HashSet<>()); this.out.put(instruction, new HashSet<>()); @@ -109,19 +113,19 @@ public void computeLiveInOuts() { liveChanged = false; for(Instruction instruction : method.getInstructions()){ //Save current liveIn and liveOut - Set liveInAux = new HashSet<>(this.in.get(instruction)); - Set liveOutAux = new HashSet<>(this.out.get(instruction)); + Set liveInAux = new HashSet<>(this.in.get(instruction)); + Set liveOutAux = new HashSet<>(this.out.get(instruction)); //Update liveIn - Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); - Set newLiveIn = unionSets(this.uses.get(instruction), difference); + Set difference = differenceSets(this.out.get(instruction), this.defs.get(instruction)); + Set newLiveIn = unionSets(this.uses.get(instruction), difference); this.in.put(instruction, newLiveIn); //Update liveOut - Set newLiveOut = new HashSet<>(); + Set newLiveOut = new HashSet<>(); for(Node successor : instruction.getSuccessors()){ - Set liveInSuccessor = this.in.get(successor); + Set liveInSuccessor = this.in.get(successor); newLiveOut = unionSets(newLiveOut, liveInSuccessor); } this.out.put(instruction, newLiveOut); From ec2ec137fb7d6772b0d05016f511162fc8e40ae3 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 16:30:34 +0100 Subject: [PATCH 214/253] Add new method to connect interfering variables --- .../interferenceGraph/MyInterferenceGraph.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 591c230..18ccc1e 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -18,11 +18,22 @@ public MyNode getNode(String varName){ } return null; } - public void addEdge(String src, String dest){ + public void addInterferenceEdge(String src, String dest){ getNode(src).getAdj().add(dest); getNode(dest).getAdj().add(src); } + public void connectInterferingVariables(List variables){ + for(int i = 0; i < variables.size(); i++){ + for(int j = i + 1; j < variables.size(); j++){ + String src = variables.get(i); + String dest = variables.get(j); + + addInterferenceEdge(src, dest); + } + } + } + public void removeNode(String varName){ MyNode node = getNode(varName); From 79bf55d1a6b932c0031a2987c1e26b1b7e3d2544 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 16:31:04 +0100 Subject: [PATCH 215/253] Add method to create interference graph --- .../optimization/RegisterAllocation.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 331bb1e..6111ee1 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -3,11 +3,7 @@ import org.specs.comp.ollir.*; import pt.up.fe.comp2023.optimization.interferenceGraph.MyInterferenceGraph; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Map; +import java.util.*; import static org.specs.comp.ollir.InstructionType.*; import static pt.up.fe.comp2023.optimization.OptimizationUtils.*; @@ -18,6 +14,7 @@ public class RegisterAllocation { private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); + private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); public RegisterAllocation(Method method) { this.method = method; method.buildCFG(); @@ -36,6 +33,7 @@ public RegisterAllocation(Method method) { System.out.println("Uses:" + uses.get(instruction)); } computeLiveInOut(); + createInterferenceGraph(); } public Set getDef(Instruction instruction){ @@ -136,4 +134,21 @@ public void computeLiveInOut() { } } while(liveChanged); } + + private void createInterferenceGraph() { + List localVars = getLocalVars(this.method); + + //Add a node for each variable + for(String var : localVars) + this.interferenceGraph.addNode(var); + + //Compute edges + for(Instruction instruction : this.method.getInstructions()){ + List liveIn = new ArrayList<>(this.in.get(instruction)); + List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); + + this.interferenceGraph.connectInterferingVariables(liveIn); + this.interferenceGraph.connectInterferingVariables(defAndLiveOut); + } + } } From 38b2ddeb91890e658a4d6e8d204c778f78640f24 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Wed, 24 May 2023 17:04:31 +0100 Subject: [PATCH 216/253] little fix to assignment --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index a5a819f..ef435c1 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -264,7 +264,7 @@ private Void dealWithLenFieldAccess(JmmNode jmmNode, Void unused) { visit(caller); jmmNode.put("valueOl", "t" + tempVarId + ".i32"); String caller_name = caller.get("valueOl"); - code += "t" + tempVarId++ + ".i32 :=.i32 arraylength(" + caller_name + ").i32;"; + code += "t" + tempVarId++ + ".i32 :=.i32 arraylength(" + caller_name + ").i32;\n"; return null; } @@ -457,7 +457,7 @@ private Void dealWithAssignment(JmmNode jmmNode, Void unused) { if (isLocal) code += "\t\t" + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isParam) - code += "\t\t$" + idParam + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; + code += "\t\t$" + idParam + "." + left + OllirUtils.ollirTypes(var.getType()) + " :=" + OllirUtils.ollirTypes(var.getType()) + " "; else if (isField) code += "\t\tputfield(this, " + left + OllirUtils.ollirTypes(var.getType()) + ", "; From e33b6140d52325110c33cdba048d5f1e2a571749 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Wed, 24 May 2023 17:40:58 +0100 Subject: [PATCH 217/253] Improve parseArgs() to handle "-r" option --- src/main/pt/up/fe/comp2023/Launcher.java | 34 +++++++++++++++++-- .../pt/up/fe/comp2023/ollir/Optimization.java | 8 +++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 713fb9a..6573699 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -84,6 +84,8 @@ public static void main(String[] args) { } OllirResult ollirResult = optimization.toOllir(semanticsResult); + if (Integer.parseInt(config.get("registerAllocation")) >= 0) + optimization.optimize(ollirResult); JasminGenerator jasminGenerator = new JasminGenerator(); JasminResult jasminResult = jasminGenerator.toJasmin(ollirResult); @@ -97,20 +99,46 @@ private static Map parseArgs(String[] args) { // Check if there is at least one argument if (args.length < 1) { - throw new RuntimeException("Usage: ./jmm [-o]"); + throw new RuntimeException("./abc [-o] [-p ]"); } // Create config Map config = new HashMap<>(); config.put("inputFile", args[0]); - config.put("registerAllocation", "-1"); config.put("debug", "false"); + config.put("optimize", "false"); + config.put("registerAllocation", "-1"); + + for (int i = 2; i < args.length; i++) { + if(args[i].equals("-o")) + config.put("optimize", "true"); + + else if(args[i].equals("-p")) { + if(i + 1 >= args.length) + throw new RuntimeException("Missing argument for -r option."); + else { + try { + int n = Integer.parseInt(args[i + 1]); + config.put("registerAllocation", Integer.toString(n)); + i++; + } catch (NumberFormatException e) { + System.out.println("Invalid argument for -r option: " + args[i + 1]); + } + } + } + } - if (Arrays.asList(args).contains("-o")) + if (Arrays.asList(args).contains("-o")) config.put("optimize", "true"); else config.put("optimize", "false"); + if (Arrays.asList(args).contains("-p")){ + Arrays.asList(args).fin + } + else + config.put("registerAllocation", "-1"); + return config; } } diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index c2ca311..f8738be 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,10 +45,12 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - ClassUnit classUnit = ollirResult.getOllirClass(); + if (Integer.parseInt(ollirResult.getConfig().get("registerAllocation")) >= 0){ + ClassUnit classUnit = ollirResult.getOllirClass(); - for(Method method : classUnit.getMethods()) - new RegisterAllocation(method); + for (Method method : classUnit.getMethods()) + new RegisterAllocation(method); + } return ollirResult; } From d264320cb84cceedab4f200feb464ecd9835d276 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Wed, 24 May 2023 19:51:55 +0100 Subject: [PATCH 218/253] Added special method to generate instruction for zero comparison --- .../comp2023/jasmin/JVMInstructionUtils.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 2b553e7..06d5886 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -235,7 +235,6 @@ public static String createLogicalInstruction(OperationType operationType) { public static String createComparisonInstruction(OperationType operationType, boolean isBranchCond) { decreaseStackSize(2); - String statementList = ""; switch (operationType) { case LTH: @@ -250,21 +249,51 @@ public static String createComparisonInstruction(OperationType operationType, bo return ""; } + public static String createZeroComparisonInstruction(OperationType operationType, boolean isBranchCond) { + decreaseStackSize(1); + + switch (operationType) { + case LTH: + return isBranchCond ? "\tiflt " : "\tiflt " + createAuxBranchStatement(); + case LTE: + return isBranchCond ? "\tifle " : "\tifle " + createAuxBranchStatement(); + case GTH: + return isBranchCond ? "\tifgt " : "\tifgt " + createAuxBranchStatement(); + case GTE: + return isBranchCond ? "\tifge " : "\tifge " + createAuxBranchStatement(); + } + return ""; + } + public static String createBinaryOpInstruction(BinaryOpInstruction instruction, HashMap varTable, boolean isBranchCond) { OperationType operationType = instruction.getOperation().getOpType(); + Element leftOperand = instruction.getLeftOperand(); + Element rightOperand = instruction.getRightOperand(); String statementList = ""; - statementList += getLoadInstruction(instruction.getLeftOperand(), varTable); - statementList += getLoadInstruction(instruction.getRightOperand(), varTable); switch (operationType) { case ADD: case SUB: case MUL: case DIV: + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); statementList += createArithmeticInstruction(operationType); break; case AND: case ANDB: case OR: case ORB: + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); statementList += createLogicalInstruction(operationType); break; case LTH: case LTE: case GTH: case GTE: - statementList += createComparisonInstruction(operationType, isBranchCond); + if (leftOperand instanceof LiteralElement && parseInt(((LiteralElement)leftOperand).getLiteral()) == 0) { + statementList += getLoadInstruction(rightOperand, varTable); + statementList += createZeroComparisonInstruction(operationType, isBranchCond); + } else if (rightOperand instanceof LiteralElement && parseInt(((LiteralElement)rightOperand).getLiteral()) == 0) { + statementList += getLoadInstruction(leftOperand, varTable); + statementList += createZeroComparisonInstruction(operationType, isBranchCond); + } else { + statementList += getLoadInstruction(leftOperand, varTable); + statementList += getLoadInstruction(rightOperand, varTable); + statementList += createComparisonInstruction(operationType, isBranchCond); + } break; } return statementList; From d0da02e7b0607d59c9c8c6608382048b1f6005ad Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Wed, 24 May 2023 22:36:04 +0100 Subject: [PATCH 219/253] Added data structure to keep track of which temps are equivalent to which vars --- .../comp2023/jasmin/JVMInstructionUtils.java | 1 + .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 06d5886..4c535c5 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -13,6 +13,7 @@ public class JVMInstructionUtils { public static int numLocals = 0; public static int stackSize = 0; public static int currStackSize = 0; + public static Map varEquivalence = new HashMap<>(); public static void increaseStackSize(int n) { currStackSize += n; diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index d8e7bdc..4ba3e5a 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Objects; public class JasminUtils { @@ -69,6 +71,19 @@ public static String createFieldDirective(Field field) { return fieldDirective + '\n'; } + public static String createConstructMethod(String superClassName) { + String methodDirective = ".method public ()V\n"; + methodDirective += "\taload_0\n"; + methodDirective += "\tinvokespecial "; + if (superClassName != null) + methodDirective += superClassName; + else + methodDirective += "java/lang/Object"; + methodDirective += "/()V\n"; + methodDirective += "\treturn\n"; + return methodDirective + ".end method\n\n"; + } + public static String createMethodSignature(String methodName, ArrayList listOfParameters, Type returnType, boolean isDeclaration) { String methodSignature = ""; methodSignature += methodName + "("; @@ -96,6 +111,7 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { + instruction.show(); String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -184,23 +200,28 @@ public static String handleMethodStatements(Method method) { return statementList; } - public static String createConstructMethod(String superClassName) { - String methodDirective = ".method public ()V\n"; - methodDirective += "\taload_0\n"; - methodDirective += "\tinvokespecial "; - if (superClassName != null) - methodDirective += superClassName; - else - methodDirective += "java/lang/Object"; - methodDirective += "/()V\n"; - methodDirective += "\treturn\n"; - return methodDirective + ".end method\n\n"; + public static void createVarEquivalence(Method method) { + JVMInstructionUtils.varEquivalence.clear(); + for (Instruction instruction: method.getInstructions()) { + if (instruction instanceof AssignInstruction) { + Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); + Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); + if (rhsInstruction instanceof SingleOpInstruction && + ((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand) { + Operand rhs = ((Operand)((SingleOpInstruction)rhsInstruction).getSingleOperand()); + + JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); + } + } + } } public static String createMethodDirective(Method method) { JVMInstructionUtils.numLocals = 0; JVMInstructionUtils.stackSize = 0; JVMInstructionUtils.currStackSize = 0; + createVarEquivalence(method); + String instructions = handleMethodStatements(method); if (method.isStaticMethod() && method.getParams().size() > 0) JVMInstructionUtils.numLocals++; From 037c91bf5692df70f49819b2dba655c3d103a82e Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 14:34:56 +0100 Subject: [PATCH 220/253] fix parenthesis --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index ef435c1..a0d6013 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -221,8 +221,8 @@ private Void dealWithMethodCall(JmmNode jmmNode, Void unused) { if (left.getKind().equals("This")) { code += "invokevirtual("; } else { - if (table.getImports().contains(left.get("value"))) { - code += "invokestatic(" + left.get("value") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called + if (table.getImports().contains(left.get("valueOl"))) { + code += "invokestatic(" + left.get("valueOl") + " , \"" + methodName + "\""; // The first arg is the object that calls the method and the second is the name of the method called isStatic = true; } else code += "invokevirtual("; From 4ba7c2383dd2a97d8638b7c043678f1d533043e2 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 14:39:58 +0100 Subject: [PATCH 221/253] fix? --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index a0d6013..dbed159 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -386,6 +386,7 @@ private Void dealWithArrayAssignment(JmmNode jmmNode, Void unused) { JmmNode right = jmmNode.getChildren().get(0); JmmNode last = jmmNode.getChildren().get(1); visit(right); + visit(last); if (isLocal) code += "\t\t" + left; @@ -395,11 +396,7 @@ else if (isField) code += "\t\tt" + tempVarId + ".array.i32 :=.array.i32 getfield(this, " + left + ".array.i32).array.i32;" + "\n\t\tt" + tempVarId++; - code += "[" + right.get("valueOl") + "].i32 :=.i32 "; - - visit(last); - - code += last.get("valueOl") +";\n"; + code += "[" + right.get("valueOl") + "].i32 :=.i32 " + last.get("valueOl") +";\n"; return null; } From a2af6b3235488fbc7f3bf48f4c1e1dfb99143e69 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Thu, 25 May 2023 17:21:45 +0100 Subject: [PATCH 222/253] fix error --- src/main/pt/up/fe/comp2023/ollir/Optimization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index dbed159..0bcddfc 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -70,7 +70,7 @@ private Void dealWithCycle(JmmNode jmmNode, Void unused) { // What occurs if the condition is met code += "\t\tloop" + ifId + ":\n\t"; visit(jmmNode.getJmmChild(1)); code += "\t\t"; visit(jmmNode.getJmmChild(0)); code += "\n"; - code += "\t\t if( " + temp + ") goto loop" + ifId + ";\n"; + code += "\t\t if( " + jmmNode.getJmmChild(0).get("valueOl") + ") goto loop" + ifId + ";\n"; // End of If code +="\t\tend_loop" + ifId + ":\n\t"; From 37d980963a1b99ca60f8b18c105d8ed4a9946252 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 17:24:13 +0100 Subject: [PATCH 223/253] Remove var name from known constants if the assignment is inside a cycle --- .../pt/up/fe/comp2023/optimization/ConstantPropagation.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java index 1e46c23..c31abf8 100644 --- a/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java +++ b/src/main/pt/up/fe/comp2023/optimization/ConstantPropagation.java @@ -78,6 +78,9 @@ private Void dealWithCycle(JmmNode jmmNode, Map constants) { private Void dealWithAssignment(JmmNode jmmNode, Map constants) { String varName = jmmNode.get("varname"); + if(jmmNode.getAncestor("Cycle").isPresent()) + constants.remove(varName); + JmmNode exprNode = jmmNode.getJmmChild(0); visit(exprNode, constants); From 1f9f86c8d0d8981a18ba03e0692e1a5acc410e89 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 17:37:26 +0100 Subject: [PATCH 224/253] Improve parseArgs() method to handle "-r" option --- src/main/pt/up/fe/comp2023/Launcher.java | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index 6573699..fcf54e6 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -73,7 +73,7 @@ public static void main(String[] args) { Optimization optimization = new Optimization(); - //Apply Constant Propagation and Constant Folding optimizations + // Apply Constant Propagation and Constant Folding optimizations if (Boolean.parseBoolean(config.get("optimize"))) { System.out.println("Applying optimizations..."); @@ -84,6 +84,8 @@ public static void main(String[] args) { } OllirResult ollirResult = optimization.toOllir(semanticsResult); + + // Optimize register allocation if (Integer.parseInt(config.get("registerAllocation")) >= 0) optimization.optimize(ollirResult); @@ -98,9 +100,8 @@ private static Map parseArgs(String[] args) { SpecsLogs.info("Executing with args: " + Arrays.toString(args)); // Check if there is at least one argument - if (args.length < 1) { - throw new RuntimeException("./abc [-o] [-p ]"); - } + if (args.length < 1) + throw new RuntimeException("Usage: ./jmm [-o] [-p ]"); // Create config Map config = new HashMap<>(); @@ -127,18 +128,6 @@ else if(args[i].equals("-p")) { } } } - - if (Arrays.asList(args).contains("-o")) - config.put("optimize", "true"); - else - config.put("optimize", "false"); - - if (Arrays.asList(args).contains("-p")){ - Arrays.asList(args).fin - } - else - config.put("registerAllocation", "-1"); - return config; } } From cbc9aa44c1da7def584c4c618c6737384615e3ae Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Thu, 25 May 2023 18:53:59 +0100 Subject: [PATCH 225/253] Small fix to parseArgs() method --- src/main/pt/up/fe/comp2023/Launcher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/Launcher.java b/src/main/pt/up/fe/comp2023/Launcher.java index fcf54e6..50073c9 100644 --- a/src/main/pt/up/fe/comp2023/Launcher.java +++ b/src/main/pt/up/fe/comp2023/Launcher.java @@ -110,11 +110,11 @@ private static Map parseArgs(String[] args) { config.put("optimize", "false"); config.put("registerAllocation", "-1"); - for (int i = 2; i < args.length; i++) { + for (int i = 1; i < args.length; i++) { if(args[i].equals("-o")) config.put("optimize", "true"); - else if(args[i].equals("-p")) { + else if(args[i].equals("-r")) { if(i + 1 >= args.length) throw new RuntimeException("Missing argument for -r option."); else { From a8dfb3b38f973c3be39e253a69d39a571064626a Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 11:06:41 +0100 Subject: [PATCH 226/253] Improve RegisterAllocation to receive allocation option --- .../pt/up/fe/comp2023/ollir/Optimization.java | 7 +++--- .../optimization/RegisterAllocation.java | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index f8738be..d902d3d 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,11 +45,12 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - if (Integer.parseInt(ollirResult.getConfig().get("registerAllocation")) >= 0){ - ClassUnit classUnit = ollirResult.getOllirClass(); + int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().get("registerAllocation")); + if (registerAllocationOption >= 0){ + ClassUnit classUnit = ollirResult.getOllirClass(); for (Method method : classUnit.getMethods()) - new RegisterAllocation(method); + new RegisterAllocation(method, registerAllocationOption); } return ollirResult; } diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 6111ee1..a1c84e6 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -10,30 +10,34 @@ public class RegisterAllocation { private final Method method; + private final int registerAllocationOption; private final Map> defs = new HashMap<>(); private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); - public RegisterAllocation(Method method) { + public RegisterAllocation(Method method, int registerAllocationOption) { + this.registerAllocationOption = registerAllocationOption; this.method = method; - method.buildCFG(); - - //TODO: remove - System.out.println(method.getMethodName()); - System.out.println("------------------"); + method.buildCFG(); for (Instruction instruction : method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); this.uses.put(instruction, getUse(instruction, new HashSet<>())); + } + computeLiveInOut(); + createInterferenceGraph(); - //TODO: remove + //TODO: remove + System.out.println(method.getMethodName()); + System.out.println("------------------"); + for(Instruction instruction : method.getInstructions()){ instruction.show(); System.out.println("Defs:" + defs.get(instruction)); System.out.println("Uses:" + uses.get(instruction)); + System.out.println("In:" + in.get(instruction)); + System.out.println(("Out: "+ out.get(instruction))); } - computeLiveInOut(); - createInterferenceGraph(); } public Set getDef(Instruction instruction){ From 019f13330cd94df8044e2ac027d803bf5b1a38e1 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 11:12:09 +0100 Subject: [PATCH 227/253] Refactor RegisterAllocation class --- .../optimization/RegisterAllocation.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index a1c84e6..6205ecc 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -20,13 +20,18 @@ public RegisterAllocation(Method method, int registerAllocationOption) { this.registerAllocationOption = registerAllocationOption; this.method = method; - method.buildCFG(); - for (Instruction instruction : method.getInstructions()){ + livenessAnalysis(); + createInterferenceGraph(); + graphColoring(); + } + + private void livenessAnalysis(){ + this.method.buildCFG(); + for (Instruction instruction : this.method.getInstructions()){ this.defs.put(instruction, getDef(instruction)); this.uses.put(instruction, getUse(instruction, new HashSet<>())); } computeLiveInOut(); - createInterferenceGraph(); //TODO: remove System.out.println(method.getMethodName()); @@ -40,7 +45,28 @@ public RegisterAllocation(Method method, int registerAllocationOption) { } } - public Set getDef(Instruction instruction){ + private void createInterferenceGraph() { + List localVars = getLocalVars(this.method); + + //Add a node for each variable + for(String var : localVars) + this.interferenceGraph.addNode(var); + + //Compute edges + for(Instruction instruction : this.method.getInstructions()){ + List liveIn = new ArrayList<>(this.in.get(instruction)); + List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); + + this.interferenceGraph.connectInterferingVariables(liveIn); + this.interferenceGraph.connectInterferingVariables(defAndLiveOut); + } + } + + private void graphColoring() { + //TODO + } + + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); if(instruction.getInstType() == ASSIGN) { @@ -53,7 +79,7 @@ public Set getDef(Instruction instruction){ return def; } - public Set getUse(Instruction instruction, Set result){ + private Set getUse(Instruction instruction, Set result){ switch (instruction.getInstType()) { case ASSIGN -> { AssignInstruction assignInst = (AssignInstruction) instruction; @@ -104,7 +130,7 @@ public Set getUse(Instruction instruction, Set result){ return result; } - public void computeLiveInOut() { + private void computeLiveInOut() { for (Instruction instruction : method.getInstructions()){ this.in.put(instruction, new HashSet<>()); this.out.put(instruction, new HashSet<>()); @@ -138,21 +164,4 @@ public void computeLiveInOut() { } } while(liveChanged); } - - private void createInterferenceGraph() { - List localVars = getLocalVars(this.method); - - //Add a node for each variable - for(String var : localVars) - this.interferenceGraph.addNode(var); - - //Compute edges - for(Instruction instruction : this.method.getInstructions()){ - List liveIn = new ArrayList<>(this.in.get(instruction)); - List defAndLiveOut = new ArrayList<>(unionSets(this.defs.get(instruction), this.out.get(instruction))); - - this.interferenceGraph.connectInterferingVariables(liveIn); - this.interferenceGraph.connectInterferingVariables(defAndLiveOut); - } - } } From 1b83e62d8f7b04f88bd2acf47105e513f446c970 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 11:48:14 +0100 Subject: [PATCH 228/253] Used var equivalence to know when to use iinc --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 4c535c5..9b8f830 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -192,14 +192,14 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - destName.equals(((Operand)leftOperand).getName()) && + (destName.equals(((Operand)leftOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - destName.equals(((Operand)rightOperand).getName()) && + (destName.equals(((Operand)rightOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; From 3e1a4444a6c6c99c8a22e713cabdf65246ff539d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 12:23:43 +0100 Subject: [PATCH 229/253] Implement method to find optimal coloring --- .../MyInterferenceGraph.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 18ccc1e..9855bfb 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -1,10 +1,13 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); + private Map nodeColor = new HashMap<>(); public void addNode(String variable){ MyNode newNode = new MyNode(variable); @@ -43,4 +46,30 @@ public void removeNode(String varName){ } this.nodes.remove(node); } + + public Map isMColoringFeasible(int maxColors){ + //TODO + + return this.nodeColor; + } + + public Map findOptimalColoring(){ + int maxColors = this.nodes.size(); + + for(MyNode node : this.nodes){ + for(int color = 0; color < maxColors; color++){ + if(isValidColor(node, color)) + nodeColor.put(node.getVariable(), color); + } + } + return this.nodeColor; + } + + private boolean isValidColor(MyNode node, int color){ + for(String adj : node.getAdj()){ + if(nodeColor.get(adj) == color) + return false; + } + return true; + } } From 5cd37811bd9fdccaef574b0814a93fad7b9a2757 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 12:54:21 +0100 Subject: [PATCH 230/253] Refactor: method to check if a temp value is being assigned to a variable --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 16 +++++++++++++--- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 11 +++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 9b8f830..f130dde 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -192,14 +192,14 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - (destName.equals(((Operand)leftOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && + (destName.equals(((Operand)leftOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - (destName.equals(((Operand)rightOperand).getName()) || (JVMInstructionUtils.varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && + (destName.equals(((Operand)rightOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; @@ -312,11 +312,21 @@ public static String createNoperInstruction(SingleOpInstruction instruction, Has return getLoadInstruction(operand, varTable); } + public static boolean checkTempAssign(AssignInstruction instruction) { + Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); + Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); + if (!(rhsInstruction instanceof SingleOpInstruction)) + return false; + if (!(((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand)) + return false; + return true; + } + public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); String statementList = ""; if (instruction.getRhs() instanceof BinaryOpInstruction) { - statementList = checkInc((BinaryOpInstruction) instruction.getRhs(), assignElement, varTable); + statementList = checkInc((BinaryOpInstruction)instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) return statementList; } diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index 4ba3e5a..b8fc0e8 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -203,15 +203,10 @@ public static String handleMethodStatements(Method method) { public static void createVarEquivalence(Method method) { JVMInstructionUtils.varEquivalence.clear(); for (Instruction instruction: method.getInstructions()) { - if (instruction instanceof AssignInstruction) { + if (instruction instanceof AssignInstruction && JVMInstructionUtils.checkTempAssign((AssignInstruction)instruction)) { Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); - Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); - if (rhsInstruction instanceof SingleOpInstruction && - ((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand) { - Operand rhs = ((Operand)((SingleOpInstruction)rhsInstruction).getSingleOperand()); - - JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); - } + Operand rhs = ((Operand)((SingleOpInstruction)(((AssignInstruction)instruction).getRhs())).getSingleOperand()); + JVMInstructionUtils.varEquivalence.put(rhs.getName(), lhs.getName()); } } } From 0b2294faef5f2374631246b683686b0d0964c04d Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:11:42 +0100 Subject: [PATCH 231/253] Add method to check if a graph is m coloring feasible --- .../MyInterferenceGraph.java | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 9855bfb..d41e16a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -1,14 +1,19 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); private Map nodeColor = new HashMap<>(); + public MyInterferenceGraph deepCopy(){ + MyInterferenceGraph copy = new MyInterferenceGraph(); + + for(MyNode node : this.nodes) + copy.addNode(node.getVariable()); + return copy; + } + public void addNode(String variable){ MyNode newNode = new MyNode(variable); this.nodes.add(newNode); @@ -37,19 +42,43 @@ public void connectInterferingVariables(List variables){ } } - public void removeNode(String varName){ - MyNode node = getNode(varName); - + public void removeNode(MyNode node){ for(String adj : node.getAdj()){ MyNode adjNode = getNode(adj); - adjNode.removeAdj(varName); + adjNode.removeAdj(node.getVariable()); } this.nodes.remove(node); } public Map isMColoringFeasible(int maxColors){ - //TODO + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = new Stack<>(); + boolean foundNode; + + while(copyGraph.nodes.size() > 0){ + foundNode = false; + Iterator iterator = copyGraph.nodes.iterator(); + + while (iterator.hasNext()) { + MyNode node = iterator.next(); + if (node.getAdj().size() < maxColors) { + foundNode = true; + stack.push(node.getVariable()); + copyGraph.removeNode(node); + } + } + if (!foundNode) + throw new RuntimeException("The provided number of registers is not enough to store the variables."); + } + + while (!stack.isEmpty()){ + String nodeName = stack.pop(); + for(int color = 0; color < maxColors; color++){ + if(isValidColor(getNode(nodeName), color)) + this.nodeColor.put(nodeName, color); + } + } return this.nodeColor; } From cb4ad97cdf6875563b17ee1f5a9640388552b5db Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:16:08 +0100 Subject: [PATCH 232/253] Refactor: add method to compute M coloring stack --- .../interferenceGraph/MyInterferenceGraph.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index d41e16a..c901564 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -50,14 +50,13 @@ public void removeNode(MyNode node){ this.nodes.remove(node); } - public Map isMColoringFeasible(int maxColors){ - MyInterferenceGraph copyGraph = deepCopy(); + public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); boolean foundNode; - while(copyGraph.nodes.size() > 0){ + while (this.nodes.size() > 0) { foundNode = false; - Iterator iterator = copyGraph.nodes.iterator(); + Iterator iterator = this.nodes.iterator(); while (iterator.hasNext()) { MyNode node = iterator.next(); @@ -65,12 +64,18 @@ public Map isMColoringFeasible(int maxColors){ if (node.getAdj().size() < maxColors) { foundNode = true; stack.push(node.getVariable()); - copyGraph.removeNode(node); + this.removeNode(node); } } if (!foundNode) throw new RuntimeException("The provided number of registers is not enough to store the variables."); } + return stack; + } + + public Map isMColoringFeasible(int maxColors){ + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = copyGraph.computeMColoringStack(maxColors); while (!stack.isEmpty()){ String nodeName = stack.pop(); From 573191318b1a978a4f15bfdd25b18ec5559b3f13 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:18:23 +0100 Subject: [PATCH 233/253] Add fuction to check if a method has access to 'this' --- .../pt/up/fe/comp2023/optimization/OptimizationUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index e80cdb2..4c6a92d 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -66,4 +66,12 @@ public static List getLocalVars(Method method) { public static String toVarName(Element element){ return ((Operand)element).getName(); } + + public static int methodAccessThis(Method method) { + return method.isStaticMethod() ? 0 : 1; + } + + public static int numParams(Method method){ + return method.getParams().size(); + } } From 3bf5809aa6b5f2f206e9437bbee14796e1b010c4 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:19:28 +0100 Subject: [PATCH 234/253] Implement graphColoring in RegisterAllocation --- .../comp2023/optimization/RegisterAllocation.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 6205ecc..9056cf5 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -11,18 +11,21 @@ public class RegisterAllocation { private final Method method; private final int registerAllocationOption; + private Map optimalRegisters = new HashMap<>(); private final Map> defs = new HashMap<>(); private final Map> uses = new HashMap<>(); private final Map> in = new HashMap<>(); private final Map> out = new HashMap<>(); private final MyInterferenceGraph interferenceGraph = new MyInterferenceGraph(); + public RegisterAllocation(Method method, int registerAllocationOption) { this.registerAllocationOption = registerAllocationOption; this.method = method; livenessAnalysis(); createInterferenceGraph(); - graphColoring(); + graphColoring(); //Updates optimalRegisters + //updateVarsRegisters(); } private void livenessAnalysis(){ @@ -63,9 +66,14 @@ private void createInterferenceGraph() { } private void graphColoring() { - //TODO + if(registerAllocationOption > 0) { // Try to use at most local variables + int k = registerAllocationOption - methodAccessThis(method) - numParams(method); + this.optimalRegisters = this.interferenceGraph.isMColoringFeasible(k); + } + else // Try to use as few local variables as it can + this.optimalRegisters = this.interferenceGraph.findOptimalColoring(); } - + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); From fc36d1d8235f73253fb319d24c509f9deaf119ef Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:30:22 +0100 Subject: [PATCH 235/253] Add method to update virtual registers --- .../comp2023/optimization/RegisterAllocation.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index 9056cf5..b924185 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -25,7 +25,7 @@ public RegisterAllocation(Method method, int registerAllocationOption) { livenessAnalysis(); createInterferenceGraph(); graphColoring(); //Updates optimalRegisters - //updateVarsRegisters(); + updateVirtualRegisters(); } private void livenessAnalysis(){ @@ -74,6 +74,18 @@ private void graphColoring() { this.optimalRegisters = this.interferenceGraph.findOptimalColoring(); } + private void updateVirtualRegisters(){ + int firstLocalVarRegister = methodAccessThis(method) + numParams(method); + + for (Map.Entry entry : optimalRegisters.entrySet()) { + String var = entry.getKey(); + Integer register = entry.getValue(); + int virtualRegister = firstLocalVarRegister + register; + + method.getVarTable().get(var).setVirtualReg(virtualRegister); + } + } + private Set getDef(Instruction instruction){ Set def = new HashSet<>(); From a9d1b0acf032e471106dca5ab3d3bb8220a00930 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Fri, 26 May 2023 13:41:35 +0100 Subject: [PATCH 236/253] Refactor the method that checks if an Element is a local var --- .../optimization/OptimizationUtils.java | 3 +-- .../interferenceGraph/MyInterferenceGraph.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 4c6a92d..8bf8e89 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -39,9 +39,8 @@ public static Set unionSets(Set set1, Set set2) { public static boolean isLocalVar(Element element, Method method) { HashMap varTable = method.getVarTable(); String varName = ((Operand)element).getName(); - int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); - return varTable.get(varName).getVirtualReg() >= firstLocalVarRegister; + return isLocalVar(varName, method); } public static boolean isLocalVar(String identifier, Method method) { diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index c901564..2f717ac 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -4,7 +4,7 @@ public class MyInterferenceGraph { private final List nodes = new ArrayList<>(); - private Map nodeColor = new HashMap<>(); + private final Map nodeColor = new HashMap<>(); public MyInterferenceGraph deepCopy(){ MyInterferenceGraph copy = new MyInterferenceGraph(); @@ -26,6 +26,7 @@ public MyNode getNode(String varName){ } return null; } + public void addInterferenceEdge(String src, String dest){ getNode(src).getAdj().add(dest); getNode(dest).getAdj().add(src); @@ -50,6 +51,14 @@ public void removeNode(MyNode node){ this.nodes.remove(node); } + private boolean isValidColor(MyNode node, int color){ + for(String adj : node.getAdj()){ + if(nodeColor.get(adj) == color) + return false; + } + return true; + } + public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); boolean foundNode; @@ -99,11 +108,4 @@ public Map findOptimalColoring(){ return this.nodeColor; } - private boolean isValidColor(MyNode node, int color){ - for(String adj : node.getAdj()){ - if(nodeColor.get(adj) == color) - return false; - } - return true; - } } From ecc3450b50866e785c40c058bd80f479375bd9cc Mon Sep 17 00:00:00 2001 From: Comp2023 TP Teachers Date: Fri, 26 May 2023 16:56:38 +0100 Subject: [PATCH 237/253] Updates OLLIR JAR to support interface TreeNode (e.g. Instruction now has .getChildren()) --- libs/comp2023-ollir-sources.jar | Bin 56192 -> 58443 bytes libs/comp2023-ollir.jar | Bin 91980 -> 95878 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/comp2023-ollir-sources.jar b/libs/comp2023-ollir-sources.jar index 7841631f482cad36b4be784084ae396e31a27b9a..d6cfa168433f1cbafc3d1cf571ff1fb2df931483 100644 GIT binary patch delta 16641 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 P!1eZ}d?QMa{L}hBREFYx diff --git a/libs/comp2023-ollir.jar b/libs/comp2023-ollir.jar index 5dfb25f5b00665edf8b15216f6719a25b04cca83..e31b06abea4891000c6003ba921c843933d96a30 100644 GIT binary patch delta 28741 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 z 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 J2GptH{ttmOV7&kU From b7d7382e835bef3553d4c2a2e8cb4a7affb7f9f8 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Fri, 26 May 2023 18:29:47 +0100 Subject: [PATCH 238/253] Made assign instruction load dependent on whether there was an iinc instruction --- .../comp2023/jasmin/JVMInstructionUtils.java | 35 ++++++++++++++----- .../pt/up/fe/comp2023/jasmin/JasminUtils.java | 6 ++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index f130dde..ee13743 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -14,6 +14,7 @@ public class JVMInstructionUtils { public static int stackSize = 0; public static int currStackSize = 0; public static Map varEquivalence = new HashMap<>(); + public static Map iincVars = new HashMap<>(); public static void increaseStackSize(int n) { currStackSize += n; @@ -188,20 +189,30 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); + String iincVarEquivalent = varEquivalence.get(destName); + + if (iincVarEquivalent == null) + return ""; if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement && - (destName.equals(((Operand)leftOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)leftOperand).getName()))) && - parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) - return "\tiinc " + varTable.get(((Operand)leftOperand).getName()).getVirtualReg() + " 1\n"; + parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) { + if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) + iincVars.put(iincVarEquivalent, destName); + if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " 1\n"; + } if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement) && - (destName.equals(((Operand)rightOperand).getName()) || (varEquivalence.get(destName).equals(((Operand)rightOperand).getName()))) && - parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) - return "\tiinc " + varTable.get(((Operand)rightOperand).getName()).getVirtualReg() + " 1\n"; + parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) { + if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) + iincVars.put(iincVarEquivalent, destName); + if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " 1\n"; + } return ""; } @@ -317,14 +328,20 @@ public static boolean checkTempAssign(AssignInstruction instruction) { Instruction rhsInstruction = ((AssignInstruction)instruction).getRhs(); if (!(rhsInstruction instanceof SingleOpInstruction)) return false; - if (!(((SingleOpInstruction)rhsInstruction).getSingleOperand() instanceof Operand)) - return false; - return true; + return ((SingleOpInstruction) rhsInstruction).getSingleOperand() instanceof Operand; } public static String createAssignStatement(AssignInstruction instruction, HashMap varTable) { Element assignElement = instruction.getDest(); String statementList = ""; + + if (checkTempAssign(instruction)) { + Element rhsElement = ((SingleOpInstruction)instruction.getRhs()).getSingleOperand(); + String iincVarEquivalent = iincVars.get(((Operand)assignElement).getName()); + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rhsElement).getName())) + return ""; + } + if (instruction.getRhs() instanceof BinaryOpInstruction) { statementList = checkInc((BinaryOpInstruction)instruction.getRhs(), assignElement, varTable); if (!statementList.equals("")) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java index b8fc0e8..f9811c1 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JasminUtils.java @@ -4,8 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Objects; public class JasminUtils { @@ -111,7 +109,6 @@ public static String createMethodDeclaration(Method method) { } public static String handleInstruction(Instruction instruction, HashMap varTable, boolean isRhs) { - instruction.show(); String statementList = ""; switch (instruction.getInstType()) { case ASSIGN: @@ -201,7 +198,10 @@ public static String handleMethodStatements(Method method) { } public static void createVarEquivalence(Method method) { + JVMInstructionUtils.iincVars.clear(); JVMInstructionUtils.varEquivalence.clear(); + JVMInstructionUtils.iincVars.clear(); + for (Instruction instruction: method.getInstructions()) { if (instruction instanceof AssignInstruction && JVMInstructionUtils.checkTempAssign((AssignInstruction)instruction)) { Operand lhs = ((Operand)((AssignInstruction)instruction).getDest()); From 1d8c9b9875e7de59511ae7159d7eebc604cfda00 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:22:00 +0100 Subject: [PATCH 239/253] Set default value of registerAllocation key --- .../pt/up/fe/comp2023/ollir/Optimization.java | 2 +- .../MyInterferenceGraph.java | 21 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/ollir/Optimization.java b/src/main/pt/up/fe/comp2023/ollir/Optimization.java index 18c076a..deda0a0 100644 --- a/src/main/pt/up/fe/comp2023/ollir/Optimization.java +++ b/src/main/pt/up/fe/comp2023/ollir/Optimization.java @@ -45,7 +45,7 @@ public JmmSemanticsResult optimize(JmmSemanticsResult semanticsResult) { } public OllirResult optimize(OllirResult ollirResult) { - int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().get("registerAllocation")); + int registerAllocationOption = Integer.parseInt(ollirResult.getConfig().getOrDefault("registerAllocation", "-1")); if (registerAllocationOption >= 0){ ClassUnit classUnit = ollirResult.getOllirClass(); diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 2f717ac..8296e3f 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -61,22 +61,21 @@ private boolean isValidColor(MyNode node, int color){ public Stack computeMColoringStack(int maxColors){ Stack stack = new Stack<>(); - boolean foundNode; while (this.nodes.size() > 0) { - foundNode = false; - Iterator iterator = this.nodes.iterator(); + MyNode nodeToRemove = null; - while (iterator.hasNext()) { - MyNode node = iterator.next(); - - if (node.getAdj().size() < maxColors) { - foundNode = true; - stack.push(node.getVariable()); - this.removeNode(node); + for(MyNode node : this.nodes){ + if(node.getAdj().size() < maxColors){ + nodeToRemove = node; + break; } } - if (!foundNode) + if(nodeToRemove != null){ + stack.push(nodeToRemove.getVariable()); + this.removeNode(nodeToRemove); + } + else throw new RuntimeException("The provided number of registers is not enough to store the variables."); } return stack; From d2710838b3f4a76f39572b7a2098425caa6e07fd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:24:48 +0100 Subject: [PATCH 240/253] Refactor isLocalVar() using methodAccessThis() --- src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java index 8bf8e89..6b059c3 100644 --- a/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java +++ b/src/main/pt/up/fe/comp2023/optimization/OptimizationUtils.java @@ -45,7 +45,7 @@ public static boolean isLocalVar(Element element, Method method) { public static boolean isLocalVar(String identifier, Method method) { HashMap varTable = method.getVarTable(); - int firstLocalVarRegister = method.isStaticMethod() ? 0 : 1 + method.getParams().size(); + int firstLocalVarRegister = methodAccessThis(method) + method.getParams().size(); return varTable.get(identifier).getVirtualReg() >= firstLocalVarRegister; } From 37e6c227a837e6ced79019498cfdf10d718809cd Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sat, 27 May 2023 19:52:57 +0100 Subject: [PATCH 241/253] Improved findOptimalColoring() --- .../MyInterferenceGraph.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 8296e3f..37ec6f2 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -81,6 +81,30 @@ public Stack computeMColoringStack(int maxColors){ return stack; } + public Stack computeOptimalColoringStack(int maxColors){ + Stack stack = new Stack<>(); + + while (this.nodes.size() > 0) { + MyNode nodeToRemove = null; + + for(MyNode node : this.nodes){ + if(node.getAdj().size() < maxColors){ + nodeToRemove = node; + break; + } + } + if(nodeToRemove != null){ + stack.push(nodeToRemove.getVariable()); + this.removeNode(nodeToRemove); + } + else{ + stack.clear(); + return stack; + } + } + return stack; + } + public Map isMColoringFeasible(int maxColors){ MyInterferenceGraph copyGraph = deepCopy(); Stack stack = copyGraph.computeMColoringStack(maxColors); @@ -98,11 +122,22 @@ public Map isMColoringFeasible(int maxColors){ public Map findOptimalColoring(){ int maxColors = this.nodes.size(); - for(MyNode node : this.nodes){ - for(int color = 0; color < maxColors; color++){ - if(isValidColor(node, color)) - nodeColor.put(node.getVariable(), color); + for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ + this.nodeColor.clear(); + MyInterferenceGraph copyGraph = deepCopy(); + Stack stack = copyGraph.computeOptimalColoringStack(currentMaxColors); + + if(stack.isEmpty()) + continue; + + while (!stack.isEmpty()){ + String nodeName = stack.pop(); + for(int color = 0; color < maxColors; color++){ + if(isValidColor(getNode(nodeName), color)) + this.nodeColor.put(nodeName, color); + } } + break; } return this.nodeColor; } From 631228d25c5d311af1d27acf5c22037a007811f5 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 20:52:16 +0000 Subject: [PATCH 242/253] Used iinc for other additions besides 1 --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index ee13743..4d94357 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -196,22 +196,22 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && - rightOperand instanceof LiteralElement && - parseInt(((LiteralElement)rightOperand).getLiteral()) == 1) { + rightOperand instanceof LiteralElement) { if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " 1\n"; + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; } if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && - !(rightOperand instanceof LiteralElement) && - parseInt(((LiteralElement)leftOperand).getLiteral()) == 1) { + !(rightOperand instanceof LiteralElement)) { if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " 1\n"; + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; } return ""; From 71f11ccea544c31d719852280c3a27ba3e008b16 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:13:25 +0000 Subject: [PATCH 243/253] Fixed var equivalence data structure usage in iinc to also accept ollir without temps --- .../up/fe/comp2023/jasmin/JVMInstructionUtils.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 4d94357..090095f 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -191,15 +191,13 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); - if (iincVarEquivalent == null) - return ""; - if (instruction.getOperation().getOpType() == OperationType.ADD && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (iincVarEquivalent.equals(((Operand) leftOperand).getName())) + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand) leftOperand).getName()) || iincVarEquivalent.equals(((Operand) leftOperand).getName())) + if (destName.equals(((Operand) leftOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; } @@ -207,9 +205,10 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if (instruction.getOperation().getOpType() == OperationType.ADD && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - if (iincVarEquivalent.equals(((Operand)rightOperand).getName())) + if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand)rightOperand).getName()) || iincVarEquivalent.equals(((Operand)rightOperand).getName())) + if (destName.equals(((Operand)rightOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; } From ae10e7937f5309dc5c89f74d20d4e2190cc3cf65 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:22:17 +0000 Subject: [PATCH 244/253] Implemented iinc for negative constants --- .../fe/comp2023/jasmin/JVMInstructionUtils.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 090095f..64ca0c3 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -186,31 +186,36 @@ public static String createUnaryOpStatement(UnaryOpInstruction instruction, Hash } public static String checkInc(BinaryOpInstruction instruction, Element dest, HashMap varTable) { + OperationType operationType = instruction.getOperation().getOpType(); Element leftOperand = instruction.getLeftOperand(); Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); - if (instruction.getOperation().getOpType() == OperationType.ADD && + if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { + if (instruction.getOperation().getOpType() == OperationType.ADD) + if (instruction.getOperation().getOpType() == OperationType.SUB) if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() - + " " + ((LiteralElement)rightOperand).getLiteral() + "\n"; + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " + + (operationType == OperationType.SUB ? "-" : "") + + ((LiteralElement)rightOperand).getLiteral() + "\n"; } - if (instruction.getOperation().getOpType() == OperationType.ADD && + if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand)rightOperand).getName()) || (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() - + " " + ((LiteralElement)leftOperand).getLiteral() + "\n"; + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " + + (operationType == OperationType.SUB ? "-" : "") + + ((LiteralElement)leftOperand).getLiteral() + "\n"; } return ""; From 5f24e892650503418cd9132894080c8677f50c45 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sat, 27 May 2023 21:27:49 +0000 Subject: [PATCH 245/253] Removed unused if --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 64ca0c3..15d10a2 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -195,8 +195,6 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (instruction.getOperation().getOpType() == OperationType.ADD) - if (instruction.getOperation().getOpType() == OperationType.SUB) if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); if (destName.equals(((Operand) leftOperand).getName()) || From a48208d536ca4f4c076b801765edf6fb265a105f Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 14:47:11 +0100 Subject: [PATCH 246/253] Refactor MyInterferenceGraph --- .../optimization/RegisterAllocation.java | 11 ----------- .../MyInterferenceGraph.java | 18 +++++++++--------- .../interferenceGraph/MyNode.java | 19 +++++++++---------- .../comp2023/semantic/ExpressionAnalysis.java | 2 +- 4 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java index b924185..d72ea82 100644 --- a/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java +++ b/src/main/pt/up/fe/comp2023/optimization/RegisterAllocation.java @@ -35,17 +35,6 @@ private void livenessAnalysis(){ this.uses.put(instruction, getUse(instruction, new HashSet<>())); } computeLiveInOut(); - - //TODO: remove - System.out.println(method.getMethodName()); - System.out.println("------------------"); - for(Instruction instruction : method.getInstructions()){ - instruction.show(); - System.out.println("Defs:" + defs.get(instruction)); - System.out.println("Uses:" + uses.get(instruction)); - System.out.println("In:" + in.get(instruction)); - System.out.println(("Out: "+ out.get(instruction))); - } } private void createInterferenceGraph() { diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 37ec6f2..c189fb8 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -28,8 +28,8 @@ public MyNode getNode(String varName){ } public void addInterferenceEdge(String src, String dest){ - getNode(src).getAdj().add(dest); - getNode(dest).getAdj().add(src); + getNode(src).addNeighbour(dest); + getNode(dest).addNeighbour(src); } public void connectInterferingVariables(List variables){ @@ -44,16 +44,16 @@ public void connectInterferingVariables(List variables){ } public void removeNode(MyNode node){ - for(String adj : node.getAdj()){ - MyNode adjNode = getNode(adj); - adjNode.removeAdj(node.getVariable()); + for(String neighbour : node.getNeighbours()){ + MyNode neighbourNode = getNode(neighbour); + neighbourNode.removeNeighbour(node.getVariable()); } this.nodes.remove(node); } private boolean isValidColor(MyNode node, int color){ - for(String adj : node.getAdj()){ - if(nodeColor.get(adj) == color) + for(String neighbour : node.getNeighbours()){ + if(nodeColor.get(neighbour) == color) return false; } return true; @@ -66,7 +66,7 @@ public Stack computeMColoringStack(int maxColors){ MyNode nodeToRemove = null; for(MyNode node : this.nodes){ - if(node.getAdj().size() < maxColors){ + if(node.getDegree() < maxColors){ nodeToRemove = node; break; } @@ -88,7 +88,7 @@ public Stack computeOptimalColoringStack(int maxColors){ MyNode nodeToRemove = null; for(MyNode node : this.nodes){ - if(node.getAdj().size() < maxColors){ + if(node.getDegree() < maxColors){ nodeToRemove = node; break; } diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java index e3ea03b..ffd784b 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyNode.java @@ -1,12 +1,11 @@ package pt.up.fe.comp2023.optimization.interferenceGraph; -import org.specs.comp.ollir.Element; import java.util.HashSet; import java.util.Set; public class MyNode { private final String varName; - private final Set adj = new HashSet<>(); + private final Set neighbours = new HashSet<>(); public MyNode(String varName){ this.varName = varName; @@ -16,19 +15,19 @@ public String getVariable() { return this.varName; } - public Set getAdj() { - return adj; + public Set getNeighbours() { + return neighbours; } - public void addAdj(String varName) { - this.adj.add(varName); + public void addNeighbour(String varName) { + this.neighbours.add(varName); } - public int getNodeDegree() { - return this.adj.size(); + public int getDegree() { + return this.neighbours.size(); } - public void removeAdj(String varName){ - this.adj.remove(varName); + public void removeNeighbour(String varName){ + this.neighbours.remove(varName); } } diff --git a/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java index 0e5cc40..2b5eac9 100644 --- a/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java +++ b/src/main/pt/up/fe/comp2023/semantic/ExpressionAnalysis.java @@ -225,7 +225,7 @@ else if(findImport(this.imports, objectClassName)){ } String message = "Cannot find '" + objectClassName + "'."; - this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); //TODO: use column of 'classname' + this.reports.add(new Report(ReportType.ERROR, Stage.SEMANTIC, getNodeLine(jmmNode), getNodeColumn(jmmNode), message)); jmmNode.put(TYPENAME, UNKNOWN); return UNKNOWN_TYPE; } From 59151fe8df30bd7da2bf6879a5c2ecb98a896ef2 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 14:52:22 +0100 Subject: [PATCH 247/253] Refactor method that computes the coloring stack --- .../MyInterferenceGraph.java | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index c189fb8..7ef0e67 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -59,7 +59,7 @@ private boolean isValidColor(MyNode node, int color){ return true; } - public Stack computeMColoringStack(int maxColors){ + public Stack computeColoringStack(int maxColors, boolean isOptimal){ Stack stack = new Stack<>(); while (this.nodes.size() > 0) { @@ -75,39 +75,19 @@ public Stack computeMColoringStack(int maxColors){ stack.push(nodeToRemove.getVariable()); this.removeNode(nodeToRemove); } - else - throw new RuntimeException("The provided number of registers is not enough to store the variables."); - } - return stack; - } - - public Stack computeOptimalColoringStack(int maxColors){ - Stack stack = new Stack<>(); - - while (this.nodes.size() > 0) { - MyNode nodeToRemove = null; - - for(MyNode node : this.nodes){ - if(node.getDegree() < maxColors){ - nodeToRemove = node; - break; - } - } - if(nodeToRemove != null){ - stack.push(nodeToRemove.getVariable()); - this.removeNode(nodeToRemove); - } - else{ + else if (isOptimal){ stack.clear(); return stack; } + else + throw new RuntimeException("The provided number of registers is not enough to store the local variables."); } return stack; } public Map isMColoringFeasible(int maxColors){ MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeMColoringStack(maxColors); + Stack stack = copyGraph.computeColoringStack(maxColors, false); while (!stack.isEmpty()){ String nodeName = stack.pop(); @@ -125,7 +105,7 @@ public Map findOptimalColoring(){ for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ this.nodeColor.clear(); MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeOptimalColoringStack(currentMaxColors); + Stack stack = copyGraph.computeColoringStack(currentMaxColors, true); if(stack.isEmpty()) continue; From 80e9cf9f051da4fb51e43368256dd35cd43f24ce Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 28 May 2023 15:03:57 +0000 Subject: [PATCH 248/253] Fixed limits through which iinc can be used --- .../comp2023/jasmin/JVMInstructionUtils.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 15d10a2..1abc42b 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -195,25 +195,35 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())) + String increment = ""; + if (operationType == OperationType.ADD && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 127) + increment = ((LiteralElement)rightOperand).getLiteral(); + else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 128) + increment = "-" + ((LiteralElement)rightOperand).getLiteral(); + if (!Objects.equals(increment, "") && iincVarEquivalent != null && + iincVarEquivalent.equals(((Operand) leftOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand) leftOperand).getName()) || - (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + " " - + (operationType == OperationType.SUB ? "-" : "") - + ((LiteralElement)rightOperand).getLiteral() + "\n"; + if (!Objects.equals(increment, "") && (destName.equals(((Operand) leftOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand) leftOperand).getName())))) + return "\tiinc " + varTable.get(((Operand) leftOperand).getName()).getVirtualReg() + + " " + increment + "\n"; } if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - if (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())) + String increment = ""; + if (operationType == OperationType.ADD && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 127) + increment = ((LiteralElement)leftOperand).getLiteral(); + else if (operationType == OperationType.SUB && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 128) + increment = "-" + ((LiteralElement)leftOperand).getLiteral(); + if (!Objects.equals(increment, "") && iincVarEquivalent != null && + iincVarEquivalent.equals(((Operand)rightOperand).getName())) iincVars.put(iincVarEquivalent, destName); - if (destName.equals(((Operand)rightOperand).getName()) || - (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName()))) - return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + " " - + (operationType == OperationType.SUB ? "-" : "") - + ((LiteralElement)leftOperand).getLiteral() + "\n"; + if (!Objects.equals(increment, "") && (destName.equals(((Operand)rightOperand).getName()) || + (iincVarEquivalent != null && iincVarEquivalent.equals(((Operand)rightOperand).getName())))) + return "\tiinc " + varTable.get(((Operand) rightOperand).getName()).getVirtualReg() + + " " + increment + "\n"; } return ""; From ec3d9ca332889b2cd3f37e17f82d786ade3c4cf7 Mon Sep 17 00:00:00 2001 From: Isabel Amaral Date: Sun, 28 May 2023 15:06:41 +0000 Subject: [PATCH 249/253] Small adjustment --- src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java index 1abc42b..9d28f2b 100644 --- a/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java +++ b/src/main/pt/up/fe/comp2023/jasmin/JVMInstructionUtils.java @@ -191,11 +191,11 @@ public static String checkInc(BinaryOpInstruction instruction, Element dest, Has Element rightOperand = instruction.getRightOperand(); String destName = ((Operand)dest).getName(); String iincVarEquivalent = varEquivalence.get(destName); + String increment = ""; if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && !(leftOperand instanceof LiteralElement) && rightOperand instanceof LiteralElement) { - String increment = ""; if (operationType == OperationType.ADD && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 127) increment = ((LiteralElement)rightOperand).getLiteral(); else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOperand).getLiteral()) <= 128) @@ -212,7 +212,6 @@ else if (operationType == OperationType.SUB && parseInt(((LiteralElement)rightOp if ((operationType == OperationType.ADD || operationType == OperationType.SUB) && leftOperand instanceof LiteralElement && !(rightOperand instanceof LiteralElement)) { - String increment = ""; if (operationType == OperationType.ADD && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 127) increment = ((LiteralElement)leftOperand).getLiteral(); else if (operationType == OperationType.SUB && parseInt(((LiteralElement)leftOperand).getLiteral()) <= 128) From 919a0cbb493bcf639fec59bf43d5d859bd3d7728 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 18:34:40 +0100 Subject: [PATCH 250/253] Small fix to isValidColor() method --- .../optimization/interferenceGraph/MyInterferenceGraph.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 7ef0e67..1ce8fed 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -53,7 +53,7 @@ public void removeNode(MyNode node){ private boolean isValidColor(MyNode node, int color){ for(String neighbour : node.getNeighbours()){ - if(nodeColor.get(neighbour) == color) + if(nodeColor.getOrDefault(neighbour, -1) == color) return false; } return true; From 5f31a9a22b8a6c188e2b8ca9c390456832e2bee9 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 19:11:52 +0100 Subject: [PATCH 251/253] Improve findOptimalColoring --- .../MyInterferenceGraph.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java index 1ce8fed..fc6d84a 100644 --- a/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java +++ b/src/main/pt/up/fe/comp2023/optimization/interferenceGraph/MyInterferenceGraph.java @@ -59,7 +59,7 @@ private boolean isValidColor(MyNode node, int color){ return true; } - public Stack computeColoringStack(int maxColors, boolean isOptimal){ + public Stack computeColoringStack(int maxColors) throws RuntimeException{ Stack stack = new Stack<>(); while (this.nodes.size() > 0) { @@ -75,19 +75,15 @@ public Stack computeColoringStack(int maxColors, boolean isOptimal){ stack.push(nodeToRemove.getVariable()); this.removeNode(nodeToRemove); } - else if (isOptimal){ - stack.clear(); - return stack; - } else throw new RuntimeException("The provided number of registers is not enough to store the local variables."); } return stack; } - public Map isMColoringFeasible(int maxColors){ + public Map isMColoringFeasible(int maxColors) throws RuntimeException{ MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeColoringStack(maxColors, false); + Stack stack = copyGraph.computeColoringStack(maxColors); while (!stack.isEmpty()){ String nodeName = stack.pop(); @@ -103,19 +99,11 @@ public Map findOptimalColoring(){ int maxColors = this.nodes.size(); for(int currentMaxColors = 1; currentMaxColors <= maxColors; currentMaxColors++){ - this.nodeColor.clear(); - MyInterferenceGraph copyGraph = deepCopy(); - Stack stack = copyGraph.computeColoringStack(currentMaxColors, true); + try{ + this.isMColoringFeasible(currentMaxColors); - if(stack.isEmpty()) + }catch (RuntimeException e){ //currentMaxColor is not enough continue; - - while (!stack.isEmpty()){ - String nodeName = stack.pop(); - for(int color = 0; color < maxColors; color++){ - if(isValidColor(getNode(nodeName), color)) - this.nodeColor.put(nodeName, color); - } } break; } From becef83efc0db5e3bbd79042f0ce03d4fb63e083 Mon Sep 17 00:00:00 2001 From: Milena Gouveia Date: Sun, 28 May 2023 21:19:23 +0100 Subject: [PATCH 252/253] Update README.md --- README.md | 69 ++++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 3cfd557..0d8416d 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,22 @@ -# Compilers Project - -For this project, you need to install [Java](https://jdk.java.net/), [Gradle](https://gradle.org/install/), and [Git](https://git-scm.com/downloads/) (and optionally, a [Git GUI client](https://git-scm.com/downloads/guis), such as TortoiseGit or GitHub Desktop). Please check the [compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html) for Java and Gradle versions. - -## Project setup - -There are some import folders in the repository. Your development source code is inside the subfolder named ``src/main``. Specifically, your initially application is in the folder ``src/main/pt/up/fe/comp2023``, and the grammar is in the subfolder ``src/main/antlr/comp2023/grammar``. Finally, the subfolder named ``test`` contains your unit tests. - -## Compile and Running - -To compile and install the program, run ``gradle installDist``. This will compile your classes and create a launcher script in the folder ``./build/install/jmm/bin``. For convenience, there are two script files in the root folder, one for Windows (``jmm.bat``) and another for Linux (``jmm``), that call this launcher script. - -After compilation, a series of tests will be automatically executed. The build will stop if any test fails. Whenever you want to ignore the tests and build the program anyway, you can call Gradle with the flag ``-x test``. - - -## Tests - -The base repository comes with two classes that contains unitary tests in the package ``pt.up.fe.comp``, ``TutorialTest`` and `` GrammarTest``. The tests in ``TutorialTest`` should all pass just using the provided code. ``GrammarTest`` contains tests for the complete Java-- grammar, and most should fail. By the end of Checkpoint 1, all tests should pass. - -The class ``GrammarTest`` contains several static String variables at the beginning of the class where you should put the name of your rules for each type of rule that appears there. You have to set these variables to pass all tests. - -To test the program, run ``gradle test``. This will execute the build, and run the JUnit tests in the ``test`` folder. If you want to see output printed during the tests, use the flag ``-i`` (i.e., ``gradle test -i``). - -You can also see a test report by opening the file ``./build/reports/tests/test/index.html``. - - -### Reports -We also included in this project the class ``pt.up.fe.comp.jmm.report.Report``. This class is used to generate important reports, including error and warning messages, but also can be used to include debugging and logging information. E.g. When you want to generate an error, create a new Report with the ``Error`` type and provide the stage in which the error occurred. - -### Parser Interface - -We have included the interface ``pt.up.fe.comp.jmm.parser.JmmParser``, for which we already provide an example implementation in the file ``src/main/pt/up/fe/comp2023/SimpleParser.java``. - -To configure the name of the class of the JmmParser implementation that should be automatically used for tests, use the file ``config.properties`` (more details below). - -### Compilation Stages - -The project is divided in four compilation stages, that you will be developing during the semester. The stages are Parser, Analysis, Optimization and Backend, and for each of these stages there is a corresponding Java interface that you will have to implement (e.g. for the Parser stage, you have to implement the interface JmmParser). - - -### config.properties - -The testing framework, which uses the class ``pt.up.fe.comp.TestUtils``, has methods to test each of the four compilation stages (e.g., ``TestUtils.parse()`` for testing the Parser stage). - -In order for the test class to find your implementations for the stages, it uses the file ``config.properties`` that is in root of your repository. It has four fields, one for each stage (i.e. ``ParserClass``, ``AnalysisClass``, ``OptimizationClass``, ``BackendClass``), and initially it only has one value, ``pt.up.fe.comp2023.SimpleParser``, associated with the first stage. - -During the development of your compiler you will update this file in order to setup the classes that implement each of the compilation stages. +# Compilers Project (Group 7B) + +## Group members +- Isabel Amaral (up202006677) +- Mariana Rocha (up202004656) +- Milena Gouveia (up202008862) + +## Distribution of work +- Isabel Amaral (33%) +- Mariana Rocha (33%) +- Milena Gouveia (33%) + +## Implemented optimizations +- Option `-o`: + - constant propagation + - constant folding +- Option `–r=` (register allocation): + - `n ≥ 1`: the compiler tries to use at most `` local variables when generating Jasmin instructions. It aborts and reports an error if `` is not enough to store the local variables. + - `n = −1`: This is the default value where the compiler uses as many variables as originally present in the OLLIR representation. + +## Self-assessment +The developed project seems to be working as expected except for the optimization where the compiler tries to use the fewest registers as possible (option `-r 0`). However, considering that all the project requirements and all the remaining optimizations were implemented, we believe that our project deserves a grade of 19-19.5 out of 20. From ea5d907ed13b27e714fd4f40393f119f143bce47 Mon Sep 17 00:00:00 2001 From: Mariana <73724268+golangis@users.noreply.github.com> Date: Sat, 10 Jun 2023 18:19:01 +0100 Subject: [PATCH 253/253] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0d8416d..ca40c0e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Compilers Project (Group 7B) -## Group members -- Isabel Amaral (up202006677) -- Mariana Rocha (up202004656) -- Milena Gouveia (up202008862) +## 👥 Group members +- Isabel Amaral (up202006677) +- Mariana Rocha (up202004656) +- Milena Gouveia (up202008862) -## Distribution of work -- Isabel Amaral (33%) -- Mariana Rocha (33%) -- Milena Gouveia (33%) +## 👩‍💻 Distribution of work +- Isabel Amaral (33%) - Jasmin +- Mariana Rocha (33%) - Ollir +- Milena Gouveia (33%) - Semantic Analysis and Optimizations -## Implemented optimizations +## 🪛 Implemented optimizations - Option `-o`: - constant propagation - constant folding @@ -18,5 +18,5 @@ - `n ≥ 1`: the compiler tries to use at most `` local variables when generating Jasmin instructions. It aborts and reports an error if `` is not enough to store the local variables. - `n = −1`: This is the default value where the compiler uses as many variables as originally present in the OLLIR representation. -## Self-assessment +## 🔎 Self-assessment The developed project seems to be working as expected except for the optimization where the compiler tries to use the fewest registers as possible (option `-r 0`). However, considering that all the project requirements and all the remaining optimizations were implemented, we believe that our project deserves a grade of 19-19.5 out of 20.