ANTLR 解析键值列表

ANTLR parse key value list

我是 ANTLR 的新手,我正在尝试解析类似

的东西

ref:something title:(别的东西) blah ref other

并获得一个像

这样的列表
  1. KEY = ref VALUE = something
  2. KEY = 标题 VALUE = 其他内容
  3. KEY = null VALUE = blah
  4. KEY = null VALUE = ref // 与项目 1 键相同的 ref 字符串
  5. KEY = null VALUE = 其他

我的语法是

searchCriteriaList 
    locals[List<object> s = new List<object>()]
           : t+=criteriaBean (WS t+=criteriaBean)* { $s.addAll($t); }
           ;

criteriaBean : (KEY ':' WS* expression)
             | expression ;

expression  : '(' WORD (WS WORD)* ')'
            | WORD ;

/*
 * Lexer Rules
 */

fragment A  : ('A'|'a') ;
fragment B  : ('B'|'b') ;
fragment C  : ('C'|'c') ;
fragment D  : ('D'|'d') ;
fragment E  : ('E'|'e') ;
fragment F  : ('F'|'f') ;
fragment G  : ('G'|'g') ;
fragment H  : ('H'|'h') ;
fragment I  : ('I'|'i') ;
fragment J  : ('J'|'j') ;
fragment K  : ('K'|'k') ;
fragment L  : ('L'|'l') ;
fragment M  : ('M'|'m') ;
fragment N  : ('N'|'n') ;
fragment O  : ('O'|'o') ;
fragment P  : ('P'|'p') ;
fragment Q  : ('Q'|'q') ;
fragment R  : ('R'|'r') ;
fragment S  : ('S'|'s') ;
fragment T  : ('T'|'t') ;
fragment U  : ('U'|'u') ;
fragment V  : ('V'|'v') ;
fragment W  : ('W'|'w') ;
fragment X  : ('X'|'x') ;
fragment Y  : ('Y'|'y') ;
fragment Z  : ('Z'|'z') ;


fragment LOWERCASE  : [a-z] ;
fragment UPPERCASE  : [A-Z] ;

TITLE   : T I T L E ;
MESSAGE : M E S S A G E ;
REF     : R E F ;

KEY     : TITLE | MESSAGE | REF ;
WORD    : (LOWERCASE | UPPERCASE | '_')+ ;
WS      : [ \t\u000C\r\n] ;

当我尝试解析字符串时出现 2 个异常,并且在 addAll 方法中我最终得到 3 个元素而不是 5 个。 有人能指出我正确的方向吗?我做错了什么?

谢谢, S

PS:我得到的异常是:

Exception of type 'Antlr4.Runtime.InputMismatchException' was thrown.
InputStream: {ref:something title:(something else) blah ref other }
OffendingToken: {[@0,0:2='ref',<5>,1:0]}

词法分析器在构造标记时尝试匹配尽可能多的字符。当 2 个或多个 lexer 规则匹配相同的字符时,第一个定义的规则 "wins"。考虑到这一点,将永远不会创建 KEY 令牌,因为 TITLEMESSAGEREF 是在其上方定义的:

TITLE   : T I T L E ;
MESSAGE : M E S S A G E ;
REF     : R E F ;

KEY     : TITLE | MESSAGE | REF ;
WORD    : (LOWERCASE | UPPERCASE | '_')+ ;

所以输入ref总是成为REF标记,从不成为KEYWORD。您需要做的是从 KEY 创建一个解析器规则。

此外,由于您希望 WORD 也匹配您的关键字,因此您不应该这样做:

expression
 : '(' WORD (WS WORD)* ')'
 | WORD 
 ;

而是这样的:

expression
 : '(' word (WS word)* ')'
 | word 
 ;

word
 : key
 | WORD
 ;

key
 : TITLE
 | MESSAGE
 | REF
 ;

哦,还有这个:

fragment Z  : ('Z'|'z') ;

可以改写为:

fragment Z  : [Zz] ;

您在解析器规则中乱放 WS 标记是否有特殊原因?您可以在标记化期间删除它们:

WS      : [ \t\u000C\r\n] -> skip;