@tabnas/gbnf
v0.1.17
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 the 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: an 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 shared
compiler @tabnas/bnf reads the start rule's nullability off the IR 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.
