An educational foray into compiler writing. Written in C, compiling C to x86 assembly (handy x86 reference site, assembly directives reference, System V ABI reference).
Technically targeting C11 (standard PDF), but we will implement such a small subset of C that it's academic.
Table of Contents
- positive integers (no other types yet)
- integer constants
- logical negation (
!FOO) - bitwise negation (
~FOO) - addition (
foo + bar) - subtraction (
foo - barbinary only) - multiplication (
foo * bar) - less than comparison (
foo < bar,foo <= bar) - comments (
// fooand/* foo */) - sequences of statements (
foo; bar) - return statements
- if statements (
if (foo) { bar }, noelseyet) - local variables (
intonly, function scope only, must be initialised) - variable assignment (
intonly) - while loops (
while (foo) { bar }) - function calls (only
int foo()i.e. no arguments, returning int) - preprocessor usage (we shell out to gcc)
GPL v2 license.
You will need clang, lex and yacc installed. GNU Bison is known
to work, other yacc implementations may not.
Compiling babyc:
# Compile the compiler.
$ make
Usage:
# Run it, producing an assembly file.
$ build/babyc test_programs/immediate__return_1.c
# Use the GNU toolchain to assemble and link.
$ ./link
Viewing the code after preprocessing:
$ build/babyc --dump-expansion test_programs/if_false__return_2.c
Viewing the AST:
$ build/babyc --dump-ast test_programs/if_false__return_2.c
Running tests:
$ make test
If you're debugging a compiled program that segfaults, you may want to simply read the out.s file.
To use gdb (given we have no signal table, function prologues or other conveniences), do the following:
$ gdb out
(gdb) run
... it segfaults
(gdb) layout asm
... shows which line the segfault occurred on
(gdb) info registers
... shows the current state of the registers (`layout reg' also
... provides this data)
If you want to debug a program that doesn't segfault, you can set a breakpoint to the entrypoint:
$ gdb out
(gdb) info files
...
Entry point: 0x80000000
...
(gdb) break *0x80000000
(gdb) run
The make command will generate warnings, fix them. You can also run with clang-analyzer to catch further issues:
$ scan-build make
For code formatting, run:
$ make format