| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package Mini; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.PrintWriter; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Objects; |
| import java.util.Vector; |
| |
| import org.apache.bcel.Const; |
| import org.apache.bcel.classfile.JavaClass; |
| import org.apache.bcel.generic.ClassGen; |
| import org.apache.bcel.generic.ConstantPoolGen; |
| |
| public class MiniC { |
| private static Vector<String> errors; |
| private static Vector<String> warnings; |
| private static String file; |
| private static int pass; |
| |
| static final void addError(final int line, final int column, final String err) { |
| if (pass != 2) { |
| errors.addElement(file + ":" + fillup(line, 3) + "," + fillup(column, 2) + ": " + err); |
| } |
| } |
| |
| static final void addWarning(final int line, final int column, final String err) { |
| warnings.addElement("Warning: " + file + ":" + fillup(line, 3) + "," + fillup(column, 3) + ": " + err); |
| } |
| |
| static final void addWarning(final String err) { |
| warnings.addElement(err); |
| } |
| |
| static final String fillup(final int n, final int len) { |
| final String str = Integer.toString(n); |
| final int diff = len - str.length(); |
| |
| if (diff <= 0) { |
| return str; |
| } |
| final char[] chs = new char[diff]; |
| |
| for (int i = 0; i < diff; i++) { |
| chs[i] = ' '; |
| } |
| |
| return new String(chs) + str; |
| } |
| |
| public static void main(final String[] argv) { |
| final String[] fileName = new String[argv.length]; |
| |
| int files = 0; |
| MiniParser parser; |
| String baseName; |
| boolean byteCode = true; |
| |
| try { |
| /* |
| * Parse command line arguments. |
| */ |
| for (final String element : argv) { |
| if (element.charAt(0) == '-') { // command line switch |
| if (element.equals("-java")) { |
| byteCode = false; |
| } else if (element.equals("-bytecode")) { |
| byteCode = true; |
| } else { |
| throw new Exception("Unknown option: " + element); |
| } |
| } else { // add file name to list |
| fileName[files++] = element; |
| } |
| } |
| |
| if (files == 0) { |
| System.err.println("Nothing to compile."); |
| } |
| |
| for (int j = 0; j < files; j++) { |
| errors = new Vector<>(); |
| warnings = new Vector<>(); |
| pass = 0; |
| |
| if (j == 0) { |
| // side-effects |
| parser = new MiniParser(new FileInputStream(fileName[0])); |
| Objects.requireNonNull(parser, "parser"); |
| } else { |
| MiniParser.ReInit(new FileInputStream(fileName[j])); |
| } |
| |
| int index = fileName[j].lastIndexOf('.'); |
| if (index > 0) { |
| baseName = fileName[j].substring(0, index); |
| } else { |
| baseName = fileName[j]; |
| } |
| |
| if ((index = baseName.lastIndexOf(File.separatorChar)) > 0) { |
| baseName = baseName.substring(index + 1); |
| } |
| |
| file = fileName[j]; |
| |
| System.out.println("Parsing..."); |
| MiniParser.Program(); |
| ASTProgram program = (ASTProgram) MiniParser.jjtree.rootNode(); |
| |
| System.out.println("Pass 1: Optimizing parse tree..."); |
| pass = 1; |
| program = program.traverse(); |
| // program.dump(">"); |
| |
| if (errors.isEmpty()) { |
| System.out.println("Pass 2: Type checking (I)..."); |
| program.eval(pass = 2); |
| } |
| |
| if (errors.isEmpty()) { |
| System.out.println("Pass 3: Type checking (II)..."); |
| program.eval(pass = 3); |
| } |
| |
| errors.forEach(System.out::println); |
| |
| warnings.forEach(System.out::println); |
| |
| if (errors.isEmpty()) { |
| if (byteCode) { |
| System.out.println("Pass 5: Generating byte code..."); |
| final ClassGen classGen = new ClassGen(baseName, "java.lang.Object", fileName[j], |
| Const.ACC_PUBLIC | Const.ACC_FINAL | Const.ACC_SUPER, null); |
| final ConstantPoolGen cp = classGen.getConstantPool(); |
| |
| program.byte_code(classGen, cp); |
| final JavaClass clazz = classGen.getJavaClass(); |
| clazz.dump(baseName + JavaClass.EXTENSION); |
| } else { |
| System.out.println("Pass 5: Generating Java code..."); |
| try (PrintWriter out = new PrintWriter(baseName + ".java", StandardCharsets.UTF_8.name())) { |
| program.code(out, baseName); |
| } |
| |
| System.out.println("Pass 6: Compiling Java code..."); |
| |
| final String[] args = { "javac", baseName + ".java" }; |
| // sun.tools.javac.Main compiler = new sun.tools.javac.Main(System.err, "javac"); |
| try { |
| final Process p = Runtime.getRuntime().exec(args); |
| p.waitFor(); |
| } catch (final Exception e) { |
| System.out.println(e); |
| } |
| |
| // compiler.compile(args); |
| } |
| } |
| |
| if (!errors.isEmpty() || !warnings.isEmpty()) { |
| System.out.println(errors.size() + " errors and " + warnings.size() + " warnings."); |
| } |
| } |
| } catch (final Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |