【问题标题】:ANTLR 4 extraneous input matching non lexer itemANTLR 4 无关输入匹配非词法分析器项目
【发布时间】:2017-10-22 07:16:26
【问题描述】:

我有这样的语法:

grammar MyGrammar;

field  : f1 (STROKE f2 f3)? ;

f1 : FIELDTEXT+ ;
f2 : 'A' ;
f3 : NUMBER4 ; 

FIELDTEXT    : ~['/'] ;
NUMBER4  : [0-9][0-9][0-9][0-9];
STROKE : '/' ;

这很好用,并且字段f1 f2 f3 都正确填充。

除非/ 左侧有一个A,(无论是否存在可选部分)这还会导致错误:

extraneous input 'A' expecting {<EOF>, FIELDTEXT, '/'}

一些示例数据:

PHOEN

-> 好的。

KLM405/A4046

-> 好的。

SAW502A

-> 不行,'A' 在 f1 中。

BAW617/A5136

-> 不行,'A' 在 f1 中。

我不明白为什么“A”在这里是个问题(这些字段仍然被填充)。

【问题讨论】:

  • 请给出您正在解析的输入。
  • @BernardK - 添加了输入。

标签: antlr antlr4


【解决方案1】:

SAW502A 的问题在于 'A' 是一个单独的标记,隐式定义:

f2 : 'A' ;

(如果明确定义,则相同):

[@16,19:19='S',<FIELDTEXT>,3:0]
[@17,20:20='A',<'A'>,3:1]
[@18,21:21='W',<FIELDTEXT>,3:2]
[@19,22:22='5',<FIELDTEXT>,3:3]
[@20,23:23='0',<FIELDTEXT>,3:4]
[@21,24:24='2',<FIELDTEXT>,3:5]
[@22,25:25='A',<'A'>,3:6]
[@23,26:26='\n',<FIELDTEXT>,3:7]

并且规则f1 不允许除FIELDTEXT 之外的任何其他内容。 它适用于:

f1 : ( FIELDTEXT | 'A' )+ ;

文件Question.g4

grammar Question;

question
@init {System.out.println("Question last update 2305");}
    : line+ EOF
    ;
line
    : f1 (STROKE f2 f3)? NL
      {System.out.println("f1=" + $f1.text + " f2=" + $f2.text + " f3=" + $f3.text);}
    ;

f1 : ( FIELDTEXT | 'A' )+ ;
f2 : 'A' ;
f3 : NUMBER4 ; 

NUMBER4   : [0-9][0-9][0-9][0-9] ;
STROKE    : '/' ;
NL        : [\r\n]+ ; // -> channel(HIDDEN) ;
WS        : [ \t]+ -> skip ;
FIELDTEXT : ~[/] ;

输入文件t.text

PHOEN
KLM405/A4046
SAW502A
BAW617/A5136

执行:

$ grun Question question -tokens -diagnostics t.text
[@0,0:0='P',<FIELDTEXT>,1:0]
[@1,1:1='H',<FIELDTEXT>,1:1]
[@2,2:2='O',<FIELDTEXT>,1:2]
[@3,3:3='E',<FIELDTEXT>,1:3]
[@4,4:4='N',<FIELDTEXT>,1:4]
[@5,5:5='\n',<NL>,1:5]
[@6,6:6='K',<FIELDTEXT>,2:0]
[@7,7:7='L',<FIELDTEXT>,2:1]
[@8,8:8='M',<FIELDTEXT>,2:2]
[@9,9:9='4',<FIELDTEXT>,2:3]
[@10,10:10='0',<FIELDTEXT>,2:4]
[@11,11:11='5',<FIELDTEXT>,2:5]
[@12,12:12='/',<'/'>,2:6]
[@13,13:13='A',<'A'>,2:7]
[@14,14:17='4046',<NUMBER4>,2:8]
[@15,18:18='\n',<NL>,2:12]
[@16,19:19='S',<FIELDTEXT>,3:0]
[@17,20:20='A',<'A'>,3:1]
[@18,21:21='W',<FIELDTEXT>,3:2]
[@19,22:22='5',<FIELDTEXT>,3:3]
[@20,23:23='0',<FIELDTEXT>,3:4]
[@21,24:24='2',<FIELDTEXT>,3:5]
[@22,25:25='A',<'A'>,3:6]
[@23,26:26='\n',<NL>,3:7]
[@24,27:27='B',<FIELDTEXT>,4:0]
[@25,28:28='A',<'A'>,4:1]
[@26,29:29='W',<FIELDTEXT>,4:2]
[@27,30:30='6',<FIELDTEXT>,4:3]
[@28,31:31='1',<FIELDTEXT>,4:4]
[@29,32:32='7',<FIELDTEXT>,4:5]
[@30,33:33='/',<'/'>,4:6]
[@31,34:34='A',<'A'>,4:7]
[@32,35:38='5136',<NUMBER4>,4:8]
[@33,39:39='\n',<NL>,4:12]
[@34,40:39='<EOF>',<EOF>,5:0]
Question last update 2305
f1=PHOEN f2=null f3=null
f1=KLM405 f2=A f3=4046
f1=SAW502A f2=null f3=null
f1=BAW617 f2=A f3=5136

【讨论】:

    【解决方案2】:

    输入SAW502A 将被标记为六个FIELDTEXTs,后跟一个'A' 标记。这是一个问题,因为在该位置不允许使用“A”标记 - 只有 FIELDTEXT 标记是。显然,您希望 A 在这种情况下也成为 FIELDTEXT (并且仅在 f2 规则中被区别对待),但分词器不知道语法在特定情况下需要哪种令牌点 - 它只知道令牌规则并生成最适合的令牌。因此,每当它看到 A 时,它就会生成一个 'A' 令牌。

    请注意,这也意味着每当它看到四个连续的数字时,它都会生成NUMBER4 令牌。因此,如果您的输入是 SAW5023,您会因为意外的 NUMBER4 令牌而收到错误消息。

    您可以通过引入everythingButAStroke 非终端规则来解决A 的问题,该规则可以是FIELDTEXT'A'NUMBER4,但这不能解决@ 987654338@ 问题。每当您添加新的令牌规则时,您也会将该规则添加到everythingButAStroke。但这不是一个很好的解决方案。一方面,您添加的令牌规则越多,它就越难以管理。另一方面,您显然希望 f1 成为单个字符的列表,但现在 NUMBER4 也有四个字符的标记,这会很奇怪且不一致。

    在我看来,您的整个 field 规则可能是一个单一的终端规则(为了便于阅读,最好分成 fragments),而不是使用这样的非终端规则。这样你就不会有重叠终端规则的问题。

    【讨论】:

      【解决方案3】:

      我经常遇到否定词法分析器规则使定义其他词法分析器规则变得困难,因此我更愿意避免它们。似乎 /,如果存在,后面总是跟着一个 A。因此我有另一个解决方案。

      文件Question_x.g4

      grammar Question_x;
      
      question
      @init {System.out.println("Question last update 0112");}
          : line+ EOF
          ;
      
      line
          : f1 ( f2s='/A' f3 )? NL
            { String f2 = _localctx.f2s != null ? _localctx.f2s.getText().substring(1) : null;
              System.out.println("f1=" + $f1.text + " f2=" + f2 + " f3=" + $f3.text);}
          ;
      
      f1 : ALPHANUM | NUMBER4 ;
      f3 : NUMBER4 ; 
      
      NUMBER4   : [0-9][0-9][0-9][0-9] ;
      ALPHANUM  : [a-zA-Z0-9]+ ;
      NL        : [\r\n]+ ; // -> channel(HIDDEN) ;
      WS        : [ \t]+ -> skip ;
      

      输入文件t.text:

      PHOEN
      KLM405/A4046
      SAW502A
      BAW617/A5136
      SAW5023
      1234/A1234
      

      执行:

      $ grun Question_x question -tokens -diagnostics t.text
      [@0,0:4='PHOEN',<ALPHANUM>,1:0]
      [@1,5:5='\n',<NL>,1:5]
      [@2,6:11='KLM405',<ALPHANUM>,2:0]
      [@3,12:13='/A',<'/A'>,2:6]
      [@4,14:17='4046',<NUMBER4>,2:8]
      [@5,18:18='\n',<NL>,2:12]
      [@6,19:25='SAW502A',<ALPHANUM>,3:0]
      [@7,26:26='\n',<NL>,3:7]
      [@8,27:32='BAW617',<ALPHANUM>,4:0]
      [@9,33:34='/A',<'/A'>,4:6]
      [@10,35:38='5136',<NUMBER4>,4:8]
      [@11,39:39='\n',<NL>,4:12]
      [@12,40:46='SAW5023',<ALPHANUM>,5:0]
      [@13,47:47='\n',<NL>,5:7]
      [@14,48:51='1234',<NUMBER4>,6:0]
      [@15,52:53='/A',<'/A'>,6:4]
      [@16,54:57='1234',<NUMBER4>,6:6]
      [@17,58:58='\n',<NL>,6:10]
      [@18,59:58='<EOF>',<EOF>,7:0]
      Question last update 0112
      f1=PHOEN f2=null f3=null
      f1=KLM405 f2=A f3=4046
      f1=SAW502A f2=null f3=null
      f1=BAW617 f2=A f3=5136
      f1=SAW5023 f2=null f3=null
      f1=1234 f2=A f3=1234
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-10
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-20
        • 1970-01-01
        相关资源
        最近更新 更多