# μRust: A Simple Rust Programming Language
**Compiler 2023 Programming Assignment III
Compiler for Java Assembly Code Generation
Due Date: 2023/06/16**
[Lab3 link](https://classroom.github.com/assignment-invitations/d1e9fb450f3ab4328182a184a188b8f3)
This assignment is to generate Java assembly code (for Java Virtual Machines) of the given μRust program. The generated code will then be translated to the Java bytecode by the Java assembler, Jasmin. The generated Java bytecode should be run by the Java Virtual Machine (JVM) successfully.
* Environmental Setup
* OS: Ubuntu 20.04 LTS
* Install dependencies: ```$ sudo apt install flex bison```
* Java Virtual Machine (JVM): ```$ sudo apt install default-jre```
* Java Assembler (Jasmin) is included in the Compiler hw3 le.
* Judgmental tool: ```$ pip3 install local-judge```
## Java Assembly Code Generation
In this assignment, you have to build a μRust compiler. The descriptions for the execution steps are as follows.
1. Build your μRust compiler by injecting the Java assembly code into your flex/bison code developed in the previous assignments.
2. Run the compiler with the given μRust program (e.g., test.rs le) to generate the corresponding Java assembly code (e.g., test.j le).
3. Run the Java assembler, Jasmin, to convert the Java assembly code into the Java bytecode (e.g., test.class le).
4. Run the generated Java bytecode (e.g., test.class le) with JVM and display the results.
## Workflow Of The Assignment
You are required to build a μRust compiler based on the previous two assignments. The execution steps are described as follows.
1. Build your compiler by make command and you will get an executable named mycompiler .
2. Run your compiler using the command ```$ ./mycompiler < input.rs``` , which is built by lex and yacc, with the given μRust code ( .rs le) to generate the corresponding Java assembly code ( .j le).
3. The Java assembly code can be converted into the Java Bytecode ( .class le) through the Java assembler, Jasmin, i.e., use ```$ java -jar jasmin.jar hw3.j``` to generate Main.class .
4. Run the Java program ( .class le) with Java Virtual Machine (JVM); the program should generate the execution results required by this assignment, i.e., use ```$ java Main``` to run the executable.
## What Should Your Compiler Do?
In Assignment 3, the flex/bison only need to print out the error messages, we score your assignment depending on the JVM execution result, i.e., the output of the command: ```$ java Main .```
When ERROR occurs during the parsing phase, we expect your compiler to print out ALL error messages, as Assignment 2 did, and **DO NOT** generate the Java assembly code (.j le).
Each test case is 7pt, and you can check the correctness by local-judge (type judge command in your terminal) as hw1 and hw2.
## Submission
We use GitHub Classroom to collect assignments from students. Push your code to Github before the deadline.
## Demonstration of Your Assignment 3
The form and schedule of demonstration will be announced on Moodle later. During the demonstration, you will be asked to demonstrate your assignment downloaded from Moodle and you need to answer the questions about the logics of your codes in 5 ~ 10 minutes. Note that TA will verify that your compiler is not hardcoded to the attached inputs and outputs. For the hardcoded case, you will get 0pt.
## Reference
* Jasmin instructions: http://jasmin.sourceforge.net/instructions.html
* Java bytecode instruction listings:
https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
* Java Language and Virtual Machine Specications: https://docs.oracle.com/javase/specs/
* The Rust (not μRust) Playground: https://play.rust-lang.org/
## Appendix (Jasmin Instructions)
In this section, we list the Jasmin instructions that you may use in developing your compiler. Please note that the assignment are not limited to using the commands and approaches introduced below.
### Setup Code
A valid Jasmin program should include the code segments for the execution environment setup. Your compiler should be able to generate the setup code, together with the translated Jasmin instructions (as shown in the previous paragraphs). The example code is listed as below.
```jasmin
.source hw3.j
.class public Main
.super java/lang/Object
; ... Your generated Jasmin code for the input μRust program ...
.method public static main([Ljava/lang/String;)V ; main function
.limit stack 100 ; Define your storage size.
.limit locals 100 ; Define your local space number.
; ... Your generated Jasmin code for the input μRust program ...
return
.end method
```
### Literals
| Constant in μRust | Jasmin Instruction |
| -------- | -------- |
| 25 | ldc 25 |
| 3.14 | ldc 3.14 |
| "Hi" | ldc "Hi" |
| true / false | iconst_1 / iconst_0 |
### Print
The following example shows how to print out the constants with the Jasmin code. Note that there is a little bit dierent for the actual parameters of the println functions invoked by the invokevirtual instructions, i.e., i32 ( I ), f32 ( F ), and string ( Ljava/lang/String; ). Note also that you need to treat bool type as string when encountering print statement, and the corresponding code segments are shown as below.
* μRust Code
```rust
println(30)
print("Hello")
```
* Jasmin Code (for reference only)
```jasmin
ldc 30 ; integer
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
invokevirtual java/io/PrintStream/println(I)V
ldc "Hello" ; string
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
```
### Operations
#### Unary Operators
| μRust Operator | Jasmin Instruction(i32) | Jasmin Instruction(f32) |
| -------- | -------- | -------- |
| + | (ignore) | (ignore) |
| - | ineg | fneg |
#### Binary Operators
| μRust Operator | Jasmin Instruction(i32) | Jasmin Instruction(f32) |
| -------- | -------- | -------- |
| + | iadd | fadd |
| - | isub | fsub |
| * | imul | fmul |
| / | idiv | fdiv |
| % | irem | - |
#### Bitwise Operators
| μRust Operator | Jasmin Instruction |
| -------- | -------- |
| & | iand |
| \| | ior |
| ^ | ixor |
| << | ishl |
| >> | iushr |
The following example shows the standard unary and binary arithmetic operations in μRust and the corresponding Jasmin instructions.
* μRust Code
```rust
-5 + 3 * 2;
```
* Jasmin Code (for reference only)
```jasmin
ldc 5
ineg
ldc 3
ldc 2
imul
iadd
```
### Store/Load Variables
The following example shows how to load the constant at the top of the stack and store the value to the local variable ( x = 9; ). In addition, it then loads a constant to the Java stack, loads the content of the local variable, and adds the two values before the results are stored to the local variable ( y = 4 + x; ). Furthermore, the example code exhibits how to store a string to the local variable ( z = "Hello"; ). The contents of local variables after the execution of the Jasmin code are shown as below.
* μRust Code
```rust
x = 9;
y = 4 + x;
z = "Hello";
```
* Jasmin Code (for reference only)
```jasmin
ldc 9
istore 0 ; store 9 to x
ldc 4
iload 0 ; load x
iadd ; add 4 and x
istore 1 ; store the result to y
ldc "Hello"
astore 2 ; store a string to z
```
### Jump Instruction
| Jasmin Instruction | Description |
| -------- | -------- |
| goto <label> | direct jump |
| ifeq <label> | jump if zero |
| ifne <label> | jump if nonzero |
| iflt <label> | jump if less than zero |
| ifle <label> | jump if less than or equal to zero |
| ifgt <label> | jump if greater than zero |
| ifge <label> | jump if greater than or equal to zero |
* μRust Code
```rust
if x == 10 {
/* do something */
} else {
/* do the other thing */
}
```
* Jasmin Code (for reference only)
```jasmin
iload 0 ; load x
ldc 10 ; load integer 10
isub
ifeq L_cmp_0 ; jump to L_cmp_0 if x == 0
; if not, execute next line
iconst_0 ; false (if x != 0)
goto L_cmp_1 ; skip loading true to the stack
; by jumping to L_cmp_1
L_cmp_0: ; if x == 0 jump to here
iconst_1 ; true
L_cmp_1:
ifeq L_if_false
; -> do something
goto L_if_exit
L_if_false:
; -> do the other thing
L_if_exit:
```
### Type Conversions
The following example shows the usage of the casting instructions, i2f and f2i , where x is i32 local variable 0.
* μRust Code
```rust
x = x + 6.28 as i32;
```
* Jasmin Code (for reference only)
```jasmin
iload 0
ldc 6.28
f2i
iadd
istore 0
```
### Method Invocation
There are several forms of method-calling instructions in the JVM. In this homework, methods are called using the invokestatic instruction. The usage can be shown by following example. A function foo has signature (II)I that you have implemented in hw2, and this information is used during the code generation. The invokestatic Main/foo(II)I is used to invoke the method foo after two actual argumants ( 3 , 4 ) are loaded to the stack, and then the result of the function output will be pushed to the stack.
* μRust Code
```rust
fn foo(x: i32, y: i32) ->i32 {
return x + y;
}
fn main() {
let z: i32 = foo(3, 4);
println(z);
}
```
* Jasmin Code (for reference only)
```jasmin
.method public static foo(II)I ; Define foo function
.limit stack 20
.limit locals 20
iload 0 ; load the first argument
iload 1 ; load the second argument
iadd
ireturn
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 100
.limit locals 100
ldc 3 ; push argument to the stack
ldc 4 ; push argument to the stack
invokestatic Main/foo(II)I ; invoke `foo` method in `Main` class
istore 2 ; store the result to z
iload 2 ; load z for println
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
invokevirtual java/io/PrintStream/println(I)V
return
.end method
```