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