简体   繁体   中英

Implementing translator using ANTLR by embedding semantic actions as Java code in the g4 grammar file

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.

The compiler can't find the Stack class: you need to import it:

grammar Expr;

@header {
import java.util.Stack;
}

...

And you can't do things like $term.text = result; . You cannot re-assign the text from of a token or parser rule. Note that $term.text is just a shorthand notation for $term.getText()

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM