private void calculateFollow()

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;
            }
          }
        }
      }
    }
  }