なぜ単純にしないのですか:
expr : orExpr;
orExpr : andExpr ('or' andExpr)*;
andExpr : relExpr ('and' relExpr)*;
relExpr : addExpr (relop addExpr)?;
relop : '<' | '<=' | '>' | '>=' | '==' | '!=';
addExpr : multExpr (('+' | '-') multExpr)*;
multExpr : unaryExpr (('*' | '/') unaryExpr)*;
unaryExpr : 'not'? atom;
atom : INT | FLOAT | ID | 'true' | 'false' | '(' expr ')';
単項not
は通常、現在実行しようとしているよりも優先順位が高くなります。
これにより、 のような式が可能になりますが42 > true
、そのようなセマンティクスのチェックは、AST/ツリーを歩いているときに発生する可能性があります。
編集
入力"not(a+b >= 2 * foo/3.14159) == false"
は次のように解析されます (スペースは無視されます)。

また、出力を AST に設定し、いくつかのツリー書き換え演算子 (^
および!
)を混在させると、次のようになります。
options {
output=AST;
}
// ...
expr : orExpr;
orExpr : andExpr ('or'^ andExpr)*;
andExpr : relExpr ('and'^ relExpr)*;
relExpr : addExpr (relop^ addExpr)?;
relop : '<' | '<=' | '>' | '>=' | '==' | '!=';
addExpr : multExpr (('+' | '-')^ multExpr)*;
multExpr : unaryExpr (('*' | '/')^ unaryExpr)*;
unaryExpr : 'not'^ atom | atom;
atom : INT | FLOAT | ID | 'true' | 'false' | '('! expr ')'!;
あなたが得るだろう:
