我是ANTLR的新手,我正在尝试解析像
这样的东西参考:标题:(别的)blah ref other
并获取类似
的列表我的语法是
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个元素。 有人能指出我正确的方向吗?我做错了什么?
谢谢, 小号
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]}
答案 0 :(得分:0)
词法分析器在构造标记时尝试匹配尽可能多的字符。当2个或更多lexer规则匹配相同的字符时,首先定义的规则为“wins”。考虑到这一点,永远不会创建KEY
令牌,因为TITLE
,MESSAGE
和REF
定义在它之上:
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
令牌,永远不会成为KEY
或WORD
。您需要做的是从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;