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 ;}
}