blob: 7a2c3e7ac7db49505ea502db0ed2af6f76c86fed [file] [log] [blame]
/* Generated By:JJTree: Do not edit this line. ASTProgram.java */
/* JJT: 0.3pre1 */
package Mini;
import java.io.PrintWriter;
import java.util.Vector;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
/**
* Root node of everything, direct children are nodes of type FunDecl
*
* @version $Id$
* @author <A HREF="http://www.berlin.de/~markus.dahm/">M. Dahm</A>
*/
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.
*/
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.
* @return type of expression
*/
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 final int _readInt() throws IOException {\n" +
" System.out.print(\"Please enter a number> \");\n" +
" return Integer.parseInt(_in.readLine());\n }\n");
out.println(" private static final 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;
Method m;
InstructionList il = new InstructionList();
byte[] byte_code;
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 final 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 final 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",
"<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(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 <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(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, null,
"<init>", 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",
"<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(InstructionConstants.RETURN); // Reuse instruction constants
method = new MethodGen(ACC_STATIC, Type.VOID, Type.NO_ARGS, null,
"<clinit>", 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);
}
public void dump(String prefix) {
System.out.println(toString(prefix));
for(int i = 0; i < fun_decls.length; ++i)
fun_decls[i].dump(prefix + " ");
}
}