- Java 14
- Bash shell
- Connection to the internet
This project uses the gradle build system, which can self-bootstrap via
gradle/wrapper/graddle-wrapper.jar
.
As such, all the Makefile
does is invoke gradle to build the jar artifact.
If gradle has not been set up before, the self-bootstrapping process will
download all the requirements, freeing you from having to install anything
besides Java 14.
This project uses Java 14 features, so you will need to pass --enable-preview
if you are running the jar file yourself.
This should be handled by the ./jlitec
wrapper script.
In your shell, run:
$ make
This actually simply invokes:
$ ./gradlew jar
In your shell, run:
$ ./jlitec
I recommend trying out list.j
, which is an interactive program to manipulate a linked-list.
Assuming you have installed GCC ARM cross-compiler and QEMU user binfmt, simply run:
./jlitec arm -O3 test/arm/list.j > /tmp/a.s
arm-linux-gnueabi-gcc /tmp/a.s -o /tmp/a.out --static
/tmp/a.out
To get the subcommands and options available, run:
$ ./jlitec --help
You can also get the details of a particular subcommand, for example:
$ ./jlitec reg --help
Use arm
to generate ARM assembly.
It also takes an optimization flag -O
:
-O0
is used if not specified, which disables any optimization.-O2
for optimizations on the Lower intermediate representation-O3
for additional peephole optimizations on the generated ARM assembly.
For example:
$ ./jlitec arm -O3 test/arm/gcd_fixed.j
.cpu cortex-a7
.global main
.type main, %function
main:
STMFD SP!, {R4, LR}
LDR R0, .S0
BL puts
MOV R1, #60
MOV R2, #50
BL Gcd_0
MOV R1, R0
LDR R0, .S1
BL printf
MOV R0, #0
LDMFD SP!, {R4, PC}
.global Gcd_0
.type Gcd_0, %function
Gcd_0:
L1:
CMP R1, R2
BEQ L2
CMP R1, R2
BLE L3
SUB R1, R1, R2
B L1
L3:
SUB R2, R2, R1
B L1
L2:
MOV R0, R1
BX LR
.S0:
.word .S0S
.S1:
.word .S1S
.section .rodata
.S0S:
.asciz "The GCD of 60 and 50 is:"
.section .rodata
.S1S:
.asciz "%d\n"
Use lower
to generate Lower intermediate code.
You can also use the flag --opt
to generate Lower intermediate code after optimization.
For example:
$ ./jlitec lower --opt test/arm/gcd_fixed.j
======= Data =======
class Main {
}
class Gcd {
}
======= Methods =======
Void main() {
// START OF SPILLED TO STACK
// END OF SPILLED TO STACK
Int a;
Int b;
Gcd _t1;
Int _t2;
R0 = "The GCD of 60 and 50 is:";
CALL puts;
R1 = 60;
R2 = 50;
CALL %Gcd_0;
_t2 <- R0;
R0 = "%d\n";
R1 <- _t2;
CALL printf;
return;
}
Int Gcd_0(Gcd this, Int a, Int b) {
// START OF SPILLED TO STACK
// END OF SPILLED TO STACK
a <- R1;
b <- R2;
L1:
if (a == b) goto L2;
if (a <= b) goto L3;
a = a - b;
goto L1;
L3:
b = b - a;
goto L1;
L2:
R0 <- a;
return;
}
Use check
to perform static check (distinct-name checking and type checking).
For example:
$ ./jlitec check test/arm/gcd_fixed.j
Static check succeeded!
Or in the case of failure:
$ ./jlitec check test/type/fail/overload.j
--> test/type/fail/overload.j:4:5
Semantic error: Call with signature `f(null)' on class `C' is ambiguous. Possible method overloads: f(B), f(C)
2 | Void main(){
3 | C c;
4 | c.f(null);
| ~~~~^^^ ambiguous method call `f(null)'
5 | return;
6 | }
Use ir3
to generate the IR3 intermediate code.
IR3 is actually not really used much in the compiler and what you probably want is the Lower intermediate code.
For example:
$ ./jlitec ir3 test/arm/gcd_fixed.j
======= CData3 =======
class Main {
}
class Gcd {
}
======= CMtd3 =======
Void main(Main this) {
Int a;
Int b;
Gcd _t1;
Int _t2;
a = 60;
b = 50;
println("The GCD of 60 and 50 is:");
_t1 = new Gcd();
_t2 = %Gcd_0(_t1, a, b);
println(_t2);
}
Int %Gcd_0(Gcd this, Int a, Int b) {
L1:
if (a == b) goto L2;
if (a <= b) goto L3;
a = a - b;
goto L4;
L3:
b = b - a;
L4:
goto L1;
L2:
return a;
}
To pretty print a JLite file, you can use the pretty_print
subcommand.
For example:
$ ./jlitec pretty_print test/arm/gcd_fixed.j
class Main {
Void main() {
Int a;
Int b;
a = 60;
b = 50;
println("The GCD of 60 and 50 is:");
println(new Gcd().gcd(a, b));
}
}
class Gcd {
Int gcd(Int a, Int b) {
while (a != b) {
if (a > b) {
a = a - b;
} else {
b = b - a;
}
}
return a;
}
}
There are 2 other subcommands available that you may find useful:
lex
to print out the CUP symbols generated by the lexer.parse_tree
to print out the parse tree in JSON format.