Skip to content

davidwholm/miniracket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

miniracket

Compiler(s) built by working through Essentials of Compilation by Jeremy G. Siek.

Language Description

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)

Passes

The compiler has the following passes:

  • parse, takes a s-expression and produces an AST
  • shrink, desugars complex expressions into simpler core forms
  • uniquify, replaces all variables with unique names to make scoping and shadowing explicit
  • uncover-get!, marks all reads from mutated variables to make evaluation order specific
  • remove-complex-operands, simplifies all operands of primitive operations to be atomic, potentially resulting in additional temporary variables
  • type-check, type checks the program and associates types with all variables
  • explicate-control, flattens the AST into a linear sequence of C-like statements, and groups these into basic blocks
  • select-instructions, selects X86 instructions based on said C-like statements
  • build-control-flow, builds a control flow graph based on the basic blocks
  • uncover-live, performs liveness analysis on the program variables
  • build-interference, builds an interference graph based on the liveness analysis
  • allocate-registers, uses graph coloring to assign registers to variables when possible and spills them to the stack otherwise
  • patch-instructions, makes sure that all instructions are valid X86 (at most one memory reference per instruction, etc.), performing minor optimizations
  • prelude-and-conclusion, generates necessary prelude and conclusion to set up for the main code (stashing rbp, adjusting rsp etc.)
  • print-x86, takes the program and translates it into a string of valid X86 code, ready to be assembled

Usage

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

About

Compiler for a small Scheme-like language down to x86_64 assembly.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors