Lime Parser Generator 0.1.0
Runtime-extensible LALR(1) parser with SIMD tokenization and LLVM JIT
Loading...
Searching...
No Matches
Getting Started

Prerequisites

  • A C11 compiler: GCC 13+ or Clang 15+
  • Meson 0.60+ and Ninja (for the extension framework)
  • Optional: LLVM 14-21 (for JIT; verified on 14.0.6 and 21.1.8), Valgrind (for memory checking)

All dependencies are provided by nix develop if you use Nix.

Building the Generator

Lime's parser generator is a single C file with no dependencies:

cc -o lime lime.c

That's it. You now have a working parser generator.

Your First Grammar

Create expr.lime (the recommended extension; .y also works for compatibility with existing tooling, but .lime avoids confusion when a project has both Bison and Lime grammars side by side during a migration):

%token_type { int }
%type expr { int }
%left PLUS MINUS.
%left TIMES DIVIDE.
program ::= expr(A). { printf("Result: %d\n", A); }
expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }
expr(A) ::= expr(B) MINUS expr(C). { A = B - C; }
expr(A) ::= expr(B) TIMES expr(C). { A = B * C; }
expr(A) ::= expr(B) DIVIDE expr(C). { A = B / C; }
expr(A) ::= INTEGER(B). { A = B; }

Generate the parser:

./lime expr.lime

This produces expr.c and expr.h. The generated parser is a push-parser: you feed it tokens one at a time.

Writing a Driver

Create main.c:

#include <stdio.h>
#include <stdlib.h>
#include "expr.h"
void *ParseAlloc(void *(*allocProc)(size_t));
void ParseFree(void *parser, void (*freeProc)(void *));
void Parse(void *parser, int tokenCode, int tokenValue);
int main(void) {
void *parser = ParseAlloc(malloc);
/* Feed tokens: 3 + 4 * 2 */
Parse(parser, INTEGER, 3);
Parse(parser, PLUS, 0);
Parse(parser, INTEGER, 4);
Parse(parser, TIMES, 0);
Parse(parser, INTEGER, 2);
Parse(parser, 0, 0); /* end of input */
ParseFree(parser, free);
return 0;
}

Compile and run:

cc -o calc main.c expr.c
./calc
# Output: Result: 11

Building the Extension Framework

If you need runtime grammar extension, SIMD tokenization, or JIT:

meson setup builddir
ninja -C builddir
ninja -C builddir test

This builds:

  • The lime generator
  • liblime_parser.a — the extension framework library
  • All tests and benchmarks

LLVM / JIT Build Options

Meson flag Effect
-Dllvm=auto (default) Enable JIT if llvm-config is found, otherwise build stubs
-Dllvm=enabled Require LLVM; hard error at configure if absent
-Dllvm=disabled Never probe; build stubs only (no libLLVM in ldd)
-Dllvm-static=true Statically link LLVM into the binary (no runtime libLLVM.so dependency; binary grows by 50-80 MB)

If multiple llvm-config binaries are on PATH (common on Linux distros that ship several LLVM versions side by side) set LLVM_CONFIG=/path/to/llvm-config before meson setup to pin the choice. The flake's devShell does this automatically.

Useful Flags

Flag Description
-d dir Write output files to dir
-T file Use a custom parser template instead of limpar.c
-s Print parser statistics (states, rules, conflicts)
-L Lint: validate grammar without generating code
-F Format: rewrite grammar with consistent style
-q Quiet: don't generate the .out report file
-l Omit #line directives from generated code
-x Print version and exit

Next Steps

  • Concepts — understand snapshots, extensions, and conflict resolution
  • Integration — embed Lime in your project
  • Extensions — write runtime grammar extensions
  • Examples — working examples from calculators to full PostgreSQL grammars
  • API Reference — complete C API documentation