当我用作标识符时,我试图让一些sql关键字被接受为标识符。 Antlr的书p210暗示了这个伎俩:
id : 'if' | 'call' | 'then' | ID ;
我有类似的东西,但它没有工作,我认为这是我的误解。
regular_ident
是标识符的解析规则:
regular_ident : // (1)
KEYWORD_AS_IDENT
|
REGULAR_IDENT
;
REGULAR_IDENT
是idents的主要lex规则。它大致是这个(在这里简化),并且有效:
REGULAR_IDENT :
[a-zA-Z] ( [a-zA-Z0-9] * )
;
KEYWORD_AS_IDENT
是特殊字词列表,这里是一个摘录:
KEYWORD_AS_IDENT : // (2)
[...snip...]
| FILESTREAM
| SPARSE
| NO
| ACTION
| PERSISTED
| FILETABLE_DIRECTORY
| FILETABLE_COLLATE_FILENAME
| FILETABLE_PRIMARY_KEY_CONSTRAINT_NAME
| FILETABLE_STREAMID_UNIQUE_CONSTRAINT_NAME
| FILETABLE_FULLPATH_UNIQUE_CONSTRAINT_NAME
| COLUMN_SET
| ALL_SPARSE_COLUMNS
;
其中组件在其他地方定义:
SPARSE : 'sparse' ;
NO : 'no'
(etc)
如果我将fetch aaa
作为输入(' aaa'不是关键字),则会解析:
但如果我给它fetch sparse
它就会失败 - 稀疏'是关键字:
也许我愚蠢但我无法理解为什么,因为SPARSE
是KEYWORD_AS_IDENT
的成员。
如果我削减&将(2)中的一些粘贴到(1)中得到这个:
regular_ident :
FILESTREAM
| SPARSE
| NO
| ACTION
| PERSISTED
| FILETABLE_DIRECTORY
|
REGULAR_IDENT
;
它突然对fetch sparse
没问题,因为它现在对待稀疏'作为regular_ident:
但为什么(1)不起作用?
我可以通过内联所有KEYWORD_AS_IDENT
来解决这个问题,但我需要知道我错过了什么。
所有建议都表示赞赏。
答案 0 :(得分:1)
我在我自己的语法中使用你的第二种方法(例如MySQL.g),因为这是让它可靠运行的唯一方法。然而,这仍然是ANTLR3。我使用了hack来改变规则keyword
识别的令牌类型,以便它返回IDENTIFIER而不是单个关键字令牌。
答案 1 :(得分:1)
来自谷歌集团antlr讨论的Eric Vergnaud的回复:
LAST
在KEYWORD_AS_IDENT
之前声明,所以当词法分析器 遇到'最后',它会生成LAST
令牌,而不是aKEYWORD_AS_IDENT
。您的开始规则不接受LAST
令牌 有效的输入,因此喊叫。你的语法实际上绝对不会 产生KEYWORD_AS_IDENT
令牌,因为另一个有效令牌会 以前匹配。看来你正试图让词法分子做的工作 解析器即处理多个语义替代,但当时 令牌到达解析器已经太晚了......你试过制作吗? KEYWORD_AS_IDENT解析器规则(小写)而不是词法分析器规则?
所以我对词法分析器的理解是错误的,而且他是正确的,我试图让它来完成解析器的工作。