You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,输入中的空格会被忽略,因此该规则永远无法被匹配到。

解决方案
  1. 修正ENCODED_STRING规则:将[、]、,加入排除字符列表,确保数组符号被正确识别为独立的词法单元。
  2. 修复NOT_IN规则:新增NOT词法规则,在语法层面直接处理NOT IN的组合,适配空格被跳过的场景。
  3. 保留数组语法规则在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 00:35:55