Compiler implemented in C++ using flex, bison, llvm and clang. A toy compiler for the PCL toy language which has many similarities with Pascal.
├── compile.sh
├── data
│ ├── bsort.pcl
│ ├── hanoi.pcl
│ ├── mandelbrot.pcl
│ ├── mean.pcl
│ ├── new_dispose.pcl
│ ├── primes.pcl
│ └── reverse.pcl
├── Dockerfile
├── pcl2019.pdf
├── README.md
└── src
├── ast.cpp
├── ast.hpp
├── codegen_table.cpp
├── codegen_table.hpp
├── lexer.hpp
├── lexer.l
├── libpcl.c
├── Makefile
├── parser.y
├── pcl.cpp
├── symbol_table.cpp
├── symbol_table.hpp
├── types.cpp
└── types.hpp
Root directory:
compile.sh:Simple helper script that takes the file to be compiled as input, builds the compiler and outputs an executable nameda.outdata:The data folder contains some basic example programs in pclDockerfile:Dockerfile with instructions on how to build the compiler imagepcl2019.pdf:This file contains the language descriptionREADME.md:This filesrc:The source files for the compiler
src directory:
ast.cpp/ast.hpp:Files describing the AST that is responsible for the semantic and code generation passescodegen_table.cpp/codegen_table.hpp:A data structure to store the llvm constructs during code generationlexer.hpp:File containing the current line variable declarationlexer.l:Flex input file to generate the compiler's scannerlibpcl.c:Built in library functions. The missing functions use the C math library directly insteadMakefile:A standard makefileparser.y:Bison input file with the language's grammar to generate the program's parserpcl.cpp:Main driver program that reads the command line arguments and calls the necessary functions to parse, check and generate the outputsymbol_table.cpp/symbol_table.hpp:A data structure to do record keeping for variables and functions during the semantic passtypes.cpp/types.hpp:Type declarations that are used during the semantic pass to perform checks
NOTE: Bison needs to be at least version 3.2.
Fedora
The compiler has been tested on Fedora 32 with llvm 10.0.0, clang 10.0.0, flex 2.6.4 and bison 3.5
To install the necessary dependencies run:
sudo dnf install make llvm llvm-devel clang flex bison
Arch
The compiler has been tested on Arch Linux with llvm 10.0.0, clang 10.0.0, flex 2.6.4 and bison 3.6.4
To install the necessary dependencies run:
sudo pacman -S make llvm clang flex bison
Ubuntu
The compiler has been tested on Ubuntu 20.04 with llvm 10.0.0, clang 10.0.0, flex 2.6.4 and bison 3.5.1
To install the necessary dependencies run:
sudo apt install make llvm clang flex bison
In order to compile a file directly use the compile.sh script that takes the file to be compiled as input
and outputs an executable named a.out
To use the script either invoke the shell directly:
sh compile.sh <input_file>
or add execution permissions to the script and then execute it:
chmod +x compile.sh
./compile.sh <input_file>
After the executable is created in the current folder simply execute it:
./a.out
Inside the src folder run:
maketo build the compiler executable and the pcl librarymake cleanto delete all intermediate filesmake distcleanto delete all intermediate files and the compiler
When the -O flag is supplied, llvm optimization passes are activated.
-
pcl [-O] <input_file>.pclto produce two files. One with the.immextension containing the llvm IR of the input program and one with the.asmextension containing the assembly output of the input program. -
pcl [-O] [-i|-f]when the input program is given in standard input and the output is given in standard output. When the-iflag is specified the output contains the llvm IR of the input program and when the-fflag is specified the output contains the assmebly output of the input program.
NOTE: The .imm and .asm files are created in the same directory as the input file.
Having the .asm file of the input, we can then link our output file with the libpcl.a library and the C math library using clang:
clang <input_file>.asm /path/to/libpcl.a [-o <output_file>] -lm
(Not recommended as the resulting image file can be quite big and the output file is inside the container unless a directory is mounted inside of it)
Upon building the docker image, the data and src folders along with the compile.sh file get copied into the image.
Therefore input files for the compiler should be inside the data folder before building the image.
- Run
docker build -t compiler . - Run
docker run -it compiler - You will be dropped into an interactive shell where you can run
sh compile.sh <input_file> - Run the produced executable by executing it
./a.out