6

我正在尝试使用 Parsec 为命题演算编写解析器。解析器使用Text.Parsec.ExprbuildExpressionParser中的函数。这是我定义逻辑运算符的代码。

operators = [ [Prefix (string "~" >> return Negation)]
            , [binary "&" Conjunction]
            , [binary "|" Disjunction]
            , [binary "->" Conditional]
            , [binary "<->" Biconditional]
            ]

binary n c = Infix (spaces >> string n >> spaces >> return c) AssocRight

expr = buildExpressionParser operators term
    <?> "compound expression"

我省略了变量、术语和括号表达式的解析器,但如果您认为它们可能与问题相关,您可以阅读parser 的完整源代码

对于仅使用否定和连词的表达式,即唯一的前缀运算符和第一个中缀运算符,解析器会成功。

*Data.Logic.Propositional.Parser2> runPT expr () "" "p & ~q"
Right (p ∧ ¬q)

使用任何其他运算符的表达式在运算符的第一个字符上失败,并出现如下错误:

*Data.Logic.Propositional.Parser2> runPT expr () "" "p | q"
Left (line 1, column 3):
unexpected "|"
expecting space or "&"

如果我注释掉定义连词解析器的行,则析取解析器将起作用(但其余部分仍将失败)。将它们全部放入一个列表(即具有相同的优先级)也不起作用:同样的问题仍然存在。

谁能指出我做错了什么?非常感谢。


感谢 Daniel Fischer 提供了如此迅速而有帮助的答案。

为了使这个解析器正常工作,我还需要处理否定符号的重复应用,以便 eg~~p能够正确解析。这个 SO answer向我展示了如何做到这一点,我对解析器所做的更改可以在这里找到。

4

1 回答 1

8

你的问题是

binary n c = Infix (spaces >> string n >> spaces >> return c) AssocRight

第一个尝试的中缀运算符在失败之前会消耗一个空间,因此不会尝试后面的可能性。(Parsec 倾向于使用解析器,并且<|>仅在第一个解析器失败时才尝试运行第二个解析器而不使用任何输入。)

如果第一个中缀运算符失败,要尝试其他中缀运算符,您可以将binary解析器包装在try

binary n c = Infix (try $ ...) AssocRight

这样当这样的解析器失败时,它不会消耗任何输入,或者,更好的是,该问题的常规解决方案是spaces从中删除初始值,

binary n c = Infix (string n >> spaces >> return c) AssocRight

并让您的所有解析器在他们解析的令牌之后使用空格

variable = do c <- letter
              spaces
              return $ Variable (Var c)
        <?> "variable"

parens p = do char '('
              spaces
              x <- p
              char ')'
              spaces
              return x
        <?> "parens"

当然,如果您有可以解析具有公共前缀的运算符的解析器,您仍然需要将它们包装在 a 中try,这样如果例如解析>=失败,>>=仍然可以尝试。

模拟命题的数据类型并改变如上所述的空间消耗行为,

*PropositionalParser Text.Parsec> head $ runPT expr () "" "p | q -> r & s"
Right (Conditional (Disjunction (Variable (Var 'p')) (Variable (Var 'q'))) (Conjunction (Variable (Var 'r')) (Variable (Var 's'))))

甚至更复杂的表达式也会被解析。

于 2012-12-03T13:53:10.300 回答