2

私は、この命題論理文法のBNF 定義に基づいて、Happy で簡単な命題論理パーサーを作成しています。これが私のコードです。

{
module FNC where
import Data.Char 
import System.IO
}

-- Parser name, token types and error function name:
--
%name parse Prop
%tokentype { Token } 
%error { parseError }

-- Token list:
%token
     var { TokenVar $$ }  -- alphabetic identifier
     or { TokenOr }
     and { TokenAnd }
     '¬' { TokenNot }
     "=>" { TokenImp } -- Implication
     "<=>" { TokenDImp } --double implication
    '(' { TokenOB } --open bracket
    ')'  { TokenCB } --closing bracket
    '.' {TokenEnd}

%left "<=>"
%left "=>"
%left or
%left and
%left '¬'
%left '(' ')'
%%

--Grammar
Prop :: {Sentence}
Prop : Sentence '.' {$1}

Sentence :: {Sentence}
Sentence : AtomSent {Atom $1}
    | CompSent {Comp $1}

AtomSent :: {AtomSent}
AtomSent : var { Variable $1 }

CompSent :: {CompSent}
CompSent : '(' Sentence ')' { Bracket $2 }
    | Sentence Connective Sentence {Bin $2 $1 $3}
    | '¬' Sentence {Not $2}

Connective :: {Connective}
Connective : and {And}
    | or {Or}
    | "=>" {Imp}
    | "<=>" {DImp}


{
--Error function
parseError :: [Token] -> a
parseError _ = error ("parseError: Syntax analysis error.\n")

--Data types to represent the grammar
data Sentence
    = Atom AtomSent
    | Comp CompSent
    deriving Show

data AtomSent = Variable String deriving Show

data CompSent
      = Bin Connective Sentence Sentence
      | Not Sentence
      | Bracket Sentence
      deriving Show

data Connective
    = And
    | Or
    | Imp
    | DImp
    deriving Show

--Data types for the tokens
data Token
      = TokenVar String
      | TokenOr
      | TokenAnd
      | TokenNot
      | TokenImp
      | TokenDImp
      | TokenOB
      | TokenCB
      | TokenEnd
      deriving Show

--Lexer
lexer :: String -> [Token]
lexer [] = []  -- cadena vacia
lexer (c:cs)   -- cadena es un caracter, c, seguido de caracteres, cs.
      | isSpace c = lexer cs
      | isAlpha c = lexVar (c:cs)
      | isSymbol c = lexSym (c:cs)
      | c== '(' = TokenOB : lexer cs
      | c== ')' = TokenCB : lexer cs
      | c== '¬' = TokenNot : lexer cs --solved
      | c== '.'  = [TokenEnd]
      | otherwise = error "lexer:  Token invalido"

lexVar cs =
   case span isAlpha cs of
      ("or",rest) -> TokenOr : lexer rest
      ("and",rest)  -> TokenAnd : lexer rest
      (var,rest)   -> TokenVar var : lexer rest

lexSym cs =
    case span isSymbol cs of
        ("=>",rest) -> TokenImp : lexer rest
        ("<=>",rest) -> TokenDImp : lexer rest
}

さて、ここで2つの問題があります

  1. 何らかの理由で、4 つのシフト/リデュースの競合が発生します。優先順位によって解決されると思っていたので、競合がどこにあるかはわかりません (BNF 文法に正しく従ったと思います)...
  2. (これはどちらかというと Haskell の問題です) 私のレクサー関数では、何らかの理由で、'¬' をどうするかを記述している行で解析エラーが発生します。その行を削除すると機能します。(この問題は解決済みです)

どんな助けでも素晴らしいでしょう。

4

2 に答える 2

4

満足し-iて使用すると、情報ファイルが生成されます。このファイルには、パーサーが持つすべての状態がリストされています。また、各状態のすべての可能な遷移もリストされます。この情報を使用して、シフト/リデュースの競合が重要かどうかを判断できます。

幸福と葛藤の呼び出しに関する情報:

以下は の出力の一部です-i。State 17 以外はすべて削除しました。問題を適切にデバッグできるように、このファイルのコピーを取得することをお勧めします。ここに表示されているのは、それについて話すのを助けるためだけです:

-----------------------------------------------------------------------------
Info file generated by Happy Version 1.18.10 from FNC.y
-----------------------------------------------------------------------------

state 17 contains 4 shift/reduce conflicts.

-----------------------------------------------------------------------------
Grammar
-----------------------------------------------------------------------------
    %start_parse -> Prop                               (0)
    Prop -> Sentence '.'                               (1)
    Sentence -> AtomSent                               (2)
    Sentence -> CompSent                               (3)
    AtomSent -> var                                    (4)
    CompSent -> '(' Sentence ')'                       (5)
    CompSent -> Sentence Connective Sentence           (6)
    CompSent -> '¬' Sentence                          (7)
    Connective -> and                                  (8)
    Connective -> or                                   (9)
    Connective -> "=>"                                 (10)
    Connective -> "<=>"                                (11)

-----------------------------------------------------------------------------
Terminals
-----------------------------------------------------------------------------
    var            { TokenVar $$ }
    or             { TokenOr }
    and            { TokenAnd }
    '¬'           { TokenNot }
    "=>"           { TokenImp }
    "<=>"          { TokenDImp }
    '('            { TokenOB }
    ')'            { TokenCB }
    '.'            { TokenEnd }

-----------------------------------------------------------------------------
Non-terminals
-----------------------------------------------------------------------------
    %start_parse    rule  0
    Prop            rule  1
    Sentence        rules 2, 3
    AtomSent        rule  4
    CompSent        rules 5, 6, 7
    Connective      rules 8, 9, 10, 11

-----------------------------------------------------------------------------
States
-----------------------------------------------------------------------------
State 17

    CompSent -> Sentence . Connective Sentence          (rule 6)
    CompSent -> Sentence Connective Sentence .          (rule 6)

    or             shift, and enter state 12
            (reduce using rule 6)

    and            shift, and enter state 13
            (reduce using rule 6)

    "=>"           shift, and enter state 14
            (reduce using rule 6)

    "<=>"          shift, and enter state 15
            (reduce using rule 6)

    ')'            reduce using rule 6
    '.'            reduce using rule 6

    Connective     goto state 11

-----------------------------------------------------------------------------
Grammar Totals
-----------------------------------------------------------------------------
Number of rules: 12
Number of terminals: 9
Number of non-terminals: 6
Number of states: 19

その出力は基本的に、接続詞を調べているときに少しあいまいになっていることを示しています。あなたがリンクしたスライドは、これについて言及していることがわかりました(スライド11)、「あいまいさは優先順位¬∧∨⇒⇔または括弧によって解決されます」。

この時点で、シフト/リデュースの競合と希望する優先順位を調べて、使用しているパーサーが正しいことを行うかどうかを確認することをお勧めします。その場合は、警告を安全に無視できます。そうでない場合は、自分でもっと仕事をする必要があります。

于 2013-04-21T22:09:56.163 に答える
2

2 番に答えることができます。

| c== '¬' == TokenNot : lexer cs --problem here
--        ^^

==あるべきところに があります=

于 2013-04-21T20:02:12.547 に答える