From e9fccd7307f1fd1e9a29bccadb63b18bb0b613f8 Mon Sep 17 00:00:00 2001 From: Ken Domino Date: Thu, 12 Sep 2024 10:32:09 -0400 Subject: [PATCH] Updates to trtree with various tree output styles. --- .../UnvParseTreeDOM/TreeOutput.cs | 284 ++++++++++++------ src/trtree/Command.cs | 29 +- src/trtree/Config.cs | 6 + src/trtree/Program.cs | 1 + 4 files changed, 224 insertions(+), 96 deletions(-) diff --git a/src/ParseTreeEditing/UnvParseTreeDOM/TreeOutput.cs b/src/ParseTreeEditing/UnvParseTreeDOM/TreeOutput.cs index b9d648ec..cf2c3e57 100644 --- a/src/ParseTreeEditing/UnvParseTreeDOM/TreeOutput.cs +++ b/src/ParseTreeEditing/UnvParseTreeDOM/TreeOutput.cs @@ -1,122 +1,224 @@ using Antlr4.Runtime; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Reflection.Emit; using System.Text; -namespace ParseTreeEditing.UnvParseTreeDOM +namespace ParseTreeEditing.UnvParseTreeDOM; + +public class TreeOutput { - public class TreeOutput + private static int changed = 0; + private static bool first_time = true; + + public static StringBuilder OutputTree(UnvParseTreeNode tree, Lexer lexer, Parser parser) { - private static int changed = 0; - private static bool first_time = true; + changed = 0; + first_time = true; + var sb = new StringBuilder(); + ParenthesizedAST(tree, sb, lexer, parser); + return sb; + } - public static StringBuilder OutputTree(UnvParseTreeNode tree, Lexer lexer, Parser parser) + private static void ParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0) + { + // Antlr always names a non-terminal with first letter lowercase, + // but renames it when creating the type in C#. So, remove the prefix, + // lowercase the first letter, and remove the trailing "Context" part of + // the name. Saves big time on output! + if (tree is UnvParseTreeText t) { - changed = 0; - first_time = true; - var sb = new StringBuilder(); - ParenthesizedAST(tree, sb, lexer, parser); - return sb; + StartLine(sb, level); + sb.Append( + "( " + + " text:'" + PerformEscapes(t.Data) + "'" + + " tt:" + t.TokenType + + " chnl:" + lexer.ChannelNames[t.Channel] + //+ " l:" + t.Line + //+ " c:" + t.Column + //+ " si:" + t.StartIndex + //+ " ei:" + t.StopIndex + //+ " ti:" + t.TokenIndex + ); + sb.AppendLine(); } - - private static void ParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0) + else if (tree is UnvParseTreeAttr a) { - // Antlr always names a non-terminal with first letter lowercase, - // but renames it when creating the type in C#. So, remove the prefix, - // lowercase the first letter, and remove the trailing "Context" part of - // the name. Saves big time on output! - if (tree is UnvParseTreeText t) + StartLine(sb, level); + sb.Append("( Attribute " + a.Name as string); + sb.Append(" Value '"); + sb.Append(PerformEscapes(a.StringValue)); + sb.Append("'"); + if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length) { - StartLine(sb, level); - sb.Append( - "( " - + " text:'" + PerformEscapes(t.Data) + "'" - + " tt:" + t.TokenType - + " chnl:" + lexer.ChannelNames[t.Channel] - //+ " l:" + t.Line - //+ " c:" + t.Column - //+ " si:" + t.StartIndex - //+ " ei:" + t.StopIndex - //+ " ti:" + t.TokenIndex - ); - sb.AppendLine(); + sb.Append(" chnl:"); + sb.Append(lexer.ChannelNames[a.Channel].ToString()); } - else if (tree is UnvParseTreeAttr a) - { - StartLine(sb, level); - sb.Append("( Attribute " + a.Name as string); - sb.Append(" Value '"); - sb.Append(PerformEscapes(a.StringValue)); - sb.Append("'"); - if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length) - { - sb.Append(" chnl:"); - sb.Append(lexer.ChannelNames[a.Channel].ToString()); - } - sb.AppendLine(); - } - else if (tree is UnvParseTreeElement e) - { - var x = e; - var name = e.LocalName; - StartLine(sb, level); - sb.Append( - "( " + name - ); - sb.AppendLine(); - } - for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i) - { - var c = tree.ChildNodes.item(i); - ParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1); - } - if (level == 0) + sb.AppendLine(); + } + else if (tree is UnvParseTreeElement e) + { + var x = e; + var name = e.LocalName; + StartLine(sb, level); + sb.Append( + "( " + name + ); + sb.AppendLine(); + } + for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i) + { + var c = tree.ChildNodes.item(i); + ParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1); + } + if (level == 0) + { + for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") "); + sb.AppendLine(); + changed = 0; + } + } + + private static void StartLine(StringBuilder sb, int level = 0) + { + if (changed - level >= 0) + { + if (!first_time) { + for (int j = 0; j < level; ++j) sb.Append(" "); for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") "); sb.AppendLine(); - changed = 0; } + changed = 0; + first_time = false; } + changed = level; + for (int j = 0; j < level; ++j) sb.Append(" "); + } - private static void StartLine(StringBuilder sb, int level = 0) + private static string ToLiteral(string input) + { + using (var writer = new StringWriter()) { - if (changed - level >= 0) - { - if (!first_time) - { - for (int j = 0; j < level; ++j) sb.Append(" "); - for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") "); - sb.AppendLine(); - } - changed = 0; - first_time = false; - } - changed = level; - for (int j = 0; j < level; ++j) sb.Append(" "); + var literal = input; + literal = literal.Replace("\\", "\\\\"); + literal = literal.Replace("\b", "\\b"); + literal = literal.Replace("\n", "\\n"); + literal = literal.Replace("\t", "\\t"); + literal = literal.Replace("\r", "\\r"); + literal = literal.Replace("\f", "\\f"); + literal = literal.Replace("\"", "\\\""); + literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), ""); + return literal; } + } - private static string ToLiteral(string input) + public static string PerformEscapes(string s) + { + StringBuilder new_s = new StringBuilder(); + new_s.Append(ToLiteral(s)); + return new_s.ToString(); + } + + public static StringBuilder OutputTreeAntlrStyle(UnvParseTreeNode tree, Lexer lexer, Parser parser) + { + changed = 0; + first_time = true; + var sb = new StringBuilder(); + AntlrParenthesizedAST(tree, sb, lexer, parser); + return sb; + } + + private static void AntlrParenthesizedAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0) + { + if (tree is UnvParseTreeText t) + { + sb.Append(" " + PerformEscapes(t.Data)); + return; + } + else if (tree is UnvParseTreeAttr a) { - using (var writer = new StringWriter()) + return; + } + else if (tree is UnvParseTreeElement e) + { + var x = e; + var name = e.LocalName; + sb.Append(" (" + name); + } + for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i) + { + var c = tree.ChildNodes.item(i); + AntlrParenthesizedAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1); + } + sb.Append(")"); + } + + public static StringBuilder OutputTreeIndentStyle(UnvParseTreeNode tree, Lexer lexer, Parser parser) + { + changed = 0; + first_time = true; + var sb = new StringBuilder(); + IndentAST(tree, sb, lexer, parser); + return sb; + } + + public static void IndentAST(UnvParseTreeNode tree, StringBuilder sb, Lexer lexer, Parser parser, int level = 0) + { + if (tree is UnvParseTreeText t) + { + IndentStartLine(sb, level); + sb.Append( + "" + + "'" + PerformEscapes(t.Data) + "'" + ); + sb.AppendLine(); + } + else if (tree is UnvParseTreeAttr a) + { + IndentStartLine(sb, level); + sb.Append("Attribute " + a.Name as string); + sb.Append(" Value '"); + sb.Append(PerformEscapes(a.StringValue)); + sb.Append("'"); + if (a.Channel >= 0 && a.Channel < lexer.ChannelNames.Length) { - var literal = input; - literal = literal.Replace("\\", "\\\\"); - literal = literal.Replace("\b", "\\b"); - literal = literal.Replace("\n", "\\n"); - literal = literal.Replace("\t", "\\t"); - literal = literal.Replace("\r", "\\r"); - literal = literal.Replace("\f", "\\f"); - literal = literal.Replace("\"", "\\\""); - literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), ""); - return literal; + sb.Append(" chnl:"); + sb.Append(lexer.ChannelNames[a.Channel].ToString()); } + sb.AppendLine(); + } + else if (tree is UnvParseTreeElement e) + { + var x = e; + var name = e.LocalName; + IndentStartLine(sb, level); + sb.Append(name); + sb.AppendLine(); + } + for (int i = 0; tree.ChildNodes != null && i < tree.ChildNodes.Length; ++i) + { + var c = tree.ChildNodes.item(i); + IndentAST(c as UnvParseTreeNode, sb, lexer, parser, level + 1); + } + if (level == 0) + { + sb.AppendLine(); + changed = 0; } + } - public static string PerformEscapes(string s) + private static void IndentStartLine(StringBuilder sb, int level = 0) + { + if (changed - level >= 0) { - StringBuilder new_s = new StringBuilder(); - new_s.Append(ToLiteral(s)); - return new_s.ToString(); + changed = 0; + first_time = false; } + changed = level; + for (int j = 0; j < level; ++j) sb.Append(" "); } + } diff --git a/src/trtree/Command.cs b/src/trtree/Command.cs index 4b7cddb4..90883318 100644 --- a/src/trtree/Command.cs +++ b/src/trtree/Command.cs @@ -63,11 +63,30 @@ public void Execute(Config config) foreach (var node in nodes) { sb.AppendLine(); - sb.AppendLine( - TreeOutput.OutputTree( - node, - lexer, - parser).ToString()); + if (config.AntlrStyle) + { + sb.AppendLine( + TreeOutput.OutputTreeAntlrStyle( + node, + lexer, + parser).ToString()); + } + else if (config.ParenIndentStyle) + { + sb.AppendLine( + TreeOutput.OutputTree( + node, + lexer, + parser).ToString()); + } + else if (config.IndentStyle) + { + sb.AppendLine( + TreeOutput.OutputTreeIndentStyle( + node, + lexer, + parser).ToString()); + } } System.Console.WriteLine(sb.ToString()); diff --git a/src/trtree/Config.cs b/src/trtree/Config.cs index c019e57a..b39ccf87 100644 --- a/src/trtree/Config.cs +++ b/src/trtree/Config.cs @@ -12,4 +12,10 @@ public class Config [Option('a', "antlr-style", Required = false, HelpText = "Output tree as Antlr ToStringTree() style.")] public bool AntlrStyle { get; set; } + + [Option('i', "indent-style", Required = false, HelpText = "Output tree as plain indented style.")] + public bool IndentStyle { get; set; } + + [Option("paren-indent-style", Required = false, HelpText = "Output tree as parenthesized indented style.")] + public bool ParenIndentStyle { get; set; } } diff --git a/src/trtree/Program.cs b/src/trtree/Program.cs index 191f7a99..c7f4241e 100644 --- a/src/trtree/Program.cs +++ b/src/trtree/Program.cs @@ -67,6 +67,7 @@ public void MainInternal(string[] args) } } }); + if (!(config.ParenIndentStyle || config.IndentStyle || config.AntlrStyle)) config.ParenIndentStyle = true; new Command().Execute(config); } }