Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
=== lcc-wasm fork: a WebAssembly back end for lcc ===
This fork of drh/lcc adds a WebAssembly target, so lcc can compile C to a
runnable .wasm module. The goal is an in-browser C compiler small enough to
ship into a web page (unlike the multi-megabyte clang/emscripten toolchain).
It works today: real C -- arithmetic, loops, if/switch, recursion, pointers,
arrays, structs, function pointers -- compiles and runs in node AND the browser.
See examples/hello-world for a complete, runnable demo (199-byte module).
--- Quick start -------------------------------------------------------
# 1. build the compiler (clang needs relaxed flags for K&R-era source;
# they live in custom.mk, so a plain make works)
make BUILDDIR=build rcc
# 2. compile C -> WebAssembly text -> binary
build/rcc -target=wasm foo.c > foo.wat # our back end emits .wat
wat2wasm foo.wat -o foo.wasm # WABT assembles to .wasm
# (brew install wabt)
# 3. run it -- see examples/hello-world
cd examples/hello-world && ./build.sh
node run-node.js # -> Hello, world from lcc-wasm!
node serve.js # then open http://localhost:8080/
There is no libc yet: a program reaches the outside world by calling functions
IMPORTED from the host (node/browser JS), exactly as a winweb app calls its
runtime. hello.c imports putchar(); the JS host supplies it.
--- How the back end works --------------------------------------------
src/wasm.c (registered in bind.c) emits .wat text and leaves binary encoding to
wat2wasm. It follows the bytecode.c model -- wants_dag=0, no lburg/register
allocation -- because lcc emits its IR in post-order, which is already
WebAssembly's stack-machine evaluation order. Scalar, non-address-taken
locals/params become wasm locals; address-taken/aggregate locals live on a
shadow stack in linear memory (global $sp); globals/strings become (data)
segments; goto-style control flow becomes a br_table "giant loop" dispatch;
function pointers use an indirect (table) + call_indirect. Output is buffered
into import/memory/table/func/export/data so it assembles in module order.
For the full opcode-by-opcode mapping (LCC IR <-> WAT) with worked, verified
examples, see doc/wasm-codegen.md.
--- Status (milestones; see PLAN.md in the repo root) -----------------
M1 DONE arithmetic/bitwise/shift/casts, scalar locals, direct calls, return
M2 DONE control flow: for/while/if/switch/recursion (br_table dispatch)
M3 DONE linear memory + shadow stack; globals/strings; loads/stores;
pointers, arrays, struct fields
M4 DONE function pointers (call_indirect), struct copy, struct-by-value,
varargs (shadow-stack arg-buffer ABI)
M6 DONE self-host: lcc compiled to wasm (rcc.wasm) compiles + runs C in node
AND the browser, byte-identical to native -- see examples/self-host
M7 DONE direct binary emit: -target=wasm-bin writes .wasm with no wat2wasm
(drops the in-browser wabt dependency)
M5 next winweb integration: wire rcc.wasm into the in-page Win32 runtime
Upstream lcc README follows.
----------------------------------------------------------------------
This hierarchy is the distribution for lcc version 4.2.
lcc version 3.x is described in the book "A Retargetable C Compiler:
Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1).
There are significant differences between 3.x and 4.x, most notably in
the intermediate code. For details, see
https://drh.github.io/lcc/documents/interface4.pdf.
VERSION 4.2 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT
UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION.
LCC is a C89 ("ANSI C") compiler designed to be highly retargetable.
LOG describes the changes since the last release.
CPYRIGHT describes the conditions under you can use, copy, modify, and
distribute lcc or works derived from lcc.
doc/install.html is an HTML file that gives a complete description of
the distribution and installation instructions.
Chris Fraser / cwf@aya.yale.edu
David Hanson / drh@drhanson.net