package antlr; /* ANTLR Translator Generator * Project led by Terence Parr at http://www.jGuru.com * Software rights: http://www.antlr.org/RIGHTS.html * * $Id: Tool.java,v 1.1 2004/01/21 19:18:33 rgrimm Exp $ */ import java.io.*; import antlr.collections.impl.BitSet; import antlr.collections.impl.Vector; import antlr.PreservingFileWriter; import antlr.Version; 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 static 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 static String literalsPrefix = "LITERAL_"; protected static 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) antlr.preprocessor.Tool preTool = new 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 = "antlr." + getLanguage(behavior) + "CodeGenerator"; try { Class codeGenClass = Class.forName(codeGenClassName); codeGen = (CodeGenerator)codeGenClass.newInstance(); 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); } /** When we are 1.1 compatible... public static Object factory2 (String p, Object[] initargs) { Class c; Object o = null; try { int argslen = initargs.length; Class cl[] = new Class[argslen]; for (int i=0;i<argslen;i++) { cl[i] = Class.forName(initargs[i].getClass().getName()); } c = Class.forName (p); Constructor con = c.getConstructor (cl); o = con.newInstance (initargs); } catch (Exception e) { System.err.println ("Can't make a " + p); } return o; } */ public Object factory(String p) { Class c; Object o = null; try { c = Class.forName(p);// get class def o = c.newInstance(); // make a new one } catch (Exception e) { // either class not found, // class is interface/abstract, or // class or initializer is not accessible. warning("Can't create an object of type " + p); return null; } return o; } 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-2003 jGuru.com"); version = Version.project_version; try { if (args.length == 0) { help(); System.exit(1); } for (int i = 0; i < args.length; ++i) { if (args[i].equals("-h") || args[i].equals("-help") || args[i].equals("--help") ) { help(); System.exit(1); } } 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@jguru.com;"); System.err.println(" please send stack trace with report.]" + System.getProperty("line.separator")); e.printStackTrace(); } System.exit(0); } /** This method is used by all code generators to create new output * files. */ public PrintWriter openOutputFile(String f) throws IOException { 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); System.exit(1); } /** 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) { Vector v = new Vector(10); StringBuffer buf = new StringBuffer(100); int i = 0; while (i < list.length()) { while (i < list.length() && list.charAt(i) != separator) { buf.append(list.charAt(i)); i++; } // add element to vector v.appendElement(buf.toString()); buf.setLength(0); // must be a separator or finished. if (i < list.length()) { // not done? i++; // skip separator } } 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, "\"", "\"")); } }