Java tutorial
/******************************************************************************* * Copyright (c) 2015 Gary F. Pollice * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Used in CS4533/CS544 at Worcester Polytechnic Institute *******************************************************************************/ package dijkstra.gen; import static dijkstra.ast.ASTNode.ASTNodeType.FUNCALL; import static dijkstra.utility.DijkstraType.FUNCTION; import static dijkstra.utility.DijkstraType.UNDEFINED; import static org.objectweb.asm.Opcodes.AALOAD; import static org.objectweb.asm.Opcodes.AASTORE; import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ANEWARRAY; import static org.objectweb.asm.Opcodes.ARETURN; import static org.objectweb.asm.Opcodes.ASTORE; import static org.objectweb.asm.Opcodes.BALOAD; import static org.objectweb.asm.Opcodes.BASTORE; import static org.objectweb.asm.Opcodes.BIPUSH; import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.D2I; import static org.objectweb.asm.Opcodes.D2L; import static org.objectweb.asm.Opcodes.DADD; import static org.objectweb.asm.Opcodes.DALOAD; import static org.objectweb.asm.Opcodes.DASTORE; import static org.objectweb.asm.Opcodes.DCMPL; import static org.objectweb.asm.Opcodes.DDIV; import static org.objectweb.asm.Opcodes.DLOAD; import static org.objectweb.asm.Opcodes.DMUL; import static org.objectweb.asm.Opcodes.DNEG; import static org.objectweb.asm.Opcodes.DSTORE; import static org.objectweb.asm.Opcodes.DSUB; import static org.objectweb.asm.Opcodes.DUP; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.GOTO; import static org.objectweb.asm.Opcodes.ICONST_0; import static org.objectweb.asm.Opcodes.ICONST_1; import static org.objectweb.asm.Opcodes.IFEQ; import static org.objectweb.asm.Opcodes.IFGE; import static org.objectweb.asm.Opcodes.IFGT; import static org.objectweb.asm.Opcodes.IFLE; import static org.objectweb.asm.Opcodes.IFLT; import static org.objectweb.asm.Opcodes.IFNE; import static org.objectweb.asm.Opcodes.IF_ICMPEQ; import static org.objectweb.asm.Opcodes.IF_ICMPNE; import static org.objectweb.asm.Opcodes.ILOAD; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.ISTORE; import static org.objectweb.asm.Opcodes.L2D; import static org.objectweb.asm.Opcodes.L2I; import static org.objectweb.asm.Opcodes.LADD; import static org.objectweb.asm.Opcodes.LALOAD; import static org.objectweb.asm.Opcodes.LASTORE; import static org.objectweb.asm.Opcodes.LCMP; import static org.objectweb.asm.Opcodes.LDIV; import static org.objectweb.asm.Opcodes.LLOAD; import static org.objectweb.asm.Opcodes.LMUL; import static org.objectweb.asm.Opcodes.LNEG; import static org.objectweb.asm.Opcodes.LREM; import static org.objectweb.asm.Opcodes.LSTORE; import static org.objectweb.asm.Opcodes.LSUB; import static org.objectweb.asm.Opcodes.NEW; import static org.objectweb.asm.Opcodes.NEWARRAY; import static org.objectweb.asm.Opcodes.PUTFIELD; import static org.objectweb.asm.Opcodes.PUTSTATIC; import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.SIPUSH; import static org.objectweb.asm.Opcodes.T_BOOLEAN; import static org.objectweb.asm.Opcodes.T_DOUBLE; import static org.objectweb.asm.Opcodes.T_LONG; import static org.objectweb.asm.Opcodes.V1_8; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import dijkstra.ast.ASTNode; import dijkstra.ast.ASTNode.ASTNodeType; import dijkstra.ast.ASTNodeFactory.AlternativeNode; import dijkstra.ast.ASTNodeFactory.ArrayAccessorNode; import dijkstra.ast.ASTNodeFactory.ArrayDeclarationNode; import dijkstra.ast.ASTNodeFactory.AssignListNode; import dijkstra.ast.ASTNodeFactory.AssignNode; import dijkstra.ast.ASTNodeFactory.AttributeNode; import dijkstra.ast.ASTNodeFactory.BinaryExpressionNode; import dijkstra.ast.ASTNodeFactory.ClassDeclarationNode; import dijkstra.ast.ASTNodeFactory.ConstantNode; import dijkstra.ast.ASTNodeFactory.FunctionCallNode; import dijkstra.ast.ASTNodeFactory.FunctionDeclarationNode; import dijkstra.ast.ASTNodeFactory.GuardNode; import dijkstra.ast.ASTNodeFactory.IDNode; import dijkstra.ast.ASTNodeFactory.InputNode; import dijkstra.ast.ASTNodeFactory.IterativeNode; import dijkstra.ast.ASTNodeFactory.MethodCallNode; import dijkstra.ast.ASTNodeFactory.OutputNode; import dijkstra.ast.ASTNodeFactory.ProcedureCallNode; import dijkstra.ast.ASTNodeFactory.ProcedureDeclarationNode; import dijkstra.ast.ASTNodeFactory.ProgramNode; import dijkstra.ast.ASTNodeFactory.PropertyNode; import dijkstra.ast.ASTNodeFactory.ReturnNode; import dijkstra.ast.ASTNodeFactory.RootNode; import dijkstra.ast.ASTNodeFactory.UnaryExpressionNode; import dijkstra.ast.ASTNodeFactory.VariableDeclarationNode; import dijkstra.ast.ASTVisitor; import dijkstra.lexparse.DijkstraParser; import dijkstra.symbol.ArraySymbol; import dijkstra.symbol.ClassSymbol; import dijkstra.symbol.FunctionSymbol; import dijkstra.symbol.ObjectSymbol; import dijkstra.symbol.ProcedureSymbol; import dijkstra.symbol.Symbol; import dijkstra.symbol.SymbolTableManager; import dijkstra.utility.DijkstraType; /** * Description * @version Feb 21, 2015 */ public class DijkstraCodeGenerator extends ASTVisitor<byte[]> { private final boolean debug = true; private ClassWriter cw = null; private final Stack<MethodVisitor> mvStack; private final String DEFAULT_PACKAGE = "djkcode"; private String classPackage; final private Stack<Label> guardLabelStack; final private Stack<Symbol> returnArrayStack; final private Stack<Symbol> returnIndexStack; private String programName = null; private String fullPath = null; private boolean reading = true; private boolean inClass = false; private boolean processingClassFields = false; public DijkstraCodeGenerator() { classPackage = DEFAULT_PACKAGE; guardLabelStack = new Stack<Label>(); mvStack = new Stack<MethodVisitor>(); returnArrayStack = new Stack<Symbol>(); returnIndexStack = new Stack<Symbol>(); } public byte[] visit(RootNode root) { return root.getProgramNode().accept(this); } public byte[] visit(ClassDeclarationNode classDecl) { // prolog cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); programName = classDecl.getID().getName(); fullPath = classPackage + "/" + classDecl.getID().getName(); cw.visit(V1_8, ACC_PUBLIC + ACC_STATIC, fullPath, null, "java/lang/Object", null); cw.visitSource(classDecl.getID().getName() + ".java", null); FieldVisitor fv; List<Symbol> classSymbols = new ArrayList<Symbol>(); classSymbols.addAll(SymbolTableManager.getInstance().getClassSymbolManager(programName) .getCurrentSymbolTable().getSymbols()); for (ASTNode property : classDecl.getProperties()) { classSymbols.add(((PropertyNode) property).getID().symbol); } for (Symbol symbol : classSymbols) { String type; if (symbol.getType() == DijkstraType.ARRAY) { ArraySymbol as = (ArraySymbol) symbol; if (as.getArrayType() == DijkstraType.INT) { type = "[J"; } else if (as.getArrayType() == DijkstraType.FLOAT) { type = "[D"; } else { type = "[Z"; } } else { if (symbol.getType() == DijkstraType.INT) { type = "J"; } else if (symbol.getType() == DijkstraType.FLOAT) { type = "D"; } else { type = "Z"; } } fv = cw.visitField(ACC_PUBLIC, symbol.getId(), type, null, null); fv.visitEnd(); } final StringBuilder sig = new StringBuilder(); sig.append('('); for (Symbol property : ((ClassSymbol) classDecl.getID().symbol).getPropertySymbols()) { if (property.getType() == DijkstraType.INT) { sig.append('J'); } else if (property.getType() == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } sig.append(")V"); mvStack.push(cw.visitMethod(ACC_PUBLIC, "<init>", sig.toString(), null, null)); MethodVisitor mv = mvStack.peek(); mv.visitCode(); final Label startLabel = new Label(); mv.visitLabel(startLabel); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); int localAddr = 1; for (Symbol param : ((ClassSymbol) classDecl.getID().symbol).getPropertySymbols()) { mv.visitVarInsn(ALOAD, 0); if (param.getType() == DijkstraType.INT) { mv.visitVarInsn(LLOAD, localAddr); mv.visitFieldInsn(PUTFIELD, fullPath, param.getId(), "J"); localAddr += 2; } else if (param.getType() == DijkstraType.FLOAT) { mv.visitVarInsn(DLOAD, localAddr); mv.visitFieldInsn(PUTFIELD, fullPath, param.getId(), "D"); localAddr += 2; } else { mv.visitVarInsn(ILOAD, localAddr); mv.visitFieldInsn(PUTFIELD, fullPath, param.getId(), "Z"); localAddr += 1; } } processingClassFields = true; inClass = true; for (ASTNode body : classDecl.getDeclarations()) { body.accept(this); } inClass = false; processingClassFields = false; mv.visitInsn(RETURN); final Label endLabel = new Label(); mv.visitLabel(endLabel); mv.visitLocalVariable("this", "L" + fullPath + ";", null, startLabel, endLabel, 0); int paramLoc = 1; for (Symbol param : ((ClassSymbol) classDecl.getID().symbol).getPropertySymbols()) { if (param.getType() == DijkstraType.INT) { mv.visitLocalVariable(param.getId(), "J", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else if (param.getType() == DijkstraType.FLOAT) { mv.visitLocalVariable(param.getId(), "D", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else { mv.visitLocalVariable(param.getId(), "Z", null, startLabel, endLabel, paramLoc); paramLoc += 1; } } mv.visitMaxs(0, 0); mv.visitEnd(); mvStack.pop(); inClass = true; for (ASTNode body : classDecl.getDeclarations()) { body.accept(this); } inClass = false; // Actual end of generation cw.visitEnd(); return cw.toByteArray(); } /** * Generate the program prolog, then visit the children, then generate * the program end. * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.ProgramNode) */ public byte[] visit(ProgramNode program) { // prolog cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); programName = program.programName; fullPath = classPackage + "/" + program.programName; cw.visit(V1_8, ACC_PUBLIC + ACC_STATIC, fullPath, null, "java/lang/Object", null); cw.visitSource(program.programName + ".java", null); FieldVisitor fv; for (Symbol symbol : SymbolTableManager.getInstance().getCurrentSymbolTable().getSymbols()) { String type; if (symbol.getType() == DijkstraType.ARRAY) { ArraySymbol as = (ArraySymbol) symbol; if (as.getArrayType() == DijkstraType.INT) { type = "[J"; } else if (as.getArrayType() == DijkstraType.FLOAT) { type = "[D"; } else if (as.getArrayType() == DijkstraType.BOOLEAN) { type = "[Z"; } else { type = "L" + classPackage + "/" + ((ObjectSymbol) symbol).getObjectType() + ";"; } } else { if (symbol.getType() == DijkstraType.INT) { type = "J"; } else if (symbol.getType() == DijkstraType.FLOAT) { type = "D"; } else if (symbol.getType() == DijkstraType.BOOLEAN) { type = "Z"; } else { type = "L" + classPackage + "/" + ((ObjectSymbol) symbol).getObjectType() + ";"; } } fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, symbol.getId(), type, null, null); fv.visitEnd(); } mvStack.push(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)); MethodVisitor mv = mvStack.peek(); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); mvStack.pop(); // Start the main() method mvStack.push(cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null)); mv = mvStack.peek(); mv.visitCode(); visitChildren(program); // program end // End of main mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); // Actual end of generation cw.visitEnd(); return cw.toByteArray(); } public byte[] visit(AttributeNode node) { final MethodVisitor mv = mvStack.peek(); final String objectType = ((ObjectSymbol) node.getObj().symbol).getObjectType(); if (reading) { if (node.getObj().symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, node.getObj().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObj().symbol).getObjectType() + ";"); } else if (node.getObj().symbol.isGlobal() && inClass) { mv.visitFieldInsn(GETFIELD, fullPath, node.getObj().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObj().symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ALOAD, node.getObj().getAddress()); } if (node.getType() == DijkstraType.INT) { mv.visitFieldInsn(GETFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "J"); } else if (node.getType() == DijkstraType.FLOAT) { mv.visitFieldInsn(GETFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "D"); } else if (node.getType() == DijkstraType.BOOLEAN) { mv.visitFieldInsn(GETFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "Z"); } else { mv.visitFieldInsn(GETFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObj().symbol).getObjectType() + ";"); } } else { if (node.getType() == DijkstraType.INT) { mv.visitFieldInsn(PUTFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "J"); } else if (node.getType() == DijkstraType.FLOAT) { mv.visitFieldInsn(PUTFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "D"); } else if (node.getType() == DijkstraType.BOOLEAN) { mv.visitFieldInsn(PUTFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "Z"); } else { mv.visitFieldInsn(PUTFIELD, classPackage + "/" + objectType, node.getAttribute().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObj().symbol).getObjectType() + ";"); } } return null; } public byte[] visit(VariableDeclarationNode decl) { if (!mvStack.isEmpty() && !processingClassFields) { final MethodVisitor mv = mvStack.peek(); for (IDNode id : decl.getIdList()) { if (id.getType() == DijkstraType.INT) { mv.visitLdcInsn(new Long(0)); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "J"); } else { mv.visitVarInsn(LSTORE, id.getAddress()); } } else if (id.getType() == DijkstraType.FLOAT) { mv.visitLdcInsn(new Double(0)); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "D"); } else { mv.visitVarInsn(DSTORE, id.getAddress()); } } else if (id.getType() == DijkstraType.BOOLEAN) { // boolean mv.visitInsn(ICONST_0); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "Z"); } else { mv.visitVarInsn(ISTORE, id.getAddress()); } } } } else if (processingClassFields) { final MethodVisitor mv = mvStack.peek(); } return null; } public byte[] visit(ArrayDeclarationNode decl) { if (!mvStack.isEmpty() && !processingClassFields) { final MethodVisitor mv = mvStack.peek(); for (IDNode id : decl.getIdList()) { decl.arrayLength.accept(this); if (decl.arrayLength.type == DijkstraType.INT) { mv.visitInsn(L2I); } else { mv.visitInsn(D2I); } ArraySymbol symbol = ((ArraySymbol) id.symbol); if (id.symbol.isGlobal()) { if (symbol.getArrayType() == DijkstraType.INT) { mv.visitIntInsn(NEWARRAY, T_LONG); mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "[J"); } else if (symbol.getArrayType() == DijkstraType.FLOAT) { mv.visitIntInsn(NEWARRAY, T_DOUBLE); mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "[D"); } else if (symbol.getArrayType() == DijkstraType.BOOLEAN) { mv.visitIntInsn(NEWARRAY, T_BOOLEAN); mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "[Z"); } } else { if (symbol.getArrayType() == DijkstraType.INT) { mv.visitIntInsn(NEWARRAY, T_LONG); mv.visitVarInsn(ASTORE, id.getAddress()); } else if (symbol.getArrayType() == DijkstraType.FLOAT) { mv.visitIntInsn(NEWARRAY, T_DOUBLE); mv.visitVarInsn(ASTORE, id.getAddress()); } else if (symbol.getArrayType() == DijkstraType.BOOLEAN) { // boolean mv.visitIntInsn(NEWARRAY, T_BOOLEAN); mv.visitVarInsn(ASTORE, id.getAddress()); } } } } else if (processingClassFields) { final MethodVisitor mv = mvStack.peek(); for (IDNode id : decl.getIdList()) { mv.visitVarInsn(ALOAD, 0); decl.arrayLength.accept(this); if (decl.arrayLength.type == DijkstraType.INT) { mv.visitInsn(L2I); } else { mv.visitInsn(D2I); } ArraySymbol symbol = ((ArraySymbol) id.symbol); if (symbol.getArrayType() == DijkstraType.INT) { mv.visitIntInsn(NEWARRAY, T_LONG); mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "[J"); } else if (symbol.getArrayType() == DijkstraType.FLOAT) { mv.visitIntInsn(NEWARRAY, T_DOUBLE); mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "[D"); } else if (symbol.getArrayType() == DijkstraType.BOOLEAN) { mv.visitIntInsn(NEWARRAY, T_BOOLEAN); mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "[Z"); } } } return null; } /** * Call the runtime input for the ID and then store the result in the * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.InputNode) */ public byte[] visit(InputNode input) { final MethodVisitor mv = mvStack.peek(); for (IDNode id : input.getIDs()) { mv.visitLdcInsn(id.token.getText()); // Name of the variable if (id.getType() == DijkstraType.INT) { mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "inputLong", "(Ljava/lang/String;)J", false); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "J"); } else { mv.visitVarInsn(LSTORE, id.getAddress()); } } else if (id.getType() == DijkstraType.FLOAT) { mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "inputDouble", "(Ljava/lang/String;)D", false); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "D"); } else { mv.visitVarInsn(DSTORE, id.getAddress()); } } else { mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "inputBoolean", "(Ljava/lang/String;)Z", false); if (id.symbol.isGlobal()) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "Z"); } else { mv.visitVarInsn(ISTORE, id.getAddress()); } } } return null; } /** * Get the expression onto the stack and then call the runtime print * routine. * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.OutputNode) */ public byte[] visit(OutputNode output) { final MethodVisitor mv = mvStack.peek(); output.getExpression().accept(this); // TOS = expression value if (output.getType() == DijkstraType.INT) { mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "printLong", "(J)V", false); } else if (output.getType() == DijkstraType.FLOAT) { mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "printDouble", "(D)V", false); } else { // Boolean mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "printBoolean", "(Z)V", false); } return null; } public byte[] visit(ArrayAccessorNode arrayAccessor) { final MethodVisitor mv = mvStack.peek(); final DijkstraType arrayType = ((ArraySymbol) arrayAccessor.getId().symbol).getArrayType(); if (reading) { if (arrayAccessor.getId().symbol.isGlobal() && !inClass) { if (arrayType == DijkstraType.INT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrayAccessor.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrayAccessor.getId().getName(), "[D"); } else { mv.visitFieldInsn(GETSTATIC, fullPath, arrayAccessor.getId().getName(), "[Z"); } } else if (arrayAccessor.getId().symbol.isGlobal() && inClass) { if (arrayType == DijkstraType.INT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrayAccessor.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrayAccessor.getId().getName(), "[D"); } else { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrayAccessor.getId().getName(), "[Z"); } } else { mv.visitVarInsn(ALOAD, arrayAccessor.getId().getAddress()); } arrayAccessor.getExpression().accept(this); if (arrayAccessor.getExpression().getType() == DijkstraType.FLOAT) { mv.visitInsn(D2I); } else { mv.visitInsn(L2I); } if (arrayType == DijkstraType.INT) { mv.visitInsn(LALOAD); } else if (arrayType == DijkstraType.FLOAT) { mv.visitInsn(DALOAD); } else { mv.visitInsn(BALOAD); } } else { if (arrayType == DijkstraType.INT) { mv.visitInsn(LASTORE); } else if (arrayType == DijkstraType.FLOAT) { mv.visitInsn(DASTORE); } else { mv.visitInsn(BASTORE); } } return null; } public byte[] visit(AssignNode assign) { final MethodVisitor mv = mvStack.peek(); if (assign.getVar() instanceof ArrayAccessorNode) { final ArrayAccessorNode arrAcc = ((ArrayAccessorNode) assign.getVar()); // Load the pointer to the array final DijkstraType arrayType = ((ArraySymbol) arrAcc.getId().symbol).getArrayType(); if (arrAcc.getId().symbol.isGlobal()) { if (arrayType == DijkstraType.INT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[Z"); } } else if (arrAcc.getId().symbol.isGlobal() && inClass) { if (arrayType == DijkstraType.INT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[Z"); } } else { mv.visitVarInsn(ALOAD, arrAcc.getId().getAddress()); } // Visit the array accessor expression so we know what index we're getting arrAcc.getExpression().accept(this); // Convert the expression type to an int if (arrAcc.getExpression().getType() == DijkstraType.INT) { mv.visitInsn(L2I); } else { mv.visitInsn(D2I); } } else if (assign.getVar() instanceof AttributeNode) { if (((AttributeNode) assign.getVar()).getObj().symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, ((AttributeNode) assign.getVar()).getObj().getName(), "L" + classPackage + "/" + ((ObjectSymbol) ((AttributeNode) assign.getVar()).getObj().symbol).getObjectType() + ";"); } else if (((AttributeNode) assign.getVar()).getObj().symbol.isGlobal() && inClass) { mv.visitFieldInsn(GETFIELD, fullPath, ((AttributeNode) assign.getVar()).getObj().getName(), "L" + classPackage + "/" + ((ObjectSymbol) ((AttributeNode) assign.getVar()).getObj().symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ALOAD, ((AttributeNode) assign.getVar()).getObj().getAddress()); } // mv.visitVarInsn(ALOAD, ((AttributeNode)assign.getVar()).getObj().getAddress()); } assign.getExpression().accept(this); // TOS = expression value reading = false; if (assign.getType() == DijkstraType.INT) { if (assign.getExpression().getType() == DijkstraType.FLOAT) { mv.visitInsn(D2L); } assign.getVar().accept(this); } else if (assign.getType() == DijkstraType.FLOAT) { if (assign.getExpression().getType() == DijkstraType.INT) { mv.visitInsn(L2D); } assign.getVar().accept(this); } else if (assign.getType() == DijkstraType.BOOLEAN) { assign.getVar().accept(this); } else { assign.getVar().accept(this); // mv.visitVarInsn(ASTORE, ((IDNode)assign.getVar()).getAddress()); } reading = true; return null; } public byte[] visit(AssignListNode assignList) { final MethodVisitor mv = mvStack.peek(); final List<ASTNode> ids = assignList.getVarList(); final List<ASTNode> exprs = assignList.getExpressionList(); for (int exprsArrayIndex = 0, idsArrayIndex = 0; exprsArrayIndex < exprs .size(); idsArrayIndex++, exprsArrayIndex++) { if (ids.get(idsArrayIndex) instanceof ArrayAccessorNode) { ArrayAccessorNode arrAcc = ((ArrayAccessorNode) ids.get(idsArrayIndex)); // Load the pointer to the array final DijkstraType arrayType = ((ArraySymbol) arrAcc.getId().symbol).getArrayType(); if (arrAcc.getId().symbol.isGlobal()) { if (arrayType == DijkstraType.INT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[Z"); } } else if (arrAcc.getId().symbol.isGlobal() && inClass) { if (arrayType == DijkstraType.INT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[Z"); } } else { mv.visitVarInsn(ALOAD, arrAcc.getId().getAddress()); } // Visit the array accessor expression so we know what index we're getting arrAcc.getExpression().accept(this); // Convert the expression type to an int if (arrAcc.getExpression().getType() == DijkstraType.INT) { mv.visitInsn(L2I); } else { mv.visitInsn(D2I); } } else if (ids.get(idsArrayIndex) instanceof AttributeNode) { IDNode node = ((AttributeNode) ids.get(idsArrayIndex)).getObj(); if (node.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, node.getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.symbol).getObjectType() + ";"); } else if (node.symbol.isGlobal() && inClass) { mv.visitFieldInsn(GETFIELD, fullPath, node.getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ALOAD, node.getAddress()); } // mv.visitVarInsn(ALOAD, ((AttributeNode)ids.get(idsArrayIndex)).getObj().getAddress()); } exprs.get(exprsArrayIndex).accept(this); if (exprs.get(exprsArrayIndex).nodeType == ASTNodeType.FUNCALL) { List<DijkstraType> returnTypes = ((FunctionSymbol) ((FunctionCallNode) exprs.get(exprsArrayIndex)) .getId().symbol).getReturnTypes(); Stack<Symbol> returnValues = new Stack<Symbol>(); for (int i = returnTypes.size() - 1; i > 0; i--) { returnValues.push(new Symbol(null, UNDEFINED)); if (returnTypes.get(i) == DijkstraType.INT) { mv.visitVarInsn(LSTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } else if (returnTypes.get(i) == DijkstraType.FLOAT) { mv.visitVarInsn(DSTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } else { // boolean mv.visitVarInsn(ISTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } } for (int i = 1; i < returnTypes.size(); i++) { idsArrayIndex++; if (ids.get(idsArrayIndex) instanceof ArrayAccessorNode) { ArrayAccessorNode arrAcc = ((ArrayAccessorNode) ids.get(idsArrayIndex)); // Load the pointer to the array final DijkstraType arrayType = ((ArraySymbol) arrAcc.getId().symbol).getArrayType(); if (arrAcc.getId().symbol.isGlobal()) { if (arrayType == DijkstraType.INT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitFieldInsn(GETSTATIC, fullPath, arrAcc.getId().getName(), "[Z"); } } else if (arrAcc.getId().symbol.isGlobal() && inClass) { if (arrayType == DijkstraType.INT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[J"); } else if (arrayType == DijkstraType.FLOAT) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[D"); } else { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, arrAcc.getId().getName(), "[Z"); } } else { mv.visitVarInsn(ALOAD, arrAcc.getId().getAddress()); } // Visit the array accessor expression so we know what index we're getting arrAcc.getExpression().accept(this); // Convert the expression type to an int if (arrAcc.getExpression().getType() == DijkstraType.INT) { mv.visitInsn(L2I); } else { mv.visitInsn(D2I); } } if (returnTypes.get(i) == DijkstraType.INT) { mv.visitVarInsn(LLOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); } else if (returnTypes.get(i) == DijkstraType.FLOAT) { mv.visitVarInsn(DLOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); } else { // boolean mv.visitVarInsn(ILOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); } returnValues.pop(); } } } // Pop them off an assign them in order reading = false; final List<DijkstraType> exprTypes = getExpressionListTypes(assignList.getExpressionList()); for (int i = ids.size() - 1; i >= 0; i--) { final DijkstraType idType; if (ids.get(i) instanceof ArrayAccessorNode) { idType = ((ArraySymbol) ((ArrayAccessorNode) ids.get(i)).getId().symbol).getArrayType(); } else { idType = ids.get(i).getType(); } DijkstraType exprType = exprTypes.get(i); if (idType == DijkstraType.INT) { if (exprType == DijkstraType.FLOAT) { mv.visitInsn(D2L); } } else if (idType == DijkstraType.FLOAT) { if (exprType == DijkstraType.INT) { mv.visitInsn(L2D); } } ids.get(i).accept(this); } reading = true; return null; } /** * Helper function for visit methods that deal with expression lists. * Takes a list of expressions and identifies the number of values it evaluates to. * (Expands functions with multiple returns to get the real number of values returned) * @param expressions The list of expressions to count * @return The number of values in the expression list */ private List<DijkstraType> getExpressionListTypes(List<ASTNode> expressions) { List<DijkstraType> types = new ArrayList<DijkstraType>(); for (ASTNode expr : expressions) { if (expr.nodeType == FUNCALL) { FunctionCallNode fd = (FunctionCallNode) expr; types.addAll(((FunctionSymbol) fd.getId().symbol).getReturnTypes()); } else if (expr.nodeType == ASTNodeType.METHODCALL) { MethodCallNode fd = (MethodCallNode) expr; types.addAll(((FunctionSymbol) fd.getId().symbol).getReturnTypes()); } else { types.add(expr.getType()); } } return types; } public byte[] visit(AlternativeNode alternative) { final MethodVisitor mv = mvStack.peek(); final Label endLabel = new Label(); guardLabelStack.push(endLabel); visitChildren(alternative); guardLabelStack.pop(); mv.visitIntInsn(BIPUSH, alternative.getLineNumber()); mv.visitMethodInsn(INVOKESTATIC, "dijkstra/runtime/DijkstraRuntime", "abortNoAlternative", "(I)V", false); mv.visitLabel(endLabel); return null; } public byte[] visit(IterativeNode iterator) { final MethodVisitor mv = mvStack.peek(); final Label startLabel = new Label(); guardLabelStack.push(startLabel); mv.visitLabel(startLabel); visitChildren(iterator); guardLabelStack.pop(); return null; } public byte[] visit(GuardNode guard) { final MethodVisitor mv = mvStack.peek(); final Label failLabel = new Label(); guard.getExpression().accept(this); mv.visitJumpInsn(IFEQ, failLabel); guard.getStatement().accept(this); mv.visitJumpInsn(GOTO, guardLabelStack.peek()); mv.visitLabel(failLabel); return null; } /** * Evaluate the child expression and then negate it (logical or arithmetic). Logical * negation is more difficult because there is no logical negate instruction in the * JVM instruction set. * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.UnaryExpressionNode) */ public byte[] visit(UnaryExpressionNode unary) { final MethodVisitor mv = mvStack.peek(); visitChildren(unary); // Evaluate the expression // TOS = the child expression if (unary.type == DijkstraType.INT) { mv.visitInsn(LNEG); } else if (unary.type == DijkstraType.FLOAT) { mv.visitInsn(DNEG); } else { // Boolean ~ final Label l1 = new Label(); final Label l2 = new Label(); mv.visitJumpInsn(IFEQ, l1); mv.visitInsn(ICONST_0); // true -> false mv.visitJumpInsn(GOTO, l2); mv.visitLabel(l1); mv.visitInsn(ICONST_1); // false -> true mv.visitLabel(l2); } return null; } /** * Get the values of the left and right children on the stack and then perform * the operation. * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.BinaryExpressionNode) */ public byte[] visit(BinaryExpressionNode binary) { final MethodVisitor mv = mvStack.peek(); DijkstraType childOneType = binary.getExpr1().getType(); if (childOneType == DijkstraType.ARRAY) { childOneType = ((ArraySymbol) ((ArrayAccessorNode) binary.getExpr1()).getId().symbol).getArrayType(); } DijkstraType childTwoType = binary.getExpr2().getType(); if (childTwoType == DijkstraType.ARRAY) { childTwoType = ((ArraySymbol) ((ArrayAccessorNode) binary.getExpr2()).getId().symbol).getArrayType(); } Label lab1, lab2; if (binary.getOp() == DijkstraParser.AMP) { lab1 = new Label(); lab2 = new Label(); binary.getExpr1().accept(this); mv.visitJumpInsn(IFEQ, lab1); binary.getExpr2().accept(this); mv.visitJumpInsn(IFEQ, lab1); mv.visitInsn(ICONST_1); mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); mv.visitLabel(lab2); } else if (binary.getOp() == DijkstraParser.PIPE) { lab1 = new Label(); lab2 = new Label(); binary.getExpr1().accept(this); mv.visitJumpInsn(IFNE, lab1); binary.getExpr2().accept(this); mv.visitJumpInsn(IFNE, lab1); mv.visitInsn(ICONST_0); mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_1); mv.visitLabel(lab2); } else { binary.getExpr1().accept(this); if ((childOneType == DijkstraType.INT && childTwoType == DijkstraType.FLOAT) || (binary.getOp() == DijkstraParser.SLASH && childOneType == DijkstraType.INT)) { mv.visitInsn(L2D); } binary.getExpr2().accept(this); if ((childOneType == DijkstraType.FLOAT && childTwoType == DijkstraType.INT) || (binary.getOp() == DijkstraParser.SLASH && childTwoType == DijkstraType.INT)) { mv.visitInsn(L2D); } switch (binary.getOp()) { case DijkstraParser.LT: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); } else { mv.visitInsn(DCMPL); } mv.visitJumpInsn(IFGE, lab1); mv.visitInsn(ICONST_1); // left < right mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); // right >= left mv.visitLabel(lab2); break; case DijkstraParser.LTEQ: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); } else { mv.visitInsn(DCMPL); } mv.visitJumpInsn(IFGT, lab1); mv.visitInsn(ICONST_1); // left <= right mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); // right > left mv.visitLabel(lab2); break; case DijkstraParser.GT: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); } else { mv.visitInsn(DCMPL); } mv.visitJumpInsn(IFLE, lab1); mv.visitInsn(ICONST_1); // left > right mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); // right <= left mv.visitLabel(lab2); break; case DijkstraParser.GTEQ: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); } else { mv.visitInsn(DCMPL); } mv.visitJumpInsn(IFLT, lab1); mv.visitInsn(ICONST_1); // left >= right mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); // right < left mv.visitLabel(lab2); break; case DijkstraParser.PLUS: if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LADD); } else { mv.visitInsn(DADD); } break; case DijkstraParser.MINUS: if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LSUB); } else { mv.visitInsn(DSUB); } break; case DijkstraParser.STAR: if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LMUL); } else { mv.visitInsn(DMUL); } break; case DijkstraParser.SLASH: mv.visitInsn(DDIV); break; case DijkstraParser.MOD: mv.visitInsn(LREM); break; case DijkstraParser.DIV: mv.visitInsn(LDIV); break; case DijkstraParser.EQ: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); mv.visitJumpInsn(IFNE, lab1); } else if (childOneType == DijkstraType.BOOLEAN) { mv.visitJumpInsn(IF_ICMPNE, lab1); } else { mv.visitInsn(DCMPL); mv.visitJumpInsn(IFNE, lab1); } mv.visitInsn(ICONST_1); mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); mv.visitLabel(lab2); break; case DijkstraParser.NEQ: lab1 = new Label(); lab2 = new Label(); if (childOneType == DijkstraType.INT && childTwoType == DijkstraType.INT) { mv.visitInsn(LCMP); mv.visitJumpInsn(IFEQ, lab1); } else if (childOneType == DijkstraType.BOOLEAN) { mv.visitJumpInsn(IF_ICMPEQ, lab1); } else { mv.visitInsn(DCMPL); mv.visitJumpInsn(IFEQ, lab1); } mv.visitInsn(ICONST_1); // left != right mv.visitJumpInsn(GOTO, lab2); mv.visitLabel(lab1); mv.visitInsn(ICONST_0); // left = right mv.visitLabel(lab2); break; } } return null; } public byte[] visit(ProcedureDeclarationNode procDeclNode) { if (processingClassFields) { return null; } final String methodName = procDeclNode.getIDNode().getName(); final StringBuilder sig = new StringBuilder(); sig.append('('); for (IDNode param : procDeclNode.getParamList()) { if (param.getType() == DijkstraType.INT) { sig.append('J'); } else if (param.getType() == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } sig.append(")V"); if (inClass) { mvStack.push(cw.visitMethod(ACC_PUBLIC, methodName, sig.toString(), null, null)); } else { mvStack.push(cw.visitMethod(ACC_PUBLIC + ACC_STATIC, methodName, sig.toString(), null, null)); } final MethodVisitor mv = mvStack.peek(); JVMInfo.enterScope(inClass); // Load the parameters into the JVMInfo so it knows the proper addresses for (IDNode param : procDeclNode.getParamList()) { param.getAddress(); } mv.visitCode(); final Label startLabel = new Label(); mv.visitLabel(startLabel); procDeclNode.getCompoundNode().accept(this); mv.visitInsn(RETURN); final Label endLabel = new Label(); mv.visitLabel(endLabel); int paramLoc = 0; for (IDNode param : procDeclNode.getParamList()) { if (param.getType() == DijkstraType.INT) { mv.visitLocalVariable(param.getName(), "J", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else if (param.getType() == DijkstraType.FLOAT) { mv.visitLocalVariable(param.getName(), "D", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else { mv.visitLocalVariable(param.getName(), "Z", null, startLabel, endLabel, paramLoc); paramLoc += 1; } } mv.visitMaxs(0, 0); mv.visitEnd(); JVMInfo.exitScope(); mvStack.pop(); return null; } public byte[] visit(MethodCallNode node) { final MethodVisitor mv = mvStack.peek(); final String objectType = ((ObjectSymbol) node.getObjectId().symbol).getObjectType(); final StringBuilder sig = new StringBuilder(); sig.append('('); List<Symbol> propertySymbols; if (node.getId().symbol.getType() == DijkstraType.PROCEDURE) { propertySymbols = ((ProcedureSymbol) node.getId().symbol).getParamSymbols(); } else { propertySymbols = ((FunctionSymbol) node.getId().symbol).getParamSymbols(); } for (Symbol property : propertySymbols) { if (property.getType() == DijkstraType.INT) { sig.append('J'); } else if (property.getType() == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } if (node.getId().symbol.getType() == FUNCTION) { sig.append(")[Ljava/lang/Object;"); } else { sig.append(")V"); } if (node.getObjectId().symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, node.getObjectId().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObjectId().symbol).getObjectType() + ";"); } else if (node.getObjectId().symbol.isGlobal() && inClass) { mv.visitFieldInsn(GETFIELD, fullPath, node.getObjectId().getName(), "L" + classPackage + "/" + ((ObjectSymbol) node.getObjectId().symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ALOAD, node.getObjectId().getAddress()); } int paramIndex = 0; for (ASTNode arg : node.getArgs()) { arg.accept(this); if (arg.nodeType == FUNCALL) { paramIndex += ((FunctionSymbol) ((FunctionCallNode) arg).getId().symbol).getReturnTypes().size() - 1; } else if (propertySymbols.get(paramIndex).getType() == DijkstraType.INT && arg.getType() == DijkstraType.FLOAT) { mv.visitInsn(D2L); } else if (propertySymbols.get(paramIndex).getType() == DijkstraType.FLOAT && arg.getType() == DijkstraType.INT) { mv.visitInsn(L2D); } paramIndex++; } // mv.visitVarInsn(ALOAD, node.getObjectId().getAddress()) mv.visitMethodInsn(INVOKEVIRTUAL, classPackage + "/" + objectType, node.getId().getName(), sig.toString(), false); if (node.getId().symbol.getType() == FUNCTION) { final FunctionSymbol fSymbol = ((FunctionSymbol) node.getId().symbol); returnArrayStack.push(new ArraySymbol(null, UNDEFINED)); mv.visitVarInsn(ASTORE, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); for (int i = 0; i < fSymbol.getReturnTypes().size(); i++) { // Load the only element in the array and put it on the stack mv.visitVarInsn(ALOAD, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); mv.visitIntInsn(SIPUSH, i); mv.visitInsn(AALOAD); DijkstraType retType = fSymbol.getReturnTypes().get(i); if (retType == DijkstraType.INT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); } else if (retType == DijkstraType.FLOAT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); } else { mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); } } returnArrayStack.pop(); } return null; } public byte[] visit(ProcedureCallNode procCallNode) { final MethodVisitor mv = mvStack.peek(); final String methodName = procCallNode.getId().getName(); final StringBuilder sig = new StringBuilder(); final List<Symbol> params = ((ProcedureSymbol) procCallNode.getId().symbol).getParamSymbols(); final List<ASTNode> args = procCallNode.getArgs(); sig.append('('); for (int i = 0; i < params.size(); i++) { DijkstraType paramType = params.get(i).getType(); if (paramType == DijkstraType.INT) { sig.append('J'); } else if (paramType == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } int paramIndex = 0; for (ASTNode arg : args) { arg.accept(this); if (arg.nodeType == FUNCALL) { paramIndex += ((FunctionSymbol) ((FunctionCallNode) arg).getId().symbol).getReturnTypes().size() - 1; } else if (params.get(paramIndex).getType() == DijkstraType.INT && arg.getType() == DijkstraType.FLOAT) { mv.visitInsn(D2L); } else if (params.get(paramIndex).getType() == DijkstraType.FLOAT && arg.getType() == DijkstraType.INT) { mv.visitInsn(L2D); } paramIndex++; } sig.append(")V"); mv.visitMethodInsn(INVOKESTATIC, classPackage + "/" + programName, methodName, sig.toString(), false); return null; } public byte[] visit(FunctionDeclarationNode funDeclNode) { if (processingClassFields) { return null; } final String methodName = funDeclNode.getIDNode().getName(); final StringBuilder sig = new StringBuilder(); sig.append('('); for (IDNode param : funDeclNode.getParamList()) { if (param.getType() == DijkstraType.INT) { sig.append('J'); } else if (param.getType() == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } sig.append(')'); sig.append("[Ljava/lang/Object;"); if (inClass) { mvStack.push(cw.visitMethod(ACC_PUBLIC, methodName, sig.toString(), null, null)); } else { mvStack.push(cw.visitMethod(ACC_PUBLIC + ACC_STATIC, methodName, sig.toString(), null, null)); } final MethodVisitor mv = mvStack.peek(); JVMInfo.enterScope(inClass); // Load the parameters into the JVMInfo so it knows the proper addresses for (IDNode param : funDeclNode.getParamList()) { param.getAddress(); } mv.visitIntInsn(SIPUSH, funDeclNode.getReturnTypes().size()); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); returnArrayStack.push(new ArraySymbol(null, UNDEFINED)); mv.visitVarInsn(ASTORE, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); mv.visitInsn(ICONST_0); returnIndexStack.push(new Symbol(null, UNDEFINED)); mv.visitVarInsn(ISTORE, JVMInfo.getAddressForSymbol(returnIndexStack.peek())); mv.visitCode(); final Label startLabel = new Label(); mv.visitLabel(startLabel); funDeclNode.getCompoundNode().accept(this); returnIndexStack.pop(); mv.visitVarInsn(ALOAD, JVMInfo.getAddressForSymbol(returnArrayStack.pop())); mv.visitInsn(ARETURN); final Label endLabel = new Label(); mv.visitLabel(endLabel); int paramLoc = 0; for (IDNode param : funDeclNode.getParamList()) { if (param.getType() == DijkstraType.INT) { mv.visitLocalVariable(param.getName(), "J", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else if (param.getType() == DijkstraType.FLOAT) { mv.visitLocalVariable(param.getName(), "D", null, startLabel, endLabel, paramLoc); paramLoc += 2; } else { mv.visitLocalVariable(param.getName(), "Z", null, startLabel, endLabel, paramLoc); paramLoc += 1; } } mv.visitMaxs(0, 0); mv.visitEnd(); JVMInfo.exitScope(); mvStack.pop(); return null; } public byte[] visit(FunctionCallNode funCallNode) { final MethodVisitor mv = mvStack.peek(); final String methodName = funCallNode.getId().getName(); final StringBuilder sig = new StringBuilder(); if (funCallNode.getId().symbol instanceof FunctionSymbol) { final FunctionSymbol fSymbol = ((FunctionSymbol) funCallNode.getId().symbol); final List<Symbol> params = fSymbol.getParamSymbols(); final List<ASTNode> args = funCallNode.getArgs(); sig.append('('); for (int i = 0; i < params.size(); i++) { DijkstraType paramType = params.get(i).getType(); if (paramType == DijkstraType.INT) { sig.append('J'); } else if (paramType == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } int paramIndex = 0; for (ASTNode arg : args) { arg.accept(this); if (arg.nodeType == FUNCALL) { paramIndex += ((FunctionSymbol) ((FunctionCallNode) arg).getId().symbol).getReturnTypes().size() - 1; } else if (params.get(paramIndex).getType() == DijkstraType.INT && arg.getType() == DijkstraType.FLOAT) { mv.visitInsn(D2L); } else if (params.get(paramIndex).getType() == DijkstraType.FLOAT && arg.getType() == DijkstraType.INT) { mv.visitInsn(L2D); } paramIndex++; } sig.append(')'); sig.append("[Ljava/lang/Object;"); mv.visitMethodInsn(INVOKESTATIC, classPackage + "/" + programName, methodName, sig.toString(), false); returnArrayStack.push(new ArraySymbol(null, UNDEFINED)); mv.visitVarInsn(ASTORE, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); for (int i = 0; i < fSymbol.getReturnTypes().size(); i++) { // Load the only element in the array and put it on the stack mv.visitVarInsn(ALOAD, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); mv.visitIntInsn(SIPUSH, i); mv.visitInsn(AALOAD); DijkstraType retType = fSymbol.getReturnTypes().get(i); if (retType == DijkstraType.INT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); } else if (retType == DijkstraType.FLOAT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); } else { mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); } } returnArrayStack.pop(); } else { final ClassSymbol cSymbol = ((ClassSymbol) funCallNode.getId().symbol); final List<Symbol> properties = cSymbol.getPropertySymbols(); final List<ASTNode> args = funCallNode.getArgs(); mv.visitTypeInsn(NEW, classPackage + "/" + cSymbol.getId()); mv.visitInsn(DUP); sig.append('('); for (int i = 0; i < properties.size(); i++) { DijkstraType paramType = properties.get(i).getType(); if (paramType == DijkstraType.INT) { sig.append('J'); } else if (paramType == DijkstraType.FLOAT) { sig.append('D'); } else { sig.append('Z'); } } int paramIndex = 0; for (ASTNode arg : args) { arg.accept(this); if (arg.nodeType == FUNCALL) { paramIndex += ((FunctionSymbol) ((FunctionCallNode) arg).getId().symbol).getReturnTypes().size() - 1; } else if (properties.get(paramIndex).getType() == DijkstraType.INT && arg.getType() == DijkstraType.FLOAT) { mv.visitInsn(D2L); } else if (properties.get(paramIndex).getType() == DijkstraType.FLOAT && arg.getType() == DijkstraType.INT) { mv.visitInsn(L2D); } paramIndex++; } sig.append(')'); sig.append('V'); mv.visitMethodInsn(INVOKESPECIAL, classPackage + "/" + cSymbol.getId(), "<init>", sig.toString(), false); } return null; } public byte[] visit(ReturnNode returnNode) { final MethodVisitor mv = mvStack.peek(); for (ASTNode child : returnNode.children) { mv.visitVarInsn(ALOAD, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); // What index are we storing it in int indexAddr = JVMInfo.getAddressForSymbol(returnIndexStack.peek()); mv.visitVarInsn(ILOAD, indexAddr); child.accept(this); if (child.nodeType == FUNCALL) { final List<DijkstraType> returnTypes = ((FunctionSymbol) ((FunctionCallNode) child).getId().symbol) .getReturnTypes(); final Stack<Symbol> returnValues = new Stack<Symbol>(); for (int i = returnTypes.size() - 1; i >= 0; i--) { returnValues.push(new Symbol(null, UNDEFINED)); if (returnTypes.get(i) == DijkstraType.INT) { mv.visitVarInsn(LSTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } else if (returnTypes.get(i) == DijkstraType.FLOAT) { mv.visitVarInsn(DSTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } else { // boolean mv.visitVarInsn(ISTORE, JVMInfo.getAddressForSymbol(returnValues.peek())); } } for (int i = 0; i < returnTypes.size(); i++) { // Load the pointer to the array mv.visitVarInsn(ALOAD, JVMInfo.getAddressForSymbol(returnArrayStack.peek())); mv.visitIntInsn(SIPUSH, i); if (returnTypes.get(i) == DijkstraType.INT) { mv.visitVarInsn(LLOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); } else if (returnTypes.get(i) == DijkstraType.FLOAT) { mv.visitVarInsn(DLOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); } else { // boolean mv.visitVarInsn(ILOAD, JVMInfo.getAddressForSymbol(returnValues.peek())); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); } mv.visitInsn(AASTORE); // Increment the return index mv.visitIincInsn(indexAddr, 1); returnValues.pop(); } } else { DijkstraType retType = child.getType(); if (retType == DijkstraType.INT) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); } else if (retType == DijkstraType.FLOAT) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); } else { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); } mv.visitInsn(AASTORE); // Increment the return index mv.visitIincInsn(indexAddr, 1); } } return null; } /** * Simply load the constant value onto the stack. * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.ConstantNode) */ public byte[] visit(ConstantNode constant) { final MethodVisitor mv = mvStack.peek(); if (constant.getType() == DijkstraType.INT) { final Long l = Long.parseLong(constant.token.getText()); mv.visitLdcInsn(l); } else if (constant.getType() == DijkstraType.FLOAT) { final Double d = Double.parseDouble(constant.token.getText()); mv.visitLdcInsn(d); } else { // boolean if (constant.token.getText().equals("true")) { mv.visitInsn(ICONST_1); } else { mv.visitInsn(ICONST_0); } } return null; } /** * When visiting an ID node, we want the value of the ID on the top of stack * @see dijkstra.ast.ASTVisitor#visit(dijkstra.ast.ASTNodeFactory.IDNode) */ public byte[] visit(IDNode id) { final MethodVisitor mv = mvStack.peek(); if (reading) { if (id.getType() == DijkstraType.INT) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, id.getName(), "J"); } else if (id.symbol.isGlobal() && inClass) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, id.getName(), "J"); } else { mv.visitVarInsn(LLOAD, id.getAddress()); } } else if (id.getType() == DijkstraType.FLOAT) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, id.getName(), "D"); } else if (id.symbol.isGlobal() && inClass) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, id.getName(), "D"); } else { mv.visitVarInsn(DLOAD, id.getAddress()); } } else if (id.getType() == DijkstraType.BOOLEAN) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, id.getName(), "Z"); } else if (id.symbol.isGlobal() && inClass) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, id.getName(), "Z"); } else { mv.visitVarInsn(ILOAD, id.getAddress()); } } else { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(GETSTATIC, fullPath, id.getName(), "L" + classPackage + "/" + ((ObjectSymbol) id.symbol).getObjectType() + ";"); } else if (id.symbol.isGlobal() && inClass) { mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, fullPath, id.getName(), "L" + classPackage + "/" + ((ObjectSymbol) id.symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ALOAD, id.getAddress()); } } } else { if (id.getType() == DijkstraType.INT) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "J"); } else if (id.symbol.isGlobal() && inClass) { mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "J"); } else { mv.visitVarInsn(LSTORE, id.getAddress()); } } else if (id.getType() == DijkstraType.FLOAT) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "D"); } else if (id.symbol.isGlobal() && inClass) { mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "D"); } else { mv.visitVarInsn(DSTORE, id.getAddress()); } } else if (id.getType() == DijkstraType.BOOLEAN) { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "Z"); } else if (id.symbol.isGlobal() && inClass) { mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "Z"); } else { mv.visitVarInsn(ISTORE, id.getAddress()); } } else { if (id.symbol.isGlobal() && !inClass) { mv.visitFieldInsn(PUTSTATIC, fullPath, id.getName(), "L" + classPackage + "/" + ((ObjectSymbol) id.symbol).getObjectType() + ";"); } else if (id.symbol.isGlobal() && inClass) { mv.visitFieldInsn(PUTFIELD, fullPath, id.getName(), "L" + classPackage + "/" + ((ObjectSymbol) id.symbol).getObjectType() + ";"); } else { mv.visitVarInsn(ASTORE, id.getAddress()); } } } return null; } //------------------------ Helper methods ----------------------------- public byte[] getByteCode() { return cw.toByteArray(); } /** * @param classPackage the classPackage to set */ public void setClassPackage(String classPackage) { this.classPackage = classPackage; } }