private static void ReadDefinition(ParseResult definition, NamedParserCollection rules) { Debug.Assert(definition.Parser == Parser.Definition); var name = definition[0].Value; rules.PushNamespace(name); var branch = definition.FirstOrDefault(x => x.Parser == Parser.Branch); var statementBlock = definition.FirstOrDefault(x => x.Parser == Parser.StatementBlock); if (statementBlock != null) { ReadStatementBlock(statementBlock, rules); } Parser parser = null; if (branch != null) { parser = ReadBranch(branch, rules); } rules.PopNamespace(); if (parser != null) { rules.Add(name, parser); } }
public void WriteGrammar(string fullClassName, NamedParserCollection grammar, string rootParserName, string filePath) { using (var writer = File.CreateText(filePath)) { WriteGrammar(fullClassName, grammar, rootParserName, writer); } }
private static Parser ReadConcat(ParseResult concat, NamedParserCollection rules) { Debug.Assert(concat.Parser == Parser.Concat); return(concat.InnerCount == 1 ? ReadModifier(concat[0], rules) : new ConcatParser(concat.Select(x => ReadModifier(x, rules)))); }
private static Parser ReadBranch(ParseResult branch, NamedParserCollection rules) { Debug.Assert(branch.Parser == Parser.Branch); return(branch.InnerCount == 1 ? ReadConcat(branch[0], rules) : new BranchParser(branch.Select(x => ReadConcat(x, rules)))); }
private static Parser ReadRegex(ParseResult regex, NamedParserCollection rules) { var pattern = regex[0]; var options = regex[1]; var builder = new StringBuilder(pattern.Length); var escaped = false; for (var i = 0; i < pattern.Length; ++i) { var c = pattern.Value[i]; if (escaped) { escaped = false; switch (c) { case '/': builder.Append('/'); break; default: builder.Append("\\" + c); break; } } else if (c == '\\') { escaped = true; } else { builder.Append(c); } } var parsedOptions = RegexParser.Compiled ? RegexOptions.Compiled : RegexOptions.None; for (var i = 0; i < options.Length; ++i) { switch (options.Value[i]) { case 'i': parsedOptions |= RegexOptions.IgnoreCase; break; } } return(new Regex(builder.ToString(), parsedOptions)); }
private static Parser ReadString(ParseResult str, NamedParserCollection rules) { var value = str[0]; if (value.Length == 0) { return(EmptyParser.Instance); } var builder = new StringBuilder(value.Length); var escaped = false; for (var i = 0; i < value.Length; ++i) { var c = value.Value[i]; if (escaped) { escaped = false; switch (c) { case 'r': builder.Append('\r'); break; case 'n': builder.Append('\n'); break; case 't': builder.Append('\t'); break; default: builder.Append(c); break; } } else if (c == '\\') { escaped = true; } else { builder.Append(c); } } return(builder.ToString()); }
private static void ReadStatementBlock(ParseResult statementBlock, NamedParserCollection rules) { foreach (var statement in statementBlock) { var value = statement[0]; if (value.Parser == Parser.Definition) { ReadDefinition(value, rules); } else if (value.Parser == Parser.SpecialBlock) { ReadSpecialBlock(value, rules); } } }
public static NamedParserCollection FromString(string str) { var result = Parser.Parse(str); if (!result.Success) { throw new GrammarParseException(result); } var rules = new NamedParserCollection(); ReadStatementBlock(result[0], rules); return(rules); }
private static Parser ReadModifier(ParseResult modifier, NamedParserCollection rules) { Debug.Assert(modifier.Parser == Parser.Modifier); var prefix = modifier.FirstOrDefault(x => x.Parser == Parser.ModifierPrefix); var term = ReadTerm(modifier.First(x => x.Parser == Parser.Term), rules); var postfix = modifier.FirstOrDefault(x => x.Parser == Parser.ModifierPostfix); if (prefix != null) { switch (prefix.Value) { case "$": term = term.Strict; break; case "!": term = term.Not; break; default: throw new Exception($"Unrecognised modifier '{prefix.Value}'."); } } if (postfix != null) { switch (postfix.Value) { case "?": term = term.Optional; break; case "+": term = term.Repeated; break; case "*": term = term.Repeated.Optional; break; default: throw new Exception($"Unrecognised modifier '{postfix.Value}'."); } } return(term); }
private static void ReadSpecialBlock(ParseResult specialBlock, NamedParserCollection rules) { var header = specialBlock[0]; var block = specialBlock[1]; var stack = new Stack <IDisposable>(); while (header != null) { var item = header[0]; if (item.InnerCount == 1) { var ignore = ReadBranch(item[0], rules); stack.Push(Parse.Parser.AllowWhitespace(ignore)); } else { switch (item.Value) { case "noignore": stack.Push(Parse.Parser.ForbidWhitespace()); break; case "collapse": stack.Push(Parse.Parser.EnableCollapseIfSingleElement()); break; default: throw new NotImplementedException(item.Value); } } header = header.InnerCount == 1 ? null : header[1]; } ReadStatementBlock(block, rules); while (stack.Count > 0) { stack.Pop().Dispose(); } }
private static Parser ReadTerm(ParseResult term, NamedParserCollection rules) { Debug.Assert(term.Parser == Parser.Term); var value = term[0]; if (value.Parser == Parser.String) { return(ReadString(value, rules)); } if (value.Parser == Parser.Regex) { return(ReadRegex(value, rules)); } if (value.Parser == Parser.NonTerminal) { return(ReadNonTerminal(value, rules)); } if (value.Parser == Parser.Branch) { return(ReadBranch(value, rules)); } throw new NotImplementedException(); }
private static Parser ReadNonTerminal(ParseResult nonTerminal, NamedParserCollection rules) { var name = nonTerminal.Value; return(rules.Get(name)); }
public void WriteGrammar(string fullClassName, NamedParserCollection grammar, string rootParserName, TextWriter dest) { var writer = new CodeWriter(dest, Options); var splitName = fullClassName.Split('.'); var @namespace = splitName.Length > 1 ? string.Join(".", splitName.Take(splitName.Length - 1).ToArray()) : null; var className = splitName[splitName.Length - 1]; writer.WriteLine($"namespace {@namespace}"); using (writer.Block()) { writer.Write($"public class {className} : "); writer.Write(typeof(CustomParser)); writer.WriteLine(); using (writer.Block()) { foreach (var name in grammar.ParserNames) { writer.Write("public "); writer.Write(typeof(NamedParser)); writer.WriteLine($" {NormalizeParserName(name)};"); } writer.WriteLine(); writer.Write("protected override "); writer.Write(typeof(Parser)); writer.WriteLine(" OnDefine()"); using (writer.Block()) { writer.Write($"var {RegexOptionsVariable} = "); writer.Write(typeof(RegexParser)); writer.WriteLine($".{nameof( RegexParser.Compiled )}"); writer.Indent(); writer.Write("? "); writer.Write(typeof(RegexOptions)); writer.WriteLine($".{nameof( RegexOptions.Compiled )}"); writer.Write(": "); writer.Write(typeof(RegexOptions)); writer.WriteLine($".{nameof( RegexOptions.None )};"); writer.Unindent(); foreach (var whitespaceGroup in grammar.ParserNames.GroupBy(x => grammar[x].WhitespaceParser)) { writer.WriteLine(); CodeWriter.IBlock whitespaceBlock = null; if (whitespaceGroup.Key != null) { writer.Write("using ("); writer.Write(typeof(Parser)); writer.Write($".{nameof( Parser.AllowWhitespace )}("); WriteParser(writer, whitespaceGroup.Key); writer.WriteLine("))"); whitespaceBlock = writer.Block(); } foreach (var collapseGroup in whitespaceGroup.GroupBy(x => grammar[x].CollapseIfSingleElement)) { CodeWriter.IBlock collapseBlock = null; if (collapseGroup.Key) { writer.WriteLine(); writer.Write("using ("); writer.Write(typeof(Parser)); writer.WriteLine($".{nameof( Parser.EnableCollapseIfSingleElement )}())"); collapseBlock = writer.Block(); } foreach (var parserName in collapseGroup) { writer.Write($"this[{NormalizeParserName(parserName)}] = "); WriteParser(writer, grammar[parserName].ResolvedParser); writer.WriteLine(";"); } collapseBlock?.End(); } whitespaceBlock?.End(); } writer.WriteLine($"return {rootParserName};"); } } } dest.Flush(); }