package compiler ;

import java.io.* ;
import java.util.* ;
import COM.sootNsmoke.jvm.* ;
import COM.sootNsmoke.instructions.* ;


public class CodeGenerator extends Instructions implements RuntimeConstants, ASTVisitor {
    
    JavaClass jcf ;
    String progname ;

     int count ;             // global count for unique labels.
    
    /*
     * Number of local variables in current procedure.
     * Also includes parameter values of the procedure.
     */
    int proc_localvars ;    
                    
    boolean procdecs ;        // Are we in procedure declaration ?
    boolean procparamdecs ; // Are we in procedure params declaration ?

    Hashtable localvars ;   // This is a hack. Ideally this information should
                       // be part of the symbol table.
    String procsig ;        // Signature of the current proc.
    
    Hashtable proctable ;   // Another hack. holds methods and their signature.
                         // Should have used symbol table.


    public CodeGenerator() {
        jcf = null ;
        progname = null ;
        count = -1 ;
        proc_localvars = -1 ;        // -1 for meaningless.
        procdecs = false ;
        procparamdecs = false ;
        localvars = null ;
        procsig = null ;
        proctable  = new Hashtable() ;
    }

    public void generate(AST ast){
        ast.visit(this, null) ;
    }

      public Object visitCompilationUnit(CompilationUnit p, Object arg) {
        if(p.cd != null){
            p.cd.visit(this,null);
        }
        return null ;
    }

    public Object visitClassDeclaration(ClassDeclaration p, Object arg) {
        Sequence main_codeseq ;
        jcf = new JavaClass(p.classname.terminal, "java/lang/Object");
        progname = p.classname.terminal ;

        main_codeseq = nop();
        if(p.classbody != null){
            main_codeseq = (Sequence) p.classbody.visit(this, null) ;
        }




        // Add the default constructor to the class
        // Assumption : 0 will be the number for this object always
        Sequence const_sequence = aload(0) ;

        // This is the default one argument constructor. So it always calls
        // java.lang.Object's
        // init (<init> is the name of the constructor within bytecode format) and returns
        // Ideally this should be done withing visitFunctionDec aftet checking the method
        // name is equal to class name then generating the code for the method, which will
        // then be the constructor with name <init>

        const_sequence = const_sequence.append(invokespecial("java/lang/Object", "<init>", "()V"));
        const_sequence = const_sequence.append(return_()) ;

    
        System.out.println(const_sequence.toString());
        jcf.addMethod("<init>", "()V", ACC_PUBLIC, const_sequence.max_stack(),1, const_sequence.toByteArray(jcf), null, null, null) ;

        // ie do the following
        // Move all the new changes above classbody.visit()

        //main_codeseq = main_codeseq.append(return_()) ;
        //System.out.println(main_codeseq.toString());
        //byte[] code = main_codeseq.toByteArray(jcf);
        //jcf.addMethod("main", "([Ljava/lang/String;)V",(ACC_PUBLIC | ACC_STATIC), main_codeseq.max_stack(),1, code, null, null, null) ;

        try{
            jcf.write(new FileOutputStream(p.classname.terminal+".class"));
        }catch (java.io.IOException ioe){
            System.out.println(ioe) ;
        }
        return null ;
    }

    public Object visitClassBody(ClassBody p,Object arg) {
        Sequence seq = (Sequence) p.ds.visit(this,null);
        return seq ;
    }

    public Object visitVariableDeclarations(VariableDeclarations p,Object arg) {
                System.out.println("Code Generation: In Visit Variable Declarations");



        if (!procdecs && (p.type.primitivetype.toString().equals("[ int ]") || p.type.primitivetype.toString().equals("[ boolean ]"))){
            if(p.staticvariable!=null){
                jcf.addField(p.variablename.terminal, (ACC_PUBLIC | ACC_STATIC), 0) ;                                
            }else{
                jcf.addField(p.variablename.terminal, (ACC_PUBLIC ), 0) ;                                
            }
        }

        else if (procdecs) {
            localvars.put(p.variablename.terminal, new Integer(proc_localvars)) ;





            if (procparamdecs && (p.type.primitivetype.toString().equals("[ int ]") || p.type.primitivetype.toString().equals("[ boolean ]"))){
                System.out.println("Adding int to signature ") ;
                procsig = procsig+"I" ;
            }
            else
                { System.out.println("not Adding int to signature "+p.type.primitivetype+procparamdecs) ; }
            proc_localvars = proc_localvars + 1 ;
        }
        // TBD , should be changed for HW6.
        return null ;
    }

    public Object visitFunctionDeclarations(FunctionDeclarations p,Object arg) {
        Sequence procseq = null ;

        procseq = nop() ;

        proc_localvars =  0 ;
        procdecs = true ;
        localvars = new Hashtable() ;
        procsig = "(" ;

        if (p.parameterlist != null)    {
            procparamdecs = true ;
            p.parameterlist.visit(this, null) ;
            procparamdecs = false ;

            procsig = procsig+")" ;

            // TBD : handle image.
            if(p.type.ptype == true){
                if (p.type.primitivetype.terminal.equals("int") || p.type.primitivetype.terminal.equals("boolean")) {
                    //procseq = procseq.append(ireturn()) ;   // TBD : remove this ?
                    procsig = procsig+"I" ;
                }else if (p.type.primitivetype.terminal.equals("void")){
                    //procseq = procseq.append(return_()) ;
                    procsig = procsig+"V" ;
                }
            }
            proctable.put(p.functionname.terminal, procsig) ;
        }else{
            procsig = procsig+")" ;

            // TBD : handle image.
            if(p.type.ptype == true){
                if (p.type.primitivetype.terminal.equals("int") || p.type.primitivetype.terminal.equals("boolean")) {
                    //procseq = procseq.append(ireturn()) ;   // TBD : remove this ?
                    procsig = procsig+"I" ;
                }else if (p.type.primitivetype.terminal.equals("void")){
                    //procseq = procseq.append(return_()) ;
                    procsig = procsig+"V" ;
                }
            }
        }

        if(p.block != null){
            if (p.block.dec != null) {
                p.block.dec.visit(this, null) ;
            }
            if (p.block.cmd != null) {
                procseq = (Sequence) p.block.cmd.visit(this, null) ;
            }
        }

        // TBD : chk this jcf
        byte[] procCode = procseq.toByteArray(jcf);
        System.out.println(" Fnction : "+p.functionname.terminal+" start ************") ;
        System.out.println("No of local vars + params :"+proc_localvars);
        System.out.println("Local Variables :"+localvars);
        System.out.println("Stack size :"+procseq.max_stack());
        System.out.println("Signature :"+procsig);
        System.out.println(procseq.toString());
        System.out.println(" Function : "+p.functionname.terminal+"end ************") ;

            if(p.staticfunction!=null){


        // I really don't know why this proc_localvars+1 is required. But with this it works.

        jcf.addMethod(p.functionname.terminal, procsig, (ACC_PUBLIC | ACC_STATIC),
                    procseq.max_stack(), proc_localvars+1, procCode,
                        null, null, null) ;
        }else{
        // I really don't know why this proc_localvars+1 is required. But with this it works.
        jcf.addMethod(p.functionname.terminal, procsig, (ACC_PUBLIC),
                    procseq.max_stack(), proc_localvars+1, procCode,
                        null, null, null) ;

        }
        proc_localvars = -1 ;
        procdecs = false ;
        localvars = null ;
        procsig = null ;
        return procseq ;
    }
        
    public Object visitBlock(Block p,Object arg) {
        return null ;
    }

    public Object visitMethodCallExpression(MethodCallExpression p,Object arg) {
        System.out.println("Code Generation : In Visit MethodCall Expression") ;
        Sequence codeseq = null ;
        String signature = (String) proctable.get(p.tan.name.name) ;
        if (p.exp   != null){
            codeseq = (Sequence) p.exp.visit(this, null) ;
            System.out.println("Code Generation : In Visit Function Expression" + p.tan.name.name + signature) ;
            codeseq = codeseq.append(invokestatic(progname, p.tan.name.name, signature));
        }else{
            codeseq = invokestatic(progname, p.tan.name.name, signature) ;
        }
        return codeseq ;
    }
        
    public Object visitMethodCallCommand(MethodCallCommand p,Object arg) {
        System.out.println("Code Generation : In Visit MethodCall Command ") ;
        Sequence codeseq = null ;
        String signature = (String) proctable.get(p.tan.name.name) ;
        if (p.exp != null){
            codeseq = (Sequence) p.exp.visit(this, null) ;
            codeseq = codeseq.append(invokestatic(progname, p.tan.name.name, signature));
        }else{
            codeseq = invokestatic(progname, p.tan.name.name, signature) ;
        }
        return codeseq ;
    }

    public Object visitAssignmentCommand(AssignmentCommand p,Object arg) {
        Sequence codeseq = null ;
        System.out.println("Code Generation : In Visit Assignment Command ") ;
        codeseq = (Sequence) p.exp.visit(this, null) ;

        if (procdecs){
            Integer location = (Integer) localvars.get(p.tan.name.name) ;

            // THIS WILL RAISE A CLASS CAST EXCEPTION IF YOU TRY SAY j = 10 anywhere.
            // p.exp.visit will always return a sequence object. You cannot convert that
            // to string. Get the type information from the symbol table as you know the
            // variable name.
            // presently I am commenting this piece of code and assuming only ints are
            // there so that I can test the rest of the code.

             // String temp = (String)p.exp.visit(this,null);
            if ( location != null) {
                // THIS IS MY TEMP FIX
                    codeseq = codeseq.append(istore(location.intValue())) ;

                // the varexpr refers to local variable.
/*                if ( temp.equals("int") || temp.equals("bool") ){
                    codeseq = codeseq.append(istore(location.intValue())) ;
                }
                if ( p.exp.type.equals("image") ){
                    codeseq = codeseq.append(astore(location.intValue())) ;
                }*/
                return codeseq ;
            }
            // the varexpr refers to global variable.
        }

// SAME AS ABOVE ASSUMING ONLY INTS
        codeseq = codeseq.append(putstatic(progname, p.tan.name.name, "I")) ;

// IMPORTANT : Infact this is sufficient as you don't have image or any other objects for now, but only ints and
// bools.
        // String temp = (String)p.exp.visit(this,null);
        // System.out.println("Code Generation: In Visit Assignment command "+temp) ;
/*        if ( temp.equals("int") || temp.equals("bool") ){
            codeseq = codeseq.append(putstatic(progname, p.tan.name.name, "I")) ;
        }

        else if ( p.exp.type.equals("image") ){
            codeseq = codeseq.append(putstatic(progname, p.id.t,
                    "Ljava/awt/image/BufferedImage;")) ;
        }*/
        return codeseq ;
    }

    public Object visitUnaryOpExpression(UnaryOpExpression p,Object arg){
        System.out.println("Code Generation : In Visit UnaryOp Expression") ;
        Sequence codeseq = null ;
        String id = null ;
        codeseq = (Sequence) p.exp.visit(this, null) ;

        if (p.op.terminal.equals("+")){
            codeseq = codeseq.append(nop()) ;
        }else if (p.op.terminal.equals("-")){
            codeseq = codeseq.append(ldc(-1)) ;
            codeseq = codeseq.append(imul()) ;
        }else if (p.op.terminal.equals("!")){//SOME CHANGE HERE. I USED SAME CODE FOR "~"
            id = getNewId() ;
            codeseq = codeseq.append(ifeq("zero"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done_una"+id)) ;
            codeseq = codeseq.append(label("zero"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done_una"+id)) ;
        }
        return codeseq ;
    }

    public Object visitBinaryOpExpression(BinaryOpExpression p,Object arg){
        System.out.println("Code Generation : In Visit BinaryOp Expression") ;
        
        Sequence codeseq = null ;
        Sequence tmpseq = null ;
        String id = null ;
        codeseq = (Sequence) p.expressionone.visit(this, null) ;
        tmpseq = (Sequence) p.expressiontwo.visit(this, null) ;
        codeseq = codeseq.append(tmpseq) ;
        
        if (p.operator.terminal.equals("+")){
            codeseq = codeseq.append(iadd()) ;
        }else if (p.operator.terminal.equals("-")){
            codeseq = codeseq.append(isub()) ;
        }else if (p.operator.terminal.equals("*")){
            codeseq = codeseq.append(imul()) ;
        }else if (p.operator.terminal.equals("/")){
            codeseq = codeseq.append(idiv()) ;
        }else if (p.operator.terminal.equals("&&")){
            codeseq = codeseq.append(iand()) ;
        }else if (p.operator.terminal.equals("||")){
            codeseq = codeseq.append(ior()) ;
        }else if (p.operator.terminal.equals("==")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmpeq("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }else if (p.operator.terminal.equals("!=")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmpne("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }else if (p.operator.terminal.equals("<=")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmple("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }else if (p.operator.terminal.equals("<")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmplt("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }else if (p.operator.terminal.equals(">")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmpgt("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }else if (p.operator.terminal.equals(">=")){
            id = getNewId() ;
            codeseq = codeseq.append(if_icmpge("true"+id)) ;
            codeseq = codeseq.append(ldc(0)) ;
            codeseq = codeseq.append(goto_("done"+id)) ;
            codeseq = codeseq.append(label("true"+id)) ;
            codeseq = codeseq.append(ldc(1)) ;
            codeseq = codeseq.append(label("done"+id)) ;
        }
        return codeseq ;
    }

    public Object visitIntegerLiteralExpression(IntegerLiteralExpression p,Object arg) {
        System.out.println("Code Generation : In Visit Integer Literal Expression") ;
        Sequence codeseq = null ;

        System.out.println("Value:........"+p.value);
        int numlit  = (new Integer(p.value)).intValue() ;
        System.out.println("Value:........"+numlit);
        //codeseq = codeseq.append(ldc(numlit)) ;
        codeseq = ldc(numlit) ;

        return codeseq ;
    }

    public Object visitBooleanLiteralExpression(BooleanLiteralExpression p,Object arg) {
        System.out.println("Code Generation : In Visit Boolean Literal Expression") ;
        Sequence codeseq = null ;
        String boollit = p.value;
    
        if (boollit.equals("true")){
            //codeseq = codeseq.append(ldc(1)) ;
            codeseq = ldc(1) ;
        }else
            if (boollit.equals("false")){
                //codeseq = codeseq.append(ldc(0)) ;
                codeseq = ldc(0) ;
            }
        return codeseq ;
    }

    public Object visitNullLiteralExpression(NullLiteralExpression p,Object arg) {
        return null ;
    }

    public Object visitSequenceExpression(SequenceExpression p,Object arg){
        System.out.println("Code Generation : In Visit Sequence Expression ") ;
        Sequence s1 = (Sequence) p.expressionone.visit(this, null) ;
        Sequence s2 = (Sequence) p.expressiontwo.visit(this, null) ;
                // SIVA CHANGED s2 can be null
        if ( s2 != null)
        {
        s1 = s1.append(s2) ;
        }
        return s1 ;
    }
    
    public Object visitSequenceCommand(SequenceCommand p,Object arg) {
        System.out.println("Code Generation : In Visit Sequence Command ") ;
        Sequence s1 = (Sequence) p.commandone.visit(this, arg) ;
        Sequence s2 = (Sequence) p.commandtwo.visit(this, arg) ;
        // SIVA CHANGED s2 can be null
        if ( s2 != null )
        {
        s1 = s1.append(s2) ;
        }
        return s1 ;
    }


    public Object visitSequenceDeclarations(SequenceDeclarations p,Object arg) {
        p.declarationsone.visit(this, null) ;
        p.declarationstwo.visit(this, null) ;
        return null ;
    }
        
    public Object visitIfElseCommand(IfElseCommand p, Object arg) {
        System.out.println("Code Generation : In Visit IfElse Command ") ;
        Sequence codeseq = null ;
        String id = getNewId() ;

        codeseq = (Sequence) p.expression.visit(this, null) ;
        codeseq = codeseq.append(ifeq("elsepart"+id)) ;

        if (p.command != null){
            codeseq = codeseq.append((Sequence) p.command.visit(this, null)) ;
        }

        codeseq = codeseq.append(goto_("endif"+id)) ;
        codeseq = codeseq.append(label("elsepart"+id)) ;

        if (p.ecommand != null){
               codeseq = codeseq.append((Sequence) p.ecommand.visit(this, null)) ;
        }

        codeseq = codeseq.append(label("endif"+id)) ;

        return codeseq ;
    }

    public Object visitWhileCommand(WhileCommand p, Object arg) {
        System.out.println("Code Generation : In Visit While Command ") ;
        Sequence codeseq = null ;
        String id = getNewId() ;
        
        codeseq = goto_("test"+id) ;
        codeseq = codeseq.append(label("body"+id)) ;
        if (p.command != null){
            codeseq = codeseq.append((Sequence) p.command.visit(this, null)) ;
        }

        codeseq = codeseq.append(label("test"+id)) ;
        codeseq = codeseq.append((Sequence) p.expression.visit(this, null)) ;
        codeseq = codeseq.append(ifne("body"+id)) ;
    
        return codeseq ;
    }    

        
    public Object visitReturnCommand(ReturnCommand p, Object arg) {
        System.out.println("Code Generation : In Visit Return Command ") ;
        Sequence codeseq = null ;

        if (p.expression != null){
            codeseq = (Sequence) p.expression.visit(this, null) ;
            System.out.println("Type of expression : "+p.expression.type_of_expression) ;


            // It is "thisandname". something wrong with the assumption.
             // as we don't handle any other types than int and bool in codegen
            // I am removing the type check and always returning int.
            codeseq = codeseq.append(ireturn()) ;

/*
                        if (p.expression.type_of_expression.equals("int") || p.expression.type_of_expression.equals("boolean")){
                codeseq = codeseq.append(ireturn()) ;
            }else
                if (p.expression.type_of_expression.equals("void")){
                    // Should not be here
                    //codeseq = codeseq.append(return_()) ;
                    //codeseq = return_() ;
                } */
        }else{
            codeseq = return_() ;
        }
        return codeseq ;
    }    

    public Object visitName(Name p,Object arg){

        // not of type objects. will work for local and instance variables.

        Sequence codeseq = null ;
        System.out.println("Code Generation : In Visit Name ") ;
        

        if (procdecs){
            Integer location = (Integer) localvars.get(p.name) ;
                codeseq = iload(location.intValue()) ;
                return codeseq ;
            // the varexpr refers to global variable.
        }


        codeseq = getstatic(progname, p.name, "I") ;


        return codeseq ;
    }

    public Object visitStatic(Static p,Object arg){
        return null ;
    }

    public Object visitModifier(Modifier p,Object arg){
        return null ;
    }

    public Object visitTerminal(Terminal p,Object arg){
        return null ;
    }

    public String getNewId(){
        count = count + 1 ;
        return (new Integer(count).toString()) ;
    }

    public Object visitSimplePWLExpression(SimplePWLExpression p,Object arg) { return null ;}

    public Object visitClassInstanceCreationExpression(ClassInstanceCreationExpression p,Object arg){ return null ;}

    public Object visitThisAndNameExpression(ThisAndNameExpression p,Object arg) {

    
    // Assuming "this" won't be there.
    return p.tan.visit(this, null) ;

    }

    public Object visitJustThis(JustThis p,Object arg) { return null ;}

    public Object visitThisAndName(ThisAndName p,Object arg){

    // Assuming "this" won't be there.
    // SIVA changed ...
    return p.name.visit(this, null) ;

    }

    public Object visitPrimitiveType(PrimitiveType p,Object arg){ return null ;}

    public Object visitReferenceType(ReferenceType p,Object arg){ return null ;}
}

Hosted by www.Geocities.ws

1