diff --git a/runtime/CSharp/tests/issue-3510/ChannelTest.g4 b/runtime/CSharp/tests/issue-3510/ChannelTest.g4 new file mode 100644 index 0000000000..27947a253f --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/ChannelTest.g4 @@ -0,0 +1,7 @@ +grammar ChannelTest; + +prog : INT+ EOF; +INT : [0-9]+; +AAA : [a-z]+ -> channel(HIDDEN); // Note--lowercase "channel" +BBB : [A-Z]+ -> Channel(HIDDEN); // Note--uppercase "Channel" +WS : [ \t\r\n] -> skip; diff --git a/runtime/CSharp/tests/issue-3510/ErrorListener.cs b/runtime/CSharp/tests/issue-3510/ErrorListener.cs new file mode 100644 index 0000000000..1d610a3b56 --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/ErrorListener.cs @@ -0,0 +1,18 @@ +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +public class ErrorListener : ConsoleErrorListener +{ + public bool had_error; + + public override void SyntaxError(TextWriter output, IRecognizer recognizer, S offendingSymbol, int line, + int col, string msg, RecognitionException e) + { + had_error = true; + base.SyntaxError(output, recognizer, offendingSymbol, line, col, msg, e); + } +} diff --git a/runtime/CSharp/tests/issue-3510/Program.cs b/runtime/CSharp/tests/issue-3510/Program.cs new file mode 100644 index 0000000000..edbc54d033 --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/Program.cs @@ -0,0 +1,90 @@ +using Antlr4.Runtime; +using System; +using System.Linq; +using System.Text; + +public class Program +{ + static void Main(string[] args) + { + bool show_tree = false; + bool show_tokens = false; + string file_name = null; + string input = null; + for (int i = 0; i < args.Length; ++i) + { + if (args[i].Equals("-tokens")) + { + show_tokens = true; + continue; + } + else if (args[i].Equals("-tree")) + { + show_tree = true; + continue; + } + else if (args[i].Equals("-input")) + input = args[i]; + else if (args[i].Equals("-file")) + file_name = args[++i]; + } + ICharStream str = null; + if (input == null && file_name == null) + { + StringBuilder sb = new StringBuilder(); + int ch; + while ((ch = System.Console.Read()) != -1) + { + sb.Append((char)ch); + } + input = sb.ToString(); + str = CharStreams.fromString(input); + } + else if (input != null) + { + str = CharStreams.fromString(input); + } + else if (file_name != null) + { + str = CharStreams.fromPath(file_name); + } + var lexer = new ChannelTestLexer(str); + if (show_tokens) + { + StringBuilder new_s = new StringBuilder(); + for (int i = 0; ; ++i) + { + var ro_token = lexer.NextToken(); + var token = (CommonToken)ro_token; + token.TokenIndex = i; + new_s.AppendLine(token.ToString()); + if (token.Type == Antlr4.Runtime.TokenConstants.EOF) + break; + } + System.Console.Error.WriteLine(new_s.ToString()); + } + lexer.Reset(); + var tokens = new CommonTokenStream(lexer); + var parser = new ChannelTestParser(tokens); + var listener_lexer = new ErrorListener(); + var listener_parser = new ErrorListener(); + lexer.AddErrorListener(listener_lexer); + parser.AddErrorListener(listener_parser); + parser.Profile = true; + var tree = parser.prog(); + if (listener_lexer.had_error || listener_parser.had_error) + { + System.Console.Error.WriteLine("parse failed."); + } + else + { + System.Console.Error.WriteLine("parse succeeded."); + } + if (show_tree) + { + System.Console.Error.WriteLine(tree.ToStringTree()); + } + System.Console.Out.WriteLine(String.Join(", ", parser.ParseInfo.getDecisionInfo().Select(d => d.ToString()))); + System.Environment.Exit(listener_lexer.had_error || listener_parser.had_error ? 1 : 0); + } +} diff --git a/runtime/CSharp/tests/issue-3510/Test.csproj b/runtime/CSharp/tests/issue-3510/Test.csproj new file mode 100644 index 0000000000..0065bf7594 --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/Test.csproj @@ -0,0 +1,26 @@ + + + net5.0 + Exe + + + + + + + + ../../../../tool/target/antlr4-*-SNAPSHOT-complete.jar + + + + + + + + + PackageReference + + + 1701;1702;3021 + + diff --git a/runtime/CSharp/tests/issue-3510/Test.sln b/runtime/CSharp/tests/issue-3510/Test.sln new file mode 100644 index 0000000000..4768052b0f --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/Test.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31019.35 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test.csproj", "{FD11E8CC-1631-4FF3-9B44-F10084562311}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Antlr4", "..\..\src\Antlr4.csproj", "{A60B5000-4473-4D00-85C4-C3A4B469F608}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD11E8CC-1631-4FF3-9B44-F10084562311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD11E8CC-1631-4FF3-9B44-F10084562311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD11E8CC-1631-4FF3-9B44-F10084562311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD11E8CC-1631-4FF3-9B44-F10084562311}.Release|Any CPU.Build.0 = Release|Any CPU + {A60B5000-4473-4D00-85C4-C3A4B469F608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A60B5000-4473-4D00-85C4-C3A4B469F608}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A60B5000-4473-4D00-85C4-C3A4B469F608}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A60B5000-4473-4D00-85C4-C3A4B469F608}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2FFB66F7-2552-4F2B-B97E-77B5F8743ED4} + EndGlobalSection +EndGlobal diff --git a/runtime/CSharp/tests/issue-3510/TreeOutput.cs b/runtime/CSharp/tests/issue-3510/TreeOutput.cs new file mode 100644 index 0000000000..def03230bb --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/TreeOutput.cs @@ -0,0 +1,105 @@ +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +public class TreeOutput +{ + private static int changed = 0; + private static bool first_time = true; + + public static StringBuilder OutputTree(IParseTree tree, Lexer lexer, Parser parser, CommonTokenStream stream) + { + changed = 0; + first_time = true; + var sb = new StringBuilder(); + ParenthesizedAST(tree, sb, lexer, parser, stream); + return sb; + } + + private static void ParenthesizedAST(IParseTree tree, StringBuilder sb, Lexer lexer, Parser parser, CommonTokenStream stream, int level = 0) + { + if (tree as TerminalNodeImpl != null) + { + TerminalNodeImpl tok = tree as TerminalNodeImpl; + Interval interval = tok.SourceInterval; + IList inter = null; + if (tok.Symbol.TokenIndex >= 0) + inter = stream?.GetHiddenTokensToLeft(tok.Symbol.TokenIndex); + if (inter != null) + foreach (var t in inter) + { + var ty = tok.Symbol.Type; + var name = lexer.Vocabulary.GetSymbolicName(ty); + StartLine(sb, level); + sb.AppendLine("(" + name + " text = " + PerformEscapes(t.Text) + " " + lexer.ChannelNames[t.Channel]); + } + { + var ty = tok.Symbol.Type; + var name = lexer.Vocabulary.GetSymbolicName(ty); + StartLine(sb, level); + sb.AppendLine("( " + name + " i =" + tree.SourceInterval.a + + " txt =" + PerformEscapes(tree.GetText()) + + " tt =" + tok.Symbol.Type + + " " + lexer.ChannelNames[tok.Symbol.Channel]); + } + } + else + { + var x = tree as RuleContext; + var ri = x.RuleIndex; + var name = parser.RuleNames[ri]; + StartLine(sb, level); + sb.Append("( " + name); + sb.AppendLine(); + } + for (int i = 0; i= 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(" "); + } + + private static string ToLiteral(string input) + { + using (var writer = new StringWriter()) + { + var literal = input; + literal = literal.Replace("\\", "\\\\"); + return literal; + } + } + + public static string PerformEscapes(string s) + { + StringBuilder new_s = new StringBuilder(); + new_s.Append(ToLiteral(s)); + return new_s.ToString(); + } +} diff --git a/runtime/CSharp/tests/issue-3510/input.txt b/runtime/CSharp/tests/issue-3510/input.txt new file mode 100644 index 0000000000..55c21ae456 --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/input.txt @@ -0,0 +1 @@ +111 222 aaa 333 BBB 444 diff --git a/runtime/CSharp/tests/issue-3510/test.sh b/runtime/CSharp/tests/issue-3510/test.sh new file mode 100644 index 0000000000..d08f147e4f --- /dev/null +++ b/runtime/CSharp/tests/issue-3510/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +dotnet restore +dotnet build +dotnet run -file input.txt +if [[ "$?" != "0" ]] +then + echo "Issue 3510 test failed." + exit 1 +fi + diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/CSharp/CSharp.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/CSharp/CSharp.stg index 5bc87079b0..ba7db09a4a 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/CSharp/CSharp.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/CSharp/CSharp.stg @@ -762,9 +762,9 @@ LexerSkipCommand() ::= "Skip();" LexerMoreCommand() ::= "More();" LexerPopModeCommand() ::= "PopMode();" -LexerTypeCommand(arg, grammar) ::= "_type = ;" -LexerChannelCommand(arg, grammar) ::= "_channel = ;" -LexerModeCommand(arg, grammar) ::= "_mode = ;" +LexerTypeCommand(arg, grammar) ::= "Type = ;" +LexerChannelCommand(arg, grammar) ::= "Channel = ;" +LexerModeCommand(arg, grammar) ::= "CurrentMode = ;" LexerPushModeCommand(arg, grammar) ::= "PushMode();" ActionText(t) ::= ""