Skip to the content.

Grammar-level directives

Directives appear at the top of the file (before or after rules; order does not matter) and configure the generated grammar.js. All of them map directly to the same-named fields in grammar.js, except %axiom (which controls rule order) and %include (which merges files). A warning is printed to stderr for any referenced rule name that has no definition.

%extras

Declares tokens that may appear anywhere in the input — typically whitespace and comments:

%extras /\s/, comment

generates:

extras: $ => [/\s/, $.comment],

Without this directive, tree-sitter’s built-in default (skip whitespace everywhere) applies.

%conflicts

Declares rule pairs that are expected to be ambiguous, allowing tree-sitter’s GLR parser to resolve them at parse time rather than aborting grammar generation:

%conflicts [expr, term]
%conflicts [foo, bar, baz], [a, b]

generates:

conflicts: $ => [
  [$.expr, $.term],
  [$.foo, $.bar, $.baz],
  [$.a, $.b],
],

%inline

Lists rules to substitute at every call site during parser-table generation. Typically used for hidden helper rules that exist as structural glue:

%inline _helper, _wrapper

%supertypes

Lists abstract rule names that act as union types over concrete subtypes. This enriches the type annotations in language bindings:

%supertypes expression, statement, declaration

%axiom

Declares an explicit root (start) rule. Without %axiom, tree-sitter treats the first rule declared as the start symbol. Use %axiom when you want to debug a sub-rule in isolation — temporarily redirect the entry point without rearranging the file:

%axiom expr

top_level -> stmt+ ;
expr      -> term ('+' term)* ;
term      -> /[0-9]+/ ;

convert silently emits expr first in grammar.js’s rules: block so tree-sitter uses it as the start symbol, while the BNF file keeps its original declaration order.

Declaring %axiom more than once is an error, as is naming a rule that is not defined anywhere in the file.

%include

Merges another BNF file into the current grammar at the point of the directive:

%include "expressions.bnf"

Paths are relative to the including file. Includes may be nested (A includes B includes C); circular includes (A includes B includes A) are detected and reported as an error. All directives from included files are merged additively. Duplicate rule names produce a warning (last definition wins); duplicate %axiom declarations across files are an error. %include cannot be used when reading from stdin.


Previous: Syntax walkthrough · Next: Cheat sheet