• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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