Jeffrey Guenther
Jeffrey Guenther

Reputation: 901

Is there way to detect if an optional (? operator) tree grammar rule executed in an action?

path[Scope sc] returns [Path p]
@init{
List<String> parts = new ArrayList<String>();
}
    :   ^(PATH (id=IDENT{parts.add($id.text);})+ pathIndex? )
{// ACTION CODE
 // need to check if pathIndex has executed before running this code.
    if ($pathIndex.index >=0 ){
        p = new Path($sc, parts, $pathIndex.index);
    }else if($pathIndex.pathKey != ""){
        p = new Path($sc, parts, $pathIndex.pathKey);
}
;

Is there a way to detect if pathIndex was executed? In my action code, I tried testing $pathIndex == null, but ANTLR doesn't let you do that. ANTLRWorks gives a syntax error which saying "Missing attribute access on rule scope: pathIndex."

The reason why I need to do this is because in my action code I do:

$pathIndex.index

which returns 0 if the variable $pathIndex is translated to is null. When you are accessing an attribute, ANTLR generates pathIndex7!=null?pathIndex7.index:0 This causes a problem with an object because it changes a value I have preset to -1 as an error flag to 0.

Upvotes: 4

Views: 879

Answers (2)

Bart Kiers
Bart Kiers

Reputation: 170278

There are a couple of options:

1

Put your code inside the optional pathIndex:

rule
 : ^(PATH (id=IDENT{parts.add($id.text);})+ (pathIndex {/*pathIndex cannot be null here!*/} )? )
 ;

2

Use a boolean flag to denote the presence (or absence) of pathIndex:

rule
@init{boolean flag = false;}
 : ^(PATH (id=IDENT{parts.add($id.text);})+ (pathIndex {flag = true;} )? )
   {
     if(flag) {
       // ...
     }
   }
 ;

EDIT

You could also make pathIndex match nothing so that you don't need to make it optional inside path:

path[Scope sc] returns [Path p]
 : ^(PATH (id=IDENT{parts.add($id.text);})+ pathIndex)
   {
     // code
   }
 ;

pathIndex returns [int index, String pathKey]
@init {
  $index = -1;
  $pathKey = "";
}
 : ( /* some rules here */ )?
 ;

PS. Realize that the expression $pathIndex.pathKey != "" will most likely evaluate to false. To compare the contents of strings in Java, use their equals(...) method instead:

!$pathIndex.pathKey.equals("")

or if $pathIndex.pathKey can be null, you can circumvent a NPE by doing:

!"".equals($pathIndex.pathKey)

Upvotes: 4

cb4
cb4

Reputation: 9383

More information would have been helpful. However, if I understand correctly, when a value for the index is not present in the input you want to test for $pathIndex.index == null. This code does that using the pathIndex rule to return the Integer $index to the path rule:

 path
    : ^(PATH IDENT+ pathIndex?)
            { if ($pathIndex.index == null)
                    System.out.println("path index is null");
              else      
                System.out.println("path index = " + $pathIndex.index); }
    ;

 pathIndex returns [Integer index]
      : DIGIT 
            { $index = Integer.parseInt($DIGIT.getText()); }
      ;

For testing, I created these simple parser and lexer rules:

path    : 'path' IDENT+ pathIndex? -> ^(PATH IDENT+ pathIndex?)
        ;
pathIndex : DIGIT
        ;

/** lexer rules **/
DIGIT  :   '0'..'9' ;
IDENT  : LETTER+ ;
fragment LETTER : ('a'..'z' | 'A'..'Z') ;

When the index is present in the input, as in path a b c 5, the output is:

Tree = (PATH a b c 5)
path index = 5

When the index is not present in the input, as in path a b c, the output is:

Tree = (PATH a b c)
path index is null

Upvotes: 0

Related Questions