如何在 Antlr 中强制执行某些规则

How to make certain rules mandatory in Antlr

我写了下面的语法来检查条件表达式。 下面的例子是我想用这个语法实现的:

test无效
test = 1有效
test = 1 and another_test>=0.2有效
test = 1 kasd y = 1 无效(两个条件必须用 AND/OR 分隔)
a = 1 or (b=1 and c) 无效(不能有像'c'这样的孤独字符。它应该总是三元组。即字面运算符字面量)

grammar expression;

expr
 : literal_value
 | expr ( '='|'<>'| '<' | '<=' | '>' | '>=' ) expr
 | expr K_AND expr
 | expr K_OR expr
 | function_name '(' ( expr ( ',' expr )* | '*' )? ')'
 | '(' expr ')'
 ;

literal_value
 : NUMERIC_LITERAL
 | STRING_LITERAL
 | IDENTIFIER
 ;


keyword
 : K_AND
 | K_OR
;

name
 : any_name
 ;

function_name
 : any_name
 ;

database_name
 : any_name
 ;

table_name
 : any_name
 ;

column_name
 : any_name
 ;

any_name
 : IDENTIFIER
 | keyword
 | STRING_LITERAL
 | '(' any_name ')'
 ;


K_AND : A N D;
K_OR : O R;

IDENTIFIER
 : '"' (~'"' | '""')* '"'
 | '`' (~'`' | '``')* '`'
 | '[' ~']'* ']'
 | [a-zA-Z_] [a-zA-Z_0-9]*
 ;

NUMERIC_LITERAL
 : DIGIT+ ( '.' DIGIT* )? ( E [-+]? DIGIT+ )?
 | '.' DIGIT+ ( E [-+]? DIGIT+ )?
 ;

STRING_LITERAL
 : '\'' ( ~'\'' | '\'\'' )* '\''
 ;


fragment DIGIT : [0-9];

fragment A : [aA];
fragment B : [bB];
fragment C : [cC];
fragment D : [dD];
fragment E : [eE];
fragment F : [fF];
fragment G : [gG];
fragment H : [hH];
fragment I : [iI];
fragment J : [jJ];
fragment K : [kK];
fragment L : [lL];
fragment M : [mM];
fragment N : [nN];
fragment O : [oO];
fragment P : [pP];
fragment Q : [qQ];
fragment R : [rR];
fragment S : [sS];
fragment T : [tT];
fragment U : [uU];
fragment V : [vV];
fragment W : [wW];
fragment X : [xX];
fragment Y : [yY];
fragment Z : [zZ];

WS: [ \n\t\r]+ -> skip;

所以我的问题是,如何让语法适用于上述示例?我们能否使某些单词在两个三元组(字面量运算符字面量)之间成为强制性的?从某种意义上说,我只是想让解析器验证 where 子句条件,但只允许简单的条件和函数。我还希望有一个访问者可以检索 Java 中的函数、括号、任何文字等值,如何实现?

是也不是。

您可以将语法更改为仅允许对相同对象进行比较和逻辑运算的表达式:

expr
 : term ( '='|'<>'| '<' | '<=' | '>' | '>=' ) term
 | expr K_AND expr
 | expr K_OR expr
 | '(' expr ')'
 ;

term
 : literal_value
 | function_name '(' ( expr ( ',' expr )* | '*' )? ')'
 ;

如果您想允许布尔变量或函数,问题就来了——您需要在词法分析器中对 functions/vars 进行分类,并且每个终端都有不同的终端,这很棘手且容易出错。

相反,通常最好不要在解析器中进行这种检查——让您的解析器是宽容的并接受任何类似表达式的内容,并为其生成一个表达式树。然后对树进行单独传递(称为类型检查器),检查操作的操作数类型和函数的参数。

后一种方法(使用单独的类型检查器)通常会更简单、更清晰、更灵活,并且会给出更好的错误消息(而不仅仅是 'syntax error')。