快乐:这不是关键字

时间:2015-11-01 21:32:01

标签: parsing haskell happy

当您编写快乐描述时,您必须定义可能出现的所有可能类型的令牌。但您只能匹配令牌类型,而不能匹配单个令牌 ......

这有点问题。例如,考虑data关键字。根据Haskell报告,这个令牌是" reservedid"。所以我的tokeniser识别它并标记它。但是,请考虑as关键字。现在事实证明这是一个reservedid;它是一个普通的varid。它只在一个上下文中有特殊之处。你可以完全声明一个名为as的普通变量,它很好。

所以这里有一个问题:我如何具体解析as

最初我并没有真正考虑过它。我刚刚定义了一个新的令牌类型,它表示任何varid令牌的文本恰好是as

...然后我花了大约2个小时试图解决为什么地狱我的语法并没有真正发挥作用。是的,事实证明,由于此令牌类型与现有令牌类型重叠,因此声明顺序非常重要。 (!!!)从字面上看,改变声明的顺序使得语法完美解析。

但现在我很担心。我担心as永远不会被匹配为varid,只能匹配自己。所以说varid将拒绝as令牌的所有语法规则 - 这是完全错误的!

正确解决此问题的方法是什么?

1 个答案:

答案 0 :(得分:5)

GHC在其Parser.y中所做的是定义一个非终结令牌类型special_id,列出许多特殊的非关键字,例如as,然后定义tyvaridvarid(非终结)令牌一样,除了终端VARID之外还有其他选项(以及其他一些令牌,尽管他们中的大多数人都认为他们已被放入special_id也是。)

摘录:

varid :: { Located RdrName }
        : VARID            { sL1 $1 $! mkUnqual varName (getVARID $1) }
        | special_id       { sL1 $1 $! mkUnqual varName (unLoc $1) }
        | 'unsafe'         { sL1 $1 $! mkUnqual varName (fsLit "unsafe") }
        ...

special_id :: { Located FastString }
special_id
        : 'as'                  { sL1 $1 (fsLit "as") }
        | 'qualified'           { sL1 $1 (fsLit "qualified") }
        | 'hiding'              { sL1 $1 (fsLit "hiding") }
        | 'export'              { sL1 $1 (fsLit "export") }
        ...