Digging deeper into grammars and PEG in special, I wanted to have a DSL with the following syntax:
a OR (b AND c)
I am using parsimonious
here with the following grammar:
from parsimonious.grammar import Grammar
grammar = Grammar(
"""
expr = (term operator term)+
term = (lpar term rpar) / (variable operator variable)
operator = and / or
or = _? "OR" _?
and = _? "AND" _?
variable = ~r"[a-z]+"
lpar = "("
rpar = ")"
_ = ~r"\s*"
"""
)
print(grammar.parse('a OR (b AND c)'))
However, this fails for the above text with
parsimonious.exceptions.ParseError: Rule 'variable' didn't match at '(b AND c)' (line 1, column 6).
Why? Haven't I specified term
as ( term )
or term
?
Why does it choose the rule for variable
instead (which of course fails) ?
The first thing in expr
is a term
, so that's what the parser looks for.
A term
in your grammar is either
( term )
or
variable operator variable
And the input is
a OR (b AND c)
That doesn't start with a (
so the only way it can be a term
is if it matches variable operator variable
. a
is a variable
; OR
is an operator
. So the next thing to match is variable
.
Perhaps what you want is:
expr = term (operator term)*
term = (lpar expr rpar) / variable