NEO
NEO

Reputation: 2001

How to make certain rules mandatory in Antlr

I wrote the following grammar which should check for a conditional expression. Examples below is what I want to achieve using this grammar:

test invalid
test = 1 valid
test = 1 and another_test>=0.2 valid
test = 1 kasd y = 1 invalid (two conditions MUST be separated by AND/OR)
a = 1 or (b=1 and c) invalid (there cannot be a lonely character like 'c'. It should always be a triplet. i.e, literal operator literal)

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;

So my question is, how can I get the grammar to work for the examples mentioned above? Can we make certain words as mandatory between two triplets (literal operator literal)? In a sense I'm just trying to get a parser to validate the where clause condition but only simple condition and functions are permitted. I also want have a visitor that retrieves the values like function, parenthesis, any literal etc in Java, how to achieve that?

Upvotes: 0

Views: 395

Answers (1)

Chris Dodd
Chris Dodd

Reputation: 126213

Yes and no.

You can change your grammar to only allow expressions that are comparisons and logical operations on the same:

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

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

The issue comes if you want to allow boolean variables or functions -- you need to classify the functions/vars in your lexer and have a different terminal for each, which is tricky and error prone.

Instead, it is generally better to NOT do this kind of checking in the parser -- have your parser be permissive and accept anything expression-like, and generate an expression tree for it. Then have a separate pass over the tree (called a type checker) that checks the types of the operands of operations and the arguments to functions.

This latter approach (with a separate type checker) generally ends up being much simpler, clearer, more flexible, and gives better error messages (rather than just 'syntax error').

Upvotes: 1

Related Questions