Возьми эту фиктивную antlr4-грамматику:
grammar testingGrammar;
@header{package gen;}
dsopt_rename: 'rename' (OLDN=ID '=' NEWN=ID)+;
ID: [a-zA-Z_];
Моя цель - Java.Я хочу получить два списка: oldNames и newNames;можно сделать так:
@Override
public DsOption visitDsopt_rename(Dsopt_renameContext ctx) {
LinkedList<String> oldNames = new LinkedList<String>();
LinkedList<String> newNames = new LinkedList<String>();
for (int i=0; i < ctx.ID().size(); ++i) {
LinkedList<String> rename = (i%2 == 1) ? oldNames : newNames;
rename.add(ctx.ID(i).getText());
}
return new DsOptRename(oldNames, newNames);
}
Я бы предпочел следующее - также известное как "второй подход" - (если бы это сработало):
@Override
public DsOption visitDsopt_rename(Dsopt_renameContext ctx) {
LinkedList<String> oldNames = new LinkedList<String>();
LinkedList<String> newNames = new LinkedList<String>();
ctx.OLDN().forEach(e -> oldNames.add(e.getText()));
ctx.NEWN().forEach(e -> oldNames.add(e.getText()));
return new DsOptRename(oldNames, newNames);
}
Очевидно, метки ctx.OLDN (без скобок) и ctx.NEWN просто сохраняют первую итерацию списка, а не весь список (в то время как, например, ID хранит весь список).
Первый вопрос: 1. Возможно исправитьвторой код, чтобы выполнить работу, используя второй подход (т.е. не касаясь грамматики)?Имейте в виду, что этот пример был достаточно легким, чтобы первый код работал нормально, но если бы у меня было правило, например «пример: (ID ID? ID) +;»потребуется другой подход;возможно, это невозможно исправить, потому что этот подход не должен работать в первую очередь (правило должно быть определено по-другому).
Каков лучший способ изменить грамматику, чтобы сделать это;Я думаю:
grammar testingGrammar;
@header{package gen;}
dsopt_rename: 'rename' (oldn '=' newn)+;
oldn: ID;
newn: ID;
ID: [a-zA-Z_];
но это, вероятно, подвержено ошибкам, потому что oldn и newn могут совпадать непреднамеренно.
Спасибо за ваше время!