This project was developed as part of the Compilers course in the second semester of the third year of the degree program. The main goal is to build a functional compiler for a high-level programming language called Java--, which is based on Java but includes some simplifications and extensions for educational purposes.
The project aims to expose students to various aspects of programming language design and implementation by building a working compiler for Java--. The compiler includes the following stages:
-
Lexical and Syntactic Analysis:
- Implementation of a lexer and parser using ANTLR.
- Adaptation of the provided grammar to support the Java-- language.
-
Semantic Analysis:
- Construction of a symbol table to store information about classes, methods, variables, and their types.
- Validation of the code's semantics, including type checking and declaration verification.
-
Intermediate Code Generation (OLLIR):
- Conversion of the AST into an Object-Oriented Low-Level Intermediate Representation (OLLIR).
- Implementation of optimizations such as constant propagation and constant folding.
-
Jasmin Code Generation:
- Translation of OLLIR code into JVM bytecode using the Jasmin format.
- Calculation of
.limit stack
and.limit locals
directives to optimize JVM resource usage.
The project includes a suite of tests to validate the compiler's functionality in various scenarios, ensuring correctness and robustness.
Here we listed the optimizations we have implemented in our jmm compiler.
We implemented all the register allocation strategies supported by the compiler:
-
n = 0: The compiler attempts to minimize the number of JVM local variables by reusing local variables wherever possible.
-
n = 1: The compiler uses the same number of local variables as in the original OLLIR code, preserving the variable mapping.
-
n >= 1: The compiler limits the number of local variables to
<n>
(≥ 1). It includes:-
Mapping between method-level variables and JVM local variables.
-
Lifetime analysis of variables.
-
Graph coloring-based register allocation.
-
These approaches are correctly integrated and selectable via the -r=<n>
option.
With the -o
flag, we implemented the following AST-level optimizations:
-
Constant Propagation:
-
Detects variables with constant values and replaces their usages with the constant.
-
Reduces the number of required JVM variables and simplifies expressions.
-
-
Constant Folding:
-
Evaluates constant expressions at compile time (e.g.,
10 + 5
becomes15
). -
Reduces runtime computation and further simplifies the AST.
-
Name | Number | Contribution | |
---|---|---|---|
Gonçalo Cunha Marques | 202206205 | up202206205@up.pt | 33% |
Miguel Lopes Guerrinha | 202205038 | up202205038@up.pt | 33% |
Rui Pedro da Silva Cruz | 202208011 | up202208011@up.pt | 33% |