aboutsummaryrefslogtreecommitdiff
path: root/antlr-3.4/tool/src/main/java/org/antlr/Tool.java
blob: b336baf90de9845b67c1c8586e61a5b7b907f9e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
/*
 * [The "BSD license"]
 *  Copyright (c) 2010 Terence Parr
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.antlr;

import org.antlr.analysis.*;
import org.antlr.codegen.CodeGenerator;
import org.antlr.misc.Graph;
import org.antlr.runtime.misc.Stats;
import org.antlr.tool.*;
import org.stringtemplate.v4.STGroup;

import java.io.*;
import java.util.*;

/** The main ANTLR entry point.  Read a grammar and generate a parser. */
public class Tool {

    public final Properties antlrSettings = new Properties();
    public String VERSION = "3.4";
    //public static final String VERSION = "${project.version}";
    public static final String UNINITIALIZED_DIR = "<unset-dir>";
    private List<String> grammarFileNames = new ArrayList<String>();
    private boolean generate_NFA_dot = false;
    private boolean generate_DFA_dot = false;
    private String outputDirectory = ".";
    private boolean haveOutputDir = false;
    private String inputDirectory = null;
    private String parentGrammarDirectory;
    private String grammarOutputDirectory;
    private boolean haveInputDir = false;
    private String libDirectory = ".";
    private boolean debug = false;
    private boolean trace = false;
    private boolean profile = false;
    private boolean report = false;
    private boolean printGrammar = false;
    private boolean depend = false;
    private boolean forceAllFilesToOutputDir = false;
    private boolean forceRelativeOutput = false;
    protected boolean deleteTempLexer = true;
    private boolean verbose = false;
    /** Don't process grammar file if generated files are newer than grammar */
    private boolean make = false;
    private boolean showBanner = true;
	private static boolean exitNow = false;
	private static boolean return_dont_exit = false;


	public String forcedLanguageOption; // -language L on command line

    // The internal options are for my use on the command line during dev
    //
    public static boolean internalOption_PrintGrammarTree = false;
    public static boolean internalOption_PrintDFA = false;
    public static boolean internalOption_ShowNFAConfigsInDFA = false;
    public static boolean internalOption_watchNFAConversion = false;

    /**
     * A list of dependency generators that are accumulated aaaas (and if) the
     * tool is required to sort the provided grammars into build dependency order.
    protected Map<String, BuildDependencyGenerator> buildDependencyGenerators;
     */

    public static void main(String[] args) {
        Tool antlr = new Tool(args);

        if (!exitNow) {
            antlr.process();
			if ( return_dont_exit ) return;
            if (ErrorManager.getNumErrors() > 0) {
                System.exit(1);
            }
            System.exit(0);
        }
    }

    /**
     * Load the properties file org/antlr/antlr.properties and populate any
     * variables that must be initialized from it, such as the version of ANTLR.
     */
    private void loadResources() {
        InputStream in = null;
        in = this.getClass().getResourceAsStream("antlr.properties");

        // If we found the resource, then load it, otherwise revert to the
        // defaults.
        //
        if (in != null) {
            try {
                // Load the resources into the map
                //
                antlrSettings.load(in);

                // Set any variables that we need to populate from the resources
                //
//                VERSION = antlrSettings.getProperty("antlr.version");
            } catch (Exception e) {
                // Do nothing, just leave the defaults in place
            }
        }
    }

    public Tool() {
        loadResources();
    }

    public Tool(String[] args) {
        loadResources();

        // Set all the options and pick up all the named grammar files
        processArgs(args);
    }

    public void processArgs(String[] args) {

        if (isVerbose()) {
            ErrorManager.info("ANTLR Parser Generator  Version " + VERSION);
            showBanner = false;
        }

        if (args == null || args.length == 0) {
            help();
            return;
        }
        for (int i = 0; i < args.length; i++) {
            if (args[i].equals("-o") || args[i].equals("-fo")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing output directory with -fo/-o option; ignoring");
                }
                else {
                    if (args[i].equals("-fo")) { // force output into dir
                        setForceAllFilesToOutputDir(true);
                    }
                    i++;
                    outputDirectory = args[i];
                    if (outputDirectory.endsWith("/") ||
                        outputDirectory.endsWith("\\")) {
                        outputDirectory =
                            outputDirectory.substring(0, getOutputDirectory().length() - 1);
                    }
                    File outDir = new File(outputDirectory);
                    haveOutputDir = true;
                    if (outDir.exists() && !outDir.isDirectory()) {
                        ErrorManager.error(ErrorManager.MSG_OUTPUT_DIR_IS_FILE, outputDirectory);
                        setLibDirectory(".");
                    }
                }
            }
			else if (args[i].equals("-lib")) {
				if (i + 1 >= args.length) {
					System.err.println("missing library directory with -lib option; ignoring");
				}
				else {
					i++;
					setLibDirectory(args[i]);
					if (getLibraryDirectory().endsWith("/") ||
						getLibraryDirectory().endsWith("\\")) {
						setLibDirectory(getLibraryDirectory().substring(0, getLibraryDirectory().length() - 1));
					}
					File outDir = new File(getLibraryDirectory());
					if (!outDir.exists()) {
						ErrorManager.error(ErrorManager.MSG_DIR_NOT_FOUND, getLibraryDirectory());
						setLibDirectory(".");
					}
				}
			}
			else if (args[i].equals("-language")) {
				if (i + 1 >= args.length) {
					System.err.println("missing language name; ignoring");
				}
				else {
					i++;
					forcedLanguageOption = args[i];
				}
			}
            else if (args[i].equals("-nfa")) {
                setGenerate_NFA_dot(true);
            }
            else if (args[i].equals("-dfa")) {
                setGenerate_DFA_dot(true);
            }
            else if (args[i].equals("-debug")) {
                setDebug(true);
            }
            else if (args[i].equals("-trace")) {
                setTrace(true);
            }
            else if (args[i].equals("-report")) {
                setReport(true);
            }
            else if (args[i].equals("-profile")) {
                setProfile(true);
            }
            else if (args[i].equals("-print")) {
                setPrintGrammar(true);
            }
            else if (args[i].equals("-depend")) {
                setDepend(true);
            }
            else if (args[i].equals("-verbose")) {
                setVerbose(true);
            }
            else if (args[i].equals("-version")) {
                version();
                exitNow = true;
            }
            else if (args[i].equals("-make")) {
                setMake(true);
            }
            else if (args[i].equals("-message-format")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing output format with -message-format option; using default");
                }
                else {
                    i++;
                    ErrorManager.setFormat(args[i]);
                }
            }
            else if (args[i].equals("-Xgrtree")) {
                internalOption_PrintGrammarTree = true; // print grammar tree
            }
            else if (args[i].equals("-Xdfa")) {
                internalOption_PrintDFA = true;
            }
            else if (args[i].equals("-Xnoprune")) {
                DFAOptimizer.PRUNE_EBNF_EXIT_BRANCHES = false;
            }
            else if (args[i].equals("-Xnocollapse")) {
                DFAOptimizer.COLLAPSE_ALL_PARALLEL_EDGES = false;
            }
            else if (args[i].equals("-Xdbgconversion")) {
                NFAToDFAConverter.debug = true;
            }
            else if (args[i].equals("-Xmultithreaded")) {
                NFAToDFAConverter.SINGLE_THREADED_NFA_CONVERSION = false;
            }
            else if (args[i].equals("-Xnomergestopstates")) {
                DFAOptimizer.MERGE_STOP_STATES = false;
            }
            else if (args[i].equals("-Xdfaverbose")) {
                internalOption_ShowNFAConfigsInDFA = true;
            }
            else if (args[i].equals("-Xwatchconversion")) {
                internalOption_watchNFAConversion = true;
            }
            else if (args[i].equals("-XdbgST")) {
                CodeGenerator.LAUNCH_ST_INSPECTOR = true;
				STGroup.trackCreationEvents = true;
				return_dont_exit = true;
            }
            else if (args[i].equals("-Xmaxinlinedfastates")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing max inline dfa states -Xmaxinlinedfastates option; ignoring");
                }
                else {
                    i++;
                    CodeGenerator.MAX_ACYCLIC_DFA_STATES_INLINE = Integer.parseInt(args[i]);
                }
            }
            else if (args[i].equals("-Xmaxswitchcaselabels")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing max switch case labels -Xmaxswitchcaselabels option; ignoring");
                }
                else {
                    i++;
                    CodeGenerator.MAX_SWITCH_CASE_LABELS = Integer.parseInt(args[i]);
                }
            }
            else if (args[i].equals("-Xminswitchalts")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing min switch alternatives -Xminswitchalts option; ignoring");
                }
                else {
                    i++;
                    CodeGenerator.MIN_SWITCH_ALTS = Integer.parseInt(args[i]);
                }
            }
            else if (args[i].equals("-Xm")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing max recursion with -Xm option; ignoring");
                }
                else {
                    i++;
                    NFAContext.MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK = Integer.parseInt(args[i]);
                }
            }
            else if (args[i].equals("-Xmaxdfaedges")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing max number of edges with -Xmaxdfaedges option; ignoring");
                }
                else {
                    i++;
                    DFA.MAX_STATE_TRANSITIONS_FOR_TABLE = Integer.parseInt(args[i]);
                }
            }
            else if (args[i].equals("-Xconversiontimeout")) {
                if (i + 1 >= args.length) {
                    System.err.println("missing max time in ms -Xconversiontimeout option; ignoring");
                }
                else {
                    i++;
                    DFA.MAX_TIME_PER_DFA_CREATION = Integer.parseInt(args[i]);
                }
            }
			else if (args[i].equals("-Xnfastates")) {
				DecisionProbe.verbose = true;
			}
			else if (args[i].equals("-Xsavelexer")) {
				deleteTempLexer = false;
			}
            else if (args[i].equals("-X")) {
                Xhelp();
            }
            else {
                if (args[i].charAt(0) != '-') {
                    // Must be the grammar file
                    addGrammarFile(args[i]);
                }
            }
        }
    }

    /*
    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)) {
    System.err.println("invalid command-line argument: " + args[a] + "; ignored");
    }
    }
    }
     */

    /**
     * Checks to see if the list of outputFiles all exist, and have
     * last-modified timestamps which are later than the last-modified
     * timestamp of all the grammar files involved in build the output
     * (imports must be checked). If these conditions hold, the method
     * returns false, otherwise, it returns true.
     *
     * @param grammarFileName The grammar file we are checking
     */
    public boolean buildRequired(String grammarFileName)
        throws IOException
    {
        BuildDependencyGenerator bd =
            new BuildDependencyGenerator(this, grammarFileName);

        List<File> outputFiles = bd.getGeneratedFileList();
        List<File> inputFiles = bd.getDependenciesFileList();
        // Note that input directory must be set to use buildRequired
        File grammarFile;
        if (haveInputDir) {
            grammarFile = new File(inputDirectory, grammarFileName);
        }
        else {
            grammarFile = new File(grammarFileName);
        }
        long grammarLastModified = grammarFile.lastModified();
        for (File outputFile : outputFiles) {
            if (!outputFile.exists() || grammarLastModified > outputFile.lastModified()) {
                // One of the output files does not exist or is out of date, so we must build it
                return true;
            }
            // Check all of the imported grammars and see if any of these are younger
            // than any of the output files.
            if (inputFiles != null) {
                for (File inputFile : inputFiles) {

                    if (inputFile.lastModified() > outputFile.lastModified()) {
                        // One of the imported grammar files has been updated so we must build
                        return true;
                    }
                }
            }
        }
        if (isVerbose()) {
            System.out.println("Grammar " + grammarFile + " is up to date - build skipped");
        }
        return false;
    }

    public void process() {
        boolean exceptionWhenWritingLexerFile = false;
        String lexerGrammarFileName = null;		// necessary at this scope to have access in the catch below

        // Have to be tricky here when Maven or build tools call in and must new Tool()
        // before setting options. The banner won't display that way!
        if (isVerbose() && showBanner) {
            ErrorManager.info("ANTLR Parser Generator  Version " + VERSION);
            showBanner = false;
        }

        try {
            sortGrammarFiles(); // update grammarFileNames
        }
        catch (Exception e) {
            ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR,e);
        }
        catch (Error e) {
            ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR, e);
        }

        for (String grammarFileName : grammarFileNames) {
            // If we are in make mode (to support build tools like Maven) and the
            // file is already up to date, then we do not build it (and in verbose mode
            // we will say so).
            if (make) {
                try {
                    if ( !buildRequired(grammarFileName) ) continue;
                }
                catch (Exception e) {
                    ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR,e);
                }
            }

            if (isVerbose() && !isDepend()) {
                System.out.println(grammarFileName);
            }
            try {
                if (isDepend()) {
                    BuildDependencyGenerator dep =
                        new BuildDependencyGenerator(this, grammarFileName);
                    /*
                    List outputFiles = dep.getGeneratedFileList();
                    List dependents = dep.getDependenciesFileList();
                    System.out.println("output: "+outputFiles);
                    System.out.println("dependents: "+dependents);
                     */
                    System.out.println(dep.getDependencies().render());
                    continue;
                }

                Grammar rootGrammar = getRootGrammar(grammarFileName);
                // we now have all grammars read in as ASTs
                // (i.e., root and all delegates)
				rootGrammar.composite.assignTokenTypes();
				//rootGrammar.composite.translateLeftRecursiveRules();
				rootGrammar.addRulesForSyntacticPredicates();
				rootGrammar.composite.defineGrammarSymbols();
                rootGrammar.composite.createNFAs();

                generateRecognizer(rootGrammar);

                if (isPrintGrammar()) {
                    rootGrammar.printGrammar(System.out);
                }

                if (isReport()) {
					GrammarReport2 greport = new GrammarReport2(rootGrammar);
					System.out.print(greport.toString());
//                    GrammarReport greport = new GrammarReport(rootGrammar);
//                    System.out.println(greport.toString());
//                    // print out a backtracking report too (that is not encoded into log)
//                    System.out.println(greport.getBacktrackingReport());
                }
                if (isProfile()) {
                    GrammarReport greport = new GrammarReport(rootGrammar);
                    Stats.writeReport(GrammarReport.GRAMMAR_STATS_FILENAME,
                                      greport.toNotifyString());
                }

                // now handle the lexer if one was created for a merged spec
                String lexerGrammarStr = rootGrammar.getLexerGrammar();
                //System.out.println("lexer rootGrammar:\n"+lexerGrammarStr);
                if (rootGrammar.type == Grammar.COMBINED && lexerGrammarStr != null) {
                    lexerGrammarFileName = rootGrammar.getImplicitlyGeneratedLexerFileName();
                    try {
                        Writer w = getOutputFile(rootGrammar, lexerGrammarFileName);
                        w.write(lexerGrammarStr);
                        w.close();
                    }
                    catch (IOException e) {
                        // emit different error message when creating the implicit lexer fails
                        // due to write permission error
                        exceptionWhenWritingLexerFile = true;
                        throw e;
                    }
                    try {
                        StringReader sr = new StringReader(lexerGrammarStr);
                        Grammar lexerGrammar = new Grammar(this);
                        lexerGrammar.composite.watchNFAConversion = internalOption_watchNFAConversion;
                        lexerGrammar.implicitLexer = true;
                        //lexerGrammar.setTool(this);
                        File lexerGrammarFullFile =
                            new File(getFileDirectory(lexerGrammarFileName), lexerGrammarFileName);
                        lexerGrammar.setFileName(lexerGrammarFullFile.toString());

                        lexerGrammar.importTokenVocabulary(rootGrammar);
                        lexerGrammar.parseAndBuildAST(sr);

                        sr.close();

                        lexerGrammar.composite.assignTokenTypes();
						lexerGrammar.addRulesForSyntacticPredicates();
                        lexerGrammar.composite.defineGrammarSymbols();
                        lexerGrammar.composite.createNFAs();

                        generateRecognizer(lexerGrammar);
                    }
                    finally {
                        // make sure we clean up
                        if (deleteTempLexer) {
                            File outputDir = getOutputDirectory(lexerGrammarFileName);
                            File outputFile = new File(outputDir, lexerGrammarFileName);
                            outputFile.delete();
                        }
                    }
                }
            }
            catch (IOException e) {
                if (exceptionWhenWritingLexerFile) {
                    ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, e);
                }
                else {
                    ErrorManager.error(ErrorManager.MSG_CANNOT_OPEN_FILE,
                                       grammarFileName);
                }
            }
            catch (Exception e) {
                ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR, grammarFileName, e);
            }
            /*
           finally {
           System.out.println("creates="+ Interval.creates);
           System.out.println("hits="+ Interval.hits);
           System.out.println("misses="+ Interval.misses);
           System.out.println("outOfRange="+ Interval.outOfRange);
           }
            */
        }
    }

    public void sortGrammarFiles() throws IOException {
        //System.out.println("Grammar names "+getGrammarFileNames());
        Graph g = new Graph();
        List<String> missingFiles = new ArrayList<String>();
        for (String gfile : grammarFileNames) {
            try {
                GrammarSpelunker grammar = new GrammarSpelunker(inputDirectory, gfile);
                grammar.parse();
                String vocabName = grammar.getTokenVocab();
                String grammarName = grammar.getGrammarName();
                // Make all grammars depend on any tokenVocab options
                if ( vocabName!=null ) g.addEdge(gfile, vocabName+CodeGenerator.VOCAB_FILE_EXTENSION);
                // Make all generated tokens files depend on their grammars
                g.addEdge(grammarName+CodeGenerator.VOCAB_FILE_EXTENSION, gfile);
            }
            catch (FileNotFoundException fnfe) {
                ErrorManager.error(ErrorManager.MSG_CANNOT_OPEN_FILE, gfile);
                missingFiles.add(gfile);
            }
        }
        List<Object> sorted = g.sort();
        //System.out.println("sorted="+sorted);
        grammarFileNames.clear(); // wipe so we can give new ordered list
        for (int i = 0; i < sorted.size(); i++) {
            String f = (String)sorted.get(i);
            if ( missingFiles.contains(f) ) continue;
            if ( !(f.endsWith(".g") || f.endsWith(".g3")) ) continue;
            grammarFileNames.add(f);
        }
        //System.out.println("new grammars="+grammarFileNames);
    }

    /** Get a grammar mentioned on the command-line and any delegates */
    public Grammar getRootGrammar(String grammarFileName)
        throws IOException
    {
        //ST.setLintMode(true);
        // grammars mentioned on command line are either roots or single grammars.
        // create the necessary composite in case it's got delegates; even
        // single grammar needs it to get token types.
        CompositeGrammar composite = new CompositeGrammar();
        Grammar grammar = new Grammar(this, grammarFileName, composite);
        composite.setDelegationRoot(grammar);
        FileReader fr = null;
        File f = null;

        if (haveInputDir) {
            f = new File(inputDirectory, grammarFileName);
        }
        else {
            f = new File(grammarFileName);
        }

        // Store the location of this grammar as if we import files, we can then
        // search for imports in the same location as the original grammar as well as in
        // the lib directory.
        //
        parentGrammarDirectory = f.getParent();

        if (grammarFileName.lastIndexOf(File.separatorChar) == -1) {
            grammarOutputDirectory = ".";
        }
        else {
            grammarOutputDirectory = grammarFileName.substring(0, grammarFileName.lastIndexOf(File.separatorChar));
        }
        fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);
        grammar.parseAndBuildAST(br);
        composite.watchNFAConversion = internalOption_watchNFAConversion;
        br.close();
        fr.close();
        return grammar;
    }

    /** Create NFA, DFA and generate code for grammar.
     *  Create NFA for any delegates first.  Once all NFA are created,
     *  it's ok to create DFA, which must check for left-recursion.  That check
     *  is done by walking the full NFA, which therefore must be complete.
     *  After all NFA, comes DFA conversion for root grammar then code gen for
     *  root grammar.  DFA and code gen for delegates comes next.
     */
    protected void generateRecognizer(Grammar grammar) {
        String language = (String) grammar.getOption("language");
        if (language != null) {
            CodeGenerator generator = new CodeGenerator(this, grammar, language);
            grammar.setCodeGenerator(generator);
            generator.setDebug(isDebug());
            generator.setProfile(isProfile());
            generator.setTrace(isTrace());

            // generate NFA early in case of crash later (for debugging)
            if (isGenerate_NFA_dot()) {
                generateNFAs(grammar);
            }

            // GENERATE CODE
            generator.genRecognizer();

            if (isGenerate_DFA_dot()) {
                generateDFAs(grammar);
            }

            List<Grammar> delegates = grammar.getDirectDelegates();
            for (int i = 0; delegates != null && i < delegates.size(); i++) {
                Grammar delegate = (Grammar) delegates.get(i);
                if (delegate != grammar) { // already processing this one
                    generateRecognizer(delegate);
                }
            }
        }
    }

    public void generateDFAs(Grammar g) {
        for (int d = 1; d <= g.getNumberOfDecisions(); d++) {
            DFA dfa = g.getLookaheadDFA(d);
            if (dfa == null) {
                continue; // not there for some reason, ignore
            }
            DOTGenerator dotGenerator = new DOTGenerator(g);
            String dot = dotGenerator.getDOT(dfa.startState);
            String dotFileName = g.name + "." + "dec-" + d;
            if (g.implicitLexer) {
                dotFileName = g.name + Grammar.grammarTypeToFileNameSuffix[g.type] + "." + "dec-" + d;
            }
            try {
                writeDOTFile(g, dotFileName, dot);
            } catch (IOException ioe) {
                ErrorManager.error(ErrorManager.MSG_CANNOT_GEN_DOT_FILE,
                                   dotFileName,
                                   ioe);
            }
        }
    }

    protected void generateNFAs(Grammar g) {
        DOTGenerator dotGenerator = new DOTGenerator(g);
        Collection rules = g.getAllImportedRules();
        rules.addAll(g.getRules());

        for (Iterator itr = rules.iterator(); itr.hasNext();) {
            Rule r = (Rule) itr.next();
            try {
                String dot = dotGenerator.getDOT(r.startState);
                if (dot != null) {
                    writeDOTFile(g, r, dot);
                }
            } catch (IOException ioe) {
                ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, ioe);
            }
        }
    }

    protected void writeDOTFile(Grammar g, Rule r, String dot) throws IOException {
        writeDOTFile(g, r.grammar.name + "." + r.name, dot);
    }

    protected void writeDOTFile(Grammar g, String name, String dot) throws IOException {
        Writer fw = getOutputFile(g, name + ".dot");
        fw.write(dot);
        fw.close();
    }

    private static void version() {
        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
    }

    private static void help() {
        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
        System.err.println("usage: java org.antlr.Tool [args] file.g [file2.g file3.g ...]");
        System.err.println("  -o outputDir          specify output directory where all output is generated");
        System.err.println("  -fo outputDir         same as -o but force even files with relative paths to dir");
        System.err.println("  -lib dir              specify location of token files");
        System.err.println("  -depend               generate file dependencies");
        System.err.println("  -report               print out a report about the grammar(s) processed");
        System.err.println("  -print                print out the grammar without actions");
        System.err.println("  -debug                generate a parser that emits debugging events");
		System.err.println("  -profile              generate a parser that computes profiling information");
		System.err.println("  -trace                generate a recognizer that traces rule entry/exit");
        System.err.println("  -nfa                  generate an NFA for each rule");
        System.err.println("  -dfa                  generate a DFA for each decision point");
        System.err.println("  -message-format name  specify output style for messages");
        System.err.println("  -verbose              generate ANTLR version and other information");
        System.err.println("  -make                 only build if generated files older than grammar");
		System.err.println("  -version              print the version of ANTLR and exit.");
		System.err.println("  -language L           override language grammar option; generate L");
        System.err.println("  -X                    display extended argument list");
    }

    private static void Xhelp() {
        ErrorManager.info("ANTLR Parser Generator  Version " + new Tool().VERSION);
        System.err.println("  -Xgrtree                print the grammar AST");
        System.err.println("  -Xdfa                   print DFA as text ");
        System.err.println("  -Xnoprune               test lookahead against EBNF block exit branches");
        System.err.println("  -Xnocollapse            collapse incident edges into DFA states");
		System.err.println("  -Xdbgconversion         dump lots of info during NFA conversion");
		System.err.println("  -Xconversiontimeout     use to restrict NFA conversion exponentiality");
        System.err.println("  -Xmultithreaded         run the analysis in 2 threads");
        System.err.println("  -Xnomergestopstates     do not merge stop states");
        System.err.println("  -Xdfaverbose            generate DFA states in DOT with NFA configs");
        System.err.println("  -Xwatchconversion       print a message for each NFA before converting");
        System.err.println("  -XdbgST                 put tags at start/stop of all templates in output");
        System.err.println("  -Xnfastates             for nondeterminisms, list NFA states for each path");
        System.err.println("  -Xm m                   max number of rule invocations during conversion           [" + NFAContext.MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK + "]");
        System.err.println("  -Xmaxdfaedges m         max \"comfortable\" number of edges for single DFA state     [" + DFA.MAX_STATE_TRANSITIONS_FOR_TABLE + "]");
        System.err.println("  -Xmaxinlinedfastates m  max DFA states before table used rather than inlining      [" + CodeGenerator.MADSI_DEFAULT +"]");
        System.err.println("  -Xmaxswitchcaselabels m don't generate switch() statements for dfas bigger  than m [" + CodeGenerator.MSCL_DEFAULT +"]");
		System.err.println("  -Xminswitchalts m       don't generate switch() statements for dfas smaller than m [" + CodeGenerator.MSA_DEFAULT + "]");
		System.err.println("  -Xsavelexer             don't delete temporary lexers generated from combined grammars");
    }

    /**
     * Set the threshold of case labels beyond which ANTLR will not instruct the target template
     * to generate switch() { case xxx: ...
     *
     * @param maxSwitchCaseLabels Maximum number of case lables that ANTLR should allow the target code
     */
    public void setMaxSwitchCaseLabels(int maxSwitchCaseLabels) {
        CodeGenerator.MAX_SWITCH_CASE_LABELS = maxSwitchCaseLabels;
    }

    /**
     * Set the threshold of the number alts, below which ANTLR will not instruct the target
     * template to use a switch statement.
     *
     * @param minSwitchAlts the minimum number of alts required to use a switch staement
     */
    public void setMinSwitchAlts(int minSwitchAlts) {
        CodeGenerator.MIN_SWITCH_ALTS = minSwitchAlts;
    }

    /**
     * Set the location (base directory) where output files should be produced
     * by the ANTLR tool.
     * @param outputDirectory
     */
    public void setOutputDirectory(String outputDirectory) {
        haveOutputDir = true;
        this.outputDirectory = outputDirectory;
    }

    /**
     * Used by build tools to force the output files to always be
     * relative to the base output directory, even though the tool
     * had to set the output directory to an absolute path as it
     * cannot rely on the workign directory like command line invocation
     * can.
     *
     * @param forceRelativeOutput true if output files hould always be relative to base output directory
     */
    public void setForceRelativeOutput(boolean forceRelativeOutput) {
        this.forceRelativeOutput = forceRelativeOutput;
    }

    /**
     * Set the base location of input files. Normally (when the tool is
     * invoked from the command line), the inputDirectory is not set, but
     * for build tools such as Maven, we need to be able to locate the input
     * files relative to the base, as the working directory could be anywhere and
     * changing workig directories is not a valid concept for JVMs because of threading and
     * so on. Setting the directory just means that the getFileDirectory() method will
     * try to open files relative to this input directory.
     *
     * @param inputDirectory Input source base directory
     */
    public void setInputDirectory(String inputDirectory) {
        this.inputDirectory = inputDirectory;
        haveInputDir = true;
    }

    /** This method is used by all code generators to create new output
     *  files. If the outputDir set by -o is not present it will be created.
     *  The final filename is sensitive to the output directory and
     *  the directory where the grammar file was found.  If -o is /tmp
     *  and the original grammar file was foo/t.g then output files
     *  go in /tmp/foo.
     *
     *  The output dir -o spec takes precedence if it's absolute.
     *  E.g., if the grammar file dir is absolute the output dir is given
     *  precendence. "-o /tmp /usr/lib/t.g" results in "/tmp/T.java" as
     *  output (assuming t.g holds T.java).
     *
     *  If no -o is specified, then just write to the directory where the
     *  grammar file was found.
     *
     *  If outputDirectory==null then write a String.
     */
    public Writer getOutputFile(Grammar g, String fileName) throws IOException {
        if (getOutputDirectory() == null) {
            return new StringWriter();
        }
        // output directory is a function of where the grammar file lives
        // for subdir/T.g, you get subdir here.  Well, depends on -o etc...
        // But, if this is a .tokens file, then we force the output to
        // be the base output directory (or current directory if there is not a -o)
        //
        File outputDir;
        if (fileName.endsWith(CodeGenerator.VOCAB_FILE_EXTENSION)) {
            if (haveOutputDir) {
                outputDir = new File(getOutputDirectory());
            }
            else {
                outputDir = new File(".");
            }
        }
        else {
            outputDir = getOutputDirectory(g.getFileName());
        }
        File outputFile = new File(outputDir, fileName);

        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }
        FileWriter fw = new FileWriter(outputFile);
        return new BufferedWriter(fw);
    }

    /**
     * Return the location where ANTLR will generate output files for a given file. This is a
     * base directory and output files will be relative to here in some cases
     * such as when -o option is used and input files are given relative
     * to the input directory.
     *
     * @param fileNameWithPath path to input source
     * @return
     */
    public File getOutputDirectory(String fileNameWithPath) {

        File outputDir = new File(getOutputDirectory());
        String fileDirectory;

        // Some files are given to us without a PATH but should should
        // still be written to the output directory in the relative path of
        // the output directory. The file directory is either the set of sub directories
        // or just or the relative path recorded for the parent grammar. This means
        // that when we write the tokens files, or the .java files for imported grammars
        // taht we will write them in the correct place.
        //
        if (fileNameWithPath.lastIndexOf(File.separatorChar) == -1) {

            // No path is included in the file name, so make the file
            // directory the same as the parent grammar (which might sitll be just ""
            // but when it is not, we will write the file in the correct place.
            //
            fileDirectory = grammarOutputDirectory;

        }
        else {
            fileDirectory = fileNameWithPath.substring(0, fileNameWithPath.lastIndexOf(File.separatorChar));
        }
        if (haveOutputDir) {
            // -o /tmp /var/lib/t.g => /tmp/T.java
            // -o subdir/output /usr/lib/t.g => subdir/output/T.java
            // -o . /usr/lib/t.g => ./T.java
            if ((fileDirectory != null && !forceRelativeOutput) &&
                (new File(fileDirectory).isAbsolute() ||
                 fileDirectory.startsWith("~")) || // isAbsolute doesn't count this :(
                isForceAllFilesToOutputDir()) {
                // somebody set the dir, it takes precendence; write new file there
                outputDir = new File(getOutputDirectory());
            }
            else {
                // -o /tmp subdir/t.g => /tmp/subdir/t.g
                if (fileDirectory != null) {
                    outputDir = new File(getOutputDirectory(), fileDirectory);
                }
                else {
                    outputDir = new File(getOutputDirectory());
                }
            }
        }
        else {
            // they didn't specify a -o dir so just write to location
            // where grammar is, absolute or relative, this will only happen
            // with command line invocation as build tools will always
            // supply an output directory.
            //
            outputDir = new File(fileDirectory);
        }
        return outputDir;
    }

    /**
     * Name a file from the -lib dir.  Imported grammars and .tokens files
     *
     * If we do not locate the file in the library directory, then we try
     * the location of the originating grammar.
     *
     * @param fileName input name we are looking for
     * @return Path to file that we think shuold be the import file
     *
     * @throws java.io.IOException
     */
    public String getLibraryFile(String fileName) throws IOException {

        // First, see if we can find the file in the library directory
        //
        File f = new File(getLibraryDirectory() + File.separator + fileName);

        if (f.exists()) {

            // Found in the library directory
            //
            return f.getAbsolutePath();
        }

        // Need to assume it is in the same location as the input file. Note that
        // this is only relevant for external build tools and when the input grammar
        // was specified relative to the source directory (working directory if using
        // the command line.
        //
        return parentGrammarDirectory + File.separator + fileName;
    }

    /** Return the directory containing the grammar file for this grammar.
     *  normally this is a relative path from current directory.  People will
     *  often do "java org.antlr.Tool grammars/*.g3"  So the file will be
     *  "grammars/foo.g3" etc...  This method returns "grammars".
     *
     *  If we have been given a specific input directory as a base, then
     *  we must find the directory relative to this directory, unless the
     *  file name is given to us in absolute terms.
     */
    public String getFileDirectory(String fileName) {

        File f;
        if (haveInputDir && !fileName.startsWith(File.separator)) {
            f = new File(inputDirectory, fileName);
        }
        else {
            f = new File(fileName);
        }
        // And ask Java what the base directory of this location is
        //
        return f.getParent();
    }

    /** Return a File descriptor for vocab file.  Look in library or
     *  in -o output path.  antlr -o foo T.g U.g where U needs T.tokens
     *  won't work unless we look in foo too. If we do not find the
     *  file in the lib directory then must assume that the .tokens file
     *  is going to be generated as part of this build and we have defined
     *  .tokens files so that they ALWAYS are generated in the base output
     *  directory, which means the current directory for the command line tool if there
     *  was no output directory specified.
     */
    public File getImportedVocabFile(String vocabName) {

        File f = new File(getLibraryDirectory(),
                          File.separator +
                          vocabName +
                          CodeGenerator.VOCAB_FILE_EXTENSION);
        if (f.exists()) {
            return f;
        }

        // We did not find the vocab file in the lib directory, so we need
        // to look for it in the output directory which is where .tokens
        // files are generated (in the base, not relative to the input
        // location.)
        //
        if (haveOutputDir) {
            f = new File(getOutputDirectory(), vocabName + CodeGenerator.VOCAB_FILE_EXTENSION);
        }
        else {
            f = new File(vocabName + CodeGenerator.VOCAB_FILE_EXTENSION);
        }
        return f;
    }

    /** If the tool needs to panic/exit, how do we do that?
     */
    public void panic() {
        throw new Error("ANTLR panic");
    }

    /** Return a time stamp string accurate to sec: yyyy-mm-dd hh:mm:ss
     */
    public static String getCurrentTimeStamp() {
        GregorianCalendar calendar = new java.util.GregorianCalendar();
        int y = calendar.get(Calendar.YEAR);
        int m = calendar.get(Calendar.MONTH) + 1; // zero-based for months
        int d = calendar.get(Calendar.DAY_OF_MONTH);
        int h = calendar.get(Calendar.HOUR_OF_DAY);
        int min = calendar.get(Calendar.MINUTE);
        int sec = calendar.get(Calendar.SECOND);
        String sy = String.valueOf(y);
        String sm = m < 10 ? "0" + m : String.valueOf(m);
        String sd = d < 10 ? "0" + d : String.valueOf(d);
        String sh = h < 10 ? "0" + h : String.valueOf(h);
        String smin = min < 10 ? "0" + min : String.valueOf(min);
        String ssec = sec < 10 ? "0" + sec : String.valueOf(sec);
        return new StringBuffer().append(sy).append("-").append(sm).append("-").append(sd).append(" ").append(sh).append(":").append(smin).append(":").append(ssec).toString();
    }

    /**
     * Provide the List of all grammar file names that the ANTLR tool will
     * process or has processed.
     *
     * @return the grammarFileNames
     */
    public List<String> getGrammarFileNames() {
        return grammarFileNames;
    }

    /**
     * Indicates whether ANTLR has gnerated or will generate a description of
     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
     *
     * @return the generate_NFA_dot
     */
    public boolean isGenerate_NFA_dot() {
        return generate_NFA_dot;
    }

    /**
     * Indicates whether ANTLR has generated or will generate a description of
     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
     *
     * @return the generate_DFA_dot
     */
    public boolean isGenerate_DFA_dot() {
        return generate_DFA_dot;
    }

    /**
     * Return the Path to the base output directory, where ANTLR
     * will generate all the output files for the current language target as
     * well as any ancillary files such as .tokens vocab files.
     *
     * @return the output Directory
     */
    public String getOutputDirectory() {
        return outputDirectory;
    }

    /**
     * Return the Path to the directory in which ANTLR will search for ancillary
     * files such as .tokens vocab files and imported grammar files.
     *
     * @return the lib Directory
     */
    public String getLibraryDirectory() {
        return libDirectory;
    }

    /**
     * Indicate if ANTLR has generated, or will generate a debug version of the
     * recognizer. Debug versions of a parser communicate with a debugger such
     * as that contained in ANTLRWorks and at start up will 'hang' waiting for
     * a connection on an IP port (49100 by default).
     *
     * @return the debug flag
     */
    public boolean isDebug() {
        return debug;
    }

    /**
     * Indicate whether ANTLR has generated, or will generate a version of the
     * recognizer that prints trace messages on entry and exit of each rule.
     *
     * @return the trace flag
     */
    public boolean isTrace() {
        return trace;
    }

    /**
     * Indicates whether ANTLR has generated or will generate a version of the
     * recognizer that gathers statistics about its execution, which it prints when
     * it terminates.
     *
     * @return the profile
     */
    public boolean isProfile() {
        return profile;
    }

    /**
     * Indicates whether ANTLR has generated or will generate a report of various
     * elements of the grammar analysis, once it it has finished analyzing a grammar
     * file.
     *
     * @return the report flag
     */
    public boolean isReport() {
        return report;
    }

    /**
     * Indicates whether ANTLR has printed, or will print, a version of the input grammar
     * file(s) that is stripped of any action code embedded within.
     *
     * @return the printGrammar flag
     */
    public boolean isPrintGrammar() {
        return printGrammar;
    }

    /**
     * Indicates whether ANTLR has supplied, or will supply, a list of all the things
     * that the input grammar depends upon and all the things that will be generated
     * when that grammar is successfully analyzed.
     *
     * @return the depend flag
     */
    public boolean isDepend() {
        return depend;
    }

    /**
     * Indicates whether ANTLR will force all files to the output directory, even
     * if the input files have relative paths from the input directory.
     *
     * @return the forceAllFilesToOutputDir flag
     */
    public boolean isForceAllFilesToOutputDir() {
        return forceAllFilesToOutputDir;
    }

    /**
     * Indicates whether ANTLR will be verbose when analyzing grammar files, such as
     * displaying the names of the files it is generating and similar information.
     *
     * @return the verbose flag
     */
    public boolean isVerbose() {
        return verbose;
    }

    /**
     * Provide the current setting of the conversion timeout on DFA creation.
     *
     * @return DFA creation timeout value in milliseconds
     */
    public int getConversionTimeout() {
        return DFA.MAX_TIME_PER_DFA_CREATION;
    }

    /**
     * Returns the current setting of the message format descriptor
     * @return Current message format
     */
    public String getMessageFormat() {
        return ErrorManager.getMessageFormat().toString();
    }

    /**
     * Returns the number of errors that the analysis/processing threw up.
     * @return Error count
     */
    public int getNumErrors() {
        return ErrorManager.getNumErrors();
    }

    /**
     * Indicate whether the tool will analyze the dependencies of the provided grammar
     * file list and ensure that grammars with dependencies are built
     * after any of the other gramamrs in the list that they are dependent on. Setting
     * this option also has the side effect that any grammars that are includes for other
     * grammars in the list are excluded from individual analysis, which allows the caller
     * to invoke the tool via org.antlr.tool -make *.g and not worry about the inclusion
     * of grammars that are just includes for other grammars or what order the grammars
     * appear on the command line.
     *
     * This option was coded to make life easier for tool integration (such as Maven) but
     * may also be useful at the command line.
     *
     * @return true if the tool is currently configured to analyze and sort grammar files.
     */
    public boolean getMake() {
        return make;
    }

    /**
     * Set the message format to one of ANTLR, gnu, vs2005
     *
     * @param format
     */
    public void setMessageFormat(String format) {
        ErrorManager.setFormat(format);
    }

    /** Provide the List of all grammar file names that the ANTLR tool should process.
     *
     * @param grammarFileNames The list of grammar files to process
     */
    public void setGrammarFileNames(List<String> grammarFileNames) {
        this.grammarFileNames = grammarFileNames;
    }

    public void addGrammarFile(String grammarFileName) {
        if (!grammarFileNames.contains(grammarFileName)) {
            grammarFileNames.add(grammarFileName);
        }
    }

    /**
     * Indicate whether ANTLR should generate a description of
     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
     *
     * @param generate_NFA_dot True to generate dot descriptions
     */
    public void setGenerate_NFA_dot(boolean generate_NFA_dot) {
        this.generate_NFA_dot = generate_NFA_dot;
    }

    /**
     * Indicates whether ANTLR should generate a description of
     * all the NFAs in <a href="http://www.graphviz.org">Dot format</a>
     *
     * @param generate_DFA_dot True to generate dot descriptions
     */
    public void setGenerate_DFA_dot(boolean generate_DFA_dot) {
        this.generate_DFA_dot = generate_DFA_dot;
    }

    /**
     * Set the Path to the directory in which ANTLR will search for ancillary
     * files such as .tokens vocab files and imported grammar files.
     *
     * @param libDirectory the libDirectory to set
     */
    public void setLibDirectory(String libDirectory) {
        this.libDirectory = libDirectory;
    }

    /**
     * Indicate whether ANTLR should generate a debug version of the
     * recognizer. Debug versions of a parser communicate with a debugger such
     * as that contained in ANTLRWorks and at start up will 'hang' waiting for
     * a connection on an IP port (49100 by default).
     *
     * @param debug true to generate a debug mode parser
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /**
     * Indicate whether ANTLR should generate a version of the
     * recognizer that prints trace messages on entry and exit of each rule
     *
     * @param trace true to generate a tracing parser
     */
    public void setTrace(boolean trace) {
        this.trace = trace;
    }

    /**
     * Indicate whether ANTLR should generate a version of the
     * recognizer that gathers statistics about its execution, which it prints when
     * it terminates.
     *
     * @param profile true to generate a profiling parser
     */
    public void setProfile(boolean profile) {
        this.profile = profile;
    }

    /**
     * Indicate whether ANTLR should generate a report of various
     * elements of the grammar analysis, once it it has finished analyzing a grammar
     * file.
     *
     * @param report true to generate the analysis report
     */
    public void setReport(boolean report) {
        this.report = report;
    }

    /**
     * Indicate whether ANTLR should print a version of the input grammar
     * file(s) that is stripped of any action code embedded within.
     *
     * @param printGrammar true to generate a stripped file
     */
    public void setPrintGrammar(boolean printGrammar) {
        this.printGrammar = printGrammar;
    }

    /**
     * Indicate whether ANTLR should supply a list of all the things
     * that the input grammar depends upon and all the things that will be generated
     * when that gramamr is successfully analyzed.
     *
     * @param depend true to get depends set rather than process the grammar
     */
    public void setDepend(boolean depend) {
        this.depend = depend;
    }

    /**
     * Indicates whether ANTLR will force all files to the output directory, even
     * if the input files have relative paths from the input directory.
     *
     * @param forceAllFilesToOutputDir true to force files to output directory
     */
    public void setForceAllFilesToOutputDir(boolean forceAllFilesToOutputDir) {
        this.forceAllFilesToOutputDir = forceAllFilesToOutputDir;
    }

    /**
     * Indicate whether ANTLR should be verbose when analyzing grammar files, such as
     * displaying the names of the files it is generating and similar information.
     *
     * @param verbose true to be verbose
     */
    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    /**
     * Indicate whether the tool should analyze the dependencies of the provided grammar
     * file list and ensure that the grammars with dependencies are built
     * after any of the other gramamrs in the list that they are dependent on. Setting
     * this option also has the side effect that any grammars that are includes for other
     * grammars in the list are excluded from individual analysis, which allows the caller
     * to invoke the tool via org.antlr.tool -make *.g and not worry about the inclusion
     * of grammars that are just includes for other grammars or what order the grammars
     * appear on the command line.
     *
     * This option was coded to make life easier for tool integration (such as Maven) but
     * may also be useful at the command line.
     *
     * @param make
     */
    public void setMake(boolean make) {
        this.make = make;
    }

}