在Happy中改变/减少命题逻辑解析器中的冲突

时间:2013-04-21 19:49:36

标签: parsing haskell shift-reduce-conflict happy

我正在根据命题逻辑语法的this BNF definition创建一个简单的命题逻辑解析器,这是我的代码

{
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
}

现在,我有两个问题

  1. 出于某种原因,我得到了4次转换/减少冲突,我真的不知道它们可能在哪里,因为我认为优先级会解决它们(我认为我正确地遵循了BNF语法)...
  2. (这是一个Haskell问题)在我的词法分析器函数中,由于某种原因,我在线上解析错误,我说如何处理'¬',如果我删除那条线它的工作原理,为什么会这样? (这个问题已经解决)
  3. 任何帮助都会很棒。

2 个答案:

答案 0 :(得分:4)

如果您对-i感到满意,它将生成一个信息文件。该文件列出了解析器具有的所有状态。它还将列出每个州的所有可能转换。您可以使用此信息来确定转移/减少冲突是否是您关心的。

有关调用快乐和冲突的信息:

以下是-i的部分输出。我删除了除状态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),“模糊性通过优先级∧∧∨⇒⇔或括号来解决。”

此时,我建议查看shift / reduce冲突和所需的优先级,看看你拥有的解析器是否会做正确的事情。如果是这样,那么您可以安全地忽略警告。如果没有,你可以为自己做更多的工作。

答案 1 :(得分:2)

我可以回答第2号:

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

你有一个==,你应该有一个=