为什么,在pase树中,ANTLR会保持输入不匹配?

时间:2017-07-05 13:35:05

标签: antlr antlr4

我是ANTLR4的新手,我试图以简单的形式可视化文本输入的解析树:

grammar Expr;
contract: (I WS SEND WS quantity WS asset WS TO WS beneficiary WS ON WS send_date WS)*;
asset: '$'| 'TND' | 'USD';
quantity:Q;
beneficiary: B;
send_date : day SLASH month SLASH year;
day: D ;
month: M ;
year: Y ;
B : LETTERUP (LETTERLOW+)+ LETTERLOW*;
Q : DIGITO DIGITZ*|DIGITO DIGITZ* POINT DIGITZ*;
D : DIGIT0 DIGITO|(DIGIT1|DIGIT2)DIGITZ|DIGIT3(DIGIT0|DIGIT1);
M : DIGIT0 DIGITO| DIGIT1(DIGIT0|DIGIT1|DIGIT2);
Y : DIGIT2 DIGIT0((DIGIT1(DIGIT7|DIGIT8|DIGIT9))|(DIGIT2 DIGITZ));
I: 'I';
SEND: 'send';
TO:'to' ;
ON: 'on';
LETTER : [a-zA-Z];
LETTERUP : [A-Z];
LETTERLOW : [a-z];
DIGITZ : [0-9];
DIGITO : [1-9];
DIGIT0 : [0];
DIGIT1 : [1];
DIGIT2 : [2];
DIGIT3 : [3];
DIGIT4 : [4];
DIGIT5 : [5];
DIGIT6 : [6];
DIGIT7 : [7];
DIGIT8 : [8];
DIGIT9 : [9];
SLASH:'/';
POINT:'.'|',';
WS : (' ' | '\t' |'\n' |'\r' )+ ;

但它与send_date不匹配,如您所见:

in terminal in instector

我知道这是一个非常复杂的数字语法我只想要一些控制01< = day< = 31,01< = month< = 12和2017< = year< = 2029这些都是 有什么帮助吗?并谢谢

2 个答案:

答案 0 :(得分:2)

问题出现是因为你的语法含糊不清。 07可以匹配D和2017可以匹配Q.

你可以这样解决:

grammar Expr;
contract: (I WS SEND WS quantity WS asset WS TO WS beneficiary WS ON WS send_date WS)*;
asset: '$'| 'TND' | 'USD';
quantity:Q;
beneficiary: B;
send_date : day month year ;
day: D ;
month:  M ;
year: Y ;

D : DIGIT0 DIGITO|(DIGIT1|DIGIT2)DIGITZ|DIGIT3(DIGIT0|DIGIT1);
M : SLASH (DIGIT0 DIGITO| DIGIT1(DIGIT0|DIGIT1|DIGIT2));
Y : SLASH (DIGIT2 DIGIT0((DIGIT1(DIGIT7|DIGIT8|DIGIT9))|(DIGIT2 DIGITZ)));
B : LETTERUP (LETTERLOW+)+ LETTERLOW*;
Q : DIGITO DIGITZ*|DIGITO DIGITZ* POINT DIGITZ*;
I: 'I';
SEND: 'send';
TO:'to' ;
ON: 'on';
LETTER : [a-zA-Z];
LETTERUP : [A-Z];
LETTERLOW : [a-z];
DIGITZ : [0-9];
DIGITO : [1-9];
DIGIT0 : [0];
DIGIT1 : [1];
DIGIT2 : [2];
DIGIT3 : [3];
DIGIT4 : [4];
DIGIT5 : [5];
DIGIT6 : [6];
DIGIT7 : [7];
DIGIT8 : [8];
DIGIT9 : [9];
SLASH:'/';
POINT:'.'|',';
WS : (' ' | '\t' |'\n' |'\r' )+ ;

enter image description here

答案 1 :(得分:1)

这是一个非常复杂的数字语法。也许你可以简化:

day: NUMBER ;
month: NUMBER ;
year: NUMBER ;

NUMBER : DIGITZ+ ;
DIGITZ : [0-9];

您可以强制执行语义,例如将年份限制为[2017 ... 2020]或代码中的任何内容。只是一个想法。简化通常有帮助,然后你可以从那里加强它,知道你是否犯了错误,你总是可以恢复到至少可以工作的东西。

编辑:

你的语法不起作用的原因是因为这个月被作为一天学习:

[@0,0:0='I',<'I'>,1:0]
[@1,1:1=' ',<WS>,1:1]
[@2,2:5='send',<'send'>,1:2]
[@3,6:6=' ',<WS>,1:6]
[@4,7:9='300',<Q>,1:7]
[@5,10:10=' ',<WS>,1:10]
[@6,11:11='$',<'$'>,1:11]
[@7,12:12=' ',<WS>,1:12]
[@8,13:14='to',<'to'>,1:13]
[@9,15:15=' ',<WS>,1:15]
[@10,16:20='Ahmed',<B>,1:16]
[@11,21:21=' ',<WS>,1:21]
[@12,22:23='on',<'on'>,1:22]
[@13,24:24=' ',<WS>,1:24]
[@14,25:26='03',<D>,1:25]
[@15,27:27='/',<'/'>,1:27]
[@16,28:29='07',<D>,1:28]  <-- see, this is being lexed as a D (day)
[@17,30:30='/',<'/'>,1:30]
[@18,31:34='2017',<Q>,1:31] <-- and this is being lexed as a Q (quantity)
[@19,35:36='\r\n',<WS>,1:35]
[@20,37:36='<EOF>',<EOF>,2:0]
line 1:28 mismatched input '05' expecting M
line 1:31 mismatched input '2017' expecting Y

Lexer规则按照它们出现的顺序应用,Day出现在Month之前。数量出现在年份之前。因此,不正确的lexing。老实说,这是一个场景,我认为你需要简化并接受数字。然后在您的代码中,在代码中强制执行语义(确保年份在范围内等),并在值不在范围内时向用户提供有用的错误消息。你的总努力花费将会减少。

NEW VERSION

grammar Test2;
contract: (I SEND quantity asset TO beneficiary ON send_date)*;

asset: '$'| 'TND' | 'USD';
send_date : DATE ;
quantity: NUMBER;
beneficiary: B;

DATE : NUMBER SLASH NUMBER SLASH NUMBER ;
B : LETTERUP (LETTERLOW+)+ LETTERLOW*;
I: 'I';
SEND: 'send';
TO:'to' ;
ON: 'on';
LETTER : [a-zA-Z];
LETTERUP : [A-Z];
LETTERLOW : [a-z];
NUMBER: DIGIT+;
DIGIT : [0-9];
SLASH:'/';
POINT:'.'|',';
WS : [ \t\n\r]+ -> skip;

改进: 1.更好地处理更常规的空白。 2.简化的数字语法。 它有效。

[@0,0:0='I',<'I'>,1:0]
[@1,2:5='send',<'send'>,1:2]
[@2,7:9='300',<NUMBER>,1:7]
[@3,11:11='$',<'$'>,1:11]
[@4,13:14='to',<'to'>,1:13]
[@5,16:20='Ahmed',<B>,1:16]
[@6,22:23='on',<'on'>,1:22]
[@7,25:34='03/07/2017',<DATE>,1:25]
[@8,37:36='<EOF>',<EOF>,2:0]

问题:我简化了为数量做十进制数的能力。您可以根据需要重新添加。