antlr4 - 任何文字和关键字

时间:2015-02-04 13:44:40

标签: java antlr antlr4

我正在尝试解析以下内容:

SELECT name-of-key[random text]

这是我想要构建的更大语法的一部分。为了清楚起见,我把它留给了我们。

我提出了以下规则:

select      : 'select' NAME '[' anything ']'
            ;
anything    : (ANYTHING | NAME)+
            ;

NAME        : ('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_')+
            ;
ANYTHING    : (~(']' | '['))+
            ;
WHITESPACE  : ('\t' | ' ' | '\r' | '\n')+ -> skip
            ;

这似乎不起作用。例如,输入SELECT a[hello world!]会出现以下错误:

line 1:0 mismatched input 'SELECT a' expecting 'SELECT'

这是错误的,因为输入SELECT aANYTHING识别,而不是select。我该如何解决这个问题?我觉得我在这里缺少一些概念,但很难开始。

1 个答案:

答案 0 :(得分:7)

也许您缺少的概念是规则优先权。

[1] Lexer规则匹配最长的字符串具有优先权。

正如您所提到的,上面的ANYTHING令牌规则匹配"选择",这比(隐式)令牌规则选择'更长。匹配,因此它的优先权。非贪婪的行为用问号表示。

ANYTHING    : (~(']' | '['))+?

只是让ANYTHING规则非贪婪并不能完全解决你的问题,因为在正确匹配' select'之后,词法分析器会为空间产生一个ANYTHING标记,因为......

[2] Lexer规则首先出现具有优先权。

切换词法分析器规则WHITE_SPACE和ANYTHING解决了这个问题。下面的语法应该解析你的例子。

select      : 'select' NAME '[' anything ']'
            ;
anything    : (ANYTHING | NAME)+
            ;

NAME        : ('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_')+
            ;
WHITESPACE  : ('\t' | ' ' | '\r' | '\n')+ -> skip
            ;
ANYTHING    : (~(']' | '['))+?
            ;

我个人避免使用隐式令牌规则,特别是如果您的语法很复杂,正是因为令牌规则优先级。我会写这个。

SELECT      : 'select' ;
L_BRACKET   : '[';
R_BRACKET   : ']';

NAME        : ('a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_')+ ;
WHITESPACE  : ('\t' | ' ' | '\r' | '\n')+ -> skip ;
ANY         : . ;

select      : SELECT NAME L_BRACKET anything R_BRACKET ;
anything    : (~R_BRACKET)+ ;

还要注意" hello world"将被WHITESPACE规则吞噬。要正确管理它,您需要ANTLR 岛语法

'希望这有帮助!