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