Reputation: 33
Using this grammar i could find the exponents but the answer I get is in reverse order (example : this is what i am getting : 2 ^ 2 ^ 3 = 64 this is what i am supposed to get : 2 ^ 2 ^ 3 = 2 ^ 8 = 256 ) )
grammar SDD1
;
options {
language = Java;
}
// header for parser related java
@header {
package com.compiler.tutorial;
}
// header for lexer related java
@lexer::header {
package com.compiler.tutorial;
}
evaluator returns[int result]
: expression EOF {$result = $expression.result;}
;
expression returns[int result]
: op1=mult {$result = $op1.result;}
( '+' op2=mult {$result = $result + $op2.result;}
| '-' op2=mult {$result = $result - $op2.result;}
)*
;
mult returns [int result]
: op1 = exponent {$result = $op1.result;}
( '*' op2=exponent {$result = $result * $op2.result;}
| '/' op2=exponent {$result = $result / $op2.result;}
)*
;
exponent returns [int result]
: op1=factor {$result = $op1.result;}
( '^' op2=factor {$result = (int) Math.pow( $result,$op2.result);}
)*
;
factor returns [int result]
: NUMBER {$result = Integer.parseInt($NUMBER.text);
System.out.println ("Number= " + $result);}|
IDENT {$result = 0;}|
'(' expression ')' {$result = $expression.result;}
;
fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
IDENT: LETTER( LETTER | DIGIT )*;
NUMBER: DIGIT+;
WS: (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};
Upvotes: 1
Views: 1380
Reputation: 2112
Your problem is that ^ operator is right associative. And with your current grammar it is defined like left associative. Operators like + , - or * are left associative which is naturally expressed in ANTLR grammar. To express right associativity you need recursive rule. I altered you grammar without touching your actions inside curly braces so it gives the correct parse tree:
grammar SDD1
;
options {
language = Java;
}
// header for parser related java
@header {
package com.compiler.tutorial;
}
// header for lexer related java
@lexer::header {
package com.compiler.tutorial;
}
evaluator returns[int result]
: expression EOF {$result = $expression.result;}
;
expression returns[int result]
: op1=mult {$result = $op1.result;}
( '+' op2=mult {$result = $result + $op2.result;}
| '-' op2=mult {$result = $result - $op2.result;}
)*
;
mult returns [int result]
: op1 = exponent {$result = $op1.result;}
( '*' op2=exponent {$result = $result * $op2.result;}
| '/' op2=exponent {$result = $result / $op2.result;}
)*
;
exponent returns [int result]
: atom ('^' exponent)?
;
atom returns [int result]
: NUMBER {$result = Integer.parseInt($NUMBER.text);
System.out.println ("Number= " + $result);}|
IDENT {$result = 0;}|
'(' expression ')' {$result = $expression.result;}
;
fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
IDENT: LETTER( LETTER | DIGIT )*;
NUMBER: DIGIT+;
WS: (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};
(Notice that the key rule that I added:
exponent returns [int result]
: atom ('^' exponent)?
;
doesn't have * behind the right brace, but ?)
So for the input:
2^3^4^5
you get the following parse tree:
Upvotes: 3
Reputation: 881423
For starters, 2(23)
is 256, not 512 - there is no (non-bizarre) associativity that will give you a 512 from that expression :-)
But, if you want right-to-left associativity for your exponential operator, you'll need to modify the exponent
rule to make it greedy. In other words, allow it to take an exponent
as a secondary operand (in preference) rather than just a factor
as it currently stands.
That way, 2^2^3 will indeed evaluate as 2(23)
rather than (22)3
.
Apologies, I don't know exactly how to achieve that with ANTLR, I'm showing my age here but I'm very much a lex/yacc man :-)
But this PDF seems to be what you're after (see slide 35). Basically, you define your item subject to exponentiation I
(factor
in your case) and the exponent E
becomes:
E = I ^ E
| I
Upvotes: 2