/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Whole Platform is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.examples.lang.imp.visitors; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.whole.examples.lang.imp.model.Addition; import org.whole.examples.lang.imp.model.And; import org.whole.examples.lang.imp.model.BooleanLiteral; import org.whole.examples.lang.imp.model.Division; import org.whole.examples.lang.imp.model.DoWhileStatement; import org.whole.examples.lang.imp.model.Equals; import org.whole.examples.lang.imp.model.ForStatement; import org.whole.examples.lang.imp.model.FunctionDeclaration; import org.whole.examples.lang.imp.model.GreaterOrEquals; import org.whole.examples.lang.imp.model.GreaterThan; import org.whole.examples.lang.imp.model.IfElseStatement; import org.whole.examples.lang.imp.model.IfStatement; import org.whole.examples.lang.imp.model.IntLiteral; import org.whole.examples.lang.imp.model.LessOrEquals; import org.whole.examples.lang.imp.model.LessThan; import org.whole.examples.lang.imp.model.Multiplication; import org.whole.examples.lang.imp.model.Name; import org.whole.examples.lang.imp.model.Not; import org.whole.examples.lang.imp.model.NotEquals; import org.whole.examples.lang.imp.model.Or; import org.whole.examples.lang.imp.model.PrintStatement; import org.whole.examples.lang.imp.model.PrintlnStatement; import org.whole.examples.lang.imp.model.ReturnStatement; import org.whole.examples.lang.imp.model.StringLiteral; import org.whole.examples.lang.imp.model.Subtraction; import org.whole.examples.lang.imp.model.WhileStatement; /** * @author Riccardo Solmi */ public class ImpBytecodeGeneratorVisitor extends ImpTraverseAllVisitor implements Opcodes { protected String name; protected int resultType = TYPE_V; public static final int TYPE_V = 0; public static final int TYPE_B = 1; public static final int TYPE_I = 2; public static final int TYPE_A = 3; public ImpBytecodeGeneratorVisitor(BytecodeGeneratorOperation operation) { setOperation(operation); } public BytecodeGeneratorOperation getOperation() { return (BytecodeGeneratorOperation) super.getOperation(); } protected ClassVisitor cv() { return getOperation().getClassVisitor(); } public MethodVisitor mv() { return getOperation().getMethodVisitor(); } public void setMethodVisitor(MethodVisitor methodVisitor) { getOperation().setMethodVisitor(methodVisitor); } public void visit(FunctionDeclaration entity) { entity.getType().accept(this); entity.getName().accept(this); entity.getParameters().accept(this); MethodVisitor mv = cv().visitMethod(ACC_PUBLIC, name, "()V", null, null); mv.visitCode(); setMethodVisitor(mv); entity.getBody().accept(this); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } public void visit(ReturnStatement entity) { resultType = TYPE_V; entity.getExp().accept(this); switch (resultType) { case TYPE_V: mv().visitInsn(RETURN); break; case TYPE_B: mv().visitInsn(IRETURN); break; case TYPE_I: mv().visitInsn(IRETURN); break; case TYPE_A: mv().visitInsn(ARETURN); break; } } public static String paramType(int resultType) { switch (resultType) { case TYPE_V: return ""; case TYPE_B: return "I"; case TYPE_I: return "I"; case TYPE_A: return "Ljava/lang/String;"; default: return ""; } } public void visit(IfStatement entity) { entity.getCondition().accept(this); Label iffalse = new Label(); mv().visitJumpInsn(IF_ICMPNE, iffalse); entity.getTrueBody().accept(this); mv().visitLabel(iffalse); } public void visit(IfElseStatement entity) { entity.getCondition().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPEQ, iftrue); entity.getFalseBody().accept(this); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); entity.getTrueBody().accept(this); mv().visitLabel(end); } public void visit(WhileStatement entity) { Label loop = new Label(); Label end = new Label(); mv().visitLabel(loop); entity.getCondition().accept(this); mv().visitJumpInsn(IF_ICMPNE, end); entity.getTrueBody().accept(this); mv().visitJumpInsn(GOTO, loop); mv().visitLabel(end); } public void visit(DoWhileStatement entity) { Label loop = new Label(); mv().visitLabel(loop); entity.getTrueBody().accept(this); entity.getCondition().accept(this); mv().visitJumpInsn(IF_ICMPEQ, loop); } public void visit(ForStatement entity) { entity.getInitializer().accept(this); Label loop = new Label(); Label end = new Label(); mv().visitLabel(loop); entity.getCondition().accept(this); mv().visitJumpInsn(IF_ICMPNE, end); entity.getTrueBody().accept(this); entity.getUpdater().accept(this); mv().visitJumpInsn(GOTO, loop); mv().visitLabel(end); } public void visit(PrintStatement entity) { mv().visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); entity.getExp().accept(this); mv().visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "("+paramType(resultType)+")V"); } public void visit(PrintlnStatement entity) { mv().visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); entity.getExp().accept(this); mv().visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "("+paramType(resultType)+")V"); } public void visit(BooleanLiteral entity) { mv().visitInsn(entity.wBooleanValue() ? ICONST_1 : ICONST_0); resultType = TYPE_B; } public void visit(IntLiteral entity) { mv().visitLdcInsn(new Integer(entity.wIntValue())); resultType = TYPE_I; } public void visit(StringLiteral entity) { mv().visitLdcInsn(entity.wStringValue()); resultType = TYPE_A; } public void visit(Name entity) { name = entity.getValue(); } public void visit(Addition entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); mv().visitInsn(IADD); resultType = TYPE_I; } public void visit(Subtraction entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); mv().visitInsn(ISUB); resultType = TYPE_I; } public void visit(Multiplication entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); mv().visitInsn(IMUL); resultType = TYPE_I; } public void visit(Division entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); mv().visitInsn(IDIV); resultType = TYPE_I; } public void visit(And entity) { entity.getExp1().accept(this); mv().visitInsn(DUP); Label end = new Label(); mv().visitJumpInsn(IFEQ, end); mv().visitInsn(POP); entity.getExp2().accept(this); mv().visitLabel(end); resultType = TYPE_B; } public void visit(Or entity) { entity.getExp1().accept(this); mv().visitInsn(DUP); Label end = new Label(); mv().visitJumpInsn(IFNE, end); mv().visitInsn(POP); entity.getExp2().accept(this); mv().visitLabel(end); resultType = TYPE_B; } public void visit(Not entity) { mv().visitInsn(ICONST_1); entity.getExp().accept(this); mv().visitInsn(ISUB); resultType = TYPE_B; } public void visit(Equals entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPEQ, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } public void visit(NotEquals entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPNE, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } public void visit(LessThan entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPLT, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } public void visit(LessOrEquals entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPLE, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } public void visit(GreaterThan entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPGT, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } public void visit(GreaterOrEquals entity) { entity.getExp1().accept(this); entity.getExp2().accept(this); Label iftrue = new Label(); Label end = new Label(); mv().visitJumpInsn(IF_ICMPGE, iftrue); mv().visitInsn(ICONST_0); mv().visitJumpInsn(GOTO, end); mv().visitLabel(iftrue); mv().visitInsn(ICONST_1); mv().visitLabel(end); resultType = TYPE_B; } }