1
votes

I am trying to parse a boolean expression of the following type B1=p & A4=p | A6=p &(~A5=c)

I want a tree that I can use to evaluate the above expression. So I tried this in Antlr3 with the example in Antlr parser for and/or logic - how to get expressions between logic operators?

It worked in Antlr3. Now I want to do the same thing for Antlr 4. I came up the grammar below and it compiles. But I am having trouble writing the Java code.

Start of Antlr4 grammar

grammar TestAntlr4;

options {
  output = AST;
}

tokens { AND, OR, NOT }

  AND : '&';
  OR  : '|';
  NOT : '~';


// parser/production rules start with a lower case letter
parse
  :  expression EOF!    // omit the EOF token
  ;

expression
  :  or
  ;

or
  :  and (OR^ and)*    // make `||` the root
  ;

and
  :  not (AND^ not)*      // make `&&` the root
  ;

not
  :  NOT^ atom    // make `~` the root
  |  atom
  ;

atom
  :  ID
  |  '('! expression ')'!    // omit both `(` and `)`
  ;

// lexer/terminal rules start with an upper case letter
ID
  :
    (
    'a'..'z'
    | 'A'..'Z'
    | '0'..'9' | ' '
    | ('+'|'-'|'*'|'/'|'_')
    | '='
  )+ 
  ;

I have written the Java Code (snippet below) for getting a tree for the expression "B1=p & A4=p | A6=p &(~A5=c)". I am expecting & with children B1=p and |. The child | operator will have children A4=p and A6=p &(~A5=c). And so on. Here is that Java code but I am stuck trying to figure out how I will get the tree. I was able to do this in Antlr 3.

Java Code

String src = "B1=p & A4=p | A6=p &(~A5=c)";
CharStream stream = (CharStream)(new ANTLRInputStream(src));
TestAntlr4Lexer lexer = new TestAntlr4Lexer(stream);
parser.setBuildParseTree(true);
ParserRuleContext tree = parser.parse();
tree.inspect(parser); 
if ( tree.children.size() > 0) {
    System.out.println(" **************");
    test.getChildren(tree, parser);
}

The get Children method is below. But this does not seem to extract any tokens.

public void getChildren(ParseTree tree, TestAntlr4Parser parser ) {
   for (int i=0; i<tree.getChildCount(); i++){
       System.out.println(" Child i= " + i);
       System.out.println(" expression = <" + tree.toStringTree(parser) + ">");
       if ( tree.getChild(i).getChildCount() != 0 ) {
           this.getChildren(tree.getChild(i), parser);
       }
   }
}

Could someone help me figure out how to write the parser in Java?

1

1 Answers

3
votes

The output=AST option was removed in ANTLR 4, as well as the ^ and ! operators you used in the grammar. ANTLR 4 produces parse trees instead of ASTs, so the root of the tree produced by a rule is the rule itself. For example, given the following rule:

and : not (AND not)*;

You will end up with an AndContext tree containing NotContext and TerminalNode children for the not and AND references, respectively. To make it easier to work with the trees, AndContext will contain a generated method not() which returns a list of context objects returned by the invocations of the not rule (return type List<? extends NotContext>). It also contains a generated method AND which returns a list of the TerminalNode instances created for each AND token that was matched.