private void GenerateFollow() { NonTerminal initialSymbol = (NonTerminal)InitialSymbol; initialSymbol.AddTerminalToFollow(Terminal.Initial); bool change = true; while (change) { change = false; foreach (string key in _nonTerminalHash.Keys) { NonTerminal nonTerminal = _nonTerminalHash[key]; string rule = nonTerminal.Rule; if (rule == null || rule.Length == 0) { return; } //Separa as regras pelo | string[] rules = rule.Split('|'); foreach (string simpleRule in rules) { if (rule.Contains(' ')) { string[] symbols = simpleRule.Split(' '); bool containsEmpty; bool isTerminal; //For avançando, lidando com a regra //A -> X1 X2 X3 ... XN for (int i = 0; i < symbols.Length; i++) { Symbol ruleSymbol = Symbol.GetSymbol(symbols[i]); if (ruleSymbol is NonTerminal) { //Variável para representar o primeiro não terminal NonTerminal nonTerm1 = (NonTerminal)ruleSymbol; containsEmpty = true; isTerminal = false; //Iteração para os não terminais seguintes a ele //Esse for só acontece caso cada não terminal seguinte tiver vazio //Caso um não terminal seguinte não tenha vazio ou seja um terminal, o for pára for (int j = i + 1; j < symbols.Length && containsEmpty && !isTerminal; j++) { ruleSymbol = Symbol.GetSymbol(symbols[j]); if (ruleSymbol is NonTerminal) { //Variável para representar o segundo não terminal NonTerminal nonTerm2 = (NonTerminal)ruleSymbol; containsEmpty = nonTerm2.ContainsEmpty(); change |= nonTerm1.AddFirstsToFollows(nonTerm2); } else { isTerminal = true; } } } else if (ruleSymbol != null) { if (i != 0) { //Adiciona o terminal no follow do não-terminal imediatamente anterior Symbol cacheSymbol = Symbol.GetSymbol(symbols[i - 1]); if (cacheSymbol is NonTerminal) { NonTerminal nonTerm1 = (NonTerminal)cacheSymbol; nonTerm1.AddTerminalToFollow((Terminal)ruleSymbol); } } } } containsEmpty = true; isTerminal = false; for (int i = symbols.Length - 1; i > -1 && containsEmpty && !isTerminal; i--) { Symbol ruleSymbol = Symbol.GetSymbol(symbols[i]); if (ruleSymbol is NonTerminal) { //Variável para representar o primeiro não terminal NonTerminal nonTerm1 = (NonTerminal)ruleSymbol; containsEmpty = nonTerm1.ContainsEmpty(); nonTerm1.AddFollowsToFollows(nonTerminal); } else if (ruleSymbol != null) { //Adiciona o terminal no follow do não-terminal imediatamente anterior if (i != 0) { Symbol cacheSymbol = Symbol.GetSymbol(symbols[i - 1]); if (cacheSymbol is NonTerminal) { NonTerminal nonTerm1 = (NonTerminal)cacheSymbol; nonTerm1.AddTerminalToFollow((Terminal)ruleSymbol); } } isTerminal = true; } } } else { //Para os casos //A -> a ou A -> B //No caso do terminal, nada é adicionado. //No caso do não terminal, os follows de A são passados para os follows de B Symbol ruleSymbol = Symbol.GetSymbol(simpleRule); if (ruleSymbol is NonTerminal) { NonTerminal anotherNonTerminal = (NonTerminal)ruleSymbol; //O retorno da função é verdadeiro caso algum novo terminal seja adicionado change |= anotherNonTerminal.AddFollowsToFollows(nonTerminal); } } } } } }