A C compiler written from scratch in Ruby, built in homage to kefir C.
occ is a complete C compiler pipeline — preprocessor, lexer, parser, semantic analyzer, IR builder, and code generator — implemented in pure Ruby. It targets ARM64 (Apple Silicon macOS) and AMD64 (Linux and macOS) natively, auto-detecting the host architecture at runtime.
The project is a learning exercise in compiler construction. It is not production-ready but successfully compiles and runs real-world C libraries including Lua 5.5, zlib, SQLite, and more.
Status: Phases 1–13 are broadly complete. miniruby builds and passes its full smoke suite (894 basictest assertions). The spec builds full ruby with C extensions (stringio, date, zlib, digest, json, psych, fiddle, socket, openssl, and more). The ARM64 backend performs linear-scan register allocation over callee-saved registers x19–x28 and applies several codegen quality passes that eliminate redundant register copies and memory round-trips, reducing vm_call0_body's stack frame from 3632 to 448 bytes.
Source (.c)
→ Preprocessor (#include, #define, conditionals)
→ Lexer (tokens with source locations)
→ Parser (AST — recursive descent, C11)
→ Semantic (type checking, symbol table)
→ IR Builder (three-address code, basic blocks)
→ Codegen (ARM64 or AMD64 assembly)
→ Assembler (via system `as`)
→ Linker (via `clang`)
→ Executable
- Ruby 3.4+
clangandas(for assembling and linking — standard on macOS, available via LLVM on Linux)
git clone <repo>
cd occ
bundle installbundle exec ruby bin/occ hello.c -o hello
./hellobundle exec ruby bin/occ -c hello.c -o hello.obundle exec ruby bin/occ hello.cbundle exec ruby bin/occ -I./include -DDEBUG=1 program.c -o programbundle exec ruby bin/occ a.c b.c c.c -o program// hello.c
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}bundle exec ruby bin/occ hello.c -o hello && ./hello
# Hello, world!// fib.c
#include <stdio.h>
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
int main(void) {
for (int i = 0; i < 10; i++) {
printf("%d\n", fib(i));
}
return 0;
}bundle exec ruby bin/occ fib.c -o fib && ./fib
# 0 1 1 2 3 5 8 13 21 34All phases:
bundle exec rspecA specific phase:
bundle exec rspec spec/phase8/Third-party compilation tests (requires network, ~5–15 min first run to clone repos):
THIRDPARTY=1 bundle exec rspec spec/phase11/thirdparty_spec.rbocc compiles and passes the test suites of the following real-world C projects:
| Library | Description | Tests |
|---|---|---|
| jsmn | JSON tokenizer (~300 lines) | 16/16 |
| tinyexpr | Math expression evaluator | 4930 |
| tiny-regex-c | Regex engine | 76 |
| munit | Unit test micro-framework | 11 |
| parson | JSON library | 349 |
| smaz | Short-string compression | all |
| sds | Simple dynamic strings | 46 |
| genann | Minimal neural network | 1077 |
| utf8.h | Header-only UTF-8 library | 156 |
| linenoise | Readline replacement | all |
| Lua 5.5 | Full scripting language interpreter | all |
| zlib 1.3.2 | Compression library | all |
| SQLite 3.47.2 | Embedded SQL database (~250K lines) | CRUD + txns |
bin/occ # CLI entry point
lib/occ/
driver.rb # top-level pipeline orchestration
preprocessor.rb # #include / #define / conditionals
lexer.rb # tokenizer
parser.rb # recursive-descent C11 parser
ast.rb # AST node definitions
types.rb # C type hierarchy
symbol_table.rb # scoped symbol table
semantic.rb # type checking and analysis
ir.rb # IR builder and data structures
codegen/
base.rb # shared codegen helpers
amd64.rb # AMD64 System-V ABI backend
arm64.rb # ARM64 Apple ABI backend
include/ # bundled system headers
spec/
phase1/ … phase11/ # per-phase RSpec suites
support/
thirdparty_helper.rb # git_clone, occ_compile, shell helpers
tmp/
thirdparty_cache/ # cached third-party repos (gitignored)
TBD