ANTLR4 - label assigned to a block which is not a set
Asked Answered
R

1

5

I am getting the errors label assigned to a block which is not a set. This error occurs for my labels: child, left, right, first, and last. What I am doing is assigning a label to a group of alternatives; shouldn't this be supported?

Fragment of my grammar:

expr:
      unaryExpr '(' child=(stat | expr | NUMBER) ')'                                                #labelUnaryExpr
    | binaryExpr '(' left=(stat | expr | constant) ',' right=(stat | expr | constant) ')'           #labelBinaryExpr
    | multipleExpr '(' first=(stat | expr | constant) (',' rest=(stat | expr | constant))+ ')'      #labelMultipleExpr
    ;   
Redemptioner answered 9/6, 2015 at 23:19 Comment(0)
B
9

The problem is that alternate elements can be of different types: TerminalNodes, the various rule Contexts, and Lists of both. NUMBER and expr are clearly different types. So assignment to a single label (single variable type) is not generally possible.

Extract the alternatives out as subrules:

....
| multipleExpr '(' first=altExpr (',' rest+=altExpr)+ ')'
;

altExpr   : stat | expr | constant ;

In this particular case, you don't necessarily need labels, since the altExpr's will be captured in a List in the multipleExpr context class -- the first element of the list will always be the first encountered altExpr.

Look at the relevant context class in the generated parser to see how the labels are realized as variables.

And, when constructing labeled lists, the += assignment op is required.

Updated:

The listener will have a method

enterMultipleExpr(YourParser.MultipleExprContext ctx);

The YourParser embedded class MultipleExprContext will have a method

    public List<AltExprContext> altExpr() {
        return getRuleContexts(AltExpr.class);
    }

so ctx.altExpr() returns the list. If you implement the labels, the context will also have the public variables:

public AltExprContext first;
public List<AltExprContext> rest;

Again, look at the relevant context class in the generated parser to see what generated accessors you have to work with.

Brittni answered 10/6, 2015 at 1:23 Comment(4)
Thanks for the informative response, could you explain how I could access the list in my Listener code without labels?Redemptioner
Random fact: Yesterday I used the += operator for the first time, on an expression like multipleExpr and chose the same labels first and rest. My other options were head and tail, but I preferred the former.Solidus
@Solidus with the += operator, you can actually use the same label for what you call "first" and "rest", e.g. "elements" and they will all be accumulated in the same vector.Scrappy
@Scrappy Yes, I know, thanks. I don't remember exactly now, more than 2 years later why, but I'm pretty sure I needed to structure it like this.Solidus

© 2022 - 2024 — McMap. All rights reserved.