ANTLR语法添加数组支持遇解析错误求助
问题描述
我正在使用ANTLR解析搜索查询,支持的输入示例如下:
age > 25
或
firstname:"john"
现在需要添加对IN运算符和数组值的支持,以解析类似这样的查询:
firstname IN ["jane", "joe"]
我尝试在语法中添加数组相关规则:
array : LBRACKET (value (COMMA value)* )? RBRACKET ; value : array | IDENTIFIER | STRING | ENCODED_STRING | NUMBER | BOOL ;
但遇到问题:解析器会把数组整体识别为ENCODED_STRING,导致无法正确解析数组结构。
以下是完整的语法文件:
grammar Query; // syntactic rules input : query EOF ; query : left=query logicalOp=(AND | OR) right=query #opQuery | LPAREN query RPAREN #priorityQuery | criteria #atomQuery ; criteria : key op value ; key : IDENTIFIER ; array : LBRACKET (value (COMMA value)* )? RBRACKET ; value : array | IDENTIFIER | STRING | ENCODED_STRING | NUMBER | BOOL ; op : EQ | GT | LT | NOT_EQ | IN | NOT_IN ; // lexical rules BOOL : 'true' | 'false' ; STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ; fragment DoubleStringCharacter : ~["\\\r\n] | '\\' EscapeSequence | LineContinuation ; fragment SingleStringCharacter : ~['\\\r\n] | '\\' EscapeSequence | LineContinuation ; fragment EscapeSequence : CharacterEscapeSequence | HexEscapeSequence | UnicodeEscapeSequence ; fragment CharacterEscapeSequence : SingleEscapeCharacter | NonEscapeCharacter ; fragment HexEscapeSequence : 'x' HexDigit HexDigit ; fragment UnicodeEscapeSequence : 'u' HexDigit HexDigit HexDigit HexDigit ; fragment SingleEscapeCharacter : ['"\\bfnrtv] ; fragment NonEscapeCharacter : ~['"\\bfnrtv0-9xu\r\n] ; fragment EscapeCharacter : SingleEscapeCharacter | DecimalDigit | [xu] ; fragment LineContinuation : '\\' LineTerminatorSequence ; fragment LineTerminatorSequence : '\r\n' | LineTerminator ; fragment DecimalDigit : [0-9] ; fragment HexDigit : [0-9a-fA-F] ; fragment OctalDigit : [0-7] ; fragment POINT : '.' ; AND : 'AND' ; OR : 'OR' ; NUMBER : ('0' .. '9') ('0' .. '9')* POINT? ('0' .. '9')* ; LPAREN : '(' ; RPAREN : ')' ; LBRACKET : '[' ; RBRACKET : ']' ; GT : '>' ; LT : '<' ; EQ : ':' ; IN : 'IN' ; NOT_IN : 'NOT IN' ; NOT_EQ : '!' ; COMMA : ',' ; IDENTIFIER : [A-Za-z0-9.]+ ; ENCODED_STRING : ~([ :<>!()])+ ; LineTerminator : [\r\n\u2028\u2029] -> channel(HIDDEN) ; WS : [ \t\r\n]+ -> skip ;
问题原因
问题出在ENCODED_STRING的词法规则上:当前规则~([ :<>!()])+仅排除了空格、冒号、<、>、!、(、)这些字符,但数组相关的[、]、,并未被排除。这导致词法分析器会将包含这些数组符号的序列识别为ENCODED_STRING,而不是拆分匹配LBRACKET、RBRACKET、COMMA等单独的词法单元,进而无法触发数组的语法规则。
另外,NOT_IN规则存在潜在问题:规则定义为'NOT IN'(带空格),但WS被设置为skip,输入中的空格会被忽略,因此该规则永远无法被匹配到。
解决方案
- 修正ENCODED_STRING规则:将
[、]、,加入排除字符列表,确保数组符号被正确识别为独立的词法单元。 - 修复NOT_IN规则:新增
NOT词法规则,在语法层面直接处理NOT IN的组合,适配空格被跳过的场景。 - 保留数组语法规则在value备选列表的最高优先级(当前已满足)。
修改后的完整语法
grammar Query; // syntactic rules input : query EOF ; query : left=query logicalOp=(AND | OR) right=query #opQuery | LPAREN query RPAREN #priorityQuery | criteria #atomQuery ; criteria : key op value ; key : IDENTIFIER ; array : LBRACKET (value (COMMA value)* )? RBRACKET ; value : array | IDENTIFIER | STRING | ENCODED_STRING | NUMBER | BOOL ; op : EQ | GT | LT | NOT_EQ | IN | NOT IN // 语法层面直接处理NOT IN组合 ; // lexical rules BOOL : 'true' | 'false' ; STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ; fragment DoubleStringCharacter : ~["\\\r\n] | '\\' EscapeSequence | LineContinuation ; fragment SingleStringCharacter : ~['\\\r\n] | '\\' EscapeSequence | LineContinuation ; fragment EscapeSequence : CharacterEscapeSequence | HexEscapeSequence | UnicodeEscapeSequence ; fragment CharacterEscapeSequence : SingleEscapeCharacter | NonEscapeCharacter ; fragment HexEscapeSequence : 'x' HexDigit HexDigit ; fragment UnicodeEscapeSequence : 'u' HexDigit HexDigit HexDigit HexDigit ; fragment SingleEscapeCharacter : ['"\\bfnrtv] ; fragment NonEscapeCharacter : ~['"\\bfnrtv0-9xu\r\n] ; fragment EscapeCharacter : SingleEscapeCharacter | DecimalDigit | [xu] ; fragment LineContinuation : '\\' LineTerminatorSequence ; fragment LineTerminatorSequence : '\r\n' | LineTerminator ; fragment DecimalDigit : [0-9] ; fragment HexDigit : [0-9a-fA-F] ; fragment OctalDigit : [0-7] ; fragment POINT : '.' ; AND : 'AND' ; OR : 'OR' ; NOT : 'NOT' // 新增NOT词法规则 ; IN : 'IN' ; NUMBER : ('0' .. '9') ('0' .. '9')* POINT? ('0' .. '9')* ; LPAREN : '(' ; RPAREN : ')' ; LBRACKET : '[' ; RBRACKET : ']' ; GT : '>' ; LT : '<' ; EQ : ':' ; NOT_EQ : '!' ; COMMA : ',' ; IDENTIFIER : [A-Za-z0-9.]+ ; // 修正ENCODED_STRING,排除数组相关符号 ENCODED_STRING : ~([ :<>!()\[\],])+ ; LineTerminator : [\r\n\u2028\u2029] -> channel(HIDDEN) ; WS : [ \t\r\n]+ -> skip ;
验证说明
修改后,解析firstname IN ["jane", "joe"]时:
[会被识别为LBRACKET,]为RBRACKET,,为COMMA"jane"和"joe"会被识别为STRING- 解析器会优先匹配array规则,将整个
["jane", "joe"]识别为value下的array节点,而非ENCODED_STRING
内容的提问来源于stack exchange,提问作者Reifocs
相关产品推荐
相关产品推荐

