ANTLR 4外部输入匹配非lexer项

ANTLR 4外部输入匹配非lexer项,antlr,antlr4,Antlr,Antlr4,我的语法是这样的: 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 i

我的语法是这样的:

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, '/'}
->嗯

KLM405/A4046
SAW502A
->嗯

KLM405/A4046
SAW502A
->不好,“A”在f1中

BAW617/A5136
->不好,“A”在f1中

BAW617/A5136

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

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]
(如果明确定义,则相同):

文件
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 : ~[/] ;
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
执行:

$ 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
$ 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
$grun问题-令牌-诊断t.text
[@0,0:0='P',1:0]
[@1,1:1='H',1:1]
[@2,2:2='O',1:2]
[@3,3:3='E',1:3]
[@4,4:4='N',1:4]
[@5,5:5='\n',1:5]
[@6,6:6='K',2:0]
[@7,7:7='L',2:1]
[@8,8:8='M',2:2]
[@9,9:9='4',,2:3]
[@10,10:10='0',,2:4]
[@11,11:11='5',,2:5]
[@12,12:12='/',,2:6]
[@13,13:13='A',2:7]
[@14,14:17='4046',,2:8]
[@15,18:18='\n',2:12]
[@16,19:19='S',3:0]
[@17,20:20='A',3:1]
[@18,21:21='W',3:2]
[@19,22:22='5',,3:3]
[@20,23:23='0',,3:4]
[@21,24:24='2',,3:5]
[@22,25:25='A',3:6]
[@23,26:26='\n',3:7]
[@24,27:27='B',4:0]
[@25,28:28='A',4:1]
[@26,29:29='W',4:2]
[@27,30:30='6',,4:3]
[@28,31:31='1',,4:4]
[@29,32:32='7',,4:5]
[@30,33:33='/',,4:6]
[@31,34:34='A',4:7]
[@32,35:38='5136',,4:8]
[@33,39:39='\n',4:12]
[@34,40:39='',,5:0]
问题最后更新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

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]
(如果明确定义,则相同):

文件
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 : ~[/] ;
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
执行:

$ 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
$ 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
$grun问题-令牌-诊断t.text
[@0,0:0='P',1:0]
[@1,1:1='H',1:1]
[@2,2:2='O',1:2]
[@3,3:3='E',1:3]
[@4,4:4='N',1:4]
[@5,5:5='\n',1:5]
[@6,6:6='K',2:0]
[@7,7:7='L',2:1]
[@8,8:8='M',2:2]
[@9,9:9='4',,2:3]
[@10,10:10='0',,2:4]
[@11,11:11='5',,2:5]
[@12,12:12='/',,2:6]
[@13,13:13='A',2:7]
[@14,14:17='4046',,2:8]
[@15,18:18='\n',2:12]
[@16,19:19='S',3:0]
[@17,20:20='A',3:1]
[@18,21:21='W',3:2]
[@19,22:22='5',,3:3]
[@20,23:23='0',,3:4]
[@21,24:24='2',,3:5]
[@22,25:25='A',3:6]
[@23,26:26='\n',3:7]
[@24,27:27='B',4:0]
[@25,28:28='A',4:1]
[@26,29:29='W',4:2]
[@27,30:30='6',,4:3]
[@28,31:31='1',,4:4]
[@29,32:32='7',,4:5]
[@30,33:33='/',,4:6]
[@31,34:34='A',4:7]
[@32,35:38='5136',,4:8]
[@33,39:39='\n',4:12]
[@34,40:39='',,5:0]
问题最后更新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

输入的
SAW502A
将标记为六个
字段文本,后跟一个
'A'
标记。这是一个问题,因为该位置不允许使用“a”标记-仅允许使用
FIELDTEXT
标记。显然,您希望
A
在此上下文中也成为
FIELDTEXT
(并且在
f2
规则中的处理方式有所不同),但是标记器不知道语法在某一点上需要哪种标记-它只知道标记规则并生成最适合的标记。因此,每当它看到一个
A
,它就会生成一个
'A'
标记

请注意,这也意味着每当它看到四个连续数字时,就会生成
NUMBER4
token。因此,如果您的输入是
SAW5023
,则会由于意外的
NUMBER4
标记而出现错误

您可以通过引入
everythingButAStroke
非终端规则来解决
A
的问题,该规则可以是
字段文本
'A'
数字4
,但这无法解决
数字4
的问题。每当您添加新的令牌规则时,您也会将该规则添加到
everythingButAStroke
中。但这不是一个很好的解决方案。首先,您添加的令牌规则越多,它的可管理性就越差。另一方面,您显然希望
f1
是单个字符的列表,但是现在
NUMBER4
标记也会出现,它有四个字符,这将是奇怪和不一致的


在我看来,您的整个
字段
规则可以是一个单一的终端规则(为了可读性,理想情况下可以分为
片段
s),而不是像这样使用非终端规则。这样,您就不会遇到终端规则重叠的问题。

输入的
SAW502A
将标记为六个
字段文本,然后是一个
'A'
标记。这是一个问题,因为该位置不允许使用“a”标记-仅允许使用
FIELDTEXT
标记。显然,您希望
A
在此上下文中也成为
FIELDTEXT
(并且在
f2
规则中的处理方式有所不同),但是标记器不知道语法在某一点上需要哪种标记-它只知道标记规则并生成最适合的标记。因此,每当它看到一个
A
,它就会生成一个
'A'
标记

请注意,这也意味着每当它看到四个连续数字时,就会生成
NUMBER4
token。因此,如果您的输入是
SAW5023
,则会由于意外的
NUMBER4
标记而出现错误

您可以通过引入
everythingButAStroke
非终端规则来解决
A
的问题,该规则可以是
字段文本
'A'
数字4
,但这无法解决
数字4
的问题。每当您添加新的令牌规则时,您也会将该规则添加到
everythingButAStroke
中。但这不是一个很好的解决方案。对于