in grammar/src/main/java/jetbrains/jetpad/grammar/GrammarData.java [113:163]
private void calculateFollow() {
for (NonTerminal nt : myGrammar.getNonTerminals()) {
myFollow.put(nt, new LinkedHashSet<Terminal>());
}
boolean hasChanges = true;
myFollow.get(myGrammar.getStart()).add(myGrammar.getEnd());
while (hasChanges) {
hasChanges = false;
for (NonTerminal nt : myGrammar.getNonTerminals()) {
for (Rule rule : nt.getRules()) {
List<Symbol> symbols = rule.getSymbols();
for (int i = 0; i < symbols.size(); i++) {
Symbol s = symbols.get(i);
for (int d = 1; d < symbols.size() - i; d++) {
Symbol next = symbols.get(i + d);
if (s instanceof NonTerminal && next != null) {
NonTerminal nonTerminal = (NonTerminal) s;
Set<Terminal> follow = myFollow.get(nonTerminal);
if (next instanceof Terminal) {
hasChanges |= follow.add((Terminal) next);
break;
} else if (next instanceof NonTerminal) {
hasChanges |= follow.addAll(myFirst.get((NonTerminal) next));
if (!myNullable.contains((NonTerminal) next)) {
break;
}
}
}
}
}
for (int i = symbols.size() - 1; i >= 0; i--) {
Symbol s = symbols.get(i);
if (s instanceof Terminal) {
break;
}
if (s instanceof NonTerminal) {
NonTerminal nonTerminal = (NonTerminal) s;
hasChanges |= myFollow.get(nonTerminal).addAll(myFollow.get(nt));
if (!myNullable.contains(nonTerminal)) break;
}
}
}
}
}
}