private static EBNF 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"); } tokens.RemoveFirst(); GobbleUpComments(tokens, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); 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 EBNF { Kind = EBNFKind.Terminal, s = t }; if (t.StartsWith("<") && t.EndsWith(">")) { p.Kind = EBNFKind.ExtendedTerminal; p.s = t.Substring(1, t.Length - 2); if (p.s.Contains("?")) { throw new Exception("A special-terminal may not contain a question-mark '?'"); } if (p.s == "") { 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, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); return(p); } else { var t = tokens.First.Value; tokens.RemoveFirst(); var p = new EBNF { Kind = EBNFKind.Reference, s = t }; GobbleUpComments(tokens, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); return(p); } }
private static EBNF 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 EBNF { Kind = EBNFKind.OneOrMoreOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); } else if (tokens.First.Value == "*") { tokens.RemoveFirst(); p = new EBNF { Kind = EBNFKind.ZeroOrMoreOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); } else if (tokens.First.Value == "?") { tokens.RemoveFirst(); p = new EBNF { Kind = EBNFKind.ZeroOrOneOf, Children = new[] { p }.ToList() }; GobbleUpComments(tokens, ref p.FollowingWhitespace, ref p.FollowingComment, ref p.FollowingNewline); } else { break; } } return(p); }
public static string ToString(EBNF ebnf) { var r = ""; EBNF prevElement = null; switch (ebnf.Kind) { case EBNFKind.Terminal: r = $"'{ebnf.s.Replace("\\", "\\\\").Replace("'", "\\'")}'"; break; case EBNFKind.ExtendedTerminal: r = $"'<{ebnf.s.Replace("\\", "\\\\").Replace("'", "\\'")}>'"; break; case EBNFKind.Reference: r = ebnf.s; break; case EBNFKind.OneOrMoreOf: case EBNFKind.ZeroOrMoreOf: case EBNFKind.ZeroOrOneOf: var op = (ebnf.Kind == EBNFKind.OneOrMoreOf ? "+" : (ebnf.Kind == EBNFKind.ZeroOrMoreOf ? "*" : "?")); if (ebnf.Children[0].Kind == EBNFKind.Choice || ebnf.Children[0].Kind == EBNFKind.Sequence) { r = $"( {ToString(ebnf.Children[0])} ){op}"; } else { r = $"{ToString(ebnf.Children[0])}{op}"; } break; case EBNFKind.Choice: foreach (var c in ebnf.Children) { if (prevElement != null) { r += (r.Last() == '\t' ? "| " : " | "); } r += ToString(c); prevElement = c; } break; case EBNFKind.Sequence: foreach (var c in ebnf.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(ebnf.FollowingComment)) { r += " //" + ebnf.FollowingComment; } if (ebnf.FollowingNewline) { r += "\r\n\t"; } return(r); }
public static IEnumerable <ColorizedWord> ColorizeAntlr(EBNF ebnf) { var lastWasTab = false; EBNF prevElement = null; switch (ebnf.Kind) { case EBNFKind.Terminal: yield return(Col("'" + ebnf.s.Replace("\\", "\\\\").Replace("'", "\\'").Replace("\\\"", "\"") + "'", "Terminal")); break; case EBNFKind.ExtendedTerminal: yield return(Col(ebnf.s, "ExtendedTerminal")); break; case EBNFKind.Reference: yield return(Col(ebnf.s, "Production")); break; case EBNFKind.OneOrMoreOf: case EBNFKind.ZeroOrMoreOf: case EBNFKind.ZeroOrOneOf: var op = (ebnf.Kind == EBNFKind.OneOrMoreOf ? "+" : (ebnf.Kind == EBNFKind.ZeroOrMoreOf ? "*" : "?")); if (ebnf.Children[0].Kind == EBNFKind.Choice || ebnf.Children[0].Kind == EBNFKind.Sequence) { yield return(Col("( ", "PlainText")); foreach (var word in ColorizeAntlr(ebnf.Children[0])) { yield return(word); } yield return(Col(" )", "PlainText")); yield return(Col(op, "PlainText")); } else { foreach (var word in ColorizeAntlr(ebnf.Children[0])) { yield return(word); } yield return(Col(op, "PlainText")); } break; case EBNFKind.Choice: foreach (var c in ebnf.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 ebnf.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(ebnf.FollowingWhitespace)) { yield return(Col(ebnf.FollowingWhitespace, "Comment")); } if (!string.IsNullOrEmpty(ebnf.FollowingComment)) { yield return(Col(" //" + ebnf.FollowingComment, "Comment")); } if (ebnf.FollowingNewline) { yield return(null); yield return(Col("\t", "PlainText")); } }