Skip to content

SPL Compiler in Rust, Semester Project of CS323 Compilers

License

Notifications You must be signed in to change notification settings

chanbengz/SUSTech_CS323_Project_Incredibuild

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SUSTech CS323 Project: Incredibuild

SPL(SUSTech Programming Language) Compiler in Rust

Features

  • SPL Grammar:
    • Lexer & Parser
    • Semantic Analyser
    • Macro
  • LLVM IR Generation
  • Optimization
    • SSA
  • Advanced
    • Lifetime Analysis

Getting Started

At first, you need to setup the environment by installing Rust, Cargo and LLVM, please follow instruction in development section. Then you can build the project by running

cargo build

and emit the assembly code by running

cargo run /path/to/input.spl -o /path/to/output.S

or check the LLVM IR by running

cargo run /path/to/input.spl --llvm-ir -o /path/to/output.ll

Finally, to execute the program, you can use LLVM's interpreter or compile the assembly

cc /path/to/output.S -o /path/to/output
./output

# or
lli /path/to/output.ll

Warning

Some of the functionalities are weird in release mode.

See target/debug/incredibuild -h for more options.

File structure

.
├── Cargo.toml # Binding of submodules
├── Dockerfile # Build the environment for the project
├── docs
│   ├── cs323-project-tutorial1.pdf
│   ├── cs323-project-tutorial2.pdf
│   ├── cs323-project-tutorial3.pdf
│   ├── cs323-project-tutorial4.pdf
│   ├── midterm-project-check.pdf
│   ├── slides     # Presentation slides
│   ├── syntax.txt # SPL syntax spec
│   └── token.txt  # token spec
├── LICENSE
├── README.md
├── src
│   ├── analyser
│   │   ├── Cargo.toml # Define your dependencies in the sub-project
│   │   └── src # In lib.rs please pub mod all the crates.
│   ├── ast
│   │   ├── Cargo.toml
│   │   └── src
│   ├── irgen
│   │   ├── Cargo.toml
│   │   └── src
│   ├── lexer
│   │   ├── Cargo.toml
│   │   └── src
│   ├── main.rs # warpper
│   └── parser
│       ├── build.rs # lalrpop parser generator
│       ├── Cargo.toml
│       └── src
└── test
    ├── phase1 # Lexical & Syntax
    ├── phase2 # Semantic
    ├── phase3 # LLVM IR Generation
    ├── phase4 # Binary Generation
    ├── mid    # Midterm check phase1-2
    ├── final  # Final check phase3-4
    ├── test_0_r00.spl # Minimal testcase
    ├── test_0_r00.ll  # LLVM IR of the minimal testcase
    └── test_0_r00.out # Sample output

Development

Setting up environment might be a struggling process, you can use docker to build up the environment.

docker build -t incredibuild .

You can also choose to download the image we have already built from Docker Hub.

docker pull jaredanjerry/incredibuild:20241106 # Approximately 4.5GB

After building the project, you can set up the project by running an iteractive shell in the container. (Please mount the project root path to /incredibuild)

cd <project-root-path>
docker run -it --rm -v $(pwd):/incredibuild incredibuild
cargo run

If you want to compile files in the third stage, you may have to use -no-pie to exiplicit disable PIE(Position Independent Executable) in the gcc command.

gcc -no-pie test_printf -o test

"Bare Metal" Mac

If you're using Mac, make sure you have Rust and Cargo installed. Install LLVM environment by

brew install llvm # or use the package manager you prefer

# find where llvm is installed, for example
export LLVM_SYS_170_PREFIX=/opt/homebrew/Cellar/llvm/19.1.2 # pretend to be LLVM@17 :)

Testing

You can run test in each crate by using cargo test in the root folder. For example

cd src/lexer # or parser/analyser/irgen
cargo test

Issue

If you face network issue, luckily you can find two ways out.

  1. Modify /etc/systemd/system/docker.service.d/http-proxy.conf to add proxy.

    [Service]
    Environment="HTTP_PROXY=http://your-proxy:port"
    Environment="HTTPS_PROXY=http://your-proxy:port"
    

    Then restart docker service.

    sudo systemctl daemon-reload
    sudo systemctl restart docker
  2. Add Registry Mirror in /etc/docker/daemon.json.

    {
        "registry-mirrors": ["<your-mirror>"]
    }

Reference

Our presentation slides are available here (Chinese)

Acknowledgement: