Class Note for April 28 (Recitation): Taken by Jen-Chih Tseng // Covered topics (Code Gereration Rountin 2, 3) 1) if-then STMTS else STMTS 2) indexing arrays 3) assigning arrays 4) classNode // Almost all notes are in the handouts, please // make sure to check them out. // Conditional Statements // if (expr) stmts // else stmts {Evaluate control expr onto stack top} ifeq L1 {Code for then part} goto L2 L1: {Code for else part} L2: cg(){ // for ifThenNode condition.cg(); String elseLab = genLab(); branchZ(elseLab); thenPart.cg(); String endLab = genLab(); branch(endLab); defineLab(elseLab); elsePart.cg(); defineLab(endLab); } // Type Casts and Pelational Poerators String relationCode(int tokenCode){ // Determine relation code of an operator based on its tokenCode: switch(tokenCode){ case sym.EQ: return "eq"; case sym.NOTEQ: return "ne"; case sym.LT: return "lt"; case sym.LEQ: return "le"; case sym.GT: return "gt"; case sym.LEQ: return "le"; default: return ""; } } void branchRelationalCompare(int tokenCode, String label){ // Generate a conditional branch to label based on tokenCode: // Generate: // "if_icmp"+relationCode(tokenCode) label } void genRelationalOp(int operatorCode){ // Generate code to evaluate a relational operator String trueLab = genLab(); String skip = genLab(); branchRelationalCompare(operatorCode, trueLab); loadI(0); // Push false branch(skip); defineLab(trueLab); loadI(1); // Push true defineLab(skip); } cg(){// for binaryOpNode // First translate the left and right operands leftOperand.cg(); rightOperand.cg(); adr = stack; if(relationCode(operatorCode) == "") // Ordinary (non relational) operator binOp(selectOpCode(operatorCode)); else // relational operator genRelationalOp(operatorCode); } cg(){// castNode // First translate the operand operand.cg(); // Is the operand an int or char and the resultType a bool? if ( ((operand.type.val == Types.Integer) || (operand.type.val == Types.Character)) && (resultType instanceof boolTypeNode)){ loadI(0); genRelationalOp(sym.NOTEQ); } else if ((operand.type.val == Types.Integer) && (resultType instanceof charTypeNode)){ loadI(127); // Equal to 1111111B binOp("iand"); } } // Indexing and Assigning Arrays // The assign arrays we will use the methods int [] cloneIntArray(int[]); boolean[] cloneBoolArray(boolean[]); char[] cloneCharArray(char[]); char[] convertString(String); int [] checkIntArrayLength(int[], int[]); boolean[] checkBoolArrayLength(boolean[], boolean[]); char[] checkCharArrayLength(char[], char[]); cg(){ // for nameNode (final revision) adr = stack; if (subscriptVal.isNull()) { // Simple (unsubscripted) identifier if (varName.idinfo.kind.val == Kinds.Var || varName.idinfo.kind.val == Kinds.Value || varName.idinfo.kind.val == Kinds.ValueParm) { // id is a scalar variable, parameter or const if (varName.idinfo.adr == global){// id is a global label = varName.idinfo.label; loadGlobalInt(label); } else { // (varName.idinfo.adr == local) varIndex = varName.idinfo.varIndex; loadLocalInt(varIndex); } } else { // varName is an array var or parm if (varName.idinfo.adr == global){ label = varName.idinfo.label; loadGlobalReference(label, arrayTypeCode(varName.idinfo.type)); } else { // (varName.idinfo.adr == local) varIndex = varName.idinfo.varIndex; loadLocalReference(varIndex); } } } else { // This is subscripted variable // Push array reference first if (varName.idinfo.adr == global){ label = varName.idinfo.label; loadGlobalReference(label, arrayTypeCode(varName.idinfo.type)); } else { // (varName.idinfo.adr == local) varIndex = varName.idinfo.varIndex; loadLocalReference(varIndex); } // Next compute subscript expression subscriptVal.cg(); // Now load the array element onto the stack switch(type.val){ case Types.Integer: // generate: iaload break; case Types.Boolean: // generate: baload break; case Types.Character: // generate: caload break; } } } void computeAdr(nameNode name) { // revised // Compute address associated w/ name node // don't load the value addressed onto the stack if (name.subscriptVal.isNull()) { // Simple (unsubscripted) identifier if (name.varName.idinfo.kind.val == Kinds.Var || name.varName.idinfo.kind.val == Kinds.ValueParm) { // id is a scalar variable if (name.varName.idinfo.adr == global) { name.adr = global; name.label = name.varName.idinfo.label; } else { // varName.idinfo.adr == local name.adr = local; name.varIndex = name.varName.idinfo.varIndex; }} else { // Must be an array // Push ref to target array to check length if (name.varName.idinfo.adr == global){ label = name.varName.idinfo.label; loadGlobalReference(label, arrayTypeCode(name.varName.idinfo.type)); } else { // (name.varName.idinfo.adr == local) varIndex = name.varName.idinfo.varIndex; loadLocalReference(varIndex); } } } else { // This is subscripted variable // Push array reference first if (name.varName.idinfo.adr == global){ label = name.varName.idinfo.label; loadGlobalReference(label, arrayTypeCode(name.varName.idinfo.type)); } else { // (name.varName.idinfo.adr == local) varIndex = name.varName.idinfo.varIndex; loadLocalReference(varIndex); } // Next compute subscript expression name.subscriptVal.cg(); } } void storeName(nameNode name) { // revised if (name.subscriptVal.isNull()) { // Simple (unsubscripted) identifier if (name.varName.idinfo.kind.val == Kinds.Var || name.varName.idinfo.kind.val == Kinds.ValueParm) { if (name.adr == global) storeGlobalInt(name.label); else // (name.adr == local) storeLocalInt(name.varIndex); } else { // Must be an array // Check the lengths of the source and target arrays switch(name.type.val){ case Types.Integer: genCall("CSXLib/checkIntArrayLength([I[I)[I"); break; case Types.Boolean: genCall("CSXLib/checkBoolArrayLength([Z[Z)[Z"); break; case Types.Character: genCall("CSXLib/checkCharArrayLength([C[C)[C"); break; } // Now store source array away in target var if (name.varName.idinfo.adr == global){ label = name.varName.idinfo.label; storeGlobalReference(label, arrayTypeCode(name.varName.idinfo.type)); } else { // (name.varName.idinfo.adr == local) varIndex = name.varName.idinfo.varIndex; storeLocalReference(varIndex); } } } else // This is a subscripted variable // A reference to the target array, the // subscript expression and the source expression // have already been pushed. // Now store the source value into the array switch(type.val){ case Types.Integer: // generate: iastore break; case Types.Boolean: // generate: bastore break; case Types.Character: // generate: castore break; } }} cg(){ // for asgNode (extended) // Compute address associated with LHS computeAdr(target); // Translate RHS (an expression) source.cg(); // Check to see if source needs to be cloned or converted if (source.kind.val == Kinds.Array || source.kind.val == Kinds.RefArray) switch(source.type.val){ case Types.Integer: genCall("CSXLib/cloneIntArray([I)[I"); break; case Types.Boolean: genCall("CSXLib/cloneBoolArray([Z)[Z"); break; case Types.Character: genCall("CSXLib/cloneCharArray([C)[C"); break; } else if (source.type.val == Types.String) genCall("CSXLib/convertString(Ljava/lang/String;)[C"); // Finally, store source into the target (a name) storeName(target); } // Finally, the code generation for calssNode cg(){ //for classNode currentMethod = null; // We're not in any method body CLASS = CSXIdentifierToken.reg.toString(className.idval); // generate: // .class public CLASS // .super java/lang/Object // generate field declarations for the class members.fields.declField(); // generate: // .method public static main([Ljava/lang/String;)V // generate non-trivial field initializations members.fields.cg(); // generate: // invokestatic CLASS/main()V // return // .limit stack 2 // .end method // Fianlly translate methods members.methods.cg(); }