Я добавил ноль-или-больше и один-или-больше модификаторов в мой синтаксический анализатор PEG , что довольно просто, поскольку в PEG так мало возвратов. Более ранние итерации никогда не пересматриваются, поэтому достаточно простого цикла while
.
Однако в других контекстах модификаторы «ноль или более» и «один или более» требуют возврата назад. Например, возьмем следующее регулярное выражение:
(aa|aaa)+
Это выражение должно иметь жадное совпадение со строкой из семи a
: есть несколько способов сложить 2 и 3, чтобы получить 7. Но для этого необходимо пересмотреть более ранние итерации. Например, если выражение соответствует трем a
в первый раз и трем a
во второй раз, остается только один a
, который не может быть сопоставлен. Возвратите последние три a
и сопоставьте два a
вместо этого, и пять a
соответствуют. Тогда последние два a
также могут быть сопоставлены (то есть 3 + 2 + 2 = 7).
К счастью, регулярное выражение завершает поиск, как только оно соответствует строке. Но как насчет парсера EBNF ? Если грамматика неоднозначна, синтаксический анализатор должен использовать обратную трассировку, чтобы найти все возможные синтаксические деревья ! Если у нас есть производство
( "aa" | "aaa" )*
и строка из семи a
, полностью возвращающий парсер вернул бы все возможные способы выражения 7 через 2 и 3. И это только для семи a
: соответствует немного более длинной строке, и N -дное дерево возможностей вырастает еще один уровень . Рассмотрим N = 6:
S : ( T )*
;
T : A
| B
| C
| D
| E
| F
;
Страшный комбинаторный взрыв!
Может ли это действительно иметь место, хотя? Нет ли ограничений на модификаторы «ноль или более» и «один или более» в EBNF? Реализация их, как описано, будет намного больше работы, чем простой цикл while()
анализатора PEG, поэтому я должен задаться вопросом ...