ANTLR语法无法正常工作我究竟做错了什么?

问题描述

下面我有这个语法,用于实现一个IN运算符,该运算符采用数字或字符串列表。

grammar listFilterExpr;

listFilterExpr: entityIdNumberListFilter | entityIdStringListFilter;

entityIdNumberProperty
    : 'a.Id'
    | 'c.Id'
    | 'e.Id'
    ;
    
entityIdStringProperty
    : 'f.phone'
    ;

listFilterExpr
    : entityIdNumberListFilter
    | entityIdStringListFilter
    ;

listOperator
    : '$in:'
    ;

entityIdNumberListFilter
 :  entityIdNumberProperty listOperator numberList
 ;

 entityIdStringListFilter
 : entityIdStringProperty listOperator stringList
 ;

 numberList: '[' ID (',' ID)* ']';

 fragment ID: [1-9][0-9]*;

 stringList: '[' STRING (',' STRING)* ']';
 
 STRING
: '"'(ESC | SAFECODEPOINT)*'"'
;

fragment ESC
   : '\\' (["\\/bfnrt] | UNICODE)
   ;
   
fragment SAFECODEPOINT
   : ~ ["\\\u0000-\u001F]
   ;

如果我尝试解析以下输入:

c.Id $in: [1,1]

然后我在解析器中收到以下错误

mismatched input '1' expecting ID

请帮助我纠正此语法。

更新

我在项目的巨大语法文件中发现了以下遵循以下规则的方式,该文件在与ID匹配之前可能与“ 1”匹配:

NUMBER
   : '-'? INT ('.' [0-9] +)?
   ;
fragment INT
   : '0' | [1-9] [0-9]*
   ;

但是,如果我在ID之前写了NUMBER规则,那么其他事情就会失败,因为它们已经匹配了ID,应该已经匹配NUMBER

我该怎么办?

解决方法

如rici所述:ID不应为fragment。片段只能由其他词法分析器规则使用,它们永远不会自己成为令牌(因此不能在解析器规则中使用)。

只需从其中删除fragment关键字:ID: [1-9][0-9]*;

enter image description here

请注意,您还必须考虑空格。您可能想跳过它们:

SPACES : [ \t\r\n] -> skip;

... 输入“ 1”与预期ID不匹配 ...

这看起来像ID之外的另一个词法分析器,它也匹配输入1并在ID之前定义。在这种情况下,请查看以下问答:ANTLR 4.5 - Mismatched Input 'x' expecting 'x'

编辑

因为您的规则排序如下:

NUMBER
   : '-'? INT ('.' [0-9] +)?
   ;

fragment INT
   : '0' | [1-9] [0-9]*
   ;

ID
   : [1-9][0-9]*
   ;

该词法分析器将永远不会创建ID令牌(只会创建NUMBER令牌)。 ANTLR就是这样工作的:如果2个或更多的词法分析器规则匹配相同数量的字符,则定义的第一个“获胜”。

首先,我认为有一个仅匹配数字的ID规则很奇怪,但是,如果这是您要解析的语言,那么可以。就您而言,您可以执行以下操作:

id     : POS_NUMBER;
number : POS_NUMBER | NEG_NUMBER;

POS_NUMBER : INT ('.' [0-9] +)?;
NEG_NUMBER : '-' POS_NUMBER;

fragment INT
   : '0' | [1-9] [0-9]*
   ;

,然后在解析器规则中使用ID而不是id。以及使用number代替您现在使用的NUMBER