1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 /* Generated By:JJTree: Do not edit this line. ASTProgram.java */ 19 /* JJT: 0.3pre1 */ 20 21 package Mini; 22 import java.io.PrintWriter; 23 24 import org.apache.bcel.classfile.Field; 25 import org.apache.bcel.generic.ALOAD; 26 import org.apache.bcel.generic.ClassGen; 27 import org.apache.bcel.generic.ConstantPoolGen; 28 import org.apache.bcel.generic.GETSTATIC; 29 import org.apache.bcel.generic.ILOAD; 30 import org.apache.bcel.generic.INVOKESPECIAL; 31 import org.apache.bcel.generic.INVOKESTATIC; 32 import org.apache.bcel.generic.INVOKEVIRTUAL; 33 import org.apache.bcel.generic.InstructionConstants; 34 import org.apache.bcel.generic.InstructionList; 35 import org.apache.bcel.generic.MethodGen; 36 import org.apache.bcel.generic.NEW; 37 import org.apache.bcel.generic.PUSH; 38 import org.apache.bcel.generic.PUTSTATIC; 39 import org.apache.bcel.generic.RETURN; 40 import org.apache.bcel.generic.Type; 41 42 /** 43 * Root node of everything, direct children are nodes of type FunDecl 44 * 45 * @version $Id$ 46 */ 47 public class ASTProgram extends SimpleNode 48 implements MiniParserConstants, MiniParserTreeConstants, org.apache.bcel.Constants { 49 private ASTFunDecl[] fun_decls; // Children: Function declarations 50 private Environment env; // Environment contains variables and functions 51 ASTProgram(int id)52 ASTProgram(int id) { 53 super(id); 54 55 env = new Environment(); 56 57 /* Add predefined functions WRITE/READ. 58 * WRITE has one arg of type T_INT, both return T_INT. 59 */ 60 ASTIdent ident = new ASTIdent("WRITE", T_INT, -1, -1); 61 ASTIdent[] args = { new ASTIdent("", T_INT, -1, -1) }; 62 Function fun = new Function(ident, args, true); 63 env.put(fun); 64 65 ident = new ASTIdent("READ", T_INT, -1, -1); 66 args = new ASTIdent[0]; 67 fun = new Function(ident, args, true); 68 env.put(fun); 69 70 /* Add predefined idents TRUE/FALSE of type T_BOOLEAN 71 */ 72 ident = new ASTIdent("TRUE", T_BOOLEAN, -1, -1); 73 Variable var = new Variable(ident, true); 74 env.put(var); 75 76 ident = new ASTIdent("FALSE", T_BOOLEAN, -1, -1); 77 var = new Variable(ident, true); 78 env.put(var); 79 } 80 ASTProgram(MiniParser p, int id)81 ASTProgram(MiniParser p, int id) { 82 super(p, id); 83 } 84 jjtCreate(MiniParser p, int id)85 public static Node jjtCreate(MiniParser p, int id) { 86 return new ASTProgram(p, id); 87 } 88 89 /** 90 * Overrides SimpleNode.closeNode(). 91 * Cast children to appropiate type. 92 */ 93 @Override closeNode()94 public void closeNode() { 95 if(children != null) { // Non-empty program ? 96 fun_decls = new ASTFunDecl[children.length]; 97 System.arraycopy(children, 0, fun_decls, 0, children.length); 98 children=null; // Throw away old reference 99 } 100 } 101 102 /** 103 * First pass of parse tree. 104 * 105 * Put everything into the environment, which is copied appropiately to each 106 * recursion level, i.e. each FunDecl gets its own copy that it can further 107 * manipulate. 108 * 109 * Checks for name clashes of function declarations. 110 */ traverse()111 public ASTProgram traverse() { 112 ASTFunDecl f; 113 ASTIdent name; 114 String fname; 115 EnvEntry fun; 116 Function main=null; 117 118 if(fun_decls != null) { 119 // Put function names into hash table aka. environment 120 for(int i=0; i < fun_decls.length; i++) { 121 f = fun_decls[i]; 122 name = f.getName(); 123 fname = name.getName(); 124 fun = env.get(fname); // Lookup in env 125 126 if(fun != null) { 127 MiniC.addError(f.getLine(), f.getColumn(), 128 "Redeclaration of " + fun + "."); 129 } else { 130 env.put(new Function(name, null)); // `args' will be set by FunDecl.traverse() 131 } 132 133 134 } 135 136 // Go for it 137 for(int i=0; i < fun_decls.length; i++) { 138 fun_decls[i] = fun_decls[i].traverse((Environment)env.clone()); 139 140 // Look for `main' routine 141 fname = fun_decls[i].getName().getName(); 142 if(fname.equals("main")) { 143 main = (Function)env.get(fname); 144 } 145 } 146 147 if(main == null) { 148 MiniC.addError(0, 0, "You didn't declare a `main' function."); 149 } else if(main.getNoArgs() != 0) { 150 MiniC.addError(main.getLine(), main.getColumn(), 151 "Main function has too many arguments declared."); 152 } 153 } 154 155 return this; 156 } 157 158 /** 159 * Second pass, determine type of each node, if possible. 160 */ eval(int pass)161 public void eval(int pass) { 162 163 for(int i=0; i < fun_decls.length; i++) { 164 fun_decls[i].eval(pass); 165 166 if(pass == 3) { // Final check for unresolved types 167 ASTIdent name = fun_decls[i].getName(); 168 169 if(name.getType() == T_UNKNOWN) { 170 MiniC.addError(name.getColumn(), name.getLine(), 171 "Type of function " + name.getName() + 172 " can not be determined (infinite recursion?)."); 173 } 174 } 175 } 176 } 177 178 /** 179 * Fifth pass, produce Java code. 180 */ code(PrintWriter out, String name)181 public void code(PrintWriter out, String name) { 182 out.println("import java.io.BufferedReader;"); 183 out.println("import java.io.InputStreamReader;"); 184 out.println("import java.io.IOException;\n"); 185 186 out.println("public final class " + name + " {"); 187 out.println(" private static BufferedReader _in = new BufferedReader" + 188 "(new InputStreamReader(System.in));\n"); 189 190 out.println(" private static int _readInt() throws IOException {\n" + 191 " System.out.print(\"Please enter a number> \");\n" + 192 " return Integer.parseInt(_in.readLine());\n }\n"); 193 194 out.println(" private static int _writeInt(int n) {\n" + 195 " System.out.println(\"Result: \" + n);\n return 0;\n }\n"); 196 197 for(int i=0; i < fun_decls.length; i++) { 198 fun_decls[i].code(out); 199 } 200 201 out.println("}"); 202 } 203 204 /** 205 * Fifth pass, produce Java byte code. 206 */ byte_code(ClassGen class_gen, ConstantPoolGen cp)207 public void byte_code(ClassGen class_gen, ConstantPoolGen cp) { 208 /* private static BufferedReader _in; 209 */ 210 class_gen.addField(new Field(ACC_PRIVATE | ACC_STATIC, 211 cp.addUtf8("_in"), 212 cp.addUtf8("Ljava/io/BufferedReader;"), 213 null, cp.getConstantPool())); 214 215 MethodGen method; 216 InstructionList il = new InstructionList(); 217 String class_name = class_gen.getClassName(); 218 219 /* Often used constant pool entries 220 */ 221 int _in = cp.addFieldref(class_name, "_in", "Ljava/io/BufferedReader;"); 222 223 int out = cp.addFieldref("java.lang.System", "out", 224 "Ljava/io/PrintStream;"); 225 226 il.append(new GETSTATIC(out)); 227 il.append(new PUSH(cp, "Please enter a number> ")); 228 il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.PrintStream", 229 "print", 230 "(Ljava/lang/String;)V"))); 231 il.append(new GETSTATIC(_in)); 232 il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.BufferedReader", 233 "readLine", 234 "()Ljava/lang/String;"))); 235 il.append(new INVOKESTATIC(cp.addMethodref("java.lang.Integer", 236 "parseInt", 237 "(Ljava/lang/String;)I"))); 238 il.append(InstructionConstants.IRETURN); 239 240 /* private static int _readInt() throws IOException 241 */ 242 method = new MethodGen(ACC_STATIC | ACC_PRIVATE | ACC_FINAL, 243 Type.INT, Type.NO_ARGS, null, 244 "_readInt", class_name, il, cp); 245 246 method.addException("java.io.IOException"); 247 248 method.setMaxStack(2); 249 class_gen.addMethod(method.getMethod()); 250 251 /* private static int _writeInt(int i) throws IOException 252 */ 253 Type[] args = { Type.INT }; 254 String[] argv = { "i" } ; 255 il = new InstructionList(); 256 il.append(new GETSTATIC(out)); 257 il.append(new NEW(cp.addClass("java.lang.StringBuffer"))); 258 il.append(InstructionConstants.DUP); 259 il.append(new PUSH(cp, "Result: ")); 260 il.append(new INVOKESPECIAL(cp.addMethodref("java.lang.StringBuffer", 261 "<init>", 262 "(Ljava/lang/String;)V"))); 263 264 il.append(new ILOAD(0)); 265 il.append(new INVOKEVIRTUAL(cp.addMethodref("java.lang.StringBuffer", 266 "append", 267 "(I)Ljava/lang/StringBuffer;"))); 268 269 il.append(new INVOKEVIRTUAL(cp.addMethodref("java.lang.StringBuffer", 270 "toString", 271 "()Ljava/lang/String;"))); 272 273 il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.PrintStream", 274 "println", 275 "(Ljava/lang/String;)V"))); 276 il.append(new PUSH(cp, 0)); 277 il.append(InstructionConstants.IRETURN); // Reuse objects, if possible 278 279 method = new MethodGen(ACC_STATIC | ACC_PRIVATE | ACC_FINAL, 280 Type.INT, args, argv, 281 "_writeInt", class_name, il, cp); 282 283 method.setMaxStack(4); 284 class_gen.addMethod(method.getMethod()); 285 286 /* public <init> -- constructor 287 */ 288 il.dispose(); // Dispose instruction handles for better memory utilization 289 290 il = new InstructionList(); 291 il.append(new ALOAD(0)); // Push `this' 292 il.append(new INVOKESPECIAL(cp.addMethodref("java.lang.Object", 293 "<init>", "()V"))); 294 il.append(new RETURN()); 295 296 method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, null, 297 "<init>", class_name, il, cp); 298 299 method.setMaxStack(1); 300 class_gen.addMethod(method.getMethod()); 301 302 /* class initializer 303 */ 304 il.dispose(); // Dispose instruction handles for better memory utilization 305 il = new InstructionList(); 306 il.append(new NEW(cp.addClass("java.io.BufferedReader"))); 307 il.append(InstructionConstants.DUP); 308 il.append(new NEW(cp.addClass("java.io.InputStreamReader"))); 309 il.append(InstructionConstants.DUP); 310 il.append(new GETSTATIC(cp.addFieldref("java.lang.System", "in", 311 "Ljava/io/InputStream;"))); 312 il.append(new INVOKESPECIAL(cp.addMethodref("java.io.InputStreamReader", 313 "<init>", "(Ljava/io/InputStream;)V"))); 314 il.append(new INVOKESPECIAL(cp.addMethodref("java.io.BufferedReader", 315 "<init>", "(Ljava/io/Reader;)V"))); 316 il.append(new PUTSTATIC(_in)); 317 il.append(InstructionConstants.RETURN); // Reuse instruction constants 318 319 method = new MethodGen(ACC_STATIC, Type.VOID, Type.NO_ARGS, null, 320 "<clinit>", class_name, il, cp); 321 322 method.setMaxStack(5); 323 class_gen.addMethod(method.getMethod()); 324 325 for(int i=0; i < fun_decls.length; i++) { 326 fun_decls[i].byte_code(class_gen, cp); 327 } 328 } 329 330 @Override dump(String prefix)331 public void dump(String prefix) { 332 System.out.println(toString(prefix)); 333 334 for(int i = 0; i < fun_decls.length; ++i) { 335 fun_decls[i].dump(prefix + " "); 336 } 337 } 338 } 339