Compiler(s) built by working through Essentials of Compilation by Jeremy G. Siek.
program := expr
expr := integer | boolean | identifier | let | if | primitive | begin | while | set! | void
let := (let ((identifier expr)) expr)
if := (if expr expr expr)
primitive := (primitive-op expr*)
primitive-op := + | - | read | eq? | < | <= | > | >= | and | or | not
begin := (begin expr* expr)
while := (while expr expr)
set! := (set! identifier expr)
void := (void)
The compiler has the following passes:
parse, takes a s-expression and produces an ASTshrink, desugars complex expressions into simpler core formsuniquify, replaces all variables with unique names to make scoping and shadowing explicituncover-get!, marks all reads from mutated variables to make evaluation order specificremove-complex-operands, simplifies all operands of primitive operations to be atomic, potentially resulting in additional temporary variablestype-check, type checks the program and associates types with all variablesexplicate-control, flattens the AST into a linear sequence of C-like statements, and groups these into basic blocksselect-instructions, selects X86 instructions based on said C-like statementsbuild-control-flow, builds a control flow graph based on the basic blocksuncover-live, performs liveness analysis on the program variablesbuild-interference, builds an interference graph based on the liveness analysisallocate-registers, uses graph coloring to assign registers to variables when possible and spills them to the stack otherwisepatch-instructions, makes sure that all instructions are valid X86 (at most one memory reference per instruction, etc.), performing minor optimizationsprelude-and-conclusion, generates necessary prelude and conclusion to set up for the main code (stashingrbp, adjustingrspetc.)print-x86, takes the program and translates it into a string of valid X86 code, ready to be assembled
The compiler takes either a filename to read from or reads from stdin. It spits out x86 assembly code, which can be redirected to file.
$ racket main.rkt > program.S
(let ([x 0])
(begin
(while (< x 10)
(set! x (+ x 1)))
(+ x 32)))^D
$ cat program.S
.globl _main
_block2920:
movq %rcx, %rax
addq $32, %rax
jmp _conclusion
_loop_header2918:
cmpq $10, %rcx
jl _loop_body2919
jmp _block2920
_loop_body2919:
addq $1, %rcx
jmp _loop_header2918
_main:
pushq %rbp
movq %rsp, %rbp
jmp _start
_start:
movq $0, %rcx
jmp _loop_header2918
_conclusion:
popq %rbp
retq
$ gcc program.S runtime.c -o program
$ ./program
$ echo $?
42