【问题标题】:ANTLR grammar not working as expected. What am I doing wrong?ANTLR 语法未按预期工作。我究竟做错了什么?
【发布时间】:2020-10-13 07:01:01
【问题描述】:

我有下面这个语法来实现一个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]*
   ;

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

我该怎么办?

【问题讨论】:

  • 我认为你不希望 ID 成为 fragment
  • 即使我删除fragment,它也会给我同样的错误。
  • @teenup 那么您可能没有重新生成词法分析器和解析器,因为它在删除 fragment 时有效。另一种选择是您删除了太多刚刚发布的规则,并且您有一些冲突的词法分析器规则,您没有在原始问题中使用。始终发布一个独立的示例,以便其他人看到您所看到的。

标签: parsing antlr grammar lexer


【解决方案1】:

正如 rici 所说:ID 不应该是 fragment。片段只能被其他词法规则使用,它们永远不会成为自己的标记(因此不能在解析器规则中使用)。

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

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

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

【讨论】:

  • 谢谢。我正在查看您的回答,并将尝试根据它修复我的项目并恢复。
  • 从这个答案中学习,我发现我的语法可能有冲突,并更新了上面的问题以添加详细信息。如果可能,请帮忙解决。
  • @teenup 结帐我的编辑
  • 好的。谢谢您的答复。在研究了您的初步答案后,我能够弄清楚。
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
  • 2013-08-06
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 2016-07-18
  • 1970-01-01
相关资源
最近更新 更多