Alternation: longest match vs. first match¶
RFC 5234 does not specify the precise behavior of alternation. The ABNF definition of ABNF appears to assume longest match, but other grammars expect first match — for example, Dhall. abnf therefore makes the behavior configurable per grammar.
The class attribute Rule.first_match_alternation selects the behavior for a
particular grammar (represented by a Rule subclass):
False(default) — alternation returns the longest match. In the event of a tie, the first match (by declaration order) is returned.True— the first matching alternative is returned.
from abnf import Rule
class FirstMatchGrammar(Rule):
first_match_alternation = True
Why it matters¶
Consider astring = 1*ASTRING-CHAR / string. Under longest-match semantics, the
parser must try both arms and compare — it cannot commit to 1*ASTRING-CHAR until
it knows string would not have matched more. Under first-match semantics, the
first arm that succeeds is taken immediately, which is cheaper but can change which
parse tree you get for an ambiguous grammar.
Choosing longest match is what makes abnf faithful to RFC grammars out of the box; choosing first match lets you model PEG-like grammars that depend on ordered choice. The trade-off in cost is discussed in Backtracking and caching and Rust backend performance.