This project is a compiler for Easy, a simple programming language. The compiler's output is Jasmin assembler, which can be assembled into Java Bytecode, i.e. the programs can be executed on the JVM.
- Project roadmap and changelog show the project's progress
- Language documentation describe Easy in greater detail.
- Compilation of Easy sourcecode into Jasmin assembler, which can be translated into Java Bytecode (the bytecode representation of an Easy program equals a Java class and behaves like it)
- Translation of each statement in the sourcecode into one clear block of Jasmin assembler, beginning with a comment containing its identifier and original line number
- Calculation and limitation of maximum depth of stack and count of local variables during compilation
- Type-checking right after parsing
- Helpful error messages, if applicable with exact line and position in the sourcecode (for parsing- and type-checking-errors)
- Optional liveness-analysis per function
- detection of unused arguments
- detection of unused variable declarations
- detection of unused variable values (limitation: false alerts in loops, if a variable is read in the loop's condition)
- determination of required number of registers
In this section, we describe how to setup this project locally.
If you use VSCode, you should use our dev-container. It sets up a working environment with all dependencies for you.
Install java 17 and gradle 1.7.
Simply run gradle build
to install most dependencies.
Jasmin is not available on MavenCentral yet.
Please download Jasmin 2.4 from SourceForge and put the jar into /libs
.
We use Gradle for dependency-management, building and testing the compiler.
Simply run gradle build
to create a runnable jar at /build/libs/EasyCompiler.jar
.
Gradle creates the EasyCompiler.jar
which compiles an .easy
file into a .j
file containing Jasmin assembler code.
In the following example, we describe how to compile an Easy program into Java bytecode.
- Create the file
hello_world.easy
at root and copy the following program.none <- main() { println("Hello world!"); }
- Run the Easy compiler with
java -jar build/libs/EasyCompiler.jar -compile hello_world.easy
. It createshello_world.j
which contains a Jasmin assembler representation of our Easy code. - Run
java -jar libs/jasmin.jar hello_world.j
to transformhello_world.j
intohello_world.class
, which contains Java bytecode. - Finally, run
java hello_world
to start the compiled program, which should outputHello world!
.
We test analyses and other testable features using input files, and test code generation by running the Easy Compiler and running the compiled programs on the JVM.
It was planned to use a mocked filesystem for generated Jasmin-files and class-files during tests.
Unfortunately we cannot call jasmin.jar and the produced class-files via Runtime.getRuntime.exec
, as the command starts a new process.
An in-memory filesystem would work great, if we could use all functions in one process.
As a trade-off, gradle deletes the generated files after running the tests.