为什么在 pase tree 中,ANTLR 保持输入不匹配?
Why , in pase tree , ANTLR keep mismatching input?
我是 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
不匹配,正如您在此处看到的那样:
我知道这是一个非常复杂的数字语法我只是想要一些控制 01<= day <= 31 , 01<= month <= 12 and 2017<= year <= 2029 就是这样
有什么帮助吗?并感谢
这是一个非常复杂的数字语法。也许你可以简化:
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
词法分析器规则按照它们出现的顺序应用,日出现在月之前。数量出现在年份之前。因此,词法分析不当。老实说,在这种情况下,我认为您需要简化并只接受数字。然后在您的代码中,强制执行代码中的语义(确保年份在范围内等),并在值不在范围内时向用户提供有用的错误消息。这样一来,您的总精力支出就会减少。
新版本
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. 简化数字语法。
3. 有效
[@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]
问题:我简化了用小数表示数量的能力。您可以根据需要将其添加回去。
出现这个问题是因为你的语法有歧义。 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' )+ ;
我是 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
不匹配,正如您在此处看到的那样:
我知道这是一个非常复杂的数字语法我只是想要一些控制 01<= day <= 31 , 01<= month <= 12 and 2017<= year <= 2029 就是这样 有什么帮助吗?并感谢
这是一个非常复杂的数字语法。也许你可以简化:
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
词法分析器规则按照它们出现的顺序应用,日出现在月之前。数量出现在年份之前。因此,词法分析不当。老实说,在这种情况下,我认为您需要简化并只接受数字。然后在您的代码中,强制执行代码中的语义(确保年份在范围内等),并在值不在范围内时向用户提供有用的错误消息。这样一来,您的总精力支出就会减少。
新版本
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. 简化数字语法。 3. 有效
[@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]
问题:我简化了用小数表示数量的能力。您可以根据需要将其添加回去。
出现这个问题是因为你的语法有歧义。 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' )+ ;