protected virtual ParserConfiguration <IN, OUT> ExtractEbnfParserConfiguration(Type parserClass, Parser <EbnfTokenGeneric, GrammarNode <IN> > grammarParser) { var conf = new ParserConfiguration <IN, OUT>(); var nonTerminals = new Dictionary <string, NonTerminal <IN> >(); var methods = parserClass.GetMethods().ToList(); methods = methods.Where(m => { var attributes = m.GetCustomAttributes().ToList(); var attr = attributes.Find(a => a.GetType() == typeof(ProductionAttribute)); return(attr != null); }).ToList(); methods.ForEach(m => { var attributes = (ProductionAttribute[])m.GetCustomAttributes(typeof(ProductionAttribute), true); foreach (var attr in attributes) { var ruleString = attr.RuleString; var parseResult = grammarParser.Parse(ruleString); if (!parseResult.IsError) { var rule = (Rule <IN>)parseResult.Result; rule.RuleString = ruleString; rule.SetVisitor(m); NonTerminal <IN> nonT = null; if (!nonTerminals.ContainsKey(rule.NonTerminalName)) { nonT = new NonTerminal <IN>(rule.NonTerminalName, new List <Rule <IN> >()); } else { nonT = nonTerminals[rule.NonTerminalName]; } nonT.Rules.Add(rule); nonTerminals[rule.NonTerminalName] = nonT; } else { var message = parseResult .Errors .Select(e => e.ErrorMessage) .Aggregate((e1, e2) => e1 + "\n" + e2); message = $"rule error [{ruleString}] : {message}"; throw new ParserConfigurationException(message); } } }); conf.NonTerminals = nonTerminals; return(conf); }
private static NonTerminal <IN> BuildNonTerminal <IN>(bool last, string name, string nextName, List <OperationMetaData <IN> > operations, Dictionary <int, List <OperationMetaData <IN> > > operationsByPrecedence) where IN : struct { var nonTerminal = new NonTerminal <IN>(name, new List <Rule <IN> >()); foreach (var operation in operations) { if (operation.Affix == Affix.InFix) { var rule = new Rule <IN>(); rule.Clauses.Add(new NonTerminalClause <IN>(nextName)); rule.Clauses.Add(new TerminalClause <IN>(operation.OperatorToken)); rule.Clauses.Add(new NonTerminalClause <IN>(name)); rule.IsExpressionRule = true; rule.ExpressionAffix = operation.Affix; rule.SetVisitor(operation); nonTerminal.Rules.Add(rule); } else if (operation.Affix == Affix.PreFix) { var rule = new Rule <IN>(); rule.Clauses.Add(new TerminalClause <IN>(operation.OperatorToken)); rule.Clauses.Add(new NonTerminalClause <IN>(nextName)); rule.IsExpressionRule = true; rule.ExpressionAffix = operation.Affix; rule.SetVisitor(operation); nonTerminal.Rules.Add(rule); } else if (operation.Affix == Affix.PostFix) { var rule = new Rule <IN>(); rule.Clauses.Add(new NonTerminalClause <IN>(nextName)); rule.Clauses.Add(new TerminalClause <IN>(operation.OperatorToken)); rule.IsExpressionRule = true; rule.ExpressionAffix = operation.Affix; rule.SetVisitor(operation); nonTerminal.Rules.Add(rule); } } var rule0 = new Rule <IN>(); rule0.Clauses.Add(new NonTerminalClause <IN>(nextName)); rule0.IsExpressionRule = true; rule0.ExpressionAffix = Affix.NotOperator; rule0.IsByPassRule = true; nonTerminal.Rules.Add(rule0); return(nonTerminal); }
private static void GenerateExpressionParser <IN, OUT>(ParserConfiguration <IN, OUT> configuration, string operandNonTerminal, Dictionary <int, List <OperationMetaData <IN> > > operationsByPrecedence, string parserClassName) where IN : struct { var precedences = operationsByPrecedence.Keys.ToList(); precedences.Sort(); var max = precedences.Max(); for (var i = 0; i < precedences.Count; i++) { var precedence = precedences[i]; var nextPrecedence = i < precedences.Count - 1 ? precedences[i + 1] : -1; var operations = operationsByPrecedence[precedence]; var name = GetNonTerminalNameForPrecedence(precedence, operationsByPrecedence, operandNonTerminal); var nextName = GetNonTerminalNameForPrecedence(nextPrecedence, operationsByPrecedence, operandNonTerminal); var nonTerminal = BuildNonTerminal(i == precedences.Count - 1, name, nextName, operations, operationsByPrecedence); configuration.NonTerminals[nonTerminal.Name] = nonTerminal; } // entry point non terminal var entrypoint = new NonTerminal <IN>($"{parserClassName}_expressions", new List <Rule <IN> >()); var prec = precedences[0]; var lowestname = GetNonTerminalNameForPrecedence(prec, operationsByPrecedence, operandNonTerminal); var rule = new Rule <IN>(); rule.Clauses.Add(new NonTerminalClause <IN>(lowestname)); rule.IsByPassRule = true; rule.IsExpressionRule = true; rule.ExpressionAffix = Affix.NotOperator; configuration.NonTerminals[entrypoint.Name] = entrypoint; entrypoint.Rules.Add(rule); }