Homework 3

This commit is contained in:
Carlos Galindo 2020-01-15 22:32:25 +01:00
commit 0afc86ceeb
Signed by: kauron
GPG key ID: 83E68706DEE119A3
129 changed files with 3163 additions and 4316 deletions

View file

@ -2,9 +2,10 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/antlr-4.4-complete.jar"/>
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="lib/antlr-4.7.1-complete.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/javaliParserObf.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Javali-HW2</name>
<name>Javali-HW3</name>
<comment></comment>
<projects>
</projects>

View file

@ -1,13 +0,0 @@
antlr4.antlrRegisteredTools=4.4@/tmp/antlr-4.4-complete.jar\:4.7.1@/home/carlos/eth/cd/nop90/HW2/lib/antlr-4.7.1-complete.jar
antlr4.antlrToolPath=/home/carlos/eth/cd/nop90/HW2/lib/antlr-4.7.1-complete.jar
antlr4.encoding=UTF-8
antlr4.listener=true
antlr4.visitor=false
antlr4.vmArgs=
antlr4ide.is_project_specific=true
autobuilding=true
eclipse.preferences.version=1
is_project_specific=
outlet.DEFAULT_OUTPUT.cleanupDerived=true
outlet.DEFAULT_OUTPUT.derived=true
outlet.DEFAULT_OUTPUT.directory=./target/generated-sources/antlr4

View file

@ -1,7 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -1,5 +1,6 @@
Grade: 29/30
Grade: 25/25
251/251 tests passed [25/25]
105/105 tests passed [20/20]
Submitted test cases: [5/5]
Submitted test cases: [4/5]

55
README.md Normal file
View file

@ -0,0 +1,55 @@
# Compiler design
## Parser and syntactic analysis
See repo containing [Homework #2](https://svn.inf.ethz.ch/svn/trg/cd_students/ss18/teams/nop90/HW2).
## Semantic analysis
This project checks a list class declaration as trees of Ast nodes for
possible semantic errors.
### Design
The semantic checks described [here](./SemanticChecks.md) are implemented in three
phases.
1. Circular inheritance check (just with the names, and checking for non-existent
types) to avoid stack overflow problems in the main analysis. May throw a
`NO_SUCH_TYPE` error if the parent of a given class doesn't exist.
2. Main semantic analysis, performed by `StmtAnalyzer` and `ExprAnalyzer`,
two visitors that traverse each `ClassDecl` and all of its contents looking
for semantic errors. Some types and methods may not have been discovered
when they are accessed, and to that end the functions `findType(String)`
and `findMethod(String,ClassSymbol)` lookup both, searching unvisited class
and method declarations in order to find the corresponding symbol.
3. Lookup of start point (method `void main()` in `Main` class)
### Testing
A set of test cases (Javali programs, valid and invalid) are provided. The ones
designed specifically for this homework assignment are located in
`javali_tests/HW3_nop90`, and they cover all the code in the `cd.frontend.semantic`
and `cd.ir` packages. They cover all the kinds of errors that can arise
from a semantic analysis of Javali programs. As the order of the errors
is not determined, each test case only checks one failing condition, and
therefore many more test cases are needed for this homework than for
previous ones.
The test files are organized in folders, with names ending in Tests or Errors,
the latter only contain test cases that result in semantic errors.
To run the tests that exist in the `javali_tests` folder you can simply run
$ ant clean clean-test compile test
### Development environment
This project is designed for Eclipse and GNU/Linux, but it can be run
in other environments, as long as they have a 32bit `IA 86x assembly` compiler
and a `JVM`. Check the `Config` class for more information.
### Documentation
Available as [javadoc](javadoc/index.html). It is generated running the following command:
$ ant clean-doc generate-doc
### Important files
* `TODO.md`: contains tasks to complete
* `SemanticChecks.md`: contains the semantic checks numbered for quick reference
* [Javali Grammar](https://www.ethz.ch/content/dam/ethz/special-interest/infk/inst-cs/lst-dam/documents/Education/Classes/Spring2018/210_Compiler_Design/Homework/javali.pdf)
* [HW3 statement](https://www.ethz.ch/content/dam/ethz/special-interest/infk/inst-cs/lst-dam/documents/Education/Classes/Spring2018/210_Compiler_Design/Homework/hw3.pdf)

43
SemanticChecks.md Normal file
View file

@ -0,0 +1,43 @@
# Class and method declaration errors
1. All programs must have a method main() with void return type in the class Main (`INVALID_START_POINT`)
2. The superclass of each class exists (`NO_SUCH_TYPE`)
3. There is no circular inheritance (`CIRCULAR_INHERITANCE`)
4. No class is declared with the name `Object` (`OBJECT_CLASS_DEFINED`)
5. Unique names (`DOUBLE_DECLARATION`) for each group:
1. Class names
2. Field names in a single class (field shadowing is allowed)
3. Method names in a single class (Override is allowed, overloading not)
4. Method parameters and local variable names
6. Overridden methods must: (`INVALID_OVERRIDE`)
1. Have the same number of parameters
2. The return types must match
3. The type of the parameters must match (name can differ)
# Method body errors
1. `write()` must take one argument of type `int` (`TYPE_ERROR`)
2. `read()` and `writeln()` must take no arguments (`WRONG_NUMBER_OF_ARGUMENTS`)
3. The condition of a `while` or `if` statement must be typed `booelan` (`TYPE_ERROR`)
4. Assignments: the type of the right-hand side must be a suptype of the type of the left-hand side. (`TYPE_ERROR`)
5. Operators (`TYPE_ERROR`):
1. `*`, `/`, `%`, `+`, `-`, `<`, `>`, `<=`, `>=` take `int` arguments only.
2. `!`, `&&`, `||` take `boolean` arguments only.
3. `==` and `!=` takes any couple of arguments as long as one of the types is a subtype of the other.
4. A cast is only possible if one of the types is a subtype of the other
6. Method invocation, must match with declaration:
1. The number of parameters (`WRONG_NUMBER_OF_ARGUMENTS`)
2. The type of each of the parameters (`TYPE_ERROR`)
7. Arrays:
1. When indexing, the index expression must be an `int` (`TYPE_ERROR`)
2. When creating one, the index expression must be an `int` (`TYPE_ERROR`)
8. The constant `null` can be assigned to any reference type.
9. The type name in a `new` statement must exist (`NO_SUCH_TYPE`)
10. The left-hand side of an assignment can only be: (`NOT_ASSIGNABLE`)
1. A variable
2. A field
3. Array dereferences (indexing)
11. There must be no attempt to access the field or method of a
non-object type, such as arrays or primitive types (`TYPE_ERROR`)
12. A method with a return type must have a return statement at the end
of all its paths (`MISSING_RETURN`). A while loop is not a valid return
regardless of the condition. A ifElse must have a return on both the
else and otherwise block. There may be some statements after a return.

75
TODO.md Normal file
View file

@ -0,0 +1,75 @@
## Possible code changes
### General
* DONE Use more specific messages when throwing a `SemanticFailure` exception. This has the caveat that the automated testing relies on those tests?
### StmtAnalyzer
* DONE Propagate the change of class parameter from `ExprAnalyzer`.
* DONE Complete checks for `MISSING_RETURN`, some ideas:
* DONE Assume no instructions will appear after a return statement and analyze only the last `Stmt` using other visitor
with different class parameters (for example passing the desired type and returning a `Optional<TypeSymbol>`).
* DONE Decide the logic behind a return statement in a `while` loop, maybe treat it as an `if` with an empty `else` block.
* A `while` as last instruction is not a valid return.
* A `if` as last instruction must have a valid return a the end of its then and otherwise blocks.
### ExprAnalyzer
* DONE Change the second class parameter to give method AND class information (needed by var and this nodes)
* DISCARDED Add a ClassSymbol to MethodSymbol and use it as class parameter, the problem arises when visiting a method,
should an empty method with the proper class be provided? Could also be solved by using `Symbol` as class parameter.
* DONE Create a new class that includes a `ClassSymbol` and a `MethodSymbol` and use that. Keep `MethodSymbol == null`
when appropriate.
## Tests
This tests have been selected to increase to 100% the code coverage obtained by running the tests designed for the previous HW,
which are in folder svn/HW2/javali_tests/HW2_nop90
As they are mostly related to errors that haven't been triggered, each test should be separate, in order to generate all
of the errors.
### Remaining
### Done
* access var from class or superclass
* test ! operator
* type error in unaryOp
* type error in array size
* call method from superclass
* call a method that doesn't exist
* call a method with the wrong type of params
* call a method with the wrong number of params
* assign to all possible syntactically correct options
* field
* var
* array index
* method (error)
* this (error)
* indexing both types error
* try to access a field of something that is not a class type
* typing error in cast
* AND and OR operations
* equals operators (a case that is OK and another that's not)
* binary operation with wrong type (any but == and !=)
* search for a type that doesn't exist in a method body
* don't have a Main class
* don't have a main() method in the Main class (all possibilities)
* wrong name
* wrong return value
* wrong parameters
* inherited main method (it should work)
* write something that is not an integer
* declare a variable mutiple times (local variables)
* declare a local variable with the same name as a parameter
* check MISSING_RETURN
* nested ifElse as end of method
* while as end of method
* normal returns at the end of the method
* return with further statements after it
* while with non-int condition
* use a array type that hasn't been discovered yet
* ```class A { B[] name; } class B {}```
* name a class Object
* name a class like another class
* name a parameter like another
* override methods and try to break that
* same return type
* same number of params
* same type of params
* name a variable like another (field level)

View file

@ -1,4 +1,4 @@
<project name="compiler-design" default="generate-parser" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">
<project name="compiler-design" default="test" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">
<!-- A very simple ant file that primarily exists to run cup and lex;
it also includes targets to build the compiler and run tests for those
@ -8,55 +8,25 @@
<property name="src.dir" value="${basedir}/src"/>
<property name="test.dir" value="${basedir}/test"/>
<property name="javali_tests.dir" value="${basedir}/javali_tests"/>
<property name="parser.dir" value="${src.dir}/cd/frontend/parser"/>
<property name="parser.jar" value="${basedir}/lib/javaliParserObf.jar"/>
<property name="build.dir" value="${basedir}/bin"/>
<property name="junit.jar" value="${basedir}/lib/junit-4.12.jar"/>
<property name="hamcrest.jar" value="${basedir}/lib/hamcrest-core-1.3.jar"/>
<property name="antlr.jar" value="${basedir}/lib/antlr-4.7.1-complete.jar"/>
<property name="antlr.jar" value="${basedir}/lib/antlr-4.4-complete.jar"/>
<property name="antlr.profile" value="false"/>
<property name="antlr.report" value="false"/>
<property name="jacocoant.jar" value="${basedir}/lib/jacocoant.jar"/>
<property name="coverage.file" location="${build.dir}/jacoco.exec"/>
<property name="min.coverage" value="0.5"/>
<property name="coverage.check" value="cd.frontend.*:cd.backend.*"/>
<target name="generate-parser">
<echo message="ANTLR4 ${parser.dir}/Javali.g4" level="info"/>
<echo>${basedir}</echo>
<java classname="org.antlr.v4.Tool" failonerror="true" classpath="${antlr.jar}">
<arg value="${parser.dir}/Javali.g4" />
<arg value="-o" />
<arg value="${parser.dir}" />
<arg value="-no-listener" />
<arg value="-visitor" />
</java>
</target>
<!-- Deletes the generated ANTLR parser files. Don't use in HW1! -->
<target name="clean-parser">
<delete file="${parser.dir}/Javali.tokens"/>
<delete file="${parser.dir}/JavaliLexer.java"/>
<delete file="${parser.dir}/JavaliParser.java"/>
<delete file="${parser.dir}/JavaliWalker.tokens"/>
<delete file="${parser.dir}/JavaliWalker.java"/>
<delete file="${parser.dir}/JavaliBaseListener.java"/>
<delete file="${parser.dir}/JavaliBaseVisitor.java"/>
<delete file="${parser.dir}/JavaliListener.java"/>
<delete file="${parser.dir}/JavaliVisitor.java"/>
<delete file="${parser.dir}/JavaliLexer.tokens"/>
<delete file="${parser.dir}/Javali.interp"/>
<delete file="${parser.dir}/JavaliLexer.interp"/>
</target>
<property name="doc.dir" value="javadoc"/>
<!-- Cleans generated code, but NOT the parser source! -->
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<!-- Builds the compiler framework for HW > HW1. -->
<target name="compile" depends="generate-parser">
<target name="compile">
<mkdir dir="${build.dir}"/>
<javac debug="true" destdir="${build.dir}" includeantruntime="false">
@ -66,6 +36,7 @@
<pathelement location="${antlr.jar}"/>
<pathelement location="${junit.jar}"/>
<pathelement location="${hamcrest.jar}"/>
<pathelement location="${parser.jar}"/>
</classpath>
</javac>
</target>
@ -108,4 +79,40 @@
<fail if="tests-failed" />
</target>
<target name="test-coverage-report">
<jacoco:report>
<executiondata>
<file file="${coverage.file}"/>
</executiondata>
<structure name="JaCoCo Ant Example">
<classfiles>
<fileset dir="${build.dir}"/>
</classfiles>
<sourcefiles encoding="UTF-8">
<fileset dir="${src.dir}"/>
</sourcefiles>
</structure>
<check>
<rule element="PACKAGE" includes="${coverage.check}">
<limit counter="LINE" value="COVEREDRATIO" minimum="${min.coverage}"/>
</rule>
</check>
</jacoco:report>
<echo message="Coverage above ${min.coverage} in ${coverage.check}: OK" level="info"/>
</target>
<target name="clean-doc">
<delete dir="javadoc"/>
</target>
<target name="generate-doc">
<javadoc sourcepath="${src.dir}" destdir="${doc.dir}"
private="true" use="true" author="true">
<package name="cd"/>
<package name="cd.frontend.semantic"/>
<package name="cd.ir"/>
<arg value="-notimestamp"/>
</javadoc>
</target>
</project>

View file

@ -0,0 +1,9 @@
// Test that you cannot invoke a method on an integer.
class Main {
void main() {
int x;
x = 1;
x.foo();
}
}

View file

@ -0,0 +1,9 @@
/* Test that the circular inheritance between Foo and Bar is detected */
class Foo extends Bar { }
class Bar extends Foo { }
class Main {
void main() {
writeln();
}
}

View file

@ -0,0 +1,11 @@
/* Test that if conditions must be boolean */
class Main {
void main() {
if (84 / 2) {
write(1);
writeln();
}
write(2);
writeln();
}
}

View file

@ -0,0 +1,14 @@
/* Test that an invalid field name is detected */
class X {
int field;
}
class Main {
void main() {
X x;
x = new X();
x.field = 0;
x.notafield = 1; /* ILLEGAL: bad field name */
}
}

View file

@ -0,0 +1,30 @@
/* Test that fields are inherited */
class A {
int foo;
}
class B extends A {
int bar;
}
class Main {
void main() {
A a;
B b;
a = new A();
a.foo = 1;
write(a.foo);
a = new B();
a.foo = 2;
write(a.foo);
b = new B();
b.foo = 3;
b.bar = 4;
write(b.foo);
write(b.bar);
}
}

View file

@ -0,0 +1,16 @@
// Test that arrays are not covariant
class Main {
void main() {
boolean y;
A[] Array1;
B[] Array2;
Array2 = new B[10];
Array1 = Array2;
}
}
class B extends A {}
class A {}

View file

@ -0,0 +1,11 @@
// The left-hand side of an assignment cannot be a method call
// Valid options are variable accesses, fields or an indexed array
class Main {
void main() {
action() = read();
}
int action() {
return 0;
}
}

View file

@ -0,0 +1,15 @@
// The left-hand side of an assignment cannot be a reference to this
// Valid options are variable accesses, fields or an indexed array
class Main {
void main () {
int b;
int[] c;
c = new int[5];
this.a = 10;
b = 10;
c[4] = 10;
this = null;
}
int a;
}

View file

@ -0,0 +1,14 @@
// any array is a subtype of Object
// assignment and 'is equal' with an object of type 'Object' is fine
class Main {
void main() {
boolean y;
Object x;
int[] testArray;
testArray = new int[10];
x = testArray;
testArray = null;
x = null;
}
}

View file

@ -0,0 +1,8 @@
// Multiple classes can't share the same name
class Aclass {}
class Aclass {}
class Main {
void main() {}
}

View file

@ -0,0 +1,8 @@
// Two fields in a class cannot share the same name
class Main {
void main() {}
int a;
Object b;
Main a;
}

Some files were not shown because too many files have changed in this diff Show more