antlr/Antlr4.Runtime/Misc/TestRig.cs

338 lines
12 KiB
C#

/*
* [The "BSD license"]
* Copyright (c) 2013 Terence Parr
* Copyright (c) 2013 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Sharpen;
using Sharpen.Reflect;
namespace Antlr4.Runtime.Misc
{
/// <summary>
/// Run a lexer/parser combo, optionally printing tree string or generating
/// postscript file.
/// </summary>
/// <remarks>
/// Run a lexer/parser combo, optionally printing tree string or generating
/// postscript file. Optionally taking input file.
/// $ java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName
/// [-tree]
/// [-tokens] [-gui] [-ps file.ps]
/// [-trace]
/// [-diagnostics]
/// [-SLL]
/// [input-filename(s)]
/// </remarks>
public class TestRig
{
public static readonly string LexerStartRuleName = "tokens";
protected internal string grammarName;
protected internal string startRuleName;
protected internal readonly IList<string> inputFiles = new List<string>();
protected internal bool printTree = false;
protected internal bool gui = false;
protected internal string psFile = null;
protected internal bool showTokens = false;
protected internal bool trace = false;
protected internal bool diagnostics = false;
protected internal string encoding = null;
protected internal bool Sll = false;
/// <exception cref="System.Exception"></exception>
public TestRig(string[] args)
{
if (args.Length < 2)
{
System.Console.Error.WriteLine("java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName\n"
+ " [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]\n" + " [-trace] [-diagnostics] [-SLL]\n"
+ " [input-filename(s)]");
System.Console.Error.WriteLine("Use startRuleName='tokens' if GrammarName is a lexer grammar."
);
System.Console.Error.WriteLine("Omitting input-filename makes rig read from stdin."
);
return;
}
int i = 0;
grammarName = args[i];
i++;
startRuleName = args[i];
i++;
while (i < args.Length)
{
string arg = args[i];
i++;
if (arg[0] != '-')
{
// input file name
inputFiles.AddItem(arg);
continue;
}
if (arg.Equals("-tree"))
{
printTree = true;
}
if (arg.Equals("-gui"))
{
gui = true;
}
if (arg.Equals("-tokens"))
{
showTokens = true;
}
else
{
if (arg.Equals("-trace"))
{
trace = true;
}
else
{
if (arg.Equals("-SLL"))
{
Sll = true;
}
else
{
if (arg.Equals("-diagnostics"))
{
diagnostics = true;
}
else
{
if (arg.Equals("-encoding"))
{
if (i >= args.Length)
{
System.Console.Error.WriteLine("missing encoding on -encoding");
return;
}
encoding = args[i];
i++;
}
else
{
if (arg.Equals("-ps"))
{
if (i >= args.Length)
{
System.Console.Error.WriteLine("missing filename on -ps");
return;
}
psFile = args[i];
i++;
}
}
}
}
}
}
}
}
/// <exception cref="System.Exception"></exception>
public static void Main(string[] args)
{
Antlr4.Runtime.Misc.TestRig testRig = new Antlr4.Runtime.Misc.TestRig(args);
testRig.Process();
}
/// <exception cref="System.Exception"></exception>
public virtual void Process()
{
// System.out.println("exec "+grammarName+"."+startRuleName);
string lexerName = grammarName + "Lexer";
ClassLoader cl = Sharpen.Thread.CurrentThread().GetContextClassLoader();
Type lexerClass = null;
try
{
lexerClass = cl.LoadClass(lexerName).AsSubclass<Lexer>();
}
catch (TypeLoadException)
{
// might be pure lexer grammar; no Lexer suffix then
lexerName = grammarName;
try
{
lexerClass = cl.LoadClass(lexerName).AsSubclass<Lexer>();
}
catch (TypeLoadException)
{
System.Console.Error.WriteLine("Can't load " + lexerName + " as lexer or parser");
return;
}
}
Constructor<Lexer> lexerCtor = lexerClass.GetConstructor(typeof(ICharStream));
Lexer lexer = lexerCtor.NewInstance((ICharStream)null);
Type parserClass = null;
Parser parser = null;
if (!startRuleName.Equals(LexerStartRuleName))
{
string parserName = grammarName + "Parser";
parserClass = (Type)cl.LoadClass(parserName).AsSubclass<Parser>();
if (parserClass == null)
{
System.Console.Error.WriteLine("Can't load " + parserName);
}
Constructor<Parser> parserCtor = parserClass.GetConstructor(typeof(ITokenStream));
parser = parserCtor.NewInstance((ITokenStream)null);
}
if (inputFiles.IsEmpty())
{
Stream @is = Sharpen.Runtime.@in;
StreamReader r;
if (encoding != null)
{
r = new StreamReader(@is, encoding);
}
else
{
r = new StreamReader(@is);
}
Process(lexer, parserClass, parser, @is, r);
return;
}
foreach (string inputFile in inputFiles)
{
Stream @is = Sharpen.Runtime.@in;
if (inputFile != null)
{
@is = new FileInputStream(inputFile);
}
StreamReader r;
if (encoding != null)
{
r = new StreamReader(@is, encoding);
}
else
{
r = new StreamReader(@is);
}
if (inputFiles.Count > 1)
{
System.Console.Error.WriteLine(inputFile);
}
Process(lexer, parserClass, parser, @is, r);
}
}
/// <exception cref="System.IO.IOException"></exception>
/// <exception cref="System.MemberAccessException"></exception>
/// <exception cref="System.Reflection.TargetInvocationException"></exception>
/// <exception cref="Javax.Print.PrintException"></exception>
protected internal virtual void Process<_T0>(Lexer lexer, Type<_T0> parserClass,
Parser parser, Stream @is, StreamReader r) where _T0:Parser
{
try
{
AntlrInputStream input = new AntlrInputStream(r);
lexer.SetInputStream(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.Fill();
if (showTokens)
{
foreach (object tok in tokens.GetTokens())
{
System.Console.Out.WriteLine(tok);
}
}
if (startRuleName.Equals(LexerStartRuleName))
{
return;
}
if (diagnostics)
{
parser.AddErrorListener(new DiagnosticErrorListener());
parser.Interpreter.SetPredictionMode(PredictionMode.LlExactAmbigDetection);
}
if (printTree || gui || psFile != null)
{
parser.BuildParseTree = true;
}
if (Sll)
{
// overrides diagnostics
parser.Interpreter.SetPredictionMode(PredictionMode.Sll);
}
parser.SetInputStream(tokens);
parser.Trace = trace;
try
{
MethodInfo startRule = parserClass.GetMethod(startRuleName, (Type[])null);
ParserRuleContext tree = (ParserRuleContext)startRule.Invoke(parser, (object[])null
);
if (printTree)
{
System.Console.Out.WriteLine(tree.ToStringTree(parser));
}
if (gui)
{
tree.Inspect(parser);
}
if (psFile != null)
{
tree.Save(parser, psFile);
}
}
catch (NoSuchMethodException)
{
// Generate postscript
System.Console.Error.WriteLine("No method for rule " + startRuleName + " or it has arguments"
);
}
}
finally
{
if (r != null)
{
r.Close();
}
if (@is != null)
{
@is.Close();
}
}
}
}
}