antlr4 - 任何文字和关键字

Jes*_*aro 2 java antlr antlr4

我试图解析以下内容:

SELECT name-of-key[random text]
Run Code Online (Sandbox Code Playgroud)

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

我想出了以下规则:

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

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

这似乎不起作用.例如,输入SELECT a[hello world!]提供以下错误:

line 1:0 mismatched input 'SELECT a' expecting 'SELECT'
Run Code Online (Sandbox Code Playgroud)

这是错误的,因为输入SELECT a被识别ANYTHING,而不是select.我该如何解决这个问题?我觉得我在这里遗漏了一些概念,但很难开始.

Mar*_* Q. 7

也许你缺少的概念是规则优先权.

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

正如您所提到的,上面的ANYTHING标记规则匹配"select a",它比(隐式)标记规则"select"匹配的更长,因此它的优先级.非贪婪行为用问号表示.

ANYTHING    : (~(']' | '['))+?
Run Code Online (Sandbox Code Playgroud)

只是让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    : (~(']' | '['))+?
            ;
Run Code Online (Sandbox Code Playgroud)

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

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)+ ;
Run Code Online (Sandbox Code Playgroud)

另请注意,"hello world"中的空格将被WHITESPACE规则吞噬.要正确管理它,您需要ANTLR 岛语法.

'希望这可以帮助!