Подтвердить что ты не робот

Parsec.Expr повторяется Оператор Prefix/Postfix не поддерживается

В документации для Parsec.Expr.buildExpressionParser указано:

Префиксные и постфиксные операторы с одинаковым приоритетом могут возникать только один раз (т.е. - 2 не допускается, если - префикс отрицателен).

и, действительно, это укусит меня, поскольку язык, который я пытаюсь выполнить, позволяет произвольно повторять его префикс и постфиксные операторы (подумайте о выражении C, как **a[1][2]).

Итак, почему Parsec делает это ограничение и как я могу его обойти?

Я думаю, что могу перенести свои синтаксические анализаторы префикса/постфикса в парсер term, поскольку они имеют самый высокий приоритет.

то есть.

**a + 1

анализируется как

(*(*(a)))+(1)

но что я мог сделать, если бы я хотел, чтобы он разбирался как

*(*((a)+(1)))

Если buildExpressionParser сделал то, что я хочу, я мог бы просто перестроить порядок операторов в таблице.

Примечание См. здесь для лучшего решения

4b9b3361

Ответ 1

Я решил это сам, используя chainl1:

prefix  p = Prefix  . chainl1 p $ return       (.)
postfix p = Postfix . chainl1 p $ return (flip (.))

Эти комбинаторы используют chainl1 с парсером op, который всегда преуспевает, и просто составляет функции, возвращаемые парсером term в порядке слева направо или справа налево. Они могут использоваться в таблице buildExprParser; где вы бы это сделали:

exprTable = [ [ Postfix subscr
              , Postfix dot
              ]
            , [ Prefix pos
              , Prefix neg
              ]
            ]

сделайте следующее:

exprTable = [ [ postfix $ choice [ subscr
                                 , dot
                                 ]
              ]
            , [ prefix $ choice [ pos
                                , neg
                                ]
              ]
            ]

таким образом, buildExprParser все еще может использоваться для установки приоритета оператора, но теперь он видит только один оператор Prefix или Postfix при каждом приоритете. Тем не менее, этот оператор имеет возможность размножать столько копий, сколько может, и возвращать функцию, которая заставляет ее выглядеть так, как если бы был только один оператор.