1	package antlr;
2	
3	/**
4	 * <b>SOFTWARE RIGHTS</b>
5	 * <p>
6	 * ANTLR 2.5.0 MageLang Institute, 1998
7	 * <p>
8	 * We reserve no legal rights to the ANTLR--it is fully in the
9	 * public domain. An individual or company may do whatever
10	 * they wish with source code distributed with ANTLR or the
11	 * code generated by ANTLR, including the incorporation of
12	 * ANTLR, or its output, into commerical software.
13	 * <p>
14	 * We encourage users to develop software with ANTLR. However,
15	 * we do ask that credit is given to us for developing
16	 * ANTLR. By "credit", we mean that if you use ANTLR or
17	 * incorporate any source code into one of your programs
18	 * (commercial product, research project, or otherwise) that
19	 * you acknowledge this fact somewhere in the documentation,
20	 * research report, etc... If you like ANTLR and have
21	 * developed a nice tool with the output, please mention that
22	 * you developed it using ANTLR. In addition, we ask that the
23	 * headers remain intact in our source code. As long as these
24	 * guidelines are kept, we expect to continue enhancing this
25	 * system and expect to make other tools available as they are
26	 * completed.
27	 * <p>
28	 * The ANTLR gang:
29	 * @version ANTLR 2.5.0 MageLang Institute, 1998
30	 * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
31	 * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
32	 */
33	
34	import java.io.*;
35	import antlr.collections.impl.BitSet;
36	import antlr.collections.impl.Vector;
37	public class Tool {
38		// Object that handles analysis errors
39		ToolErrorHandler errorHandler;
40	
41		// Was there an error during parsing or analysis?
42		protected boolean hasError = false;
43	
44		// Generate diagnostics? (vs code)
45		boolean genDiagnostics = false;
46	
47		/** Generate HTML vs code? */
48		boolean genHTML = false;
49		
50		/** Current output directory for generated files */
51		protected static String outputDir = ".";
52	
53		// Grammar input
54		String grammarFile;
55		transient Reader f = new InputStreamReader(System.in);
56		// SAS: changed for proper text io
57		//	transient DataInputStream in = null;
58	
59		protected static String literalsPrefix = "LITERAL_";
60		protected static boolean upperCaseMangledLiterals = false;
61	
62		private static BitSet cmdLineArgValid = new BitSet();
63	
64	
65		/** Construct a new Tool. */
66		public Tool() {
67			// SAS: removed private so could create subclass
68			errorHandler = new DefaultToolErrorHandler();
69		}
70	private static void checkForInvalidArguments(String[] args, BitSet cmdLineArgValid) {
71		// check for invalid command line args
72		for (int a = 0; a < args.length; a++) {
73			if (!cmdLineArgValid.member(a)) {
74				warning("invalid command-line argument: " + args[a] + "; ignored");
75			}
76		}
77	}
78	// This example is from the book _Java in a Nutshell_ by David Flanagan.
79	// Written by David Flanagan.  Copyright (c) 1996 O'Reilly & Associates.
80	// You may study, use, modify, and distribute this example for any purpose.
81	// This example is provided WITHOUT WARRANTY either expressed or implied.
82	
83	  public static void copyFile(String source_name, String dest_name) 
84		   throws IOException
85	  {
86		File source_file = new File(source_name);
87		File destination_file = new File(dest_name);
88		FileReader source = null; // SAS: changed for proper text io
89		FileWriter destination = null;
90		char[] buffer;
91		int bytes_read;
92		
93		try {
94		  // First make sure the specified source file 
95		  // exists, is a file, and is readable.
96		  if (!source_file.exists() || !source_file.isFile())
97		throw new FileCopyException("FileCopy: no such source file: " +
98					    source_name);
99		  if (!source_file.canRead())
100		throw new FileCopyException("FileCopy: source file " + 
101					    "is unreadable: " + source_name);
102		  
103		  // If the destination exists, make sure it is a writeable file
104		  // and ask before overwriting it.  If the destination doesn't
105		  // exist, make sure the directory exists and is writeable.
106		  if (destination_file.exists()) {
107		if (destination_file.isFile()) {
108		  DataInputStream in = new DataInputStream(System.in);
109		  String response;
110		  
111		  if (!destination_file.canWrite())
112		    throw new FileCopyException("FileCopy: destination " +
113											"file is unwriteable: " + dest_name);
114		  /*
115		    System.out.print("File " + dest_name + 
116								 " already exists.  Overwrite? (Y/N): ");
117				     System.out.flush();
118				     response = in.readLine();
119				     if (!response.equals("Y") && !response.equals("y"))
120				     throw new FileCopyException("FileCopy: copy cancelled.");
121				     */
122		}
123		else{
124		  throw new FileCopyException("FileCopy: destination "
125					      + "is not a file: " +  dest_name);
126		}
127		  }
128		  else {
129		File parentdir = parent(destination_file);
130		if (!parentdir.exists())
131		  throw new FileCopyException("FileCopy: destination "
132					      + "directory doesn't exist: " + dest_name);
133		if (!parentdir.canWrite())
134		  throw new FileCopyException("FileCopy: destination "
135					      + "directory is unwriteable: " + dest_name);
136		  }
137		  
138		  // If we've gotten this far, then everything is okay; we can
139		  // copy the file.
140		  source = new FileReader(source_file);
141		  destination = new FileWriter(destination_file);
142		  buffer = new char[1024];
143		  while(true) {
144		bytes_read = source.read(buffer,0,1024);
145		if (bytes_read == -1) break;
146		destination.write(buffer, 0, bytes_read);
147		  }
148		}
149		// No matter what happens, always close any streams we've opened.
150		finally {
151		  if (source != null) 
152					try { source.close(); } catch (IOException e) { ; }
153			if (destination != null) 
154					try { destination.close(); } catch (IOException e) { ; }
155		}
156	  }  
157		/** Perform processing on the grammar file.   Can only be called from main()
158		 * @param args The command-line arguments passed to main()
159		 */
160		void doEverything(String[] args) {
161			// SAS: removed "private" so subclass can call
162			//      (The subclass is for the VAJ interface)
163			// run the preprocessor to handle inheritance first.
164			Toolr.preprocessor.Tool preTool = new antlr.preprocessor.Tool(this, args);
165			if ( !preTool.preprocess() ) {
166				System.exit(1);
167			}	
168			String[] modifiedArgs = preTool.preprocessedArgList();
169	
170			// process arguments for the Tool
171			processArguments(modifiedArgs);
172	
173			try {
174				if (grammarFile != null) {
175					f = new FileReader(grammarFile);
176				}
177			}
178			catch (IOException e) {
179				System.err.println("Error: cannot open grammar file " + grammarFile);
180				help();
181				System.exit(1);
182			}
183	
184			TokenBuffer tokenBuf = new TokenBuffer(new ANTLRLexer(f));
185			LLkAnalyzer analyzer = new LLkAnalyzer(this);
186			MakeGrammar behavior = new MakeGrammar(this, args, analyzer);
187	
188			try {
189				ANTLRParser p = new ANTLRParser(tokenBuf, behavior, this);
190				p.grammar();
191				if (hasError) {
192					System.out.println("Exiting due to errors.");
193					System.exit(1);
194				}
195				checkForInvalidArguments(modifiedArgs, cmdLineArgValid);
196	
197				// Create the right code generator according to the "language" option
198				CodeGenerator codeGen;
199	
200				// SAS: created getLanguage() method so subclass can override
201				//      (necessary for VAJ interface)
202				String codeGenClassName = "antlr." + getLanguage(behavior) + "CodeGenerator";
203				try {
204					Class codeGenClass = Class.forName(codeGenClassName);
205					codeGen = (CodeGenerator)codeGenClass.newInstance();
206					codeGen.setBehavior(behavior);
207					codeGen.setAnalyzer(analyzer);
208					codeGen.setTool(this);
209					codeGen.gen();
210				}
211				catch (ClassNotFoundException cnfe) {
212					panic("Cannot instantiate code-generator: " + codeGenClassName);
213				}
214				catch (InstantiationException ie) {
215					panic("Cannot instantiate code-generator: " + codeGenClassName);
216				}
217				catch (IllegalArgumentException ie) {
218					panic("Cannot instantiate code-generator: " + codeGenClassName);
219				}
220				catch (IllegalAccessException iae) {
221					panic("code-generator class '" + codeGenClassName + "' is not accessible");
222				}
223			}
224			catch (MismatchedTokenException mt) {
225				System.err.println("Unhandled parser error: " + mt.getMessage());
226			}
227			catch (NoViableAltException nva) {
228				System.err.println("Unhandled parser error: " + nva.getMessage());
229			}
230			catch (ParserException pe) {
231				System.err.println("Unhandled parser error: " + pe.getMessage());
232			}
233			catch (IOException io) {
234				System.err.println("IOException: " + io.getMessage());
235			}
236		}
237		/** Issue an error 
238		 * @param s The message
239		 */
240		public void error(String s) {
241			hasError = true;
242			System.out.println("error: "+s);
243		}
244		/** Issue an error with line number information 
245		 * @param s The message
246		 * @param line The grammar file line number on which the error occured
247		 */
248		public void error(String s, int line) {
249			hasError = true;
250			System.out.println("error: line "+line+": "+s);
251		}
252	/** When we are 1.1 compatible...
253	public static Object factory2 (String p, Object[] initargs) {
254	  Class c;
255	  Object o = null;
256	  try {
257		int argslen = initargs.length;
258		Class cl[] = new Class[argslen];
259		for (int i=0;i<argslen;i++) {
260		  cl[i] = Class.forName(initargs[i].getClass().getName());
261		}
262		c = Class.forName (p);
263		Constructor con = c.getConstructor (cl);
264		o = con.newInstance (initargs);
265	  } catch (Exception e) {
266		System.err.println ("Can't make a " + p);
267	  }
268	  return o;
269	}
270	*/
271	public static Object factory(String p) {
272	  Class c;
273	  Object o=null;
274	  try {
275			c = Class.forName(p);// get class def
276			o = c.newInstance(); // make a new one
277	  }
278	  catch (Exception e) {
279			// either class not found,
280			// class is interface/abstract, or
281			// class or initializer is not accessible.
282			warning("Can't create an object of type " + p);
283			return null;
284	  }
285	  return o;
286	}
287		public static String fileMinusPath(String f) {
288			String separator = System.getProperty("file.separator");
289			int endOfPath = f.lastIndexOf(separator);
290			if ( endOfPath == -1 ) {
291				return f;	// no path found
292			}	
293			return f.substring(endOfPath+1);
294		}
295		/** Determine the language used for this run of ANTLR
296		 *  This was made a method so the subclass can override it
297		 */
298		public String getLanguage(MakeGrammar behavior) {
299			if (genDiagnostics) {
300				return "Diagnostic";
301			}
302			if (genHTML) {
303				return "HTML";
304			}
305			return behavior.language;
306		}
307		public static String getOutputDirectory() { return outputDir; }
308	private static void help() {
309		System.err.println("usage: java antlr.Tool [args] file.g");
310		System.err.println("  -o outputDir      specify output directory where all output generated.");
311		System.err.println("  -debug            launch the ParseView debugger upon parser invocation.");
312		System.err.println("  -html             generate an html file from your grammar (minus actions).");
313		System.err.println("  -trace            have all rules call traceIn/traceOut.");
314		System.err.println("  -traceParser      have parser rules call traceIn/traceOut.");
315		System.err.println("  -traceLexer       have lexer rules call traceIn/traceOut.");
316		System.err.println("  -traceTreeWalker  have tree walker rules call traceIn/traceOut.");
317	}
318		public static void main(String[] args) {
319			System.err.println("ANTLR Parser Generator   Version "+
320								ANTLRParser.version+"   1989-1998 MageLang Institute");
321			try {
322				if ( args.length==0 ) {
323					help();
324				}
325				Tool theTool = new Tool();
326				theTool.doEverything(args);
327				theTool = null;
328			}
329			catch (Exception e) {
330				System.err.println(System.getProperty("line.separator")+
331					System.getProperty("line.separator"));
332				System.err.println("#$%%*&@# internal error: "+e.toString());
333				System.err.println("[complain to nearest government official");
334				System.err.println(" or send hate-mail to parrt@parr-research.com;");
335				System.err.println(" please send stack trace with report.]"+
336					System.getProperty("line.separator"));
337				e.printStackTrace();
338			}
339			System.exit(0);	
340		}
341		public static PrintWriter openOutputFile(String f) throws IOException {
342			return new PrintWriter(new FileWriter(outputDir+System.getProperty("file.separator")+f));
343		}
344		/** Issue an unknown fatal error */
345		public static void panic() {
346			System.err.println("panic");
347			System.exit(1);
348		}
349		/** Issue a fatal error message 
350		 * @param s The message
351		 */
352		public static void panic(String s) {
353			System.err.println("panic: "+s);
354			System.exit(1);
355		}
356	  // File.getParent() can return null when the file is specified without
357	  // a directory or is in the root directory.  
358	  // This method handles those cases.
359	  public static File parent(File f) {
360		String dirname = f.getParent();
361		if (dirname == null) {
362		  if (f.isAbsolute()) return new File(File.separator);
363		  else return new File(System.getProperty("user.dir"));
364		}
365		return new File(dirname);
366	  }  
367		/** Parse a list such as "f1.g;f2.g;..." and return a Vector
368		 *  of the elements.
369		 */
370		public static Vector parseSeparatedList(String list, char separator) {
371			Vector v = new Vector(10);		
372			StringBuffer buf = new StringBuffer(100);
373			int i=0;
374			while ( i<list.length() ) {
375				while ( i<list.length() && list.charAt(i)!=separator ) {
376					buf.append(list.charAt(i));
377					i++;
378				}
379				// add element to vector
380				v.appendElement(buf.toString());
381				buf.setLength(0);
382				// must be a separator or finished.
383				if ( i<list.length() ) {	// not done?
384					i++;	// skip separator
385				}	
386			}
387			if ( v.size()==0 ) return null;	
388			return v;
389		}
390		/** given a filename, strip off the directory prefix (if any)
391		 *  and return it.  Return "./" if f has no dir prefix.
392		 */
393		public static String pathToFile(String f) {
394			String separator = System.getProperty("file.separator");
395			int endOfPath = f.lastIndexOf(separator);
396			if ( endOfPath == -1 ) {
397				// no path, use current directory
398				return "."+System.getProperty("file.separator");
399			}	
400			return f.substring(0, endOfPath+1);
401		}
402	/** Process the command-line arguments.  Can only be called by Tool.
403	 * @param args The command-line arguments passed to main()
404	 */
405	private void processArguments(String[] args) {
406		for (int i = 0; i < args.length; i++) {
407			if (args[i].equals("-diagnostic")) {
408				genDiagnostics = true;
409				genHTML = false;
410				Tool.setArgOK(i);
411			} else {
412				if (args[i].equals("-o")) {
413					Tool.setArgOK(i);
414					if (i + 1 >= args.length) {
415						error("missing output directory with -o option; ignoring");
416					} else {
417						i++;
418						setOutputDirectory(args[i]);
419						Tool.setArgOK(i);
420					}
421				} else
422					if (args[i].equals("-html")) {
423						genHTML = true;
424						genDiagnostics = false;
425						Tool.setArgOK(i);
426					} else {
427						if (args[i].charAt(0) != '-') {
428							// Must be the grammar file
429							grammarFile = args[i];
430							Tool.setArgOK(i);
431						}
432					}
433			}
434		}
435	}
436		public static void setArgOK(int i) {
437			cmdLineArgValid.add(i);
438		}
439		public static void setOutputDirectory(String o) { outputDir = o; }
440		/** General-purpose utility function for removing 
441		 * characters from back of string 
442		 * @param s The string to process
443		 * @param c The character to remove
444		 * @return The resulting string
445		 */
446		static public String stripBack(String s, char c) {
447			while (s.length() > 0 && s.charAt(s.length()-1) == c)
448			{
449				s = s.substring(0, s.length()-1);
450			}
451			return s;
452		}
453		/** General-purpose utility function for removing 
454		 * characters from back of string 
455		 * @param s The string to process
456		 * @param remove A string containing the set of characters to remove
457		 * @return The resulting string
458		 */
459		static public String stripBack(String s, String remove) {
460			boolean changed;
461			do {
462				changed = false;
463				for (int i = 0; i < remove.length(); i++) {
464					char c = remove.charAt(i);
465					while (s.length() > 0 && s.charAt(s.length()-1) == c)
466					{
467						changed = true;
468						s = s.substring(0, s.length()-1);
469					}
470				}
471			} while (changed);
472			return s;
473		}
474		/** General-purpose utility function for removing 
475		 * characters from front of string 
476		 * @param s The string to process
477		 * @param c The character to remove
478		 * @return The resulting string
479		 */
480		static public String stripFront(String s, char c) {
481			while (s.length() > 0 && s.charAt(0) == c) {
482				s = s.substring(1);
483			}
484			return s;
485		}
486		/** General-purpose utility function for removing 
487		 * characters from front of string 
488		 * @param s The string to process
489		 * @param remove A string containing the set of characters to remove
490		 * @return The resulting string
491		 */
492		static public String stripFront(String s, String remove) {
493			boolean changed;
494			do {
495				changed = false;
496				for (int i = 0; i < remove.length(); i++) {
497					char c = remove.charAt(i);
498					while (s.length() > 0 && s.charAt(0) == c) {
499						changed = true;
500						s = s.substring(1);
501					}
502				}
503			} while (changed);
504			return s;
505		}
506		/** General-purpose utility function for removing 
507		 * characters from the front and back of string 
508		 * @param s The string to process
509		 * @param head exact string to strip from head
510		 * @param tail exact string to strip from tail
511		 * @return The resulting string
512		 */
513		public static String stripFrontBack(String src, String head, String tail) {
514			int h = src.indexOf(head);
515			int t = src.lastIndexOf(tail);
516			if ( h==-1 || t==-1 ) return src;
517			return src.substring(h+1,t);
518		}
519		/** Issue an error; used for general tool errors not for grammar stuff
520		 * @param s The message
521		 */
522		public static void toolError(String s) {
523			System.out.println("error: "+s);
524		}
525		/** Issue a warning 
526		 * @param s the message
527		 */
528		public static void warning(String s) {
529			System.out.println("warning: "+s);
530		}
531		/** Issue a warning with line number information 
532		 * @param s The message
533		 * @param line The grammar file line number on which the error occured
534		 */
535		public static void warning(String s, int line) {
536			System.out.println("warning; line "+line+": "+s);
537		}
538	}
539