@tabnas/gbnf
v0.1.8
Published
llama.cpp GBNF grammar compiler for the tabnas parser.
Maintainers
Readme
@tabnas/gbnf
GBNF grammar compiler for the
tabnas parser.
Takes GBNF source (the
llama.cpp
dialect — ::= and |, case-sensitive literals, a mandatory root)
and emits a tabnas GrammarSpec. Installed on an engine, the spec
parses inputs in that grammar and builds a {rule, src, kids} AST — so
you can answer "does this string match my grammar?" without loading a
model.
Install
npm install @tabnas/parser @tabnas/bnf @tabnas/gbnfUse
const { Tabnas } = require('@tabnas/parser')
const { gbnf } = require('@tabnas/gbnf')
const tn = new Tabnas({ plugins: [gbnf] })
tn.gbnf(`root ::= "hi" | "hello"`)
tn.parse('hi') // => ({ rule: 'root', src: 'hi', kids: [] })Exact by construction
GBNF is scannerless: the grammar accounts for every character, including the spaces. The engine's defaults are JSON-shaped and lenient, so the emitted spec turns them off — empty ignore set, no space/line/comment/ string/number/text matchers. What is left is the grammar's own fixed tokens (its literals) and match tokens (its classes).
const { Tabnas } = require('@tabnas/parser')
const { gbnf } = require('@tabnas/gbnf')
const tn = new Tabnas({ plugins: [gbnf] })
tn.gbnf(`root ::= "a" "b"`)
tn.parse('ab').src // => 'ab'
let rejected = false
try { tn.parse('a b') } catch (e) { rejected = true }
rejected // => trueWhether the empty input is in the language is settled at compile time,
because the engine short-circuits '' before any rule runs: the
compiler walks the IR for a derivation of the empty string from root
and emits lex: { empty: … } to match.
const { gbnfConvert } = require('@tabnas/gbnf')
gbnfConvert(`root ::= "x"`).options.lex // => ({ empty: false, relex: true })
gbnfConvert(`root ::= "x"*`).options.lex // => ({ empty: true, relex: true })The validator CLI
gbnf-check installs with the package: compile a grammar, check
samples against it, read the exit code (0 all accepted, 1 a
rejection, 2 no compile, 3 usage). --json emits a stable report
for tooling and AI agents.
npx gbnf-check grammar.gbnf sample.txt
npx gbnf-check grammar.gbnf --text 'candidate' --jsonSee doc/reference.md for options, exit codes, and the JSON report shape.
What this package owns
Only the notation. The compilation itself — desugaring repetition into
helper rules, left-recursion elimination, probe dispatch, literal
lifting, token allocation, first-set analysis, chain emission — lives in
@tabnas/bnf, shared with the ABNF and
EBNF front-ends:
GBNF text ──parseGbnf──▶ Grammar IR ──emitGrammarSpec──▶ GrammarSpecsrc/converter.ts is the first arrow (a tabnas grammar that reads GBNF,
plus the terminal decoders and the lexer settings the spec carries);
src/gbnf.ts is the plugin facade.
Documentation
Four-quadrant Diátaxis docs:
- tutorial.md — learning-oriented: zero to a working parser, step by step.
- guide.md — task-oriented recipes for real problems.
- reference.md — the exact API and GBNF syntax supported.
- concepts.md — how the compiler works and why.
- known-gaps.md — where this and llama.cpp diverge, and what causes each divergence.
License
MIT. Copyright (c) Richard Rodger.
