public Production(bool isInitial, NonTerminal lvalue, BnfTermList rvalues) { LValue = lvalue; foreach (GrammarTerm rv in rvalues) { if (rv != Grammar.Empty) { RValues.Add(rv); } } foreach (GrammarTerm term in RValues) { Terminal terminal = term as Terminal; if (terminal == null) { continue; } HasTerminals = true; if (terminal.Category == TokenCategory.Error) { IsError = true; } } for (int p = 0; p <= RValues.Count; p++) { LR0Items.Add(new LR0Item(this, p)); } }
public readonly LR0ItemList LR0Items = new LR0ItemList(); //LR0 items based on this production public Production(bool isInitial, NonTerminal lvalue, BnfTermList rvalues) { LValue = lvalue; //copy RValues skipping Empty pseudo-terminal foreach (BnfTerm rv in rvalues) { if (rv != Grammar.Empty) { RValues.Add(rv); } } //Calculate flags foreach (BnfTerm term in RValues) { Terminal terminal = term as Terminal; if (terminal == null) { continue; } HasTerminals = true; if (terminal.Category == TokenCategory.Error) { IsError = true; } }//foreach //Note that we add an extra LR0Item with p = RValues.Count for (int p = 0; p <= RValues.Count; p++) { LR0Items.Add(new LR0Item(this, p)); } }//constructor
public virtual void VerifyLanguageData() { var gd = Context.Language.GrammarData; //Collect all terminals and non-terminals var terms = new BnfTermSet(); //SL does not understand co/contravariance, so doing merge one-by-one foreach (var t in gd.Terminals) terms.Add(t); foreach (var t in gd.NonTerminals) terms.Add(t); var missingList = new BnfTermList(); foreach (var term in terms) { var terminal = term as Terminal; if (terminal != null && terminal.Category != TokenCategory.Content) continue; //only content terminals if (term.Flags.IsSet(TermFlags.NoAstNode)) continue; var config = term.AstConfig; if (config.NodeCreator != null || config.DefaultNodeCreator != null) continue; //We must check NodeType if (config.NodeType == null) config.NodeType = GetDefaultNodeType(term); if (config.NodeType == null) missingList.Add(term); else config.DefaultNodeCreator = CompileDefaultNodeCreator(config.NodeType); } if (missingList.Count > 0) // AST node type is not specified for term {0}. Either assign Term.AstConfig.NodeType, or specify default type(s) in AstBuilder. Context.AddMessage(ErrorLevel.Error, SourceLocation.Empty, Resources.ErrNodeTypeNotSetOn, string.Join(", ", missingList)); Context.Language.AstDataVerified = true; }
public virtual void VerifyLanguageData() { var gd = Context.Language.GrammarData; //Collect all terminals and non-terminals var terms = new BnfTermSet(); //SL does not understand co/contravariance, so doing merge one-by-one foreach (var t in gd.Terminals) { terms.Add(t); } foreach (var t in gd.NonTerminals) { terms.Add(t); } var missingList = new BnfTermList(); foreach (var term in terms) { var terminal = term as Terminal; if (terminal != null && terminal.Category != TokenCategory.Content) { continue; //only content terminals } if (term.Flags.IsSet(TermFlags.NoAstNode)) { continue; } var config = term.AstConfig; if (config.NodeCreator != null || config.DefaultNodeCreator != null) { continue; } //We must check NodeType if (config.NodeType == null) { config.NodeType = GetDefaultNodeType(term); } if (config.NodeType == null) { missingList.Add(term); } else { config.DefaultNodeCreator = CompileDefaultNodeCreator(config.NodeType); } } if (missingList.Count > 0) { // AST node type is not specified for term {0}. Either assign Term.AstConfig.NodeType, or specify default type(s) in AstBuilder. Context.AddMessage(ErrorLevel.Error, SourceLocation.Empty, Resources.ErrNodeTypeNotSetOn, missingList.ToString()); } Context.Language.AstDataVerified = true; }
private Production CreateProduction(NonTerminal lvalue, BnfTermList operands) { Production prod = new Production(lvalue); //create RValues list skipping Empty terminal and collecting grammar hints foreach (BnfTerm operand in operands) { if (operand == Grammar.Empty) { continue; } //Collect hints as we go - they will be added to the next non-hint element GrammarHint hint = operand as GrammarHint; if (hint != null) { hint.Position = prod.RValues.Count; prod.Hints.Add(hint); continue; } //Check if it is a Terminal or Error element Terminal t = operand as Terminal; if (t != null) { prod.Flags |= ProductionFlags.HasTerminals; if (t.Category == TokenCategory.Error) { prod.Flags |= ProductionFlags.IsError; } } //Add the operand info and LR0 Item _itemID++; LR0Item item = new LR0Item(prod, prod.RValues.Count, _itemID); prod.LR0Items.Add(item); prod.RValues.Add(operand); }//foreach operand //set the flags if (lvalue == Data.AugmentedRoot) { prod.Flags |= ProductionFlags.IsInitial; } if (prod.RValues.Count == 0) { prod.Flags |= ProductionFlags.IsEmpty; } //Add final LRItem _itemID++; prod.LR0Items.Add(new LR0Item(prod, prod.RValues.Count, _itemID)); return(prod); }
//TODO: This needs more work. Currently it reports all individual symbols most of the time, in a message like // "Syntax error, expected: + - < > = ..."; the better method is to group operator symbols under one alias "operator". // The reason is that code picks expected key list at current(!) state only, // slightly tweaking it for non-terminals, without exploring Reduce roots // It is quite difficult to discover grouping non-terminals like "operator" in current structure. // One possible solution would be to introduce "ExtendedLookaheads" in ParserState which would include // all NonTerminals that might follow the current position. This list would be calculated at start up, // in addition to normal lookaheads. #endregion private StringList GetCurrentExpectedSymbols() { BnfTermList inputElements = new BnfTermList(); StringSet inputKeys = new StringSet(); inputKeys.AddRange(_currentState.Actions.Keys); //First check all NonTerminals foreach (NonTerminal nt in Data.NonTerminals) { if (!inputKeys.Contains(nt.Key)) { continue; } //nt is one of our available inputs; check if it has an alias. If not, don't add it to element list; // and we have already all its "Firsts" keys in the list. // If yes, add nt to element list and remove // all its "fists" symbols from the list. These removed symbols will be represented by single nt alias. if (string.IsNullOrEmpty(nt.DisplayName)) { inputKeys.Remove(nt.Key); } else { inputElements.Add(nt); foreach (string first in nt.Firsts) { inputKeys.Remove(first); } } } //Now terminals foreach (Terminal term in Data.Terminals) { if (inputKeys.Contains(term.Key)) { inputElements.Add(term); } } StringList result = new StringList(); foreach (BnfTerm term in inputElements) { result.Add(string.IsNullOrEmpty(term.DisplayName)? term.Name : term.DisplayName); } result.Sort(); return(result); }
private static void CheckWrapTailHints(GrammarData data, NonTerminal nonTerminal, BnfTermList operands) { //WrapTail hint doesn't make sense in last position, so we start with Count-2 for (int i = operands.Count - 2; i >= 0; i--) { var hint = operands[i] as GrammarHint; if (hint == null || hint.HintType != HintType.WrapTail) continue; //we have WrapTail hint; wrap all operands after this into new non-terminal var wrapNt = new NonTerminal(nonTerminal.Name + "_tail" + nonTerminal._tailCount++); wrapNt.SetOption(TermOptions.IsTransient); wrapNt.Rule = new BnfExpression(); for (int j = i + 1; j < operands.Count; j++) { wrapNt.Rule.Data[0].Add(operands[j]); } operands.RemoveRange(i, operands.Count - i); operands.Add(wrapNt); data.AllTerms.Add(wrapNt); data.NonTerminals.Add(wrapNt); }//for i }
private Production CreateProduction(NonTerminal lvalue, BnfTermList operands) { Production prod = new Production(lvalue); GrammarHintList hints = null; //create RValues list skipping Empty terminal and collecting grammar hints foreach (BnfTerm operand in operands) { if (operand == _grammar.Empty) { continue; } //Collect hints as we go - they will be added to the next non-hint element GrammarHint hint = operand as GrammarHint; if (hint != null) { if (hints == null) { hints = new GrammarHintList(); } hints.Add(hint); continue; } //Add the operand and create LR0 Item prod.RValues.Add(operand); prod.LR0Items.Add(new LR0Item(_lastItemId++, prod, prod.RValues.Count - 1, hints)); hints = null; }//foreach operand //set the flags if (prod.RValues.Count == 0) { prod.Flags |= ProductionFlags.IsEmpty; } //Add final LRItem ComputeProductionFlags(prod); prod.LR0Items.Add(new LR0Item(_lastItemId++, prod, prod.RValues.Count, hints)); return(prod); }
private void ProcessUnparseHints(BnfExpression rule) { if (rule != null) { for (int childBnfTermListIndex = 0; childBnfTermListIndex < rule.Data.Count; childBnfTermListIndex++) { BnfTermList bnfTermList = rule.Data[childBnfTermListIndex]; try { UnparseHint unparseHint = (UnparseHint)bnfTermList.SingleOrDefault(bnfTerm => bnfTerm is UnparseHint); childBnfTermListIndexToUnparseHint.Add(childBnfTermListIndex, unparseHint); } catch (InvalidOperationException) { GrammarHelper.ThrowGrammarErrorException( GrammarErrorLevel.Error, "NonTerminal '{0}' has more than one UnparseHint on its {1}. childrenlist. Only one UnparseHint is allowed per childrenlist.", this, childBnfTermListIndex + 1 ); } } } }
public override string ToString() { if (_toString != null) { return(_toString); } try { string[] pipeArr = new string[Data.Count]; for (int i = 0; i < Data.Count; i++) { BnfTermList seq = Data[i]; string[] seqArr = new string[seq.Count]; for (int j = 0; j < seq.Count; j++) { seqArr[j] = seq[j].ToString(); } pipeArr[i] = String.Join("+", seqArr); } _toString = String.Join("|", pipeArr); return(_toString); } catch (Exception e) { return("(error: " + e.Message + ")"); } }
private StringList GetCurrentExpectedSymbols() { BnfTermList inputElements = new BnfTermList(); StringSet inputKeys = new StringSet(); inputKeys.AddRange(_currentState.Actions.Keys); //First check all NonTerminals foreach (NonTerminal nt in Data.NonTerminals) { if (!inputKeys.Contains(nt.Key)) continue; //nt is one of our available inputs; check if it has an alias. If not, don't add it to element list; // and we have already all its "Firsts" keys in the list. // If yes, add nt to element list and remove // all its "fists" symbols from the list. These removed symbols will be represented by single nt alias. if (string.IsNullOrEmpty(nt.DisplayName)) inputKeys.Remove(nt.Key); else { inputElements.Add(nt); foreach(string first in nt.Firsts) inputKeys.Remove(first); } } //Now terminals foreach (Terminal term in Data.Terminals) { if (inputKeys.Contains(term.Key)) inputElements.Add(term); } StringList result = new StringList(); foreach(BnfTerm term in inputElements) result.Add(string.IsNullOrEmpty(term.DisplayName)? term.Name : term.DisplayName); result.Sort(); return result; }
private Production CreateProduction(NonTerminal lvalue, BnfTermList operands) { Production prod = new Production(lvalue); GrammarHintList hints = null; //create RValues list skipping Empty terminal and collecting grammar hints foreach (BnfTerm operand in operands) { if (operand == _grammar.Empty) continue; //Collect hints as we go - they will be added to the next non-hint element GrammarHint hint = operand as GrammarHint; if (hint != null) { if (hints == null) hints = new GrammarHintList(); hints.Add(hint); continue; } //Add the operand and create LR0 Item prod.RValues.Add(operand); prod.LR0Items.Add(new LR0Item(_lastItemId++, prod, prod.RValues.Count - 1, hints)); hints = null; }//foreach operand //set the flags if (prod.RValues.Count == 0) prod.Flags |= ProductionFlags.IsEmpty; //Add final LRItem ComputeProductionFlags(prod); prod.LR0Items.Add(new LR0Item(_lastItemId++, prod, prod.RValues.Count, hints)); return prod; }
private Production CreateProduction(NonTerminal lvalue, BnfTermList operands) { Production prod = new Production(lvalue); GrammarHintList hints = null; //create RValues list skipping Empty terminal and collecting grammar hints foreach (BnfTerm operand in operands) { if (operand == Grammar.CurrentGrammar.Empty) continue; //Collect hints as we go - they will be added to the next non-hint element GrammarHint hint = operand as GrammarHint; if (hint != null) { if (hints == null) hints = new GrammarHintList(); hints.Add(hint); continue; } //Check if it is a Terminal or Error element Terminal t = operand as Terminal; if (t != null) { prod.Flags |= ProductionFlags.HasTerminals; if (t.Category == TokenCategory.Error) prod.Flags |= ProductionFlags.IsError; } //Add the operand info and LR0 Item LR0Item item = new LR0Item(_lastItemId++, prod, prod.RValues.Count, hints); prod.LR0Items.Add(item); prod.RValues.Add(operand); hints = null; }//foreach operand //set the flags if (prod.RValues.Count == 0) prod.Flags |= ProductionFlags.IsEmpty; //Add final LRItem prod.LR0Items.Add(new LR0Item(_lastItemId++, prod, prod.RValues.Count, hints)); return prod; }
public Production(bool isInitial, NonTerminal lvalue, BnfTermList rvalues) { LValue = lvalue; foreach (GrammarTerm rv in rvalues) if (rv != Grammar.Empty) RValues.Add(rv); foreach (GrammarTerm term in RValues) { Terminal terminal = term as Terminal; if (terminal == null) continue; HasTerminals = true; if (terminal.Category == TokenCategory.Error) IsError = true; } for (int p = 0; p <= RValues.Count; p++) LR0Items.Add(new LR0Item(this, p)); }
private static void CheckWrapTailHints(GrammarData data, NonTerminal nonTerminal, BnfTermList operands) { //WrapTail hint doesn't make sense in last position, so we start with Count-2 for (int i = operands.Count - 2; i >= 0; i--) { var hint = operands[i] as GrammarHint; if (hint == null || hint.HintType != HintType.WrapTail) { continue; } //we have WrapTail hint; wrap all operands after this into new non-terminal var wrapNt = new NonTerminal(nonTerminal.Name + "_tail" + nonTerminal._tailCount++); wrapNt.SetOption(TermOptions.IsTransient); wrapNt.Rule = new BnfExpression(); for (int j = i + 1; j < operands.Count; j++) { wrapNt.Rule.Data[0].Add(operands[j]); } operands.RemoveRange(i, operands.Count - i); operands.Add(wrapNt); data.AllTerms.Add(wrapNt); data.NonTerminals.Add(wrapNt); }//for i }