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"

変数、用語、および括弧で囲まれた式のパーサーは省略しましたが、それらが問題に関連している可能性があると思われる場合は、パーサーの完全なソースを読むことができます。

パーサーは、否定と論理積のみを使用する式 (つまり、唯一の前置演算子と最初の中置演算子) に対して成功します。

*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 "&"

接続詞のパーサーを定義する行をコメント アウトすると、論理和のパーサーが機能します (ただし、残りは失敗します)。それらすべてを 1 つのリスト (つまり、同じ優先順位) に入れることもできません。同じ問題が依然として現れます。

誰かが私が間違っていることを指摘できますか? どうもありがとう。


このような迅速で役立つ回答をくれた Daniel Fischer に感謝します。

このパーサーを正しく機能させるには、否定記号の繰り返し適用を処理する必要がありました。たとえば、~~p正しく解析できるようにするためです。This SO answerはそれを行う方法を示しており、パーサーに加えた変更はhereにあります。

4

1 に答える 1

8

あなたの問題はそれです

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

最初に試行された中置演算子は、失敗する前にスペースを消費するため、後の可能性は試行されません。(Parsec はパーサーの消費を優先し、最初のパーサーが入力を消費せずに<|>失敗した場合にのみ、2 番目のパーサーを実行しようとします。)

最初の演算子が失敗した場合に他の中置演算子を試すには、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"

もちろん、共通のプレフィックスを持つ演算子を解析できるパーサーがある場合でも、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 に答える