parsing - 语法歧义: why?(问题是: "(a)"与 "(a-z)")

标签 parsing haskell grammar happy

因此,我正在尝试为单行语句实现一个非常简单的语法:

# Grammar

   c         : Character c        [a-z0-9-]
  (v)        : Vowel              (= [a,e,u,i,o])
  (c)        : Consonant
  (?)        : Any character (incl. number)
  (l)        : Any alpha char     (= [a-z])
  (n)        : Any integer        (= [0-9])
  (c1-c2)    : Range from char c1 to char c2
  (c1,c2,c3) : List including chars c1, c2 and c3

  Examples:
  h(v)(c)no(l)(l)jj-k(n)
  h(v)(c)no(l)(l)(a)(a)(n)
  h(e-g)allo
  h(e,f,g)allo
  h(x,y,z)uul
  h(x,y,z)(x,y,z)(x,y,z)(x,y,z)uul

我正在使用Happy解析器生成器(http://www.haskell.org/happy/),但是由于某种原因,似乎存在一些歧义问题。

错误消息是:“移位/减少冲突:1”

我认为这两条线存在歧义:
  | lBracket char rBracket              { (\c -> case c of
                                                 'v' -> TVowel
                                                 'c' -> TConsonant
                                                 'l' -> TLetter
                                                 'n' -> TNumber) $2 }
  | lBracket char hyphen char rBracket  { TRange $2 $4              }

一个示例情况是:“(a)”与“(a-z)”

对于这两种情况,词法分析器将给出以下内容:
(a)   : [CLBracket, CChar 'a', CRBracket]
(a-z) : [CLBracket, CChar 'a', CHyphen, CChar 'z', CRBracket]

我不明白的是,如何使用LL [2]解析器将其模棱两可。

如果这对整个Happy语法定义有帮助,请执行以下操作:
{

module XHappyParser where

import Data.Char
import Prelude   hiding (lex)
import XLexer
import XString

}

%name parse
%tokentype { Character  }
%error     { parseError }

%token
    lBracket                  { CLBracket   }
    rBracket                  { CRBracket   }
    hyphen                    { CHyphen     }
    question                  { CQuestion   }
    comma                     { CComma      }
    char                      { CChar $$    }

%%

xstring : tokens                            { XString (reverse $1)       }

tokens : token                              { [$1]                       }
       | tokens token                       { $2 : $1                    }

token : char                                { TLiteral $1                }
      | hyphen                              { TLiteral '-'               }
      | lBracket char rBracket              { (\c -> case c of
                                                     'v' -> TVowel
                                                     'c' -> TConsonant
                                                     'l' -> TLetter
                                                     'n' -> TNumber) $2 }
      | lBracket question rBracket          { TAny                      }
      | lBracket char hyphen char rBracket  { TRange $2 $4              }
      | lBracket listitems rBracket         { TList $2                  }

listitems : char                            { [$1]                      }
          | listitems comma char            { $1 ++ [$3]                }

{

parseError :: [Character] -> a
parseError _ = error "parse error"

}

谢谢!

最佳答案

这是模棱两可的:

token : [...]
      | lBracket char rBracket
      | [...] 
      | lBracket listitems rBracket

listitems : char
          | [...]

您的解析器可以接受(v)作为TString [TVowel]TString [TList ['v']],更不用说该case表达式中缺少的字符了。

解决该问题的一种可能方法是修改语法,使列表至少包含两个项目,或者对元音,辅音等使用不同的表示法。

关于parsing - 语法歧义: why?(问题是: "(a)"与 "(a-z)"),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6499561/

相关文章:

python解析文件

parsing - 将 C 类型语法编译为自定义程序集

haskell - 不知道如何正确输入我的 N 叉树

haskell - 如何在 Haskell 项目中使用 DLL?

prolog - 在 Prolog 中解析多位数的数字

c++ - 语法到 Lex/Yacc

python - BeautifulSoup 无法解析内容,因为页面加载速度太慢

java - 如何使用一个公共(public)属性对对象的数组列表进行排序

haskell - 将语义应用于自由单子(monad)

antlr - 如何在 Antlr 4/c# 中控制错误处理和同步