// the take
A pure-Python LALR parser for C99/C11 (with partial C23 support), built on PLY-style lexing and parsing. It's aimed at anyone building tooling around C source — static analyzers, code generators, obfuscators — without wanting to bind to libclang or write their own grammar. It's the parser underneath cffi's declaration handling, which is the strongest real-world validation it has.
Zero external dependencies beyond the Python interpreter itself, so it's trivial to vendor into a tool without dragging in a C toolchain or libclang bindings. The AST node set is generated from a single _c_ast.cfg config via _ast_gen.py, so the grammar and the AST stay in sync instead of drifting as hand-maintained parallel structures. It follows the C99 Annex A grammar closely rather than an ad-hoc approximation, and it's been maintained and battle-tested since the late 2000s with CI across Linux/macOS/Windows and a real test suite covering lexer, parser, and generator round-trips.
It doesn't preprocess anything itself — you need a real cpp/gcc -E/clang -E on PATH before any non-trivial file will parse, which is an extra dependency and a platform-specific headache the README mostly hand-waves past. GCC extensions are only thinly supported, which matters a lot since most real-world C (kernel headers, glibc, anything autotools-era) leans on them; you'll be patching or stripping code before this will touch it. The 'fake libc' headers in utils/fake_libc_include are a workaround, not a real solution — they're hand-maintained, excluded from the pip package, and can silently diverge from what real headers declare, which bites you quietly on edge-case typedefs. And being a hand-rolled lex/yacc parser in pure Python, it's slow on large files; there's a dedicated benchmark folder because throughput is a known, unsolved concern rather than an edge case.
We read the README, the directory tree and a key source file in October 2026. Nobody pays to be listed. How we judge →