【问题标题】:Specify order of alternatives in happy parser指定快乐解析器中的替代顺序
【发布时间】:2015-01-14 18:41:18
【问题描述】:

我正在为具有以下类型的语言开发 Happy 解析器,等等。

type :: { ... }
type :
    'void'                { ... }
  | type '*'              { ... } {- pointer    -}
  | type '(' types ')'    { ... } {- function   -}
  | ...                           {- many more! -}

types :: { ... }
    {- empty -}           { ... }
  | types ',' type        { ... }

该语言的调用语法显然不明确。

callable :: { ... }
callable :
    type                   operand    { ... }    {- return type -}
  | type '(' types ')' '*' operand    { ... }    {- return and argument types -}

type 采用函数指针的类型时,第二条规则与第一条规则的含义不同。

可以通过为不是函数指针的类型添加特殊规则来消除歧义。除非这样做并复制所有类型定义以产生类似的东西

callable :: { ... }
callable :
    typeThatIsNotAFunctionPointer operand    { ... }
  | type '(' types ')' '*'        operand    { ... }

我如何才能指定替代type operand 仅在type '(' types ')' '*' operand 替代失败时才合法?

关于堆栈溢出有很多关于为什么语法有歧义的问题(我发现至少有 7 个),还有一些关于如何消除歧义的问题,但没有关于如何指定如何解决歧义的问题。

不受欢迎的解决方案

我知道我可以将类型的语法重构为一个巨大的复杂混乱。

neverConstrainedType :: { ... }
neverConstrainedType :
    'int'                 { ... }
  | ...                   {- many more! -}

voidType :: { ... }
voidType :
    'void'

pointerType :: { ... }
pointerType :
    type '*'              { ... } {- pointer    -}

functionType :: { ... }
    type '(' types ')'    { ... } {- function    -}

type :: { ... }
type :
    neverConstrainedType  { ... }
  | voidType              { ... }
  | pointerType           { ... }
  | functionType          { ... }

typeNonVoid :: { ... }    {- this already exists -}
typeNonVoid : 
    neverConstrainedType  { ... }
  | pointerType           { ... }
  | functionType          { ... }

typeNonPointer :: { ... }
typeNonPointer :
    neverConstrainedType  { ... }
  | voidType              { ... }
  | functionType          { ... }

typeNonFunction :: { ... }
typeNonFunction :
    neverConstrainedType  { ... }
  | voidType              { ... }
  | functionType          { ... }

typeNonFunctionPointer :: { ... }
typeNonFunctionPointer :
    typeNonPointer        { ... }
  | typeNonFunction '*'   { ... }

然后将callable定义为

callable :: { ... }
callable :
    typeNonFunctionPointer                    operand    { ... }
  | type                   '(' types ')' '*'  operand    { ... }

【问题讨论】:

  • 操作数是什么样的?
  • 另外,这对您的问题并不重要,但我很好奇您对类型的定义。类型列表似乎以逗号开头 - 对吗?
  • @user5402 这些细节都不重要。知道typesoperand 出现的任何地方总是完全相同就足够了。实际上types 被定义为不能以, 开头。本质上是types' : type | types' ',' typetypes : {- empty -} | types'

标签: haskell negation happy


【解决方案1】:

基本上你有所谓的转变/减少冲突。您可以谷歌“解决移位/减少冲突”以获取更多信息和资源。

解决移位/归约冲突的基本思想是重构语法。例如,这个语法是模棱两可的:

%token id comma int
A : B comma int
B : id     
  | id comma B

可以通过重构来消除移位/减少冲突:

A : B int
B : id comma
  | id comma B

在你的情况下,你可以尝试这样的事情:

type : simple               {0}
     | func                 {0}
     | funcptr              {0}

simple : 'void'             {0}
       | simple '*'         {0}
       | funcptr '*'        {0}

func : type '(' type ')'    {0}

funcptr : func '*'          {0}

想法是这样的:

  • simple 匹配任何不是函数或函数指针的类型
  • func 匹配任何函数类型
  • funcptr 匹配任何函数指针类型

也就是说,我在发现的语法中尝试做的许多事情最好通过在创建解析树后对其进行分析来完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多