| /* |
| * 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. |
| */ |
| /* Generated By:JJTree: Do not edit this line. ASTProgram.java */ |
| /* JJT: 0.3pre1 */ |
| |
| package Mini; |
| |
| import java.io.PrintWriter; |
| |
| import org.apache.bcel.Const; |
| import org.apache.bcel.classfile.Field; |
| import org.apache.bcel.generic.ALOAD; |
| import org.apache.bcel.generic.ClassGen; |
| import org.apache.bcel.generic.ConstantPoolGen; |
| import org.apache.bcel.generic.GETSTATIC; |
| import org.apache.bcel.generic.ILOAD; |
| import org.apache.bcel.generic.INVOKESPECIAL; |
| import org.apache.bcel.generic.INVOKESTATIC; |
| import org.apache.bcel.generic.INVOKEVIRTUAL; |
| import org.apache.bcel.generic.InstructionConst; |
| import org.apache.bcel.generic.InstructionList; |
| import org.apache.bcel.generic.MethodGen; |
| import org.apache.bcel.generic.NEW; |
| import org.apache.bcel.generic.PUSH; |
| import org.apache.bcel.generic.PUTSTATIC; |
| import org.apache.bcel.generic.RETURN; |
| import org.apache.bcel.generic.Type; |
| |
| /** |
| * Root node of everything, direct children are nodes of type FunDecl. |
| */ |
| public class ASTProgram extends SimpleNode implements MiniParserConstants, MiniParserTreeConstants { |
| public static Node jjtCreate(final MiniParser p, final int id) { |
| return new ASTProgram(p, id); |
| } |
| |
| private ASTFunDecl[] fun_decls; // Children: Function declarations |
| |
| private Environment env; // Environment contains variables and functions |
| |
| ASTProgram(final int id) { |
| super(id); |
| |
| env = new Environment(); |
| |
| /* |
| * Add predefined functions WRITE/READ. WRITE has one arg of type T_INT, both return T_INT. |
| */ |
| ASTIdent ident = new ASTIdent("WRITE", Const.T_INT, -1, -1); |
| ASTIdent[] args = {new ASTIdent("", Const.T_INT, -1, -1)}; |
| Function fun = new Function(ident, args, true); |
| env.put(fun); |
| |
| ident = new ASTIdent("READ", Const.T_INT, -1, -1); |
| args = new ASTIdent[0]; |
| fun = new Function(ident, args, true); |
| env.put(fun); |
| |
| /* |
| * Add predefined idents TRUE/FALSE of type T_BOOLEAN |
| */ |
| ident = new ASTIdent("TRUE", Const.T_BOOLEAN, -1, -1); |
| Variable var = new Variable(ident, true); |
| env.put(var); |
| |
| ident = new ASTIdent("FALSE", Const.T_BOOLEAN, -1, -1); |
| var = new Variable(ident, true); |
| env.put(var); |
| } |
| |
| ASTProgram(final MiniParser p, final int id) { |
| super(p, id); |
| } |
| |
| /** |
| * Fifth pass, produce Java byte code. |
| */ |
| public void byte_code(final ClassGen classGen, final ConstantPoolGen cp) { |
| /* |
| * private static BufferedReader _in; |
| */ |
| classGen.addField( |
| new Field(Const.ACC_PRIVATE | Const.ACC_STATIC, cp.addUtf8("_in"), cp.addUtf8("Ljava/io/BufferedReader;"), null, cp.getConstantPool())); |
| |
| MethodGen method; |
| InstructionList il = new InstructionList(); |
| final String className = classGen.getClassName(); |
| |
| /* |
| * Often used constant pool entries |
| */ |
| final int _in = cp.addFieldref(className, "_in", "Ljava/io/BufferedReader;"); |
| |
| final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;"); |
| |
| il.append(new GETSTATIC(out)); |
| il.append(new PUSH(cp, "Please enter a number> ")); |
| il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.PrintStream", "print", "(Ljava/lang/String;)V"))); |
| il.append(new GETSTATIC(_in)); |
| il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.BufferedReader", "readLine", "()Ljava/lang/String;"))); |
| il.append(new INVOKESTATIC(cp.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I"))); |
| il.append(InstructionConst.IRETURN); |
| |
| /* |
| * private static int _readInt() throws IOException |
| */ |
| method = new MethodGen(Const.ACC_STATIC | Const.ACC_PRIVATE | Const.ACC_FINAL, Type.INT, Type.NO_ARGS, null, "_readInt", className, il, cp); |
| |
| method.addException("java.io.IOException"); |
| |
| method.setMaxStack(2); |
| classGen.addMethod(method.getMethod()); |
| |
| /* |
| * private static int _writeInt(int i) throws IOException |
| */ |
| final Type[] args = {Type.INT}; |
| final String[] argv = {"i"}; |
| il = new InstructionList(); |
| il.append(new GETSTATIC(out)); |
| il.append(new NEW(cp.addClass("java.lang.StringBuffer"))); |
| il.append(InstructionConst.DUP); |
| il.append(new PUSH(cp, "Result: ")); |
| il.append(new INVOKESPECIAL(cp.addMethodref("java.lang.StringBuffer", "<init>", "(Ljava/lang/String;)V"))); |
| |
| il.append(new ILOAD(0)); |
| il.append(new INVOKEVIRTUAL(cp.addMethodref("java.lang.StringBuffer", "append", "(I)Ljava/lang/StringBuffer;"))); |
| |
| il.append(new INVOKEVIRTUAL(cp.addMethodref("java.lang.StringBuffer", "toString", "()Ljava/lang/String;"))); |
| |
| il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V"))); |
| il.append(new PUSH(cp, 0)); |
| il.append(InstructionConst.IRETURN); // Reuse objects, if possible |
| |
| method = new MethodGen(Const.ACC_STATIC | Const.ACC_PRIVATE | Const.ACC_FINAL, Type.INT, args, argv, "_writeInt", className, il, cp); |
| |
| method.setMaxStack(4); |
| classGen.addMethod(method.getMethod()); |
| |
| /* |
| * public <init> -- constructor |
| */ |
| il.dispose(); // Dispose instruction handles for better memory utilization |
| |
| il = new InstructionList(); |
| il.append(new ALOAD(0)); // Push 'this' |
| il.append(new INVOKESPECIAL(cp.addMethodref("java.lang.Object", "<init>", "()V"))); |
| il.append(new RETURN()); |
| |
| method = new MethodGen(Const.ACC_PUBLIC, Type.VOID, Type.NO_ARGS, null, "<init>", className, il, cp); |
| |
| method.setMaxStack(1); |
| classGen.addMethod(method.getMethod()); |
| |
| /* |
| * class initializer |
| */ |
| il.dispose(); // Dispose instruction handles for better memory utilization |
| il = new InstructionList(); |
| il.append(new NEW(cp.addClass("java.io.BufferedReader"))); |
| il.append(InstructionConst.DUP); |
| il.append(new NEW(cp.addClass("java.io.InputStreamReader"))); |
| il.append(InstructionConst.DUP); |
| il.append(new GETSTATIC(cp.addFieldref("java.lang.System", "in", "Ljava/io/InputStream;"))); |
| il.append(new INVOKESPECIAL(cp.addMethodref("java.io.InputStreamReader", "<init>", "(Ljava/io/InputStream;)V"))); |
| il.append(new INVOKESPECIAL(cp.addMethodref("java.io.BufferedReader", "<init>", "(Ljava/io/Reader;)V"))); |
| il.append(new PUTSTATIC(_in)); |
| il.append(InstructionConst.RETURN); // Reuse instruction constants |
| |
| method = new MethodGen(Const.ACC_STATIC, Type.VOID, Type.NO_ARGS, null, "<clinit>", className, il, cp); |
| |
| method.setMaxStack(5); |
| classGen.addMethod(method.getMethod()); |
| |
| for (final ASTFunDecl fun_decl : fun_decls) { |
| fun_decl.byte_code(classGen, cp); |
| } |
| } |
| |
| /** |
| * Overrides SimpleNode.closeNode(). Cast children to appropriate type. |
| */ |
| @Override |
| public void closeNode() { |
| if (children != null) { // Non-empty program ? |
| fun_decls = new ASTFunDecl[children.length]; |
| System.arraycopy(children, 0, fun_decls, 0, children.length); |
| children = null; // Throw away old reference |
| } |
| } |
| |
| /** |
| * Fifth pass, produce Java code. |
| */ |
| public void code(final PrintWriter out, final String name) { |
| out.println("import java.io.BufferedReader;"); |
| out.println("import java.io.InputStreamReader;"); |
| out.println("import java.io.IOException;\n"); |
| |
| out.println("public final class " + name + " {"); |
| out.println(" private static BufferedReader _in = new BufferedReader" + "(new InputStreamReader(System.in));\n"); |
| |
| out.println(" private static int _readInt() throws IOException {\n" + " System.out.print(\"Please enter a number> \");\n" |
| + " return Integer.parseInt(_in.readLine());\n }\n"); |
| |
| out.println(" private static int _writeInt(int n) {\n" + " System.out.println(\"Result: \" + n);\n return 0;\n }\n"); |
| |
| for (final ASTFunDecl fun_decl : fun_decls) { |
| fun_decl.code(out); |
| } |
| |
| out.println("}"); |
| } |
| |
| @Override |
| public void dump(final String prefix) { |
| System.out.println(toString(prefix)); |
| |
| for (final ASTFunDecl fun_decl : fun_decls) { |
| fun_decl.dump(prefix + " "); |
| } |
| } |
| |
| /** |
| * Second pass, determine type of each node, if possible. |
| */ |
| public void eval(final int pass) { |
| |
| for (final ASTFunDecl fun_decl : fun_decls) { |
| fun_decl.eval(pass); |
| |
| if (pass == 3) { // Final check for unresolved types |
| final ASTIdent name = fun_decl.getName(); |
| |
| if (name.getType() == Const.T_UNKNOWN) { |
| MiniC.addError(name.getColumn(), name.getLine(), "Type of function " + name.getName() + " cannot be determined (infinite recursion?)."); |
| } |
| } |
| } |
| } |
| |
| /** |
| * First pass of parse tree. |
| * |
| * Put everything into the environment, which is copied appropriately to each recursion level, i.e. each FunDecl gets its |
| * own copy that it can further manipulate. |
| * |
| * Checks for name clashes of function declarations. |
| */ |
| public ASTProgram traverse() { |
| ASTFunDecl f; |
| ASTIdent name; |
| String fname; |
| EnvEntry fun; |
| Function main = null; |
| |
| if (fun_decls != null) { |
| // Put function names into hash table aka. environment |
| for (final ASTFunDecl fun_decl : fun_decls) { |
| f = fun_decl; |
| name = f.getName(); |
| fname = name.getName(); |
| fun = env.get(fname); // Lookup in env |
| |
| if (fun != null) { |
| MiniC.addError(f.getLine(), f.getColumn(), "Redeclaration of " + fun + "."); |
| } else { |
| env.put(new Function(name, null)); // 'args' will be set by FunDecl.traverse() |
| } |
| |
| } |
| |
| // Go for it |
| for (int i = 0; i < fun_decls.length; i++) { |
| fun_decls[i] = fun_decls[i].traverse((Environment) env.clone()); |
| |
| // Look for 'main' routine |
| fname = fun_decls[i].getName().getName(); |
| if (fname.equals("main")) { |
| main = (Function) env.get(fname); |
| } |
| } |
| |
| if (main == null) { |
| MiniC.addError(0, 0, "You didn't declare a 'main' function."); |
| } else if (main.getNoArgs() != 0) { |
| MiniC.addError(main.getLine(), main.getColumn(), "Main function has too many arguments declared."); |
| } |
| } |
| |
| return this; |
| } |
| } |