I'm trying to write a grammar to evaluate expressions.
I've started with the given example on the ANTLR website (it manage +,- and *). I added the division. But I would like to notify user if he tries to divide by 0. Moreover, I would like to add the pow in my evaluator (with an higher precedence than multiply and divide. (for example 2^3=8). Ho开发者_JAVA百科pe it's understandable. Here's my grammar Expr.g :grammar Expr;
@header {
import java.util.HashMap;
}
@members {
/** Map variable name to Integer object holding value */
HashMap memory = new HashMap();
}
prog: stat+ ;
stat: expr NEWLINE {System.out.println($expr.value);}
| ID '=' expr NEWLINE
{memory.put($ID.text, new Integer($expr.value));}
| NEWLINE
;
expr returns [int value]
: e=multExpr {$value = $e.value;}
(( '+' e=multExpr {$value += $e.value;}
| '-' e=multExpr {$value -= $e.value;}
))*
;
multExpr returns [int value]
: e=atom {$value = $e.value;}
('*' e=atom {$value *= $e.value;}
|'/' e=atom {if (e != 0) $value /= $e.value;
else System.err.println("Division par 0 !");}
)*
;
atom returns [int value]
: INT {$value = Integer.parseInt($INT.text);}
| ID
{
Integer v = (Integer)memory.get($ID.text);
if ( v!=null ) $value = v.intValue();
else System.err.println("Variable indéfinie "+$ID.text);
}
| '(' expr ')' {$value = $expr.value;}
;
ID : ('a'..'z'|'A'..'Z')+ ;
INT : '0'..'9'+ ;
NEWLINE:'\r'? '\n' ;
WS : (' '|'\t')+ {skip();} ;
Thanks in advance. Ed.
eouti wrote:
I added the division. But I would like to notify user if he tries to divide by 0.
Inside your multExpr
rule, you shouldn't do if (e != 0) ...
, but you should access e
's value
attribute instead. Also, the left-hand-side of your expression is called e
while the right-hand-side is also called e
. You'd better give them unique names:
multExpr returns [int value]
: e1=atom {$value = $e1.value;}
( '*' e2=atom {$value *= $e2.value;}
| '/' e2=atom {if ($e2.value != 0) $value /= $e2.value;
else System.err.println("Division par 0 !");}
)*
;
But, do you really want to warn the user? After this warning, the calculation will just continue at the moment. IMO, you should just let the exception be thrown.
eouti wrote:
I would like to add the pow in my evaluator (with an higher precedence than multiply and divide.
Then add a powExpr
rule in between multExpr
and atom
and let multExpr
use this powExpr
rule instead of the atom
rule:
multExpr returns [int value]
: e1=powExpr {...}
( '*' e2=powExpr {...}
| '/' e2=powExpr {...}
)*
;
powExpr returns [int value]
: atom {...}
('^' atom {...}
)*
;
atom returns [int value]
: INT {...}
| ID {...}
| '(' expr ')' {...}
;
(powExpr
doesn't literally need to be in between these rules of course...)
Also, you might want to change returns [int value]
into returns [double value]
, especially since you're using division.
精彩评论