ANTLR 4的语法

时间:2014-06-30 15:25:08

标签: antlr antlr4

我正在尝试使用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"

图像显示我的语法无法识别命令的几个部分 parse tree

令我感到困惑的是,单个部件正在正常工作, 例如仅解析&#39; expr&#39;如下面的树所示 expr tree

1 个答案:

答案 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,调试你的问题,转储解析树,看看发生了什么。