/* * 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 * * http://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.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.InstructionConstants; 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 * * @version $Id$ */ public class ASTProgram extends SimpleNode implements MiniParserConstants, MiniParserTreeConstants, org.apache.bcel.Constants { private ASTFunDecl[] fun_decls; // Children: Function declarations private Environment env; // Environment contains variables and functions ASTProgram(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", T_INT, -1, -1); ASTIdent[] args = { new ASTIdent("", T_INT, -1, -1) }; Function fun = new Function(ident, args, true); env.put(fun); ident = new ASTIdent("READ", 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", T_BOOLEAN, -1, -1); Variable var = new Variable(ident, true); env.put(var); ident = new ASTIdent("FALSE", T_BOOLEAN, -1, -1); var = new Variable(ident, true); env.put(var); } ASTProgram(MiniParser p, int id) { super(p, id); } public static Node jjtCreate(MiniParser p, int id) { return new ASTProgram(p, id); } /** * Overrides SimpleNode.closeNode(). * Cast children to appropiate 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 } } /** * First pass of parse tree. * * Put everything into the environment, which is copied appropiately 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(int i=0; i < fun_decls.length; i++) { f = fun_decls[i]; 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; } /** * Second pass, determine type of each node, if possible. */ public void eval(int pass) { for(int i=0; i < fun_decls.length; i++) { fun_decls[i].eval(pass); if(pass == 3) { // Final check for unresolved types ASTIdent name = fun_decls[i].getName(); if(name.getType() == T_UNKNOWN) { MiniC.addError(name.getColumn(), name.getLine(), "Type of function " + name.getName() + " can not be determined (infinite recursion?)."); } } } } /** * Fifth pass, produce Java code. */ public void code(PrintWriter out, 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(int i=0; i < fun_decls.length; i++) { fun_decls[i].code(out); } out.println("}"); } /** * Fifth pass, produce Java byte code. */ public void byte_code(ClassGen class_gen, ConstantPoolGen cp) { /* private static BufferedReader _in; */ class_gen.addField(new Field(ACC_PRIVATE | ACC_STATIC, cp.addUtf8("_in"), cp.addUtf8("Ljava/io/BufferedReader;"), null, cp.getConstantPool())); MethodGen method; InstructionList il = new InstructionList(); String class_name = class_gen.getClassName(); /* Often used constant pool entries */ int _in = cp.addFieldref(class_name, "_in", "Ljava/io/BufferedReader;"); 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(InstructionConstants.IRETURN); /* private static int _readInt() throws IOException */ method = new MethodGen(ACC_STATIC | ACC_PRIVATE | ACC_FINAL, Type.INT, Type.NO_ARGS, null, "_readInt", class_name, il, cp); method.addException("java.io.IOException"); method.setMaxStack(2); class_gen.addMethod(method.getMethod()); /* private static int _writeInt(int i) throws IOException */ Type[] args = { Type.INT }; String[] argv = { "i" } ; il = new InstructionList(); il.append(new GETSTATIC(out)); il.append(new NEW(cp.addClass("java.lang.StringBuffer"))); il.append(InstructionConstants.DUP); il.append(new PUSH(cp, "Result: ")); il.append(new INVOKESPECIAL(cp.addMethodref("java.lang.StringBuffer", "", "(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(InstructionConstants.IRETURN); // Reuse objects, if possible method = new MethodGen(ACC_STATIC | ACC_PRIVATE | ACC_FINAL, Type.INT, args, argv, "_writeInt", class_name, il, cp); method.setMaxStack(4); class_gen.addMethod(method.getMethod()); /* public -- 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", "", "()V"))); il.append(new RETURN()); method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, null, "", class_name, il, cp); method.setMaxStack(1); class_gen.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(InstructionConstants.DUP); il.append(new NEW(cp.addClass("java.io.InputStreamReader"))); il.append(InstructionConstants.DUP); il.append(new GETSTATIC(cp.addFieldref("java.lang.System", "in", "Ljava/io/InputStream;"))); il.append(new INVOKESPECIAL(cp.addMethodref("java.io.InputStreamReader", "", "(Ljava/io/InputStream;)V"))); il.append(new INVOKESPECIAL(cp.addMethodref("java.io.BufferedReader", "", "(Ljava/io/Reader;)V"))); il.append(new PUTSTATIC(_in)); il.append(InstructionConstants.RETURN); // Reuse instruction constants method = new MethodGen(ACC_STATIC, Type.VOID, Type.NO_ARGS, null, "", class_name, il, cp); method.setMaxStack(5); class_gen.addMethod(method.getMethod()); for(int i=0; i < fun_decls.length; i++) { fun_decls[i].byte_code(class_gen, cp); } } @Override public void dump(String prefix) { System.out.println(toString(prefix)); for(int i = 0; i < fun_decls.length; ++i) { fun_decls[i].dump(prefix + " "); } } }