Trying to edit the below grammar and define the semantic actions required to translate arithmetic expressions written in the language defined below into postfix notation.
grammar Expr;
expr: expr ('*'|'/') term
| expr ('+'|'-') term
| term
;
term: '('expr')'
| ID
| NUM
;
ID: [a-z]+;
NUM: [0-9]+;
WS: [\t\r\n]+->skip;
To implement the translator I'm embedding semantic actions as Java code in the g4 grammar file by using the push and pop operations of a stack. But when compiling I'm hit with a bunch of errors.
Here is what I have so far:
grammar Expr;
expr: expr (op=('*'|'/') term
{ Stack<String> s = new Stack<String>();
s.push($op.text);
s.push($term.text);
String result = s.pop() + s.pop() + s.pop();
$expr.text = result;
}
)
| expr (op=('+'|'-') term
{ Stack<String> s = new Stack<String>();
s.push($op.text);
s.push($term.text);
String result = s.pop() + s.pop() + s.pop();
$expr.text = result;
}
)
| term
;
term: '('expr')' { Stack<String> s = new Stack<String>();
s.push($expr.text);
String result = s.pop();
$term.text = result;
}
| ID {Stack<String> s = new Stack<String>();
s.push($ID.text);
String result = s.pop();
$term.text = result;
}
| NUM {Stack<String> s = new Stack<String>();
s.push($NUM.text);
String result = s.pop();
$term.text = result;
}
;
ID: [a-z]+;
NUM: [0-9]+;
WS: [\t\r\n]+->skip;
When compiling I'm hit with an error block
I'm not sure how to fix this or if there's a better way to implement.
There are a number of issues here:
0 - Bart already mentioned how to import Stack, and that you can't assign to $term.text.
1 - If you want ANTLR to parse with the proper order of evaluation, you'll need expr
on both sides of your operator alternatives.
2 - in the rule expr (op=('*'|'/') term)
(omitting the action code), the (
and )
have no impact.
3 - your WS
rule didn't include the space character.
4 - always initiate your parsing with a rule the ends with one EOF (this forces the parser to attempt to consume all of the input. Without it, ANTLR may "stop short" if that's all it can recognize.
5 - You don't really need to create a new Stack instance in every action (the way you're pushing and popping in your actions basically just uses that stack as a place to define temp values, and doing no real processing between pushing and popping.). A global stack, however, can be used to good effect.
With all of those things in mind...
grammar Expr
;
@header {
import java.util.Stack;
}
@members {
Stack<String> stack = new Stack<String>();
}
start: expr EOF;
expr
: expr op = ('*' | '/') expr {
var e2 = stack.pop(); // second expr is on top of stack
stack.push( stack.pop() + " " + e2 + " " + $op.text);
}
| expr op = ('+' | '-') expr {
var e2 = stack.pop(); // second expr is on top of stack
stack.push( stack.pop() + " " + e2 + " " + $op.text);
}
| term // already on stack
;
term
: '(' expr ')' // already on stack
| ID { stack.push($ID.text); }
| NUM { stack.push($NUM.text); }
;
ID: [a-z]+;
NUM: [0-9]+;
WS: [ \t\r\n]+ -> skip;