1

With the following rule:

expr:
 '(' expr ')'  #exprExpr
|   expr ( AND expr )+  #exprAnd
|  expr ( OR expr )+  #exprOr
|  atom #exprAtom
|  ID  #exprId
;

atom:
  '[' ID RELOP INT ']'
;

I would like to allow statements like this:

[a<3] and [b<4]
[a<3] or [b<4]
[a<3] or ([b<4]and [c<5])

but forbid statements like this:

[a<3] or [b<4] and [c<5]

This basic idea seems to work with this grammar. But there is one aspect/side effect, which I do not understand:

While parsing code with 3 atoms ( like atom1 and atom2 and atom3) the method exprAnd ist called twice (not once, as I would expect it to).

So code like this:

 public String visitExprAnd(myParser.ExprAndContext ctx)  {
String res = "";
int type=-1;

int nAtoms = ctx.atom().size();
for (int i=0;i<nAtoms;i++) { 
  String s = visit(ctx.expr(i));
}
return s;

}

does not work for all and-expressions at once.

So somehow I would have expected the exprAnd and exprOr rules to be more greedy.

How could one achieve this?

Mike75
  • 504
  • 3
  • 18
  • Unless I'm missing something, your grammar still accepts `[a<3] or [b<4] and [c<5]`, doesn't it? – sepp2k Apr 08 '18 at 18:58

1 Answers1

1

but forbid statements like this:

[a<3] or [b<4] and [c<5]

That is best done after parsing. Your grammar accepts this (and it should). You just need to walk the parse tree afterwards and reject it when you encounter it during a tree-traversal.

While parsing code with 3 atoms ( like atom1 and atom2 and atom3) the method exprAnd ist called twice (not once, as I would expect it to).

If you want to group these ANDs together, you should do something like this instead of grouping it all together in a single expr rule:

orExpr
 : andExpr ( OR andExpr )*
 ;

andExpr
 : atom ( AND atom )*
 ;

atom
 : '(' expr ')'         #atomExpr
 | '[' ID RELOP INT ']' #atomBracket
 | ID                   #atomId
 ;

EDIT

A complete example:

grammar Test;

parse
 : expr EOF
 ;

expr
 : orExpr
 ;

orExpr
 : andExpr ( OR andExpr )*
 ;

andExpr
 : atom ( AND atom )*
 ;

atom
 : '(' expr ')'            #atomExpr
 | '[' expr RELOP expr ']' #atomBracket
 | ID                      #atomId
 | INT                     #atomInt
 ;

RELOP : [<>] '='?;
AND   : 'and';
OR    : 'or';
INT   : [0-9]+;
ID    : [a-zA-Z_] [a-zA-Z_0-9]*;
SPACE : [ \t\r\n] -> skip;
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • I tried the seperate orExpr and andExpr rules. It seems to have a problem with statements with parenthesis like this: [12<34] and ([5<6] or [7<8]); Error is: "extraneous input '(' expecting '['" – Mike75 Apr 08 '18 at 21:04
  • I tried this to include the paranthesis rule: andExpr: bid ( AND bid )* | '(' expr ')' ; but this also gives an error (-> "expecting '[') – Mike75 Apr 08 '18 at 21:17
  • Well, `[12<34]` doesn't work because in your original grammar you defined it as such: `'[' ID RELOP INT ']'`. What you need to do is something like this: `'[' INT RELOP INT ']'` or even: `'[' expr RELOP expr ']'`. Also check my **EDIT**. – Bart Kiers Apr 09 '18 at 05:53
  • Sorry, my post was slightly misleading. I did simplify the grammar. Originally it waw like this: Ident: INT | ID; and – Mike75 Apr 09 '18 at 18:51
  • atom : ... | '[' Ident RELOP INT ']' – Mike75 Apr 09 '18 at 21:01
  • I still am testing. My version with your modified code still has the same error. Starting with your grammer code the parenthesis is processed correctly, I still dont understand, why my grammar has this error and yours not. But I will try to figure out and comment on this point if I find the difference. Thanks for your help! – Mike75 Apr 10 '18 at 18:23