当前位置: 首页 > 知识库问答 >
问题:

Antlr中不明确的Lexer规则

郭辉
2023-03-14

我有一个antlr语法,它有多个与同一个单词匹配的词法规则。在词法分析过程中无法解决这个问题,但通过语法,它就变得毫不含糊了。

示例:

conversion: NUMBER UNIT CONVERT UNIT;
NUMBER: [0-9]+;
UNIT: 'in' | 'meters' | ......;
CONVERT: 'in';

输入:<代码>1英寸(米)

单词“in”与lexer规则UNITCONVERT匹配。

如何在保持语法文件可读性的同时解决此问题?

共有2个答案

严项明
2023-03-14

根据你问题中的信息,很难说最好的解决方案是什么——例如,我不知道你的词法规则是什么——也不知道为什么你的词法规则根本不明确。

根据我对antlr的经验,lexer规则通常不具有任何语义;它们只是与某种正则表达式匹配的文本。因此,我不需要变量、方法名等,而只需要标识符,然后在更高的层次上进行计算。

换言之,似乎(从我从你的问题中收集到的一点信息)你可能会从用语法规则替换单位和转换中受益,或者只使用一条规则:

conversion: NUMBER TEXT TEXT TEXT

以及验证ANTLR侦听器/树行者等中的文本值。

编辑

感谢您使用lexer规则更新您的问题。现在很清楚为什么它失败了——正如BernardK指出的那样,antlr总是会选择第一个匹配的lexer规则。这意味着两个模棱两可的lexer规则中的第二个不可能匹配,这使得您提出的设计不可行。

我的观点是,lexer规则不是做单元验证之类事情的正确层;他们擅长结构,而不是内容。评估解析树比尝试扭曲antlr语法要实际得多。

最后,还可以对解析规则执行嵌入操作,例如根据已知的单元集验证ID标记的值。它可以工作,但会破坏语法的可重用性。

百里默
2023-03-14

当输入匹配两个lexer规则时,ANTLR选择最长的或第一个,请参见消除歧义。根据您的语法,中的将被解释为单位,从不转换,以及规则

conversion: NUMBER UNIT CONVERT UNIT;

无法工作,因为有三个UNIT令牌:

$ grun Question question -tokens -diagnostics input.txt 
[@0,0:0='1',<NUMBER>,1:0]
[@1,1:1=' ',<WS>,channel=1,1:1]
[@2,2:3='in',<UNIT>,1:2]
[@3,4:4=' ',<WS>,channel=1,1:4]
[@4,5:6='in',<UNIT>,1:5]
[@5,7:7=' ',<WS>,channel=1,1:7]
[@6,8:13='meters',<UNIT>,1:8]
[@7,14:14='\n',<NL>,1:14]
[@8,15:14='<EOF>',<EOF>,2:0]
Question last update 0159
line 1:5 missing 'in' at 'in'
line 1:8 mismatched input 'meters' expecting <EOF>

您可以只使用ID或文本标记,并用标签区分它们,如下所示:

grammar Question;

question
@init {System.out.println("Question last update 0132");}
    :   conversion NL EOF
    ;

conversion
    :   NUMBER unit1=ID convert=ID unit2=ID
        {System.out.println("Quantity " + $NUMBER.text + " " + $unit1.text +
         " to convert " + $convert.text + " " + $unit2.text);}
    ;

ID      : LETTER ( LETTER | DIGIT | '_' )* ; // or TEXT : LETTER+ ;     
NUMBER  : DIGIT+ ;

NL      : [\r\n] ;
WS      : [ \t] -> channel(HIDDEN) ; // -> skip ;

fragment LETTER : [a-zA-Z] ;
fragment DIGIT  : [0-9] ;

执行

$ grun Question question -tokens -diagnostics input.txt 
[@0,0:0='1',<NUMBER>,1:0]
[@1,1:1=' ',<WS>,channel=1,1:1]
[@2,2:3='in',<ID>,1:2]
[@3,4:4=' ',<WS>,channel=1,1:4]
[@4,5:6='in',<ID>,1:5]
[@5,7:7=' ',<WS>,channel=1,1:7]
[@6,8:13='meters',<ID>,1:8]
[@7,14:14='\n',<NL>,1:14]
[@8,15:14='<EOF>',<EOF>,2:0]
Question last update 0132
Quantity 1 in to convert in meters

标签可以从访问者中规则的上下文中获得,因此很容易区分相同类型的标记。

 类似资料:
  • 现在我得到了:错误。 我知道我的输入被AND和TERM lexer规则匹配,但我希望能够指定TERM是除与AND规则匹配的内容之外的任何内容。

  • 查看文档,ANTLR2过去有一种叫做谓词法的东西,下面的例子是这样的(灵感来自Pascal): 在我看来,这实际上是规则开头的一个积极的前瞻性断言:如果前瞻性与匹配,那么第一个规则将被应用(并与该输入的部分匹配),依此类推。 我还没有在ANTLR4中找到这样的东西。2到3迁移指南似乎没有提到这一点,而3到4更改文档指出: ANTLR3和4之间最大的区别是ANTLR4接受您给出的任何语法,除非该语法

  • 我需要以下令牌: 允许的字符包括大写、小写、数字、空格和连字符 长度不固定(长度必须至少为两个字符) 标记必须至少包含一个空格或连字符 令牌必须以大写、小写、数字、空格或连字符开头和结尾(不能以空格开头或结尾) 下面语法中的ANTLR lexer规则“alphanumericspacehyphen”除了一个情况外几乎都起作用。使用解析器规则“sic”进行测试,以下输入将解析(不带引号): 以下输入

  • 我得到了这个解析器语法,我还想用它来使用类似于Javascript模板的东西-字符串。 这个lexer语法 我不明白,为什么甚至可以匹配一些像空映射或像“world`”这样的映射,因为映射需要在中间有一个“:”。并且为什么规则模板字符串不匹配整个“Hello World”从一个滴答到另一个滴答? 编辑: 当我注意到Lexer没有被重新生成时,我得到了这样的错误:“不能为string literal

  • 我正在重新学习一些基本的Antlr,并尝试编写一个生成todo项的语法: 我遇到的问题是,有三个lexer规则特别“不匹配”,这取决于它们使用的上下文: 以下是我的完整语法以求清晰: 旁白:我知道还有其他奇怪的地方,比如一个事件的名称只能是一个单词,但我是在一次处理一个问题。