Вы хотите:
line: TYPE CNAME (MIN | MAX | ALERT)* ";" -> foo
(Примечание: ()
вместо []
.)
В синтаксисе EBNF жаворонка [item]
означает «необязательный item
»и item*
означает «любое число (возможно, ноль) из item
».Таким образом, [item]*
означает «любое число (возможно, ноль) либо item
, либо ничего».Но «любое число ничего» бесконечно неоднозначно;вы не можете сказать, сколько всего в пустой строке есть.
Поскольку вы на самом деле не намерены требовать, чтобы пункты появлялись в строгой последовательности, вы могли подумать о
line: TYPE CNAME ([MIN] [MAX] [ALERT])* ";" -> foo
Это было бы более точно, но это также привело бы к тому же сообщению об ошибке.В общем, вы не можете использовать звезду Клини на обнуляемом подшаблоне.Некоторые генераторы EBNF исправят это, удалив ε из повторного набора (а затем сделав повторение в целом необязательным), но lark не является одним из них.В этом случае исправление тривиально, но есть и другие случаи, в которых оно более раздражает.
Как регулярные выражения, (a* b*)*
, (a? b?)*
и (a|b)*
эквивалентны в том смысле, что все они распознаюттот же язык.Но регулярные выражения общеизвестно неоднозначны, и парсеры обычно предпочитают однозначные грамматики или, в худшем случае, конечно неоднозначные грамматики.Только последнее регулярное выражение попадает в эту категорию, и именно эту форму вы обычно предпочитаете.