private void Predict(ail.net.parser.EarleyParser.Chart xi_chart) { // PREDICTOR: // if [A -> ... • B ..., j] is in S(i), add [B -> • a(lpha), i] to S(i) for all rules B -> a(lpha) // no args assertion!!! if (xi_chart != (object)null) { for (int i = xi_chart.PredictedK; i < xi_chart.PredictorItems.Count; i++, xi_chart.PredictedK++) { ail.net.parser.EarleyParser.Item item = (ail.net.parser.EarleyParser.Item)xi_chart.PredictorItems[i]; ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)item.CoreItem.Rule.Rhs[item.CoreItem.Dot]; // item.CoreItem.Dot is inside rhs.count if (symbol.IsNonTerminal() && !PredictedNonTerminals[symbol.Id]) { foreach (ail.net.parser.EarleyParser.CoreItem core_item in (ArrayList)PredictTable[symbol.Id]) { AddItem(core_item, xi_chart, xi_chart, null, ail.net.parser.EarleyParser.EFlags.ePredictor, GetErrorCost(item), Charts.Count == 1); // only check for initial chart, because items were introduced // by pseudo-prediction in BuildInitialSet } PredictedNonTerminals[symbol.Id] = true; // marked as predicted } } } }
public StringBuilder DecorateTreeVisitor(int xi_level, ail.net.parser.AstNode xi_ast_node) { ail.net.framework.Assert.NonNullReference(xi_ast_node, "xi_ast_node"); StringBuilder result = new StringBuilder(); for (ail.net.parser.AstNode node = xi_ast_node; node != (object)null; node = node.Brother) { ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)GrammarPool.Instance.Pool[(int)node.Token.Type]; if (symbol != (object)null) { for (int i = 0; i < xi_level; i++) { result.Append(" "); } result.Append(symbol.Name); result.Append(Environment.NewLine); } if (node.Child != (object)null) { result.Append(DecorateTreeVisitor(xi_level + 1, node.Child)); } } return(result); }
private ail.net.parser.EarleyParser.Chart Scan(ail.net.parser.EarleyParser.Chart xi_chart) { // SCANNER: // if [A -> ... • a ..., j] is in S(i) and a = x(i)+1, add [A -> ... a • ..., j] to S(i+1) // no args assertion!!! ail.net.parser.EarleyParser.Chart result = null; if (xi_chart != (object)null) { for (int i = 0; i < xi_chart.ScannerItems.Count; i++) { ail.net.parser.EarleyParser.Item item = (ail.net.parser.EarleyParser.Item)xi_chart.ScannerItems[i]; ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)item.CoreItem.Rule.Rhs[item.CoreItem.Dot]; // item.CoreItem.Dot is inside rhs.count if (symbol.Id == Lexer.Token.Type) { if (result == (object)null) { result = AddChart(); } AddItem((ail.net.parser.EarleyParser.CoreItem)CoreItemTable[item.CoreItem.Id + 1], item.OriginalChart, result, item, ail.net.parser.EarleyParser.EFlags.eScanner, GetErrorCost(item), true); } } } return(result); }
private void PopulatePredictTable() { ail.net.framework.Assert.Condition(Grammar.Rules.Count > 0, "ail.net.parser.EarleyParser.PopulatePredictTable: Grammar.Rules.Count > 0"); PredictTableAttr = new Hashtable(); foreach (ail.net.parser.GrammarSymbol symbol in GrammarPool.Instance.Pool.Values) { if (symbol.IsNonTerminal()) { ArrayList list = new ArrayList(); PredictTable[symbol.Id] = list; for (int i = 0; i < CoreItemTable.Count; i++) { ail.net.parser.GrammarRule rule = ((ail.net.parser.EarleyParser.CoreItem)CoreItemTable[i]).Rule; ail.net.parser.GrammarSymbol l_symbol = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; int dot = ((ail.net.parser.EarleyParser.CoreItem)CoreItemTable[i]).Dot; if (l_symbol.Id == symbol.Id && dot == 0) { list.Add(CoreItemTable[i]); } } } } PredictedNonTerminalsAttr = new bool[Lexer.Token.GetTokenSize()]; PredictedNonTerminalsZeroizerAttr = new bool[Lexer.Token.GetTokenSize()]; }
public ail.net.parser.GrammarSymbol AddSymbol(int xi_symbol_id, ail.net.parser.GrammarSymbol.EType xi_type, string xi_name) { ail.net.parser.GrammarSymbol result = (ail.net.parser.GrammarSymbol)PoolAttr[xi_symbol_id]; if (result == (object)null) { result = new ail.net.parser.GrammarSymbol(); result.Id = xi_symbol_id; result.Type = xi_type; result.Name = xi_name; PoolAttr[xi_symbol_id] = result; if (result.IsNonTerminal()) { NonTerminalCountAttr++; } else if (result.IsTerminal()) { TerminalCountAttr++; } } ail.net.framework.Assert.NonNullReference(result, "result"); result.AddRef(); return(result); }
public ail.net.parser.GrammarSymbol this [int xi_symbol_id] { get { ail.net.parser.GrammarSymbol result = (ail.net.parser.GrammarSymbol)PoolAttr[xi_symbol_id]; ail.net.framework.Assert.NonNullReference(result, "result"); return(result); } }
public void BuildNullabilitySet() { // The set of nullable non-terminals can be computed by the following algorithm: // (a) Set "nullable" equal to the set of non-terminals appearing on the left side // of productions of the form N -> e // (b) Until doing so adds no new non-terminals to "nullable", examine each production // in the grammar adding to "nullable" all left-hand-sides of productions whose // right-hand-side consist entirely of symbols in "nullable" // a foreach (ail.net.parser.GrammarRule rule in RulesAttr) { if (rule.IsEmptyRule()) { ((ail.net.parser.GrammarSymbol)rule.Lhs[0]).Nullable = true; } } // b for (;;) { bool changed = false; foreach (ail.net.parser.GrammarRule rule in RulesAttr) { ail.net.parser.GrammarSymbol l_symbol = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; if (!l_symbol.Nullable) { bool nullable = true; foreach (ail.net.parser.GrammarSymbol rhs_symbol in rule.Rhs) { if (!rhs_symbol.Nullable) { nullable = false; break; } } if (nullable) { l_symbol.Nullable = true; changed = true; } } } if (!changed) { break; } } }
private void Complete(ail.net.parser.EarleyParser.Chart xi_chart) { // COMPLETER: // if [A -> ... •, j] is in S(i), add [B -> ... A • ..., k] to S(i) for all items [B -> ... • A ..., k] in S(j) // no args assertion!!! if (xi_chart != (object)null) { for (int i = xi_chart.CompletedK; i < xi_chart.CompleterItems.Count; i++, xi_chart.CompletedK++) { ail.net.parser.EarleyParser.Item completer_item = (ail.net.parser.EarleyParser.Item)xi_chart.CompleterItems[i]; ail.net.parser.GrammarSymbol l_symbol = (ail.net.parser.GrammarSymbol)completer_item.CoreItem.Rule.Lhs[0]; ail.net.parser.EarleyParser.Chart chart = completer_item.OriginalChart; for (int k = 0; k < chart.PredictorItems.Count; k++) { ail.net.parser.EarleyParser.Item preditor_item = (ail.net.parser.EarleyParser.Item)chart.PredictorItems[k]; ail.net.parser.GrammarSymbol r_symbol = (ail.net.parser.GrammarSymbol)preditor_item.CoreItem.Rule.Rhs[preditor_item.CoreItem.Dot]; // preditor_item.CoreItem.Dot is inside rhs.count if (r_symbol.Id == l_symbol.Id) { ail.net.parser.EarleyParser.Item item = AddItem((ail.net.parser.EarleyParser.CoreItem)CoreItemTable[preditor_item.CoreItem.Id + 1], preditor_item.OriginalChart, xi_chart, preditor_item, ail.net.parser.EarleyParser.EFlags.eCompleter, GetErrorCost(preditor_item), true); SetRptr(item, completer_item); // if dot is before non-terminal and that non-terminal is nullable // also add item with dot after that non-terminal while (item.CoreItem.Dot < item.CoreItem.Rule.Rhs.Count && ((ail.net.parser.GrammarSymbol)item.CoreItem.Rule.Rhs[item.CoreItem.Dot]).Nullable) { item = AddItem((ail.net.parser.EarleyParser.CoreItem)CoreItemTable[item.CoreItem.Id + 1], item.OriginalChart, xi_chart, item, ail.net.parser.EarleyParser.EFlags.eCompleter, GetErrorCost(item), true); SetRptr(item, completer_item); } } } } } }
public ail.net.parser.GrammarSymbol AddRhsSymbol(int xi_symbol_id, ail.net.parser.GrammarSymbol.EType xi_type, string xi_name) { ail.net.parser.GrammarSymbol result = GrammarPool.Instance.AddSymbol(xi_symbol_id, xi_type, xi_name); RhsAttr.Add(result); if (result.IsNonTerminal()) { RhsNonTerminalCountAttr++; } else if (result.IsTerminal()) { RhsTerminalCountAttr++; } return(result); }
private bool IsRecognizedItem(ail.net.parser.EarleyParser.Item xi_item) { ail.net.framework.Assert.NonNullReference(xi_item, "xi_item"); bool result = false; if (xi_item.CoreItem.Rule.Lhs.Count > 0 && xi_item.OriginalChart != (object)null) { ail.net.parser.GrammarSymbol lhs_symbol = (ail.net.parser.GrammarSymbol)xi_item.CoreItem.Rule.Lhs[0]; result = xi_item.CoreItem.Dot == xi_item.CoreItem.Rule.Rhs.Count && // dot at the end lhs_symbol.Id == Grammar.StartSymbolId && xi_item.OriginalChart.Id == 0; } return(result); }
public int Compare(object xi_s1, object xi_s2) { ail.net.parser.GrammarSymbol s1 = (ail.net.parser.GrammarSymbol)xi_s1; ail.net.parser.GrammarSymbol s2 = (ail.net.parser.GrammarSymbol)xi_s2; int result = s1.NameAttr == s2.NameAttr ? 1 : 0; if ((int)s1.NameAttr[0] < (int)s2.NameAttr[0]) { result = -1; } else if ((int)s1.NameAttr[0] > (int)s2.NameAttr[0]) { result = 1; } return(result); }
public int Compare(object xi_s1, object xi_s2) { ail.net.parser.GrammarSymbol s1 = (ail.net.parser.GrammarSymbol)xi_s1; ail.net.parser.GrammarSymbol s2 = (ail.net.parser.GrammarSymbol)xi_s2; int result = 0; if (s1.IdAttr < s2.IdAttr) { result = -1; } else if (s1.IdAttr > s2.IdAttr) { result = 1; } return(result); }
public int Compare(object xi_i1, object xi_i2) { ail.net.parser.GrammarSymbol i1 = (ail.net.parser.GrammarSymbol)xi_i1; ail.net.parser.GrammarSymbol i2 = (ail.net.parser.GrammarSymbol)xi_i2; int result = 0; if (i1.Id < i2.Id) { result = -1; } else if (i1.Id > i2.Id) { result = 1; } return(result); }
public void RemoveSymbol(int xi_symbol_id) { ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)PoolAttr[xi_symbol_id]; if (symbol != (object)null && symbol.Release() == 0) { if (symbol.IsNonTerminal()) { NonTerminalCountAttr--; } else if (symbol.IsTerminal()) { TerminalCountAttr--; } PoolAttr.Remove(symbol.Id); } }
public ArrayList BuildEFFirstKSet(ArrayList xi_symbols, int xi_k) { // Let's X belongs to N U T. EFFk(X a(lpha)) = EFFk(X) (+)k FIRSTk(a(lpha)). ail.net.framework.Assert.NonNullReference(xi_symbols, "xi_symbols"); ArrayList result = null; ail.net.parser.GrammarSymbol x = (ail.net.parser.GrammarSymbol)xi_symbols[0]; ArrayList alpha = new ArrayList(xi_symbols.Count - 1); // reserve for (int i = 1; i < xi_symbols.Count; i++) // the first is 'x' { alpha.Add(xi_symbols[i]); } ArrayList x_eff = ((ail.net.parser.GrammarSymbol)ail.net.parser.GrammarPool.Instance.Pool[x.Id]).EFFirstSet; ArrayList alpha_first = BuildFirstKSet(alpha); result = OperatorInfixK(x_eff, alpha_first, xi_k); return(result); }
private void BuildAstLevel(ail.net.parser.EarleyParser.Item xi_item, ail.net.parser.AstNode xi_root_node) { ail.net.framework.Assert.NonNullReference(xi_item, "xi_item"); ail.net.framework.Assert.NonNullReference(xi_root_node, "xi_root_node"); // populate a rhs stack with items of the current level Stack rhs_stack = new Stack(); PopulateRhsStack(rhs_stack, xi_item); // processing all nodes(items) of the level while (rhs_stack.Count > 0) { ail.net.parser.EarleyParser.Item curr_item = (ail.net.parser.EarleyParser.Item)rhs_stack.Pop(); ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)curr_item.CoreItem.Rule.Rhs[curr_item.CoreItem.Dot - 1]; // 'dot-1', because we pushed items with 'dot' > 0 if (symbol.IsTerminal()) { // handle terminal Semantics.HandleTerminal(xi_root_node, curr_item.MasterChart.Token); } else if (symbol.IsNonTerminal()) { // handle non-terminal if (curr_item.Rptrs.Count <= 1) { // r-ptr has exactly one element ail.net.framework.Assert.Condition(curr_item.Rptrs.Count == 1, "ail.net.parser.EarleyParser.BuildAstLevel: curr_item.Rptrs.Count == 1"); ail.net.parser.EarleyParser.Item r_ptr_item = (ail.net.parser.EarleyParser.Item)curr_item.Rptrs[0]; ail.net.parser.AstNode new_node = Semantics.HandleNonTerminalBefore(xi_root_node, r_ptr_item); if (new_node != (object)null) { r_ptr_item.Flags |= (uint)ail.net.parser.EarleyParser.EFlags.eMarked; BuildAstLevel(r_ptr_item, new_node); r_ptr_item.Flags &= ~(uint)ail.net.parser.EarleyParser.EFlags.eMarked; } Semantics.HandleNonTerminalAfter(xi_root_node, r_ptr_item); } else { // r-ptr has more than one elements, ambiguity foreach (ail.net.parser.EarleyParser.Item r_ptr_item in curr_item.Rptrs.Values) { if ((r_ptr_item.Flags & (uint)ail.net.parser.EarleyParser.EFlags.eMarked) == 0) { ail.net.parser.AstNode new_node = Semantics.HandleNonTerminalBefore(xi_root_node, r_ptr_item); if (new_node != (object)null) { r_ptr_item.Flags |= (uint)ail.net.parser.EarleyParser.EFlags.eMarked; BuildAstLevel(r_ptr_item, new_node); r_ptr_item.Flags &= ~(uint)ail.net.parser.EarleyParser.EFlags.eMarked; Semantics.HandleNonTerminalAfter(xi_root_node, r_ptr_item); break; } } } } } } }
public void BuildFirstKSet(int xi_k) { // builds FIRSTk and EFFk sets for the given grammar // Sudkump p. 498 // 1. for each a belongs to T do F'(a) = {a} // 2. for each A belongs to N do F(A) = {e(psilon)} if A is nullable or empty otherwise // 3. repeat // 3.1 for each A belongs to N do F'(A) = F(A) // 3.2 for each rule A -> w = u1u2...un with n > 0 do // F(A) = F(A) U TRUNKk(F'(u1)F'(u2)...F'(un)) // until F(A) = F'(A) for all A belongs to N // 4. FIRSTk(A) = F(A) // FIRST set is list of lists for every non-terminal in grammar, size of "lists" is K // ( ) // | \ // | --- // | | // (0,1..K) (0,1..K) // // Opredelim mnozhestvo EFFk(x), sostoyashee iz vseh elementov mnozhestva FIRSTk(x), // pri vivode kotorih neterminal na levom konce x (esli on est') ne zamenyaetsya na pustuu zepochku // // The epsilon-free first k derived symbols, EFFk(), are found by computing FIRST as above, // but tagging all symbols which are derived using epsilon productions of the form, // as non-epsilon free, and keeping only the epsilon-free derived terminals. //?? ail.net.framework.Assert.Condition(xi_k > 0, "ail.net.parser.Grammar.BuildFirstSet: xi_k > 0"); // 1. for each a belongs to T do F'(a) = {a} // 2. for each A belongs to N do F(A) = {e(psilon)} if A is nullable or empty otherwise foreach (ail.net.parser.GrammarSymbol symbol in ail.net.parser.GrammarPool.Instance.Pool.Values) { if (symbol.IsTerminal()) { ArrayList e = new ArrayList(); e.Add(symbol.Id); symbol.FirstSet.Add(e); e = new ArrayList(); e.Add(symbol.Id); symbol.EFFirstSet.Add(e); } else { if (symbol.Nullable) { ArrayList e = new ArrayList(); e.Add((int)ail.net.parser.Token.EType.eEpsilon); symbol.FirstSet.Add(e); } } } // 3. repeat for (;;) { bool changed = false; // fixed point foreach (ail.net.parser.GrammarRule rule in Rules) { // non-terminal work with ail.net.parser.GrammarSymbol non_terminal = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; int count = non_terminal.FirstSet.Count; // check if we have any empty sets bool has_empty_sets = false; foreach (ail.net.parser.GrammarSymbol symbol in rule.Rhs) { if (symbol.FirstSet.Count == 0) { has_empty_sets = true; break; } } if (has_empty_sets) { // concatanation of the empty set with any set yields the empty set continue; } // 3.2 for each rule A -> w = u1u2...un with n > 0 do // F(A) = F(A) U TRUNKk(F'(u1)F'(u2)...F'(un)) // until F(A) = F'(A) for all A belongs to N ArrayList entry = new ArrayList(); ArrayList eff_entry = new ArrayList(); for (int i = rule.Rhs.Count - 1; i >= 0; i--) // as operator (+) is associative { // it can be applied from back to the front // (+) ... (+) entry = OperatorInfixK(((ail.net.parser.GrammarSymbol)rule.Rhs[i]).FirstSet, entry, xi_k); if (!rule.IsEmptyRule()) { eff_entry = OperatorInfixK(((ail.net.parser.GrammarSymbol)rule.Rhs[i]).EFFirstSet, eff_entry, xi_k); } } // check existence if (entry != null && entry.Count > 0) { foreach (ArrayList subset in entry) { if (!HasEntry(non_terminal.FirstSet, subset)) { non_terminal.FirstSet.Add(subset); } } } if (eff_entry != (object)null && eff_entry.Count > 0) { foreach (ArrayList subset in eff_entry) { if (!HasEntry(non_terminal.EFFirstSet, subset)) { non_terminal.EFFirstSet.Add(subset); } } } changed = changed ? changed : count != non_terminal.FirstSet.Count; } if (!changed) { break; } } }
public void BuildFollowSet() { // go through the rules and for each rule we look at each non-terminal on the righthand // side. For example, we may have a rule X -> ... ABC ..., and let A be a non-terminal. // Calculate FIRST(BC...) and add all elements from this set, except 'e' to FOLLOW(A). If // 'e' is in FIRST(BC...), then we add all elements from FOLLOW(X) to FOLLOW(A). The // process is repeated until there are no more changes to the table for FOLLOW. // // The computation of Follow(A) depends of the First sets defined earlier. If B -> a(lpha)Ab(eta) // then Follow(A) must contains First(b(eta)). If 'e' belongs to First(b(eta)) (i.e., b(eta) is nullable), // or if b(eta) is empty, then Follow(A) must also contain Follow(B). ail.net.parser.GrammarSymbol symbol = (ail.net.parser.GrammarSymbol)ail.net.parser.GrammarPool.Instance.Pool[StartSymbolIdAttr]; symbol.FollowSet.Add((int)ail.net.parser.Token.EType.eEpsilon); bool changed; for (;;) { changed = false; foreach (ail.net.parser.GrammarRule rule in RulesAttr) { ail.net.parser.GrammarSymbol l_symbol = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; for (int k = 0, m = rule.Rhs.Count; k < m; k++) { ail.net.parser.GrammarSymbol r_symbol = (ail.net.parser.GrammarSymbol)rule.Rhs[k]; if (r_symbol.IsNonTerminal()) { int count = r_symbol.FollowSet.Count; ArrayList first_set = new ArrayList(); if (k < m - 1) { first_set.Add(rule.Rhs[k + 1]); // temporary storage first_set = BuildFirstSet(first_set); } for (int i = 0, n = first_set.Count; i < n; i++) { if ((int)first_set[i] != (int)ail.net.parser.Token.EType.eEpsilon && !r_symbol.FollowSet.Contains(first_set[i])) { r_symbol.FollowSet.Add(first_set[i]); } } if (k == m - 1 || first_set.Contains(ail.net.parser.Token.EType.eEpsilon)) { for (int i = 0, n = l_symbol.FollowSet.Count; i < n; i++) { if (!r_symbol.FollowSet.Contains(l_symbol.FollowSet[i])) { r_symbol.FollowSet.Add(l_symbol.FollowSet[i]); } } } changed = changed ? changed : count != r_symbol.FollowSet.Count; } } } if (!changed) { break; } } }
public void BuildFollowKSet(int xi_k) { // Sudkump p. 501 // 1. FL(S) = {e(psilon)} // 2. for each A belongs to N-{S} do FL(A) = empty // 3. repeat // 3.1 for each A belongs to N do FL'(A) = FL(A) // 3.2 for each rule A -> w = u1u2...un with w != T* do // 3.2.1 L = FL'(A) // 3.2.2 if un belongs to N then FL(un) = FL(un) U L // 3.2.3 for i = n-1 to 1 do // 3.2.3.1 L = TRUNCk(FIRSTk(ui+1)L) // 3.2.3.2 if ui belongs to N then FL(ui) = FL(ui) U L // end for // end for // until FL(A) = FL'(A) for every A belongs to N // 4. FOLLOWk(A) = FL(A) // FOLLOW set is list of lists for every non-terminal in grammar, size of "lists" is K // ( ) // | \ // | --- // | | // (0,1..K) (0,1..K) ail.net.framework.Assert.Condition(xi_k > 0, "ail.net.parser.Grammar.BuildFirstSet: xi_k > 0"); // collect all non-terminals to deal with Hashtable nonterminals = new Hashtable(); foreach (ail.net.parser.GrammarSymbol symbol in ail.net.parser.GrammarPool.Instance.Pool.Values) { if (symbol.IsNonTerminal()) { nonterminals[symbol.Id] = symbol; } } // 1. FL(S) = {e(psilon)} ArrayList fl = ((ail.net.parser.GrammarSymbol)nonterminals[StartSymbolId]).FollowSet; // trigger initialization ArrayList fl_e = new ArrayList(); // follow set element fl_e.Add((int)ail.net.parser.Token.EType.eEpsilon); fl.Add(fl_e); // 2. for each A belongs to N-{S} do FL(A) = empty foreach (ail.net.parser.GrammarSymbol symbol in nonterminals.Values) { ArrayList dummy = symbol.FollowSet; // trigger initialization } // 3. repeat for (;;) { bool changed = false; // 3.2 for each rule A -> w = u1u2...un with w != T* do foreach (ail.net.parser.GrammarRule rule in RulesAttr) { // w != T* if (rule.RhsNonTerminalCount > 0) { // 3.2.1 L = FL'(A) ail.net.parser.GrammarSymbol a = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; ArrayList l = a.FollowSet; // 3.2.2 if un belongs to N then FL(un) = FL(un) U L ail.net.parser.GrammarSymbol un = (ail.net.parser.GrammarSymbol)rule.Rhs[rule.Rhs.Count - 1]; if (un.IsNonTerminal()) { fl = ((ail.net.parser.GrammarSymbol)nonterminals[un.Id]).FollowSet; foreach (ArrayList e in l) { if (!HasEntry(fl, e)) { fl.Add(e); changed = true; } } } // 3.2.3 for i = n-1 to 1 do // 3.2.3.1 L = TRUNCk(FIRSTk(ui+1)L) // 3.2.3.2 if ui belongs to N then FL(ui) = FL(ui) U L // end for for (int i = rule.Rhs.Count - 2; i >= 0; i--) { l = OperatorInfixK(((ail.net.parser.GrammarSymbol)rule.Rhs[i + 1]).FirstSet, l, xi_k); if (((ail.net.parser.GrammarSymbol)rule.Rhs[i]).IsNonTerminal()) { fl = ((ail.net.parser.GrammarSymbol)nonterminals[((ail.net.parser.GrammarSymbol)rule.Rhs[i]).Id]).FollowSet; foreach (ArrayList e in l) { if (!HasEntry(fl, e)) { fl.Add(e); changed = true; } } } } } } if (!changed) { break; } } }
public void BuildFirstSet() { // Set First(x) equal to {x} for all terminals. // Set First(x) to {e} for all nullable non-terminals and to {} for all other non-terminals. foreach (ail.net.parser.GrammarSymbol symbol in ail.net.parser.GrammarPool.Instance.Pool.Values) { if (symbol.IsTerminal()) { symbol.FirstSet.Add(symbol.Id); } else { if (symbol.Nullable) { symbol.FirstSet.Add((int)ail.net.parser.Token.EType.eEpsilon); } } } // Repeat the following process until no further changes occur: // For each production // N -> x1 x2 ... xk // (a) Add (First(x1)-{e}) to First(N) // (b) If e belongs to First(x1) then add (First(x1)-{e}) to First(N) // (c) If e belongs to First(x1) and e belongs to First(x2) then also add (First(x2)-{e}) // to First(N) // (d) If e belongs to First(x1) and e belongs to First(x2) and e belongs to First(x3) // then also add (First(x3)-{e}) to First(N) // (e) Continue in the same manner for x4, ... , xk // // either: // repeat // for each production X -> Y1Y2 ... Yn do // if Y1 not nullable then // add FIRST(Y1) to FIRST(X) // else if Y1 ... Yi-1 are all nullable (or if i = n) then // add FIRST(Y1) U ... U FIRST(Yi) to FIRST(X) // end if // end for // until FIRST not changed in this iteration for (;;) { bool changed = false; foreach (ail.net.parser.GrammarRule rule in RulesAttr) { ail.net.parser.GrammarSymbol non_terminal = (ail.net.parser.GrammarSymbol)rule.Lhs[0]; int count = non_terminal.FirstSet.Count; foreach (ail.net.parser.GrammarSymbol r_symbol in rule.Rhs) { bool has_epsilon = false; for (int i = 0, n = r_symbol.FirstSet.Count; i < n; i++) { int r_symbol_id = (int)r_symbol.FirstSet[i]; if (r_symbol_id != (int)ail.net.parser.Token.EType.eEpsilon) { if (!non_terminal.FirstSet.Contains(r_symbol_id)) { non_terminal.FirstSet.Add(r_symbol_id); } } else { has_epsilon = true; // should be only one } } if (!has_epsilon) { break; } } changed = changed ? changed : count != non_terminal.FirstSet.Count; } if (!changed) { break; } } }