Откат FParsec во вложенном парсере

Я хочу анализировать выражения, построенные так: a is x or y or z or b is z or w, поэтому в основном у меня есть один и тот же разделитель для разных правил в моей грамматике.

Мне уже удалось разобрать такие выражения с помощью Antlr, поскольку он может довольно хорошо выполнять возврат. Но теперь я хочу разобрать его с помощью FParsec, и у меня не получается, чтобы внутренний парсер не был жадным. Мои текущие парсеры выглядят так:

let variable = // matches a,b,c,...

// variables ::= variable { "or" variable }+ ;
let variables =
    variable .>>? keyword "or" .>>.? (sepBy1 variable (keyword "or"))

let operation =
    variable .>>? keyword "is" .>>.? variables

// expression ::= operation { "or" operation }+ ;
let expression =
    operation .>>? keyword "or" .>>.? (sepBy1 variable (keyword "or"))

В моем примере синтаксический анализатор переменных использует x or y or z or b, и все это терпит неудачу в is. Это означает, что мне нужно сделать этот парсер variables менее жадным или сделать его корректным.

Я нашел похожий вопрос, где они делают версию sepBy1 с откатом, но использование этого по-прежнему не решает мою проблему. проблема. Я предполагаю, что это потому, что я хочу вернуться к вложенному парсеру.

Так как же правильно заставить FParsec принять мой ввод?


person danielspaniol    schedule 28.06.2018    source источник
comment
Я чувствую, что основная причина вашей проблемы заключается в том, что ключевое слово or имеет два разных значения. Если я правильно анализирую выражение вашего примера, вы хотите, чтобы оно анализировалось как (a is (x or y or z)) or (b is (z or w)), верно? Таким образом, одно и то же ключевое слово or означает Альтернативы для одного совпадения is, а также означает, что любое из этих выражений может быть истинным. Если вы переключите свои Альтернативы для одного совпадения is на что-то другое, например, |, тогда у вас может быть меньше трудностей. Я также придумал еще одну идею, которую я напишу в ответе, так как он довольно длинный.   -  person rmunn    schedule 29.06.2018


Ответы (1)


Помимо переключения одного из значений or на |, как я упоминал в комментарии, вы также можете использовать notFollowedBy (keyword "is") следующим образом:

let variables =
    variable .>>? keyword "or" .>>.? (sepBy1 (variable .>> (notFollowedBy (keyword "is"))) (keyword "or"))

Я не очень в восторге от этого решения, потому что его нелегко обобщить. Существуют ли другие ключевые слова, кроме is, которые могут стоять после переменной? Например, есть ли у вас синтаксис типа b matches x or y или что-то подобное? Если да, то вам нужно написать что-то вроде (notFollowedBy ((keyword "is") <|> (keyword "matches"))), и это может быстро усложниться. Но поскольку ключевое слово is — единственное, которое сбрасывает работу вашего синтаксического анализатора, использование (notFollowedBy (keyword "is")), вероятно, будет лучшим выбором.

person rmunn    schedule 29.06.2018