Description
the generated code doesn’t set fields associated with labels.
TestParserExec.testListLabelOnSet produces the following:
public static class BContext extends ParserRuleContext {
public Token INT;
public List<Token> val = new ArrayList<Token>();
public Token FLOAT;
public Token _tset26;
public List<TerminalNode> FLOAT() { return getTokens(TParser.FLOAT); }
public List<TerminalNode> INT() { return getTokens(TParser.INT); }
but actually Token INT and Token FLOAT are never used, and are a potential source of confusion, not speaking of conflicts in certain target languages such as Python.
We state that parameters and local variables become fields in the context objects; that is a nonportable way to associate fields with context objects for semantic passes over the trees later. ultimately, I think we need a parse tree factory, but the book specifically talks about this and we might break a lot of code.
I also just noticed that labels are referenced in fact using the field:
/** If we don't know location of label def x, use this template */
labelref(x) ::= "<if(!x.isLocal)>((<x.ctx.name>)_localctx).<endif><x.name>"
are you sure this is not being used? it seems to be referenced a lot in the template.
More thoughts:
b : ID val+=(INT | FLOAT)* {Token t = $ID;} ;
generates
public static class BContext extends ParserRuleContext {
public Token ID;
public Token INT;
public TerminalNode ID() { return getToken(TParser.ID, 0); }
...
}
ID is set but only i think because we ref it:
((BContext)_localctx).ID = match(ID);
ctx.ID() would also work but it’s duplication.
Adding $INT ref:
b : ID val+=(INT | FLOAT)* {Token t = $ID; $INT;} ;
gives action:
Token t = ((BContext)_localctx).ID; ((BContext)_localctx).INT;
BUT, INT not set, just ID. interesting. Maybe tokens in loops that yield lists yield superfluous fields.
Suggested solution:
- for explicit labels, always set them but leave as fields for quick access (though redundant).
- implicit $token refs always use .token() not .token