我正在尝试使用ANTLR4开发语法来解析DSL(首次尝试使用它) 语法本身有点类似于SQL应该
它应该能够解析如下命令:
select type1.attribute1 type2./xpath_expression[@id='test 1'] type3.* from source1 source2
fromDate 2014-01-12T00:00:00.123456+00:00 toDate 2014-01-13T00:00:00.123456Z
where (type1.attribute2 = "XX" AND
(type1.attribute3 <= "2014-01-12T00:00:00.123456+00:00" OR
type2./another_xpath_expression = "YY"))
编辑:我已经按照[lucas_trzesniewski]的建议将语法切换CHAR,SYMBOL和DIGIT更新为片段,但我没有得到改进。 随附的是Terence建议的解析树。我也在控制台中得到以下内容(我感到更加困惑......):
warning(125): API.g4:16:8: implicit definition of token 'CHAR' in parser
warning(125): API.g4:20:31: implicit definition of token 'SYMBOL' in parser
line 1:12 mismatched input 'p' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:19 mismatched input 't' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:27 mismatched input 'm' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:35 mismatched input '@' expecting {NUMBER, CHAR, SYMBOL}
line 1:58 no viable alternative at input 'm'
line 3:13 no viable alternative at input '(deco.m'
我能够将大部分语法放在一起,但是它无法正确匹配所有标记,因此导致解析不正确,具体取决于输入的复杂性。 通过在互联网上浏览,在我看来,主要原因是词法分析者选择最长的匹配序列,但即使经过多次尝试重写词法分析器和语法规则,我也无法实现强大的设置。
以下是我的语法和一些测试用例。 指定规则的正确方法是什么?我应该使用词法模式吗?
语法
语法API;
get : K_SELECT (((element) )+ | '*')
'from' (source )+
( K_FROM_DATE dateTimeOffset )? ( K_TO_DATE dateTimeOffset )?
('where' expr )?
EOF
;
element : qualifier DOT attribute;
qualifier : 'raw' | 'std' | 'deco' ;
attribute : ( word | xpath | '*') ;
word : CHAR (CHAR | NUMBER)*;
xpath : (xpathFragment+);
xpathFragment
: '/' ( DOT | CHAR | NUMBER | SYMBOL )+
| '[' (CHAR | NUMBER | SYMBOL )+ ']'
;
source : ( 'system1' | 'system2' | 'ALL') ; // should be generalised.
date : (NUMBER MINUS NUMBER MINUS NUMBER) ;
time : (NUMBER COLON NUMBER (COLON NUMBER ( DOT NUMBER )?)? ( 'Z' | SIGN (NUMBER COLON NUMBER )));
dateTimeOffset : date 'T' time;
filter : (element OP value) ;
value : QUOTE .+? QUOTE ;
expr
: filter
| '(' expr 'AND' expr ')'
| '(' expr 'OR' expr ')'
;
K_SELECT : 'select';
K_RANGE : 'range';
K_FROM_DATE : 'fromDate';
K_TO_DATE : 'toDate' ;
QUOTE : '"' ;
MINUS : '-';
SIGN : '+' | '-';
COLON : ':';
COMMA : ',';
DOT : '.';
OP : '=' | '<' | '<=' | '>' | '>=' | '!=';
NUMBER : DIGIT+;
fragment DIGIT : ('0'..'9');
fragment CHAR : [a-z] | [A-Z] ;
fragment SYMBOL : '@' | [-_=] | '\'' | '/' | '\\' ;
WS : [ \t\r\n]+ -> skip ;
NONWS : ~[ \t\r\n];
TEST 1
select raw./priobj/tradeid/margin[@id='222'] deco.* deco.marginType from system1 system2
fromDate 2014-01-12T00:00:00.123456+00:00 toDate 2014-01-13T00:00:00.123456Z
where ( deco.marginType >= "MV" AND ( ( raw.CretSysInst = "RMS_EXODUS" OR deco.ExtSysNum <= "1234" ) OR deco.ExtSysStr = "TEST Spaced" ) )
TEST 2
select * from ALL
TEST 3
select deco./xpath/expr/text() deco./xpath/expr[a='3' and b gt '6] raw.* from ALL where raw.attr3 = "myvalue"
图像显示我的语法无法识别命令的几个部分
令我感到困惑的是,单个部件正在正常工作, 例如仅解析&#39; expr&#39;如下面的树所示
答案 0 :(得分:1)
那样的事情:word : (CHAR (CHAR | NUMBER)+);
确实是词法分析器的工作,而不是解析器。
这:DIGIT : ('0'..'9');
应该是fragment
。同样如此:CHAR : [a-z] | [A-Z] ;
。这样,您可以编写NUMBER : CHAR+;
和WORD: CHAR (CHAR | NUMBER)*;
原因很简单:您希望在解析器中处理有意义的令牌,而不是处理部分单词。把词法分析器想象成会削减&#34;有意义点的输入文本。稍后,您希望处理完整的单词,而不是单个字符。因此,考虑一下这些削减最有意义的地方。
现在,as the ANTLR master has pointed out,调试你的问题,转储解析树,看看发生了什么。