ebnf

Zero or one of each item in any order?


How can I write a grammar that expresses a set of items that can appear zero or one times each, in any order?

e.g. A B C is valid, A C is valid, C B A is valid, A A B is invalid, A B A is invalid.

This rule enforces zero or one of each element, but also enforces a set order:

rule_1: A? B? C?

This permits any order, but also permits more than one of each:

rule_2: (A | B | C)*

This is using the Lark parser for Python - I'm unsure if this question should be tagged [lark-parser]?


Solution

  • (E)BNF handles context-free languages and a context-free language can't directly express that constraint. You have to do it explicitly like this left-factored form (others are possible but not meangingfully better)

    opts = (A nonA | B nonB | C nonC)?
    nonA = (B nonAB | C nonAC)?
    nonB = (A nonAB | C nonBC)?
    nonC = (A nonAC | B nonBC)?
    nonAB = C?
    nonAC = B?
    nonBC = A?
    

    which quickly becomes unmanageable as the number of things grows.