1
oC_RangeLiteral
            :  '*' SP? ( oC_IntegerLiteral SP? )? ( '..' SP? ( oC_IntegerLiteral SP? )? )? ;

Given a parser tree with ctx->oC_IntegerLiteral().size() == 1, How can I tell whether the first one is missing or the second one is missing?

Maybe the question title can be improved based on this concrete question.

cpchung
  • 774
  • 3
  • 8
  • 23

2 Answers2

2

You can label rule elements with name = like this:

oC_RangeLiteral
 :  '*' SP? 
    ( first=oC_IntegerLiteral SP? )? 
    ( '..' SP? ( second=oC_IntegerLiteral SP? )? )? 
 ;

Not sure how to use them with the C++ runtime, but for, say, Java, that'd look like this:

if (ctx.first != null) {
  // 'first' exists
}

if (ctx.second != null) {
  // 'second' exists
}

EDIT

Is it possible to achieve similar without modifying the grammar?

Sure, but that makes it a lot messier. You'd need to figure out if there is a .. among the children of oC_RangeLiteral and then check if the oC_IntegerLiteral comes before or after this .. token. Something like this:

// Only need to check if 1 child is present: in case of 2 or 0 children, it is clear
if (ctx.oC_IntegerLiteral().size() == 1) {

  int indexOfIntegerLiteral = ctx.children.indexOf(ctx.oC_IntegerLiteral().get(0));

  OptionalInt indexOfDotDot = java.util.stream.IntStream
      .range(0, ctx.children.size())
      .filter(i -> ctx.children.get(i).getText().equals(".."))
      .findFirst();

  System.out.printf("indexOfIntegerLiteral=%d\n", indexOfIntegerLiteral);
  System.out.printf("indexOfDotDot=%s\n", indexOfDotDot);

  if (indexOfDotDot.isPresent() && indexOfIntegerLiteral > indexOfDotDot.getAsInt()) {
    // If there is a ".." and the single `oC_IntegerLiteral` comes after it: it's the second one
  }
  else {
    // otherwise, it's the first `oC_IntegerLiteral`
  }
} 
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
1

Another way is this:

Give your terminals own token names, say

STAR: '*';
DOTDOT: '..';

With that your rules becomes:

oC_RangeLiteral
            :  STAR SP? ( oC_IntegerLiteral SP? )? ( DOTDOT SP? ( oC_IntegerLiteral SP? )? )? ;

Now in your code you just check for DOTDOT:

if (ctx->oC_IntegerLiteral().size() == 1) {
    if (ctx->DOTDOT()) {
         // ctx->oC_IntegerLiteral(0) is the second integer literal
    } else {
         // ctx->oC_IntegerLiteral(0) is the first integer literal
    }
}

As a side note: ctx->oC_IntegerLiteral().size() can be 0, because the it's optional in both cases where it appears in the rule. So, just testing the existence of DOTDOT does not tell you there's at least one integer literal.

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181