You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
614 lines
22 KiB
614 lines
22 KiB
package com.fr.third.antlr; |
|
|
|
/* ANTLR Translator Generator |
|
* Project led by Terence Parr at http://www.cs.usfca.edu |
|
* Software rights: http://www.antlr.org/license.html |
|
* |
|
* $Id: //depot/code/org.antlr/release/antlr-2.7.7/antlr/Tool.java#2 $ |
|
*/ |
|
|
|
import java.io.BufferedReader; |
|
import java.io.BufferedWriter; |
|
import java.io.DataInputStream; |
|
import java.io.File; |
|
import java.io.FileReader; |
|
import java.io.FileWriter; |
|
import java.io.IOException; |
|
import java.io.InputStreamReader; |
|
import java.io.PrintWriter; |
|
import java.io.Reader; |
|
import java.io.Writer; |
|
|
|
import com.fr.third.antlr.collections.impl.BitSet; |
|
import com.fr.third.antlr.collections.impl.Vector; |
|
|
|
|
|
public class Tool { |
|
public static String version = ""; |
|
|
|
/** Object that handles analysis errors */ |
|
ToolErrorHandler errorHandler; |
|
|
|
/** Was there an error during parsing or analysis? */ |
|
protected boolean hasError = false; |
|
|
|
/** Generate diagnostics? (vs code) */ |
|
boolean genDiagnostics = false; |
|
|
|
/** Generate DocBook vs code? */ |
|
boolean genDocBook = false; |
|
|
|
/** Generate HTML vs code? */ |
|
boolean genHTML = false; |
|
|
|
/** Current output directory for generated files */ |
|
protected String outputDir = "."; |
|
|
|
// Grammar input |
|
protected String grammarFile; |
|
transient Reader f = new InputStreamReader(System.in); |
|
// SAS: changed for proper text io |
|
// transient DataInputStream in = null; |
|
|
|
protected String literalsPrefix = "LITERAL_"; |
|
protected boolean upperCaseMangledLiterals = false; |
|
|
|
/** C++ file level options */ |
|
protected NameSpace nameSpace = null; |
|
protected String namespaceAntlr = null; |
|
protected String namespaceStd = null; |
|
protected boolean genHashLines = true; |
|
protected boolean noConstructors = false; |
|
|
|
private BitSet cmdLineArgValid = new BitSet(); |
|
|
|
/** Construct a new Tool. */ |
|
public Tool() { |
|
errorHandler = new DefaultToolErrorHandler(this); |
|
} |
|
|
|
public String getGrammarFile() { |
|
return grammarFile; |
|
} |
|
|
|
public boolean hasError() { |
|
return hasError; |
|
} |
|
|
|
public NameSpace getNameSpace() { |
|
return nameSpace; |
|
} |
|
|
|
public String getNamespaceStd() { |
|
return namespaceStd; |
|
} |
|
|
|
public String getNamespaceAntlr() { |
|
return namespaceAntlr; |
|
} |
|
|
|
public boolean getGenHashLines() { |
|
return genHashLines; |
|
} |
|
|
|
public String getLiteralsPrefix() { |
|
return literalsPrefix; |
|
} |
|
|
|
public boolean getUpperCaseMangledLiterals() { |
|
return upperCaseMangledLiterals; |
|
} |
|
|
|
public void setFileLineFormatter(FileLineFormatter formatter) { |
|
FileLineFormatter.setFormatter(formatter); |
|
} |
|
|
|
protected void checkForInvalidArguments(String[] args, BitSet cmdLineArgValid) { |
|
// check for invalid command line args |
|
for (int a = 0; a < args.length; a++) { |
|
if (!cmdLineArgValid.member(a)) { |
|
warning("invalid command-line argument: " + args[a] + "; ignored"); |
|
} |
|
} |
|
} |
|
|
|
/** This example is from the book _Java in a Nutshell_ by David |
|
* Flanagan. Written by David Flanagan. Copyright (c) 1996 |
|
* O'Reilly & Associates. You may study, use, modify, and |
|
* distribute this example for any purpose. This example is |
|
* provided WITHOUT WARRANTY either expressed or implied. */ |
|
public void copyFile(String source_name, String dest_name) |
|
throws IOException { |
|
File source_file = new File(source_name); |
|
File destination_file = new File(dest_name); |
|
Reader source = null; |
|
Writer destination = null; |
|
char[] buffer; |
|
int bytes_read; |
|
|
|
try { |
|
// First make sure the specified source file |
|
// exists, is a file, and is readable. |
|
if (!source_file.exists() || !source_file.isFile()) |
|
throw new FileCopyException("FileCopy: no such source file: " + |
|
source_name); |
|
if (!source_file.canRead()) |
|
throw new FileCopyException("FileCopy: source file " + |
|
"is unreadable: " + source_name); |
|
|
|
// If the destination exists, make sure it is a writeable file |
|
// and ask before overwriting it. If the destination doesn't |
|
// exist, make sure the directory exists and is writeable. |
|
if (destination_file.exists()) { |
|
if (destination_file.isFile()) { |
|
DataInputStream in = new DataInputStream(System.in); |
|
String response; |
|
|
|
if (!destination_file.canWrite()) |
|
throw new FileCopyException("FileCopy: destination " + |
|
"file is unwriteable: " + dest_name); |
|
/* |
|
System.out.print("File " + dest_name + |
|
" already exists. Overwrite? (Y/N): "); |
|
System.out.flush(); |
|
response = in.readLine(); |
|
if (!response.equals("Y") && !response.equals("y")) |
|
throw new FileCopyException("FileCopy: copy cancelled."); |
|
*/ |
|
} |
|
else { |
|
throw new FileCopyException("FileCopy: destination " |
|
+ "is not a file: " + dest_name); |
|
} |
|
} |
|
else { |
|
File parentdir = parent(destination_file); |
|
if (!parentdir.exists()) |
|
throw new FileCopyException("FileCopy: destination " |
|
+ "directory doesn't exist: " + dest_name); |
|
if (!parentdir.canWrite()) |
|
throw new FileCopyException("FileCopy: destination " |
|
+ "directory is unwriteable: " + dest_name); |
|
} |
|
|
|
// If we've gotten this far, then everything is okay; we can |
|
// copy the file. |
|
source = new BufferedReader(new FileReader(source_file)); |
|
destination = new BufferedWriter(new FileWriter(destination_file)); |
|
|
|
buffer = new char[1024]; |
|
while (true) { |
|
bytes_read = source.read(buffer, 0, 1024); |
|
if (bytes_read == -1) break; |
|
destination.write(buffer, 0, bytes_read); |
|
} |
|
} |
|
// No matter what happens, always close any streams we've opened. |
|
finally { |
|
if (source != null) { |
|
try { |
|
source.close(); |
|
} |
|
catch (IOException e) { |
|
; |
|
} |
|
} |
|
if (destination != null) { |
|
try { |
|
destination.close(); |
|
} |
|
catch (IOException e) { |
|
; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** Perform processing on the grammar file. Can only be called |
|
* from main() @param args The command-line arguments passed to |
|
* main(). This wrapper does the System.exit for use with command-line. |
|
*/ |
|
public void doEverythingWrapper(String[] args) { |
|
int exitCode = doEverything(args); |
|
System.exit(exitCode); |
|
} |
|
|
|
/** Process args and have ANTLR do it's stuff without calling System.exit. |
|
* Just return the result code. Makes it easy for ANT build tool. |
|
*/ |
|
public int doEverything(String[] args) { |
|
// run the preprocessor to handle inheritance first. |
|
|
|
// Start preprocessor. This strips generates an argument list |
|
// without -glib options (inside preTool) |
|
com.fr.third.antlr.preprocessor.Tool preTool = new com.fr.third.antlr.preprocessor.Tool(this, args); |
|
|
|
boolean preprocess_ok = preTool.preprocess(); |
|
String[] modifiedArgs = preTool.preprocessedArgList(); |
|
|
|
// process arguments for the Tool |
|
processArguments(modifiedArgs); |
|
if (!preprocess_ok) { |
|
return 1; |
|
} |
|
|
|
f = getGrammarReader(); |
|
|
|
ANTLRLexer lexer = new ANTLRLexer(f); |
|
TokenBuffer tokenBuf = new TokenBuffer(lexer); |
|
LLkAnalyzer analyzer = new LLkAnalyzer(this); |
|
MakeGrammar behavior = new MakeGrammar(this, args, analyzer); |
|
|
|
try { |
|
ANTLRParser p = new ANTLRParser(tokenBuf, behavior, this); |
|
p.setFilename(grammarFile); |
|
p.grammar(); |
|
if (hasError()) { |
|
fatalError("Exiting due to errors."); |
|
} |
|
checkForInvalidArguments(modifiedArgs, cmdLineArgValid); |
|
|
|
// Create the right code generator according to the "language" option |
|
CodeGenerator codeGen; |
|
|
|
// SAS: created getLanguage() method so subclass can override |
|
// (necessary for VAJ interface) |
|
String codeGenClassName = "com.fr.third.antlr." + getLanguage(behavior) + "CodeGenerator"; |
|
try { |
|
codeGen = (CodeGenerator)Utils.createInstanceOf(codeGenClassName); |
|
codeGen.setBehavior(behavior); |
|
codeGen.setAnalyzer(analyzer); |
|
codeGen.setTool(this); |
|
codeGen.gen(); |
|
} |
|
catch (ClassNotFoundException cnfe) { |
|
panic("Cannot instantiate code-generator: " + codeGenClassName); |
|
} |
|
catch (InstantiationException ie) { |
|
panic("Cannot instantiate code-generator: " + codeGenClassName); |
|
} |
|
catch (IllegalArgumentException ie) { |
|
panic("Cannot instantiate code-generator: " + codeGenClassName); |
|
} |
|
catch (IllegalAccessException iae) { |
|
panic("code-generator class '" + codeGenClassName + "' is not accessible"); |
|
} |
|
} |
|
catch (RecognitionException pe) { |
|
fatalError("Unhandled parser error: " + pe.getMessage()); |
|
} |
|
catch (TokenStreamException io) { |
|
fatalError("TokenStreamException: " + io.getMessage()); |
|
} |
|
return 0; |
|
} |
|
|
|
/** Issue an error |
|
* @param s The message |
|
*/ |
|
public void error(String s) { |
|
hasError = true; |
|
System.err.println("error: " + s); |
|
} |
|
|
|
/** Issue an error with line number information |
|
* @param s The message |
|
* @param file The file that has the error (or null) |
|
* @param line The grammar file line number on which the error occured (or -1) |
|
* @param column The grammar file column number on which the error occured (or -1) |
|
*/ |
|
public void error(String s, String file, int line, int column) { |
|
hasError = true; |
|
System.err.println(FileLineFormatter.getFormatter(). |
|
getFormatString(file, line, column) + s); |
|
} |
|
|
|
public String fileMinusPath(String f) { |
|
String separator = System.getProperty("file.separator"); |
|
int endOfPath = f.lastIndexOf(separator); |
|
if (endOfPath == -1) { |
|
return f; // no path found |
|
} |
|
return f.substring(endOfPath + 1); |
|
} |
|
|
|
/** Determine the language used for this run of ANTLR |
|
* This was made a method so the subclass can override it |
|
*/ |
|
public String getLanguage(MakeGrammar behavior) { |
|
if (genDiagnostics) { |
|
return "Diagnostic"; |
|
} |
|
if (genHTML) { |
|
return "HTML"; |
|
} |
|
if (genDocBook) { |
|
return "DocBook"; |
|
} |
|
return behavior.language; |
|
} |
|
|
|
public String getOutputDirectory() { |
|
return outputDir; |
|
} |
|
|
|
private static void help() { |
|
System.err.println("usage: java antlr.Tool [args] file.g"); |
|
System.err.println(" -o outputDir specify output directory where all output generated."); |
|
System.err.println(" -glib superGrammar specify location of supergrammar file."); |
|
System.err.println(" -debug launch the ParseView debugger upon parser invocation."); |
|
System.err.println(" -html generate a html file from your grammar."); |
|
System.err.println(" -docbook generate a docbook sgml file from your grammar."); |
|
System.err.println(" -diagnostic generate a textfile with diagnostics."); |
|
System.err.println(" -trace have all rules call traceIn/traceOut."); |
|
System.err.println(" -traceLexer have lexer rules call traceIn/traceOut."); |
|
System.err.println(" -traceParser have parser rules call traceIn/traceOut."); |
|
System.err.println(" -traceTreeParser have tree parser rules call traceIn/traceOut."); |
|
System.err.println(" -h|-help|--help this message"); |
|
} |
|
|
|
public static void main(String[] args) { |
|
System.err.println("ANTLR Parser Generator Version " + |
|
Version.project_version + " 1989-2005"); |
|
version = Version.project_version; |
|
|
|
try { |
|
boolean showHelp = false; |
|
|
|
if (args.length == 0) { |
|
showHelp = true; |
|
} |
|
else { |
|
for (int i = 0; i < args.length; ++i) { |
|
if (args[i].equals("-h") |
|
|| args[i].equals("-help") |
|
|| args[i].equals("--help") |
|
) { |
|
showHelp = true; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (showHelp) { |
|
help(); |
|
} |
|
else { |
|
Tool theTool = new Tool(); |
|
theTool.doEverything(args); |
|
theTool = null; |
|
} |
|
} |
|
catch (Exception e) { |
|
System.err.println(System.getProperty("line.separator") + |
|
System.getProperty("line.separator")); |
|
System.err.println("#$%%*&@# internal error: " + e.toString()); |
|
System.err.println("[complain to nearest government official"); |
|
System.err.println(" or send hate-mail to parrt@antlr.org;"); |
|
System.err.println(" please send stack trace with report.]" + |
|
System.getProperty("line.separator")); |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
/** This method is used by all code generators to create new output |
|
* files. If the outputDir set by -o is not present it will be created here. |
|
*/ |
|
public PrintWriter openOutputFile(String f) throws IOException { |
|
if( !".".equals(outputDir)) { |
|
File out_dir = new File(outputDir); |
|
if( ! out_dir.exists() ) |
|
out_dir.mkdirs(); |
|
} |
|
return new PrintWriter(new PreservingFileWriter(outputDir + System.getProperty("file.separator") + f)); |
|
} |
|
|
|
public Reader getGrammarReader() { |
|
Reader f = null; |
|
try { |
|
if (grammarFile != null) { |
|
f = new BufferedReader(new FileReader(grammarFile)); |
|
} |
|
} |
|
catch (IOException e) { |
|
fatalError("cannot open grammar file " + grammarFile); |
|
} |
|
return f; |
|
} |
|
|
|
/** @since 2.7.2 |
|
*/ |
|
public void reportException(Exception e, String message) { |
|
System.err.println(message == null ? e.getMessage() |
|
: message + ": " + e.getMessage()); |
|
} |
|
|
|
/** @since 2.7.2 |
|
*/ |
|
public void reportProgress(String message) { |
|
System.out.println(message); |
|
} |
|
|
|
/** An error occured that should stop the Tool from doing any work. |
|
* The default implementation currently exits (via |
|
* {@link java.lang.System.exit(int)} after printing an error message to |
|
* <var>stderr</var>. However, the tools should expect that a subclass |
|
* will override this to throw an unchecked exception such as |
|
* {@link java.lang.IllegalStateException} or another subclass of |
|
* {@link java.lang.RuntimeException}. <em>If this method is overriden, |
|
* <strong>it must never return normally</strong>; i.e. it must always |
|
* throw an exception or call System.exit</em>. |
|
* @since 2.7.2 |
|
* @param s The message |
|
*/ |
|
public void fatalError(String message) { |
|
System.err.println(message); |
|
Utils.error(message); |
|
} |
|
|
|
/** Issue an unknown fatal error. <em>If this method is overriden, |
|
* <strong>it must never return normally</strong>; i.e. it must always |
|
* throw an exception or call System.exit</em>. |
|
* @deprecated as of 2.7.2 use {@link #fatalError(String)}. By default |
|
* this method executes <code>fatalError("panic");</code>. |
|
*/ |
|
public void panic() { |
|
fatalError("panic"); |
|
} |
|
|
|
/** Issue a fatal error message. <em>If this method is overriden, |
|
* <strong>it must never return normally</strong>; i.e. it must always |
|
* throw an exception or call System.exit</em>. |
|
* @deprecated as of 2.7.2 use {@link #fatalError(String)}. By defaykt |
|
* this method executes <code>fatalError("panic: " + s);</code>. |
|
* @param s The message |
|
*/ |
|
public void panic(String s) { |
|
fatalError("panic: " + s); |
|
} |
|
|
|
// File.getParent() can return null when the file is specified without |
|
// a directory or is in the root directory. |
|
// This method handles those cases. |
|
public File parent(File f) { |
|
String dirname = f.getParent(); |
|
if (dirname == null) { |
|
if (f.isAbsolute()) |
|
return new File(File.separator); |
|
else |
|
return new File(System.getProperty("user.dir")); |
|
} |
|
return new File(dirname); |
|
} |
|
|
|
/** Parse a list such as "f1.g;f2.g;..." and return a Vector |
|
* of the elements. |
|
*/ |
|
public static Vector parseSeparatedList(String list, char separator) { |
|
java.util.StringTokenizer st = |
|
new java.util.StringTokenizer(list, String.valueOf(separator)); |
|
Vector v = new Vector(10); |
|
while ( st.hasMoreTokens() ) { |
|
v.appendElement(st.nextToken()); |
|
} |
|
if (v.size() == 0) return null; |
|
return v; |
|
} |
|
|
|
/** given a filename, strip off the directory prefix (if any) |
|
* and return it. Return "./" if f has no dir prefix. |
|
*/ |
|
public String pathToFile(String f) { |
|
String separator = System.getProperty("file.separator"); |
|
int endOfPath = f.lastIndexOf(separator); |
|
if (endOfPath == -1) { |
|
// no path, use current directory |
|
return "." + System.getProperty("file.separator"); |
|
} |
|
return f.substring(0, endOfPath + 1); |
|
} |
|
|
|
/** <p>Process the command-line arguments. Can only be called by Tool. |
|
* A bitset is collected of all correct arguments via setArgOk.</p> |
|
* @param args The command-line arguments passed to main() |
|
* |
|
*/ |
|
protected void processArguments(String[] args) { |
|
for (int i = 0; i < args.length; i++) { |
|
if (args[i].equals("-diagnostic")) { |
|
genDiagnostics = true; |
|
genHTML = false; |
|
setArgOK(i); |
|
} |
|
else if (args[i].equals("-o")) { |
|
setArgOK(i); |
|
if (i + 1 >= args.length) { |
|
error("missing output directory with -o option; ignoring"); |
|
} |
|
else { |
|
i++; |
|
setOutputDirectory(args[i]); |
|
setArgOK(i); |
|
} |
|
} |
|
else if (args[i].equals("-html")) { |
|
genHTML = true; |
|
genDiagnostics = false; |
|
setArgOK(i); |
|
} |
|
else if (args[i].equals("-docbook")) { |
|
genDocBook = true; |
|
genDiagnostics = false; |
|
setArgOK(i); |
|
} |
|
else { |
|
if (args[i].charAt(0) != '-') { |
|
// Must be the grammar file |
|
grammarFile = args[i]; |
|
setArgOK(i); |
|
} |
|
} |
|
} |
|
} |
|
|
|
public void setArgOK(int i) { |
|
cmdLineArgValid.add(i); |
|
} |
|
|
|
public void setOutputDirectory(String o) { |
|
outputDir = o; |
|
} |
|
|
|
/** Issue an error; used for general tool errors not for grammar stuff |
|
* @param s The message |
|
*/ |
|
public void toolError(String s) { |
|
System.err.println("error: " + s); |
|
} |
|
|
|
/** Issue a warning |
|
* @param s the message |
|
*/ |
|
public void warning(String s) { |
|
System.err.println("warning: " + s); |
|
} |
|
|
|
/** Issue a warning with line number information |
|
* @param s The message |
|
* @param file The file that has the warning (or null) |
|
* @param line The grammar file line number on which the warning occured (or -1) |
|
* @param column The grammar file line number on which the warning occured (or -1) |
|
*/ |
|
public void warning(String s, String file, int line, int column) { |
|
System.err.println(FileLineFormatter.getFormatter(). |
|
getFormatString(file, line, column) + "warning:" + s); |
|
} |
|
|
|
/** Issue a warning with line number information |
|
* @param s The lines of the message |
|
* @param file The file that has the warning |
|
* @param line The grammar file line number on which the warning occured |
|
*/ |
|
public void warning(String[] s, String file, int line, int column) { |
|
if (s == null || s.length == 0) { |
|
panic("bad multi-line message to Tool.warning"); |
|
} |
|
System.err.println(FileLineFormatter.getFormatter(). |
|
getFormatString(file, line, column) + "warning:" + s[0]); |
|
for (int i = 1; i < s.length; i++) { |
|
System.err.println(FileLineFormatter.getFormatter(). |
|
getFormatString(file, line, column) + " " + s[i]); |
|
} |
|
} |
|
|
|
/** |
|
* Support C++ & C# namespaces (for now). |
|
* C++: Add a nested namespace name to the current namespace. |
|
* C# : Specify an enclosing namespace for the generated code. |
|
* DAW: David Wagner -- C# support by kunle odutola |
|
*/ |
|
public void setNameSpace(String name) { |
|
if (null == nameSpace) |
|
nameSpace = new NameSpace(StringUtils.stripFrontBack(name, "\"", "\"")); |
|
} |
|
}
|
|
|