private static EbnfNode ParseAtom(LinkedList <string> tokens, ref string ExtraWhitespace, ref string ExtraComments) { if (tokens.First.Value == "(") { tokens.RemoveFirst(); var p = ParseProduction(tokens, ref ExtraWhitespace, ref ExtraComments); if (tokens.Count == 0 || tokens.First.Value != ")") { throw new Exception($"mismatched parentheses in {string.Join(", ", tokens)}"); } tokens.RemoveFirst(); GobbleUpComments(tokens, p); return(p); } else if (tokens.First.Value.StartsWith("'")) { var t = tokens.First.Value; tokens.RemoveFirst(); t = t.Substring(1, t.Length - 2); var p = new EbnfNode { Kind = EbnfKind.Terminal, Text = t }; if (t.StartsWith("<") && t.EndsWith(">")) { p.Kind = EbnfKind.ExtendedTerminal; p.Text = t.Substring(1, t.Length - 2); if (p.Text.Contains("?")) { throw new Exception("A special-terminal may not contain a question-mark '?'"); } if (p.Text == "") { throw new Exception("A terminal may not be '<>'"); } } else { if (t.Contains("'") && t.Contains("\"")) { throw new Exception("A terminal must either contain no ' or no \""); } } GobbleUpComments(tokens, p); return(p); } else { var t = tokens.First.Value; tokens.RemoveFirst(); var p = new EbnfNode { Kind = EbnfKind.Reference, Text = t }; GobbleUpComments(tokens, p); return(p); } }
private static void GobbleUpComments(LinkedList <string> tokens, EbnfNode node) { string followingWhitespace = node.FollowingWhitespace; string followingComment = node.FollowingComment; bool followingNewline = node.FollowingNewline; GobbleUpComments(tokens, ref followingWhitespace, ref followingComment, ref followingNewline); node.FollowingWhitespace = followingWhitespace; node.FollowingComment = followingComment; node.FollowingNewline = followingNewline; }
private static EbnfNode ParseUnary(LinkedList <string> tokens, ref string extraWhitespace, ref string extraComments) { var p = ParseAtom(tokens, ref extraWhitespace, ref extraComments); while (tokens.Any()) { if (tokens.First.Value == "+") { tokens.RemoveFirst(); p = new EbnfNode { Kind = EbnfKind.OneOrMoreOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, p); } else if (tokens.First.Value == "*") { tokens.RemoveFirst(); p = new EbnfNode { Kind = EbnfKind.ZeroOrMoreOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, p); } else if (tokens.First.Value == "?") { tokens.RemoveFirst(); p = new EbnfNode { Kind = EbnfKind.ZeroOrOneOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, p); } else { break; } } return(p); }
public static string ToString(EbnfNode node) { var r = ""; EbnfNode prevElement = null; switch (node.Kind) { case EbnfKind.Terminal: r = $"'{node.Text.Replace("\\", "\\\\").Replace("'", "\\'")}'"; break; case EbnfKind.ExtendedTerminal: r = $"'<{node.Text.Replace("\\", "\\\\").Replace("'", "\\'")}>'"; break; case EbnfKind.Reference: r = node.Text; break; case EbnfKind.OneOrMoreOf: case EbnfKind.ZeroOrMoreOf: case EbnfKind.ZeroOrOneOf: var op = (node.Kind == EbnfKind.OneOrMoreOf ? "+" : (node.Kind == EbnfKind.ZeroOrMoreOf ? "*" : "?")); if (node.Children[0].Kind == EbnfKind.Choice || node.Children[0].Kind == EbnfKind.Sequence) { r = $"( {ToString(node.Children[0])} ){op}"; } else { r = $"{ToString(node.Children[0])}{op}"; } break; case EbnfKind.Choice: foreach (var c in node.Children) { if (prevElement != null) { r += (r.Last() == '\t' ? "| " : " | "); } r += ToString(c); prevElement = c; } break; case EbnfKind.Sequence: foreach (var c in node.Children) { if (prevElement != null) { r += (r == "" || r.Last() == '\t' ? "" : " "); } if (c.Kind == EbnfKind.Choice) { r += "( " + ToString(c) + " )"; } else { r += ToString(c); } prevElement = c; } break; default: r = "???"; break; } if (!string.IsNullOrEmpty(node.FollowingComment)) { r += " //" + node.FollowingComment; } if (node.FollowingNewline) { r += "\r\n\t"; } return(r); }
public static IEnumerable <ColorizedWord> ColorizeAntlr(EbnfNode node) { var lastWasTab = false; EbnfNode prevElement = null; switch (node.Kind) { case EbnfKind.Terminal: yield return(Col("'" + node.Text.Replace("\\", "\\\\").Replace("'", "\\'").Replace("\\\"", "\"") + "'", "Terminal")); break; case EbnfKind.ExtendedTerminal: yield return(Col(node.Text, "ExtendedTerminal")); break; case EbnfKind.Reference: yield return(Col(node.Text, "Production")); break; case EbnfKind.OneOrMoreOf: case EbnfKind.ZeroOrMoreOf: case EbnfKind.ZeroOrOneOf: var op = (node.Kind == EbnfKind.OneOrMoreOf ? "+" : (node.Kind == EbnfKind.ZeroOrMoreOf ? "*" : "?")); if (node.Children[0].Kind == EbnfKind.Choice || node.Children[0].Kind == EbnfKind.Sequence) { yield return(Col("( ", "PlainText")); foreach (var word in ColorizeAntlr(node.Children[0])) { yield return(word); } yield return(Col(" )", "PlainText")); yield return(Col(op, "PlainText")); } else { foreach (var word in ColorizeAntlr(node.Children[0])) { yield return(word); } yield return(Col(op, "PlainText")); } break; case EbnfKind.Choice: foreach (var c in node.Children) { if (prevElement != null) { yield return(Col(lastWasTab ? "| " : "| ", "PlainText")); } foreach (var word in ColorizeAntlr(c)) { yield return(word); lastWasTab = (word?.Text == "\t"); } prevElement = c; } break; case EbnfKind.Sequence: foreach (var c in node.Children) { if (lastWasTab) { yield return(Col(" ", "PlainText")); } if (c.Kind == EbnfKind.Choice) { yield return(Col("( ", "PlainText")); foreach (var word in ColorizeAntlr(c)) { yield return(word); } yield return(Col(" )", "PlainText")); lastWasTab = false; } else { foreach (var word in ColorizeAntlr(c)) { yield return(word); lastWasTab = (word?.Text == "\t"); } } prevElement = c; } break; default: throw new NotSupportedException("Unrecognized Ebnf"); } if (!string.IsNullOrEmpty(node.FollowingWhitespace)) { yield return(Col(node.FollowingWhitespace, "Comment")); } if (!string.IsNullOrEmpty(node.FollowingComment)) { yield return(Col(" //" + node.FollowingComment, "Comment")); } if (node.FollowingNewline) { yield return(null); yield return(Col("\t", "PlainText")); } }