2

我正在根据命题逻辑语法的BNF 定义在快乐上制作一个简单的命题逻辑解析器,这是我的代码

{
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 个 shift/reduce 冲突,我真的不知道它们可能在哪里,因为我认为优先级会解决它们(而且我认为我正确地遵循了 BNF 语法)......
  2. (这是一个 Haskell 问题)在我的词法分析器函数中,由于某种原因,我在说如何处理 '¬' 的那一行出现解析错误,如果我删除该行它是有效的,为什么会这样?(这个问题解决了)

任何帮助都会很棒。

4

2 回答 2

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),“歧义通过优先级 ¬∧∨⇒⇔ 或括号解决”。

在这一点上,我建议查看移位/减少冲突和您想要的优先级,看看您拥有的解析器是否会做正确的事情。如果是这样,那么您可以放心地忽略这些警告。如果没有,你有更多的工作要做。

于 2013-04-21T22:09:56.163 回答
2

我可以回答第 2 点:

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

你有一个==在那里你应该有一个=.

于 2013-04-21T20:02:12.547 回答