1/*
2 * [The "BSD license"]
3 *  Copyright (c) 2010 Terence Parr
4 *  All rights reserved.
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions
8 *  are met:
9 *  1. Redistributions of source code must retain the above copyright
10 *      notice, this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *      derived from this software without specific prior written permission.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28package org.antlr;
29
30import org.antlr.analysis.*;
31import org.antlr.codegen.CodeGenerator;
32import org.antlr.misc.Graph;
33import org.antlr.runtime.misc.Stats;
34import org.antlr.tool.*;
35import org.stringtemplate.v4.STGroup;
36
37import java.io.*;
38import java.util.*;
39
40/** The main ANTLR entry point.  Read a grammar and generate a parser. */
41public class Tool {
42
43    public final Properties antlrSettings = new Properties();
44    public String VERSION = "3.4";
45    //public static final String VERSION = "${project.version}";
46    public static final String UNINITIALIZED_DIR = "<unset-dir>";
47    private List<String> grammarFileNames = new ArrayList<String>();
48    private boolean generate_NFA_dot = false;
49    private boolean generate_DFA_dot = false;
50    private String outputDirectory = ".";
51    private boolean haveOutputDir = false;
52    private String inputDirectory = null;
53    private String parentGrammarDirectory;
54    private String grammarOutputDirectory;
55    private boolean haveInputDir = false;
56    private String libDirectory = ".";
57    private boolean debug = false;
58    private boolean trace = false;
59    private boolean profile = false;
60    private boolean report = false;
61    private boolean printGrammar = false;
62    private boolean depend = false;
63    private boolean forceAllFilesToOutputDir = false;
64    private boolean forceRelativeOutput = false;
65    protected boolean deleteTempLexer = true;
66    private boolean verbose = false;
67    /** Don't process grammar file if generated files are newer than grammar */
68    private boolean make = false;
69    private boolean showBanner = true;
70	private static boolean exitNow = false;
71	private static boolean return_dont_exit = false;
72
73
74	public String forcedLanguageOption; // -language L on command line
75
76    // The internal options are for my use on the command line during dev
77    //
78    public static boolean internalOption_PrintGrammarTree = false;
79    public static boolean internalOption_PrintDFA = false;
80    public static boolean internalOption_ShowNFAConfigsInDFA = false;
81    public static boolean internalOption_watchNFAConversion = false;
82
83    /**
84     * A list of dependency generators that are accumulated aaaas (and if) the
85     * tool is required to sort the provided grammars into build dependency order.
86    protected Map<String, BuildDependencyGenerator> buildDependencyGenerators;
87     */
88
89    public static void main(String[] args) {
90        Tool antlr = new Tool(args);
91
92        if (!exitNow) {
93            antlr.process();
94			if ( return_dont_exit ) return;
95            if (ErrorManager.getNumErrors() > 0) {
96                System.exit(1);
97            }
98            System.exit(0);
99        }
100    }
101
102    /**
103     * Load the properties file org/antlr/antlr.properties and populate any
104     * variables that must be initialized from it, such as the version of ANTLR.
105     */
106    private void loadResources() {
107        InputStream in = null;
108        in = this.getClass().getResourceAsStream("antlr.properties");
109
110        // If we found the resource, then load it, otherwise revert to the
111        // defaults.
112        //
113        if (in != null) {
114            try {
115                // Load the resources into the map
116                //
117                antlrSettings.load(in);
118
119                // Set any variables that we need to populate from the resources
120                //
121//                VERSION = antlrSettings.getProperty("antlr.version");
122            } catch (Exception e) {
123                // Do nothing, just leave the defaults in place
124            }
125        }
126    }
127
128    public Tool() {
129        loadResources();
130    }
131
132    public Tool(String[] args) {
133        loadResources();
134
135        // Set all the options and pick up all the named grammar files
136        processArgs(args);
137    }
138
139    public void processArgs(String[] args) {
140
141        if (isVerbose()) {
142            ErrorManager.info("ANTLR Parser Generator  Version " + VERSION);
143            showBanner = false;
144        }
145
146        if (args == null || args.length == 0) {
147            help();
148            return;
149        }
150        for (int i = 0; i < args.length; i++) {
151            if (args[i].equals("-o") || args[i].equals("-fo")) {
152                if (i + 1 >= args.length) {
153                    System.err.println("missing output directory with -fo/-o option; ignoring");
154                }
155                else {
156                    if (args[i].equals("-fo")) { // force output into dir
157                        setForceAllFilesToOutputDir(true);
158                    }
159                    i++;
160                    outputDirectory = args[i];
161                    if (outputDirectory.endsWith("/") ||
162                        outputDirectory.endsWith("\\")) {
163                        outputDirectory =
164                            outputDirectory.substring(0, getOutputDirectory().length() - 1);
165                    }
166                    File outDir = new File(outputDirectory);
167                    haveOutputDir = true;
168                    if (outDir.exists() && !outDir.isDirectory()) {
169                        ErrorManager.error(ErrorManager.MSG_OUTPUT_DIR_IS_FILE, outputDirectory);
170                        setLibDirectory(".");
171                    }
172                }
173            }
174			else if (args[i].equals("-lib")) {
175				if (i + 1 >= args.length) {
176					System.err.println("missing library directory with -lib option; ignoring");
177				}
178				else {
179					i++;
180					setLibDirectory(args[i]);
181					if (getLibraryDirectory().endsWith("/") ||
182						getLibraryDirectory().endsWith("\\")) {
183						setLibDirectory(getLibraryDirectory().substring(0, getLibraryDirectory().length() - 1));
184					}
185					File outDir = new File(getLibraryDirectory());
186					if (!outDir.exists()) {
187						ErrorManager.error(ErrorManager.MSG_DIR_NOT_FOUND, getLibraryDirectory());
188						setLibDirectory(".");
189					}
190				}
191			}
192			else if (args[i].equals("-language")) {
193				if (i + 1 >= args.length) {
194					System.err.println("missing language name; ignoring");
195				}
196				else {
197					i++;
198					forcedLanguageOption = args[i];
199				}
200			}
201            else if (args[i].equals("-nfa")) {
202                setGenerate_NFA_dot(true);
203            }
204            else if (args[i].equals("-dfa")) {
205                setGenerate_DFA_dot(true);
206            }
207            else if (args[i].equals("-debug")) {
208                setDebug(true);
209            }
210            else if (args[i].equals("-trace")) {
211                setTrace(true);
212            }
213            else if (args[i].equals("-report")) {
214                setReport(true);
215            }
216            else if (args[i].equals("-profile")) {
217                setProfile(true);
218            }
219            else if (args[i].equals("-print")) {
220                setPrintGrammar(true);
221            }
222            else if (args[i].equals("-depend")) {
223                setDepend(true);
224            }
225            else if (args[i].equals("-verbose")) {
226                setVerbose(true);
227            }
228            else if (args[i].equals("-version")) {
229                version();
230                exitNow = true;
231            }
232            else if (args[i].equals("-make")) {
233                setMake(true);
234            }
235            else if (args[i].equals("-message-format")) {
236                if (i + 1 >= args.length) {
237                    System.err.println("missing output format with -message-format option; using default");
238                }
239                else {
240                    i++;
241                    ErrorManager.setFormat(args[i]);
242                }
243            }
244            else if (args[i].equals("-Xgrtree")) {
245                internalOption_PrintGrammarTree = true; // print grammar tree
246            }
247            else if (args[i].equals("-Xdfa")) {
248                internalOption_PrintDFA = true;
249            }
250            else if (args[i].equals("-Xnoprune")) {
251                DFAOptimizer.PRUNE_EBNF_EXIT_BRANCHES = false;
252            }
253            else if (args[i].equals("-Xnocollapse")) {
254                DFAOptimizer.COLLAPSE_ALL_PARALLEL_EDGES = false;
255            }
256            else if (args[i].equals("-Xdbgconversion")) {
257                NFAToDFAConverter.debug = true;
258            }
259            else if (args[i].equals("-Xmultithreaded")) {
260                NFAToDFAConverter.SINGLE_THREADED_NFA_CONVERSION = false;
261            }
262            else if (args[i].equals("-Xnomergestopstates")) {
263                DFAOptimizer.MERGE_STOP_STATES = false;
264            }
265            else if (args[i].equals("-Xdfaverbose")) {
266                internalOption_ShowNFAConfigsInDFA = true;
267            }
268            else if (args[i].equals("-Xwatchconversion")) {
269                internalOption_watchNFAConversion = true;
270            }
271            else if (args[i].equals("-XdbgST")) {
272                CodeGenerator.LAUNCH_ST_INSPECTOR = true;
273				STGroup.trackCreationEvents = true;
274				return_dont_exit = true;
275            }
276            else if (args[i].equals("-Xmaxinlinedfastates")) {
277                if (i + 1 >= args.length) {
278                    System.err.println("missing max inline dfa states -Xmaxinlinedfastates option; ignoring");
279                }
280                else {
281                    i++;
282                    CodeGenerator.MAX_ACYCLIC_DFA_STATES_INLINE = Integer.parseInt(args[i]);
283                }
284            }
285            else if (args[i].equals("-Xmaxswitchcaselabels")) {
286                if (i + 1 >= args.length) {
287                    System.err.println("missing max switch case labels -Xmaxswitchcaselabels option; ignoring");
288                }
289                else {
290                    i++;
291                    CodeGenerator.MAX_SWITCH_CASE_LABELS = Integer.parseInt(args[i]);
292                }
293            }
294            else if (args[i].equals("-Xminswitchalts")) {
295                if (i + 1 >= args.length) {
296                    System.err.println("missing min switch alternatives -Xminswitchalts option; ignoring");
297                }
298                else {
299                    i++;
300                    CodeGenerator.MIN_SWITCH_ALTS = Integer.parseInt(args[i]);
301                }
302            }
303            else if (args[i].equals("-Xm")) {
304                if (i + 1 >= args.length) {
305                    System.err.println("missing max recursion with -Xm option; ignoring");
306                }
307                else {
308                    i++;
309                    NFAContext.MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK = Integer.parseInt(args[i]);
310                }
311            }
312            else if (args[i].equals("-Xmaxdfaedges")) {
313                if (i + 1 >= args.length) {
314                    System.err.println("missing max number of edges with -Xmaxdfaedges option; ignoring");
315                }
316                else {
317                    i++;
318                    DFA.MAX_STATE_TRANSITIONS_FOR_TABLE = Integer.parseInt(args[i]);
319                }
320            }
321            else if (args[i].equals("-Xconversiontimeout")) {
322                if (i + 1 >= args.length) {
323                    System.err.println("missing max time in ms -Xconversiontimeout option; ignoring");
324                }
325                else {
326                    i++;
327                    DFA.MAX_TIME_PER_DFA_CREATION = Integer.parseInt(args[i]);
328                }
329            }
330			else if (args[i].equals("-Xnfastates")) {
331				DecisionProbe.verbose = true;
332			}
333			else if (args[i].equals("-Xsavelexer")) {
334				deleteTempLexer = false;
335			}
336            else if (args[i].equals("-X")) {
337                Xhelp();
338            }
339            else {
340                if (args[i].charAt(0) != '-') {
341                    // Must be the grammar file
342                    addGrammarFile(args[i]);
343                }
344            }
345        }
346    }
347
348    /*
349    protected void checkForInvalidArguments(String[] args, BitSet cmdLineArgValid) {
350    // check for invalid command line args
351    for (int a = 0; a < args.length; a++) {
352    if (!cmdLineArgValid.member(a)) {
353    System.err.println("invalid command-line argument: " + args[a] + "; ignored");
354    }
355    }
356    }
357     */
358
359    /**
360     * Checks to see if the list of outputFiles all exist, and have
361     * last-modified timestamps which are later than the last-modified
362     * timestamp of all the grammar files involved in build the output
363     * (imports must be checked). If these conditions hold, the method
364     * returns false, otherwise, it returns true.
365     *
366     * @param grammarFileName The grammar file we are checking
367     */
368    public boolean buildRequired(String grammarFileName)
369        throws IOException
370    {
371        BuildDependencyGenerator bd =
372            new BuildDependencyGenerator(this, grammarFileName);
373
374        List<File> outputFiles = bd.getGeneratedFileList();
375        List<File> inputFiles = bd.getDependenciesFileList();
376        // Note that input directory must be set to use buildRequired
377        File grammarFile;
378        if (haveInputDir) {
379            grammarFile = new File(inputDirectory, grammarFileName);
380        }
381        else {
382            grammarFile = new File(grammarFileName);
383        }
384        long grammarLastModified = grammarFile.lastModified();
385        for (File outputFile : outputFiles) {
386            if (!outputFile.exists() || grammarLastModified > outputFile.lastModified()) {
387                // One of the output files does not exist or is out of date, so we must build it
388                return true;
389            }
390            // Check all of the imported grammars and see if any of these are younger
391            // than any of the output files.
392            if (inputFiles != null) {
393                for (File inputFile : inputFiles) {
394
395                    if (inputFile.lastModified() > outputFile.lastModified()) {
396                        // One of the imported grammar files has been updated so we must build
397                        return true;
398                    }
399                }
400            }
401        }
402        if (isVerbose()) {
403            System.out.println("Grammar " + grammarFile + " is up to date - build skipped");
404        }
405        return false;
406    }
407
408    public void process() {
409        boolean exceptionWhenWritingLexerFile = false;
410        String lexerGrammarFileName = null;		// necessary at this scope to have access in the catch below
411
412        // Have to be tricky here when Maven or build tools call in and must new Tool()
413        // before setting options. The banner won't display that way!
414        if (isVerbose() && showBanner) {
415            ErrorManager.info("ANTLR Parser Generator  Version " + VERSION);
416            showBanner = false;
417        }
418
419        try {
420            sortGrammarFiles(); // update grammarFileNames
421        }
422        catch (Exception e) {
423            ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR,e);
424        }
425        catch (Error e) {
426            ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR, e);
427        }
428
429        for (String grammarFileName : grammarFileNames) {
430            // If we are in make mode (to support build tools like Maven) and the
431            // file is already up to date, then we do not build it (and in verbose mode
432            // we will say so).
433            if (make) {
434                try {
435                    if ( !buildRequired(grammarFileName) ) continue;
436                }
437                catch (Exception e) {
438                    ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR,e);
439                }
440            }
441
442            if (isVerbose() && !isDepend()) {
443                System.out.println(grammarFileName);
444            }
445            try {
446                if (isDepend()) {
447                    BuildDependencyGenerator dep =
448                        new BuildDependencyGenerator(this, grammarFileName);
449                    /*
450                    List outputFiles = dep.getGeneratedFileList();
451                    List dependents = dep.getDependenciesFileList();
452                    System.out.println("output: "+outputFiles);
453                    System.out.println("dependents: "+dependents);
454                     */
455                    System.out.println(dep.getDependencies().render());
456                    continue;
457                }
458
459                Grammar rootGrammar = getRootGrammar(grammarFileName);
460                // we now have all grammars read in as ASTs
461                // (i.e., root and all delegates)
462				rootGrammar.composite.assignTokenTypes();
463				//rootGrammar.composite.translateLeftRecursiveRules();
464				rootGrammar.addRulesForSyntacticPredicates();
465				rootGrammar.composite.defineGrammarSymbols();
466                rootGrammar.composite.createNFAs();
467
468                generateRecognizer(rootGrammar);
469
470                if (isPrintGrammar()) {
471                    rootGrammar.printGrammar(System.out);
472                }
473
474                if (isReport()) {
475					GrammarReport2 greport = new GrammarReport2(rootGrammar);
476					System.out.print(greport.toString());
477//                    GrammarReport greport = new GrammarReport(rootGrammar);
478//                    System.out.println(greport.toString());
479//                    // print out a backtracking report too (that is not encoded into log)
480//                    System.out.println(greport.getBacktrackingReport());
481                }
482                if (isProfile()) {
483                    GrammarReport greport = new GrammarReport(rootGrammar);
484                    Stats.writeReport(GrammarReport.GRAMMAR_STATS_FILENAME,
485                                      greport.toNotifyString());
486                }
487
488                // now handle the lexer if one was created for a merged spec
489                String lexerGrammarStr = rootGrammar.getLexerGrammar();
490                //System.out.println("lexer rootGrammar:\n"+lexerGrammarStr);
491                if (rootGrammar.type == Grammar.COMBINED && lexerGrammarStr != null) {
492                    lexerGrammarFileName = rootGrammar.getImplicitlyGeneratedLexerFileName();
493                    try {
494                        Writer w = getOutputFile(rootGrammar, lexerGrammarFileName);
495                        w.write(lexerGrammarStr);
496                        w.close();
497                    }
498                    catch (IOException e) {
499                        // emit different error message when creating the implicit lexer fails
500                        // due to write permission error
501                        exceptionWhenWritingLexerFile = true;
502                        throw e;
503                    }
504                    try {
505                        StringReader sr = new StringReader(lexerGrammarStr);
506                        Grammar lexerGrammar = new Grammar(this);
507                        lexerGrammar.composite.watchNFAConversion = internalOption_watchNFAConversion;
508                        lexerGrammar.implicitLexer = true;
509                        //lexerGrammar.setTool(this);
510                        File lexerGrammarFullFile =
511                            new File(getFileDirectory(lexerGrammarFileName), lexerGrammarFileName);
512                        lexerGrammar.setFileName(lexerGrammarFullFile.toString());
513
514                        lexerGrammar.importTokenVocabulary(rootGrammar);
515                        lexerGrammar.parseAndBuildAST(sr);
516
517                        sr.close();
518
519                        lexerGrammar.composite.assignTokenTypes();
520						lexerGrammar.addRulesForSyntacticPredicates();
521                        lexerGrammar.composite.defineGrammarSymbols();
522                        lexerGrammar.composite.createNFAs();
523
524                        generateRecognizer(lexerGrammar);
525                    }
526                    finally {
527                        // make sure we clean up
528                        if (deleteTempLexer) {
529                            File outputDir = getOutputDirectory(lexerGrammarFileName);
530                            File outputFile = new File(outputDir, lexerGrammarFileName);
531                            outputFile.delete();
532                        }
533                    }
534                }
535            }
536            catch (IOException e) {
537                if (exceptionWhenWritingLexerFile) {
538                    ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, e);
539                }
540                else {
541                    ErrorManager.error(ErrorManager.MSG_CANNOT_OPEN_FILE,
542                                       grammarFileName);
543                }
544            }
545            catch (Exception e) {
546                ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR, grammarFileName, e);
547            }
548            /*
549           finally {
550           System.out.println("creates="+ Interval.creates);
551           System.out.println("hits="+ Interval.hits);
552           System.out.println("misses="+ Interval.misses);
553           System.out.println("outOfRange="+ Interval.outOfRange);
554           }
555            */
556        }
557    }
558
559    public void sortGrammarFiles() throws IOException {
560        //System.out.println("Grammar names "+getGrammarFileNames());
561        Graph g = new Graph();
562        List<String> missingFiles = new ArrayList<String>();
563        for (String gfile : grammarFileNames) {
564            try {
565                GrammarSpelunker grammar = new GrammarSpelunker(inputDirectory, gfile);
566                grammar.parse();
567                String vocabName = grammar.getTokenVocab();
568                String grammarName = grammar.getGrammarName();
569                // Make all grammars depend on any tokenVocab options
570                if ( vocabName!=null ) g.addEdge(gfile, vocabName+CodeGenerator.VOCAB_FILE_EXTENSION);
571                // Make all generated tokens files depend on their grammars
572                g.addEdge(grammarName+CodeGenerator.VOCAB_FILE_EXTENSION, gfile);
573            }
574            catch (FileNotFoundException fnfe) {
575                ErrorManager.error(ErrorManager.MSG_CANNOT_OPEN_FILE, gfile);
576                missingFiles.add(gfile);
577            }
578        }
579        List<Object> sorted = g.sort();
580        //System.out.println("sorted="+sorted);
581        grammarFileNames.clear(); // wipe so we can give new ordered list
582        for (int i = 0; i < sorted.size(); i++) {
583            String f = (String)sorted.get(i);
584            if ( missingFiles.contains(f) ) continue;
585            if ( !(f.endsWith(".g") || f.endsWith(".g3")) ) continue;
586            grammarFileNames.add(f);
587        }
588        //System.out.println("new grammars="+grammarFileNames);
589    }
590
591    /** Get a grammar mentioned on the command-line and any delegates */
592    public Grammar getRootGrammar(String grammarFileName)
593        throws IOException
594    {
595        //ST.setLintMode(true);
596        // grammars mentioned on command line are either roots or single grammars.
597        // create the necessary composite in case it's got delegates; even
598        // single grammar needs it to get token types.
599        CompositeGrammar composite = new CompositeGrammar();
600        Grammar grammar = new Grammar(this, grammarFileName, composite);
601        composite.setDelegationRoot(grammar);
602        FileReader fr = null;
603        File f = null;
604
605        if (haveInputDir) {
606            f = new File(inputDirectory, grammarFileName);
607        }
608        else {
609            f = new File(grammarFileName);
610        }
611
612        // Store the location of this grammar as if we import files, we can then
613        // search for imports in the same location as the original grammar as well as in
614        // the lib directory.
615        //
616        parentGrammarDirectory = f.getParent();
617
618        if (grammarFileName.lastIndexOf(File.separatorChar) == -1) {
619            grammarOutputDirectory = ".";
620        }
621        else {
622            grammarOutputDirectory = grammarFileName.substring(0, grammarFileName.lastIndexOf(File.separatorChar));
623        }
624        fr = new FileReader(f);
625        BufferedReader br = new BufferedReader(fr);
626        grammar.parseAndBuildAST(br);
627        composite.watchNFAConversion = internalOption_watchNFAConversion;
628        br.close();
629        fr.close();
630        return grammar;
631    }
632
633    /** Create NFA, DFA and generate code for grammar.
634     *  Create NFA for any delegates first.  Once all NFA are created,
635     *  it's ok to create DFA, which must check for left-recursion.  That check
636     *  is done by walking the full NFA, which therefore must be complete.
637     *  After all NFA, comes DFA conversion for root grammar then code gen for
638     *  root grammar.  DFA and code gen for delegates comes next.
639     */
640    protected void generateRecognizer(Grammar grammar) {
641        String language = (String) grammar.getOption("language");
642        if (language != null) {
643            CodeGenerator generator = new CodeGenerator(this, grammar, language);
644            grammar.setCodeGenerator(generator);
645            generator.setDebug(isDebug());
646            generator.setProfile(isProfile());
647            generator.setTrace(isTrace());
648
649            // generate NFA early in case of crash later (for debugging)
650            if (isGenerate_NFA_dot()) {
651                generateNFAs(grammar);
652            }
653
654            // GENERATE CODE
655            generator.genRecognizer();
656
657            if (isGenerate_DFA_dot()) {
658                generateDFAs(grammar);
659            }
660
661            List<Grammar> delegates = grammar.getDirectDelegates();
662            for (int i = 0; delegates != null && i < delegates.size(); i++) {
663                Grammar delegate = (Grammar) delegates.get(i);
664                if (delegate != grammar) { // already processing this one
665                    generateRecognizer(delegate);
666                }
667            }
668        }
669    }
670
671    public void generateDFAs(Grammar g) {
672        for (int d = 1; d <= g.getNumberOfDecisions(); d++) {
673            DFA dfa = g.getLookaheadDFA(d);
674            if (dfa == null) {
675                continue; // not there for some reason, ignore
676            }
677            DOTGenerator dotGenerator = new DOTGenerator(g);
678            String dot = dotGenerator.getDOT(dfa.startState);
679            String dotFileName = g.name + "." + "dec-" + d;
680            if (g.implicitLexer) {
681                dotFileName = g.name + Grammar.grammarTypeToFileNameSuffix[g.type] + "." + "dec-" + d;
682            }
683            try {
684                writeDOTFile(g, dotFileName, dot);
685            } catch (IOException ioe) {
686                ErrorManager.error(ErrorManager.MSG_CANNOT_GEN_DOT_FILE,
687                                   dotFileName,
688                                   ioe);
689            }
690        }
691    }
692
693    protected void generateNFAs(Grammar g) {
694        DOTGenerator dotGenerator = new DOTGenerator(g);
695        Collection rules = g.getAllImportedRules();
696        rules.addAll(g.getRules());
697
698        for (Iterator itr = rules.iterator(); itr.hasNext();) {
699            Rule r = (Rule) itr.next();
700            try {
701                String dot = dotGenerator.getDOT(r.startState);
702                if (dot != null) {
703                    writeDOTFile(g, r, dot);
704                }
705            } catch (IOException ioe) {
706                ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, ioe);
707            }
708        }
709    }
710
711    protected void writeDOTFile(Grammar g, Rule r, String dot) throws IOException {
712        writeDOTFile(g, r.grammar.name + "." + r.name, dot);
713    }
714
715    protected void writeDOTFile(Grammar g, String name, String dot) throws IOException {
716        Writer fw = getOutputFile(g, name + ".dot");
717        fw.write(dot);
718        fw.close();
719    }
720
721    private static void version() {
722        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
723    }
724
725    private static void help() {
726        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
727        System.err.println("usage: java org.antlr.Tool [args] file.g [file2.g file3.g ...]");
728        System.err.println("  -o outputDir          specify output directory where all output is generated");
729        System.err.println("  -fo outputDir         same as -o but force even files with relative paths to dir");
730        System.err.println("  -lib dir              specify location of token files");
731        System.err.println("  -depend               generate file dependencies");
732        System.err.println("  -report               print out a report about the grammar(s) processed");
733        System.err.println("  -print                print out the grammar without actions");
734        System.err.println("  -debug                generate a parser that emits debugging events");
735		System.err.println("  -profile              generate a parser that computes profiling information");
736		System.err.println("  -trace                generate a recognizer that traces rule entry/exit");
737        System.err.println("  -nfa                  generate an NFA for each rule");
738        System.err.println("  -dfa                  generate a DFA for each decision point");
739        System.err.println("  -message-format name  specify output style for messages");
740        System.err.println("  -verbose              generate ANTLR version and other information");
741        System.err.println("  -make                 only build if generated files older than grammar");
742		System.err.println("  -version              print the version of ANTLR and exit.");
743		System.err.println("  -language L           override language grammar option; generate L");
744        System.err.println("  -X                    display extended argument list");
745    }
746
747    private static void Xhelp() {
748        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
749        System.err.println("  -Xgrtree                print the grammar AST");
750        System.err.println("  -Xdfa                   print DFA as text ");
751        System.err.println("  -Xnoprune               test lookahead against EBNF block exit branches");
752        System.err.println("  -Xnocollapse            collapse incident edges into DFA states");
753		System.err.println("  -Xdbgconversion         dump lots of info during NFA conversion");
754		System.err.println("  -Xconversiontimeout     use to restrict NFA conversion exponentiality");
755        System.err.println("  -Xmultithreaded         run the analysis in 2 threads");
756        System.err.println("  -Xnomergestopstates     do not merge stop states");
757        System.err.println("  -Xdfaverbose            generate DFA states in DOT with NFA configs");
758        System.err.println("  -Xwatchconversion       print a message for each NFA before converting");
759        System.err.println("  -XdbgST                 put tags at start/stop of all templates in output");
760        System.err.println("  -Xnfastates             for nondeterminisms, list NFA states for each path");
761        System.err.println("  -Xm m                   max number of rule invocations during conversion           [" + NFAContext.MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK + "]");
762        System.err.println("  -Xmaxdfaedges m         max \"comfortable\" number of edges for single DFA state     [" + DFA.MAX_STATE_TRANSITIONS_FOR_TABLE + "]");
763        System.err.println("  -Xmaxinlinedfastates m  max DFA states before table used rather than inlining      [" + CodeGenerator.MADSI_DEFAULT +"]");
764        System.err.println("  -Xmaxswitchcaselabels m don't generate switch() statements for dfas bigger  than m [" + CodeGenerator.MSCL_DEFAULT +"]");
765		System.err.println("  -Xminswitchalts m       don't generate switch() statements for dfas smaller than m [" + CodeGenerator.MSA_DEFAULT + "]");
766		System.err.println("  -Xsavelexer             don't delete temporary lexers generated from combined grammars");
767    }
768
769    /**
770     * Set the threshold of case labels beyond which ANTLR will not instruct the target template
771     * to generate switch() { case xxx: ...
772     *
773     * @param maxSwitchCaseLabels Maximum number of case lables that ANTLR should allow the target code
774     */
775    public void setMaxSwitchCaseLabels(int maxSwitchCaseLabels) {
776        CodeGenerator.MAX_SWITCH_CASE_LABELS = maxSwitchCaseLabels;
777    }
778
779    /**
780     * Set the threshold of the number alts, below which ANTLR will not instruct the target
781     * template to use a switch statement.
782     *
783     * @param minSwitchAlts the minimum number of alts required to use a switch staement
784     */
785    public void setMinSwitchAlts(int minSwitchAlts) {
786        CodeGenerator.MIN_SWITCH_ALTS = minSwitchAlts;
787    }
788
789    /**
790     * Set the location (base directory) where output files should be produced
791     * by the ANTLR tool.
792     * @param outputDirectory
793     */
794    public void setOutputDirectory(String outputDirectory) {
795        haveOutputDir = true;
796        this.outputDirectory = outputDirectory;
797    }
798
799    /**
800     * Used by build tools to force the output files to always be
801     * relative to the base output directory, even though the tool
802     * had to set the output directory to an absolute path as it
803     * cannot rely on the workign directory like command line invocation
804     * can.
805     *
806     * @param forceRelativeOutput true if output files hould always be relative to base output directory
807     */
808    public void setForceRelativeOutput(boolean forceRelativeOutput) {
809        this.forceRelativeOutput = forceRelativeOutput;
810    }
811
812    /**
813     * Set the base location of input files. Normally (when the tool is
814     * invoked from the command line), the inputDirectory is not set, but
815     * for build tools such as Maven, we need to be able to locate the input
816     * files relative to the base, as the working directory could be anywhere and
817     * changing workig directories is not a valid concept for JVMs because of threading and
818     * so on. Setting the directory just means that the getFileDirectory() method will
819     * try to open files relative to this input directory.
820     *
821     * @param inputDirectory Input source base directory
822     */
823    public void setInputDirectory(String inputDirectory) {
824        this.inputDirectory = inputDirectory;
825        haveInputDir = true;
826    }
827
828    /** This method is used by all code generators to create new output
829     *  files. If the outputDir set by -o is not present it will be created.
830     *  The final filename is sensitive to the output directory and
831     *  the directory where the grammar file was found.  If -o is /tmp
832     *  and the original grammar file was foo/t.g then output files
833     *  go in /tmp/foo.
834     *
835     *  The output dir -o spec takes precedence if it's absolute.
836     *  E.g., if the grammar file dir is absolute the output dir is given
837     *  precendence. "-o /tmp /usr/lib/t.g" results in "/tmp/T.java" as
838     *  output (assuming t.g holds T.java).
839     *
840     *  If no -o is specified, then just write to the directory where the
841     *  grammar file was found.
842     *
843     *  If outputDirectory==null then write a String.
844     */
845    public Writer getOutputFile(Grammar g, String fileName) throws IOException {
846        if (getOutputDirectory() == null) {
847            return new StringWriter();
848        }
849        // output directory is a function of where the grammar file lives
850        // for subdir/T.g, you get subdir here.  Well, depends on -o etc...
851        // But, if this is a .tokens file, then we force the output to
852        // be the base output directory (or current directory if there is not a -o)
853        //
854        File outputDir;
855        if (fileName.endsWith(CodeGenerator.VOCAB_FILE_EXTENSION)) {
856            if (haveOutputDir) {
857                outputDir = new File(getOutputDirectory());
858            }
859            else {
860                outputDir = new File(".");
861            }
862        }
863        else {
864            outputDir = getOutputDirectory(g.getFileName());
865        }
866        File outputFile = new File(outputDir, fileName);
867
868        if (!outputDir.exists()) {
869            outputDir.mkdirs();
870        }
871        FileWriter fw = new FileWriter(outputFile);
872        return new BufferedWriter(fw);
873    }
874
875    /**
876     * Return the location where ANTLR will generate output files for a given file. This is a
877     * base directory and output files will be relative to here in some cases
878     * such as when -o option is used and input files are given relative
879     * to the input directory.
880     *
881     * @param fileNameWithPath path to input source
882     * @return
883     */
884    public File getOutputDirectory(String fileNameWithPath) {
885
886        File outputDir = new File(getOutputDirectory());
887        String fileDirectory;
888
889        // Some files are given to us without a PATH but should should
890        // still be written to the output directory in the relative path of
891        // the output directory. The file directory is either the set of sub directories
892        // or just or the relative path recorded for the parent grammar. This means
893        // that when we write the tokens files, or the .java files for imported grammars
894        // taht we will write them in the correct place.
895        //
896        if (fileNameWithPath.lastIndexOf(File.separatorChar) == -1) {
897
898            // No path is included in the file name, so make the file
899            // directory the same as the parent grammar (which might sitll be just ""
900            // but when it is not, we will write the file in the correct place.
901            //
902            fileDirectory = grammarOutputDirectory;
903
904        }
905        else {
906            fileDirectory = fileNameWithPath.substring(0, fileNameWithPath.lastIndexOf(File.separatorChar));
907        }
908        if (haveOutputDir) {
909            // -o /tmp /var/lib/t.g => /tmp/T.java
910            // -o subdir/output /usr/lib/t.g => subdir/output/T.java
911            // -o . /usr/lib/t.g => ./T.java
912            if ((fileDirectory != null && !forceRelativeOutput) &&
913                (new File(fileDirectory).isAbsolute() ||
914                 fileDirectory.startsWith("~")) || // isAbsolute doesn't count this :(
915                isForceAllFilesToOutputDir()) {
916                // somebody set the dir, it takes precendence; write new file there
917                outputDir = new File(getOutputDirectory());
918            }
919            else {
920                // -o /tmp subdir/t.g => /tmp/subdir/t.g
921                if (fileDirectory != null) {
922                    outputDir = new File(getOutputDirectory(), fileDirectory);
923                }
924                else {
925                    outputDir = new File(getOutputDirectory());
926                }
927            }
928        }
929        else {
930            // they didn't specify a -o dir so just write to location
931            // where grammar is, absolute or relative, this will only happen
932            // with command line invocation as build tools will always
933            // supply an output directory.
934            //
935            outputDir = new File(fileDirectory);
936        }
937        return outputDir;
938    }
939
940    /**
941     * Name a file from the -lib dir.  Imported grammars and .tokens files
942     *
943     * If we do not locate the file in the library directory, then we try
944     * the location of the originating grammar.
945     *
946     * @param fileName input name we are looking for
947     * @return Path to file that we think shuold be the import file
948     *
949     * @throws java.io.IOException
950     */
951    public String getLibraryFile(String fileName) throws IOException {
952
953        // First, see if we can find the file in the library directory
954        //
955        File f = new File(getLibraryDirectory() + File.separator + fileName);
956
957        if (f.exists()) {
958
959            // Found in the library directory
960            //
961            return f.getAbsolutePath();
962        }
963
964        // Need to assume it is in the same location as the input file. Note that
965        // this is only relevant for external build tools and when the input grammar
966        // was specified relative to the source directory (working directory if using
967        // the command line.
968        //
969        return parentGrammarDirectory + File.separator + fileName;
970    }
971
972    /** Return the directory containing the grammar file for this grammar.
973     *  normally this is a relative path from current directory.  People will
974     *  often do "java org.antlr.Tool grammars/*.g3"  So the file will be
975     *  "grammars/foo.g3" etc...  This method returns "grammars".
976     *
977     *  If we have been given a specific input directory as a base, then
978     *  we must find the directory relative to this directory, unless the
979     *  file name is given to us in absolute terms.
980     */
981    public String getFileDirectory(String fileName) {
982
983        File f;
984        if (haveInputDir && !fileName.startsWith(File.separator)) {
985            f = new File(inputDirectory, fileName);
986        }
987        else {
988            f = new File(fileName);
989        }
990        // And ask Java what the base directory of this location is
991        //
992        return f.getParent();
993    }
994
995    /** Return a File descriptor for vocab file.  Look in library or
996     *  in -o output path.  antlr -o foo T.g U.g where U needs T.tokens
997     *  won't work unless we look in foo too. If we do not find the
998     *  file in the lib directory then must assume that the .tokens file
999     *  is going to be generated as part of this build and we have defined
1000     *  .tokens files so that they ALWAYS are generated in the base output
1001     *  directory, which means the current directory for the command line tool if there
1002     *  was no output directory specified.
1003     */
1004    public File getImportedVocabFile(String vocabName) {
1005
1006        File f = new File(getLibraryDirectory(),
1007                          File.separator +
1008                          vocabName +
1009                          CodeGenerator.VOCAB_FILE_EXTENSION);
1010        if (f.exists()) {
1011            return f;
1012        }
1013
1014        // We did not find the vocab file in the lib directory, so we need
1015        // to look for it in the output directory which is where .tokens
1016        // files are generated (in the base, not relative to the input
1017        // location.)
1018        //
1019        if (haveOutputDir) {
1020            f = new File(getOutputDirectory(), vocabName + CodeGenerator.VOCAB_FILE_EXTENSION);
1021        }
1022        else {
1023            f = new File(vocabName + CodeGenerator.VOCAB_FILE_EXTENSION);
1024        }
1025        return f;
1026    }
1027
1028    /** If the tool needs to panic/exit, how do we do that?
1029     */
1030    public void panic() {
1031        throw new Error("ANTLR panic");
1032    }
1033
1034    /** Return a time stamp string accurate to sec: yyyy-mm-dd hh:mm:ss
1035     */
1036    public static String getCurrentTimeStamp() {
1037        GregorianCalendar calendar = new java.util.GregorianCalendar();
1038        int y = calendar.get(Calendar.YEAR);
1039        int m = calendar.get(Calendar.MONTH) + 1; // zero-based for months
1040        int d = calendar.get(Calendar.DAY_OF_MONTH);
1041        int h = calendar.get(Calendar.HOUR_OF_DAY);
1042        int min = calendar.get(Calendar.MINUTE);
1043        int sec = calendar.get(Calendar.SECOND);
1044        String sy = String.valueOf(y);
1045        String sm = m < 10 ? "0" + m : String.valueOf(m);
1046        String sd = d < 10 ? "0" + d : String.valueOf(d);
1047        String sh = h < 10 ? "0" + h : String.valueOf(h);
1048        String smin = min < 10 ? "0" + min : String.valueOf(min);
1049        String ssec = sec < 10 ? "0" + sec : String.valueOf(sec);
1050        return new StringBuffer().append(sy).append("-").append(sm).append("-").append(sd).append(" ").append(sh).append(":").append(smin).append(":").append(ssec).toString();
1051    }
1052
1053    /**
1054     * Provide the List of all grammar file names that the ANTLR tool will
1055     * process or has processed.
1056     *
1057     * @return the grammarFileNames
1058     */
1059    public List<String> getGrammarFileNames() {
1060        return grammarFileNames;
1061    }
1062
1063    /**
1064     * Indicates whether ANTLR has gnerated or will generate a description of
1065     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
1066     *
1067     * @return the generate_NFA_dot
1068     */
1069    public boolean isGenerate_NFA_dot() {
1070        return generate_NFA_dot;
1071    }
1072
1073    /**
1074     * Indicates whether ANTLR has generated or will generate a description of
1075     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
1076     *
1077     * @return the generate_DFA_dot
1078     */
1079    public boolean isGenerate_DFA_dot() {
1080        return generate_DFA_dot;
1081    }
1082
1083    /**
1084     * Return the Path to the base output directory, where ANTLR
1085     * will generate all the output files for the current language target as
1086     * well as any ancillary files such as .tokens vocab files.
1087     *
1088     * @return the output Directory
1089     */
1090    public String getOutputDirectory() {
1091        return outputDirectory;
1092    }
1093
1094    /**
1095     * Return the Path to the directory in which ANTLR will search for ancillary
1096     * files such as .tokens vocab files and imported grammar files.
1097     *
1098     * @return the lib Directory
1099     */
1100    public String getLibraryDirectory() {
1101        return libDirectory;
1102    }
1103
1104    /**
1105     * Indicate if ANTLR has generated, or will generate a debug version of the
1106     * recognizer. Debug versions of a parser communicate with a debugger such
1107     * as that contained in ANTLRWorks and at start up will 'hang' waiting for
1108     * a connection on an IP port (49100 by default).
1109     *
1110     * @return the debug flag
1111     */
1112    public boolean isDebug() {
1113        return debug;
1114    }
1115
1116    /**
1117     * Indicate whether ANTLR has generated, or will generate a version of the
1118     * recognizer that prints trace messages on entry and exit of each rule.
1119     *
1120     * @return the trace flag
1121     */
1122    public boolean isTrace() {
1123        return trace;
1124    }
1125
1126    /**
1127     * Indicates whether ANTLR has generated or will generate a version of the
1128     * recognizer that gathers statistics about its execution, which it prints when
1129     * it terminates.
1130     *
1131     * @return the profile
1132     */
1133    public boolean isProfile() {
1134        return profile;
1135    }
1136
1137    /**
1138     * Indicates whether ANTLR has generated or will generate a report of various
1139     * elements of the grammar analysis, once it it has finished analyzing a grammar
1140     * file.
1141     *
1142     * @return the report flag
1143     */
1144    public boolean isReport() {
1145        return report;
1146    }
1147
1148    /**
1149     * Indicates whether ANTLR has printed, or will print, a version of the input grammar
1150     * file(s) that is stripped of any action code embedded within.
1151     *
1152     * @return the printGrammar flag
1153     */
1154    public boolean isPrintGrammar() {
1155        return printGrammar;
1156    }
1157
1158    /**
1159     * Indicates whether ANTLR has supplied, or will supply, a list of all the things
1160     * that the input grammar depends upon and all the things that will be generated
1161     * when that grammar is successfully analyzed.
1162     *
1163     * @return the depend flag
1164     */
1165    public boolean isDepend() {
1166        return depend;
1167    }
1168
1169    /**
1170     * Indicates whether ANTLR will force all files to the output directory, even
1171     * if the input files have relative paths from the input directory.
1172     *
1173     * @return the forceAllFilesToOutputDir flag
1174     */
1175    public boolean isForceAllFilesToOutputDir() {
1176        return forceAllFilesToOutputDir;
1177    }
1178
1179    /**
1180     * Indicates whether ANTLR will be verbose when analyzing grammar files, such as
1181     * displaying the names of the files it is generating and similar information.
1182     *
1183     * @return the verbose flag
1184     */
1185    public boolean isVerbose() {
1186        return verbose;
1187    }
1188
1189    /**
1190     * Provide the current setting of the conversion timeout on DFA creation.
1191     *
1192     * @return DFA creation timeout value in milliseconds
1193     */
1194    public int getConversionTimeout() {
1195        return DFA.MAX_TIME_PER_DFA_CREATION;
1196    }
1197
1198    /**
1199     * Returns the current setting of the message format descriptor
1200     * @return Current message format
1201     */
1202    public String getMessageFormat() {
1203        return ErrorManager.getMessageFormat().toString();
1204    }
1205
1206    /**
1207     * Returns the number of errors that the analysis/processing threw up.
1208     * @return Error count
1209     */
1210    public int getNumErrors() {
1211        return ErrorManager.getNumErrors();
1212    }
1213
1214    /**
1215     * Indicate whether the tool will analyze the dependencies of the provided grammar
1216     * file list and ensure that grammars with dependencies are built
1217     * after any of the other gramamrs in the list that they are dependent on. Setting
1218     * this option also has the side effect that any grammars that are includes for other
1219     * grammars in the list are excluded from individual analysis, which allows the caller
1220     * to invoke the tool via org.antlr.tool -make *.g and not worry about the inclusion
1221     * of grammars that are just includes for other grammars or what order the grammars
1222     * appear on the command line.
1223     *
1224     * This option was coded to make life easier for tool integration (such as Maven) but
1225     * may also be useful at the command line.
1226     *
1227     * @return true if the tool is currently configured to analyze and sort grammar files.
1228     */
1229    public boolean getMake() {
1230        return make;
1231    }
1232
1233    /**
1234     * Set the message format to one of ANTLR, gnu, vs2005
1235     *
1236     * @param format
1237     */
1238    public void setMessageFormat(String format) {
1239        ErrorManager.setFormat(format);
1240    }
1241
1242    /** Provide the List of all grammar file names that the ANTLR tool should process.
1243     *
1244     * @param grammarFileNames The list of grammar files to process
1245     */
1246    public void setGrammarFileNames(List<String> grammarFileNames) {
1247        this.grammarFileNames = grammarFileNames;
1248    }
1249
1250    public void addGrammarFile(String grammarFileName) {
1251        if (!grammarFileNames.contains(grammarFileName)) {
1252            grammarFileNames.add(grammarFileName);
1253        }
1254    }
1255
1256    /**
1257     * Indicate whether ANTLR should generate a description of
1258     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
1259     *
1260     * @param generate_NFA_dot True to generate dot descriptions
1261     */
1262    public void setGenerate_NFA_dot(boolean generate_NFA_dot) {
1263        this.generate_NFA_dot = generate_NFA_dot;
1264    }
1265
1266    /**
1267     * Indicates whether ANTLR should generate a description of
1268     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
1269     *
1270     * @param generate_DFA_dot True to generate dot descriptions
1271     */
1272    public void setGenerate_DFA_dot(boolean generate_DFA_dot) {
1273        this.generate_DFA_dot = generate_DFA_dot;
1274    }
1275
1276    /**
1277     * Set the Path to the directory in which ANTLR will search for ancillary
1278     * files such as .tokens vocab files and imported grammar files.
1279     *
1280     * @param libDirectory the libDirectory to set
1281     */
1282    public void setLibDirectory(String libDirectory) {
1283        this.libDirectory = libDirectory;
1284    }
1285
1286    /**
1287     * Indicate whether ANTLR should generate a debug version of the
1288     * recognizer. Debug versions of a parser communicate with a debugger such
1289     * as that contained in ANTLRWorks and at start up will 'hang' waiting for
1290     * a connection on an IP port (49100 by default).
1291     *
1292     * @param debug true to generate a debug mode parser
1293     */
1294    public void setDebug(boolean debug) {
1295        this.debug = debug;
1296    }
1297
1298    /**
1299     * Indicate whether ANTLR should generate a version of the
1300     * recognizer that prints trace messages on entry and exit of each rule
1301     *
1302     * @param trace true to generate a tracing parser
1303     */
1304    public void setTrace(boolean trace) {
1305        this.trace = trace;
1306    }
1307
1308    /**
1309     * Indicate whether ANTLR should generate a version of the
1310     * recognizer that gathers statistics about its execution, which it prints when
1311     * it terminates.
1312     *
1313     * @param profile true to generate a profiling parser
1314     */
1315    public void setProfile(boolean profile) {
1316        this.profile = profile;
1317    }
1318
1319    /**
1320     * Indicate whether ANTLR should generate a report of various
1321     * elements of the grammar analysis, once it it has finished analyzing a grammar
1322     * file.
1323     *
1324     * @param report true to generate the analysis report
1325     */
1326    public void setReport(boolean report) {
1327        this.report = report;
1328    }
1329
1330    /**
1331     * Indicate whether ANTLR should print a version of the input grammar
1332     * file(s) that is stripped of any action code embedded within.
1333     *
1334     * @param printGrammar true to generate a stripped file
1335     */
1336    public void setPrintGrammar(boolean printGrammar) {
1337        this.printGrammar = printGrammar;
1338    }
1339
1340    /**
1341     * Indicate whether ANTLR should supply a list of all the things
1342     * that the input grammar depends upon and all the things that will be generated
1343     * when that gramamr is successfully analyzed.
1344     *
1345     * @param depend true to get depends set rather than process the grammar
1346     */
1347    public void setDepend(boolean depend) {
1348        this.depend = depend;
1349    }
1350
1351    /**
1352     * Indicates whether ANTLR will force all files to the output directory, even
1353     * if the input files have relative paths from the input directory.
1354     *
1355     * @param forceAllFilesToOutputDir true to force files to output directory
1356     */
1357    public void setForceAllFilesToOutputDir(boolean forceAllFilesToOutputDir) {
1358        this.forceAllFilesToOutputDir = forceAllFilesToOutputDir;
1359    }
1360
1361    /**
1362     * Indicate whether ANTLR should be verbose when analyzing grammar files, such as
1363     * displaying the names of the files it is generating and similar information.
1364     *
1365     * @param verbose true to be verbose
1366     */
1367    public void setVerbose(boolean verbose) {
1368        this.verbose = verbose;
1369    }
1370
1371    /**
1372     * Indicate whether the tool should analyze the dependencies of the provided grammar
1373     * file list and ensure that the grammars with dependencies are built
1374     * after any of the other gramamrs in the list that they are dependent on. Setting
1375     * this option also has the side effect that any grammars that are includes for other
1376     * grammars in the list are excluded from individual analysis, which allows the caller
1377     * to invoke the tool via org.antlr.tool -make *.g and not worry about the inclusion
1378     * of grammars that are just includes for other grammars or what order the grammars
1379     * appear on the command line.
1380     *
1381     * This option was coded to make life easier for tool integration (such as Maven) but
1382     * may also be useful at the command line.
1383     *
1384     * @param make
1385     */
1386    public void setMake(boolean make) {
1387        this.make = make;
1388    }
1389
1390}
1391