1   // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.io.FileInputStream;
6   import java.io.FileNotFoundException;
7   
8   /**
9    * Driver class for j-- compiler using JavaCC front-end. This is the main entry
10   * point for the compiler. The compiler proceeds as follows:
11   * 
12   * (1) It reads arguments that affects its behavior.
13   * 
14   * (2) It builds a scanner.
15   * 
16   * (3) It builds a parser (using the scanner) and parses the input for producing
17   * an abstact syntax tree (AST).
18   * 
19   * (4) It sends the preAnalyze() message to that AST, which recursively descends
20   * the tree so far as the memeber headers for declaring types and members in the
21   * symbol table (represented as a string of contexts).
22   * 
23   * (5) It sends the analyze() message to that AST for declaring local variables,
24   * and cheking and assigning types to expressions. Analysis also sometimes
25   * rewrites some of the abstract syntax trees for clarifying the semantics.
26   * Analysis does all of this by recursively descending the AST down to its
27   * leaves.
28   * 
29   * (6) Finally, it sends a codegen() message to the AST for generating code.
30   * Again, codegen() recursively descends the tree, down to its leaves,
31   * generating JVM code for producing a .class or .s (SPIM) file for each defined
32   * type (class).
33   */
34  
35  public class JavaCCMain {
36  
37      /** Whether an error occurred during compilation. */
38      private static boolean errorHasOccurred;
39  
40      /**
41       * Entry point.
42       */
43  
44      public static void main(String args[]) {
45          String caller = "java jminusminus.JavaCCMain";
46          String sourceFile = "";
47          String debugOption = "";
48          String outputDir = ".";
49          boolean spimOutput = false;
50          String registerAllocation = "";
51          errorHasOccurred = false;
52          for (int i = 0; i < args.length; i++) {
53              if (args[i].equals("javaccj--")) {
54                  caller = "javaccj--";
55              } else if (args[i].endsWith(".java")) {
56                  sourceFile = args[i];
57              } else if (args[i].equals("-t") || args[i].equals("-p")
58                      || args[i].equals("-pa") || args[i].equals("-a")) {
59                  debugOption = args[i];
60              } else if (args[i].endsWith("-d") && (i + 1) < args.length) {
61                  outputDir = args[++i];
62              } else if (args[i].endsWith("-s") && (i + 1) < args.length) {
63                  spimOutput = true;
64                  registerAllocation = args[++i];
65                  if (!registerAllocation.equals("naive")
66                          && !registerAllocation.equals("linear")
67                          && !registerAllocation.equals("graph")
68                          || registerAllocation.equals("")) {
69                      printUsage(caller);
70                      return;
71                  }
72              } else if (args[i].endsWith("-r") && (i + 1) < args.length) {
73                  NPhysicalRegister.MAX_COUNT = Math.min(18, Integer
74                          .parseInt(args[++i]));
75                  NPhysicalRegister.MAX_COUNT = Math.max(1,
76                          NPhysicalRegister.MAX_COUNT);
77              } else {
78                  printUsage(caller);
79                  return;
80              }
81          }
82          if (sourceFile.equals("")) {
83              printUsage(caller);
84              return;
85          }
86  
87          JavaCCParserTokenManager javaCCScanner = null;
88          try {
89              javaCCScanner = new JavaCCParserTokenManager(new SimpleCharStream(
90                      new FileInputStream(sourceFile), 1, 1));
91          } catch (FileNotFoundException e) {
92              System.err.println("Error: file " + sourceFile + " not found.");
93          }
94  
95          if (debugOption.equals("-t")) {
96              // Just tokenize input and print the tokens to STDOUT
97              Token token;
98              do {
99                  token = javaCCScanner.getNextToken();
100                 if (token.kind == JavaCCParserConstants.ERROR) {
101                     System.err.printf(
102                             "%s:%d: Unidentified input token: '%s'\n",
103                             sourceFile, token.beginLine, token.image);
104                     errorHasOccurred |= true;
105                 } else {
106                     System.out.printf("%d\t : %s = %s\n", token.beginLine,
107                             JavaCCParserConstants.tokenImage[token.kind],
108                             token.image);
109                 }
110             } while (token.kind != JavaCCParserConstants.EOF);
111             return;
112         }
113 
114         // Parse input
115         JCompilationUnit ast = null;
116         JavaCCParser javaCCParser = new JavaCCParser(javaCCScanner);
117         javaCCParser.fileName(sourceFile);
118         try {
119             ast = javaCCParser.compilationUnit();
120             errorHasOccurred |= javaCCParser.errorHasOccurred();
121         } catch (ParseException e) {
122             System.err.println(e.getMessage());
123         }
124         if (debugOption.equals("-p")) {
125             ast.writeToStdOut(new PrettyPrinter());
126             return;
127         }
128         if (errorHasOccurred) {
129             return;
130         }
131 
132         // Do pre-analysis
133         ast.preAnalyze();
134         errorHasOccurred |= JAST.compilationUnit.errorHasOccurred();
135         if (debugOption.equals("-pa")) {
136             ast.writeToStdOut(new PrettyPrinter());
137             return;
138         }
139         if (errorHasOccurred) {
140             return;
141         }
142 
143         // Do analysis
144         ast.analyze(null);
145         errorHasOccurred |= JAST.compilationUnit.errorHasOccurred();
146         if (debugOption.equals("-a")) {
147             ast.writeToStdOut(new PrettyPrinter());
148             return;
149         }
150         if (errorHasOccurred) {
151             return;
152         }
153 
154         // Generate JVM code
155         CLEmitter clEmitter = new CLEmitter(!spimOutput);
156         clEmitter.destinationDir(outputDir);
157         ast.codegen(clEmitter);
158         errorHasOccurred |= clEmitter.errorHasOccurred();
159         if (errorHasOccurred) {
160             return;
161         }
162 
163         // If SPIM output was asked for, convert the in-memory
164         // JVM instructions to SPIM using the specified register
165         // allocation scheme.
166         if (spimOutput) {
167             NEmitter nEmitter = new NEmitter(sourceFile, ast.clFiles(),
168                     registerAllocation);
169             nEmitter.destinationDir(outputDir);
170             nEmitter.write();
171             errorHasOccurred |= nEmitter.errorHasOccurred();
172         }
173     }
174 
175     /**
176      * Return true if an error occurred during compilation; false otherwise.
177      * 
178      * @return true or false.
179      */
180 
181     public static boolean errorHasOccurred() {
182         return errorHasOccurred;
183     }
184 
185     /**
186      * Print command usage to STDOUT.
187      * 
188      * @param caller
189      *            denotes how this class is invoked.
190      */
191 
192     private static void printUsage(String caller) {
193         String usage = "Usage: "
194                 + caller
195                 + " <options> <source file>\n"
196                 + "where possible options include:\n"
197                 + "  -t Only tokenize input and print tokens to STDOUT\n"
198                 + "  -p Only parse input and print AST to STDOUT\n"
199                 + "  -pa Only parse and pre-analyze input and print "
200                 + "AST to STDOUT\n"
201                 + "  -a Only parse, pre-analyze, and analyze input "
202                 + "and print AST to STDOUT\n"
203                 + "  -s <naive|linear|graph> Generate SPIM code\n"
204                 + "  -r <num> Max. physical registers (1-18) available for allocation; default = 8\n"
205                 + "  -d <dir> Specify where to place output files; default = .";
206         System.out.println(usage);
207     }
208 
209 }
210