/* * @(#)Encoder.java 2.1 2003/10/07 * * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland * and School of Computer and Math Sciences, The Robert Gordon University, * St. Andrew Street, Aberdeen AB25 1HG, Scotland. * All rights reserved. * * This software is provided free for educational use only. It may * not be used for commercial purposes without the prior written permission * of the authors. */ package Triangle.CodeGenerator; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import Triangle.ErrorReporter; import Triangle.StdEnvironment; import Triangle.AbstractMachine.Instruction; import Triangle.AbstractMachine.Machine; import Triangle.AbstractSyntaxTrees.AST; import Triangle.AbstractSyntaxTrees.AnyTypeDenoter; import Triangle.AbstractSyntaxTrees.ArrayExpression; import Triangle.AbstractSyntaxTrees.ArrayTypeDenoter; import Triangle.AbstractSyntaxTrees.AssignCommand; import Triangle.AbstractSyntaxTrees.BinaryExpression; import Triangle.AbstractSyntaxTrees.BinaryOperatorDeclaration; import Triangle.AbstractSyntaxTrees.BoolTypeDenoter; import Triangle.AbstractSyntaxTrees.CallCommand; import Triangle.AbstractSyntaxTrees.CallExpression; import Triangle.AbstractSyntaxTrees.CharTypeDenoter; import Triangle.AbstractSyntaxTrees.CharacterExpression; import Triangle.AbstractSyntaxTrees.CharacterLiteral; import Triangle.AbstractSyntaxTrees.ConstActualParameter; import Triangle.AbstractSyntaxTrees.ConstDeclaration; import Triangle.AbstractSyntaxTrees.ConstFormalParameter; import Triangle.AbstractSyntaxTrees.Declaration; import Triangle.AbstractSyntaxTrees.DotVname; import Triangle.AbstractSyntaxTrees.EmptyActualParameterSequence; import Triangle.AbstractSyntaxTrees.EmptyCommand; import Triangle.AbstractSyntaxTrees.EmptyExpression; import Triangle.AbstractSyntaxTrees.EmptyFormalParameterSequence; import Triangle.AbstractSyntaxTrees.ErrorTypeDenoter; import Triangle.AbstractSyntaxTrees.FuncActualParameter; import Triangle.AbstractSyntaxTrees.FuncDeclaration; import Triangle.AbstractSyntaxTrees.FuncFormalParameter; import Triangle.AbstractSyntaxTrees.Identifier; import Triangle.AbstractSyntaxTrees.IfCommand; import Triangle.AbstractSyntaxTrees.IfExpression; import Triangle.AbstractSyntaxTrees.IntTypeDenoter; import Triangle.AbstractSyntaxTrees.IntegerExpression; import Triangle.AbstractSyntaxTrees.IntegerLiteral; import Triangle.AbstractSyntaxTrees.LetCommand; import Triangle.AbstractSyntaxTrees.LetExpression; import Triangle.AbstractSyntaxTrees.MultipleActualParameterSequence; import Triangle.AbstractSyntaxTrees.MultipleArrayAggregate; import Triangle.AbstractSyntaxTrees.MultipleFieldTypeDenoter; import Triangle.AbstractSyntaxTrees.MultipleFormalParameterSequence; import Triangle.AbstractSyntaxTrees.MultipleRecordAggregate; import Triangle.AbstractSyntaxTrees.Operator; import Triangle.AbstractSyntaxTrees.ProcActualParameter; import Triangle.AbstractSyntaxTrees.ProcDeclaration; import Triangle.AbstractSyntaxTrees.ProcFormalParameter; import Triangle.AbstractSyntaxTrees.Program; import Triangle.AbstractSyntaxTrees.RecordExpression; import Triangle.AbstractSyntaxTrees.RecordTypeDenoter; import Triangle.AbstractSyntaxTrees.SequentialCommand; import Triangle.AbstractSyntaxTrees.SequentialDeclaration; import Triangle.AbstractSyntaxTrees.SimpleTypeDenoter; import Triangle.AbstractSyntaxTrees.SimpleVname; import Triangle.AbstractSyntaxTrees.SingleActualParameterSequence; import Triangle.AbstractSyntaxTrees.SingleArrayAggregate; import Triangle.AbstractSyntaxTrees.SingleFieldTypeDenoter; import Triangle.AbstractSyntaxTrees.SingleFormalParameterSequence; import Triangle.AbstractSyntaxTrees.SingleRecordAggregate; import Triangle.AbstractSyntaxTrees.SubscriptVname; import Triangle.AbstractSyntaxTrees.TypeDeclaration; import Triangle.AbstractSyntaxTrees.UnaryExpression; import Triangle.AbstractSyntaxTrees.UnaryOperatorDeclaration; import Triangle.AbstractSyntaxTrees.VarActualParameter; import Triangle.AbstractSyntaxTrees.VarDeclaration; import Triangle.AbstractSyntaxTrees.VarFormalParameter; import Triangle.AbstractSyntaxTrees.Visitor; import Triangle.AbstractSyntaxTrees.Vname; import Triangle.AbstractSyntaxTrees.VnameExpression; import Triangle.AbstractSyntaxTrees.WhileCommand; public final class Encoder implements Visitor { // Commands @Override public Object visitAssignCommand(AssignCommand ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.E.visit(this, frame); encodeStore(ast.V, new Frame(frame, valSize.intValue()), valSize.intValue()); return null; } @Override public Object visitCallCommand(CallCommand ast, Object o) { Frame frame = (Frame) o; Integer argsSize = (Integer) ast.APS.visit(this, frame); ast.I.visit(this, new Frame(frame.level, argsSize)); return null; } @Override public Object visitEmptyCommand(EmptyCommand ast, Object o) { return null; } @Override public Object visitIfCommand(IfCommand ast, Object o) { Frame frame = (Frame) o; int jumpifAddr, jumpAddr; Integer valSize = (Integer) ast.E.visit(this, frame); jumpifAddr = nextInstrAddr; emit(Machine.JUMPIFop, Machine.falseRep, Machine.CBr, 0); ast.C1.visit(this, frame); jumpAddr = nextInstrAddr; emit(Machine.JUMPop, 0, Machine.CBr, 0); patch(jumpifAddr, nextInstrAddr); ast.C2.visit(this, frame); patch(jumpAddr, nextInstrAddr); return null; } @Override public Object visitLetCommand(LetCommand ast, Object o) { Frame frame = (Frame) o; int extraSize = ((Integer) ast.D.visit(this, frame)).intValue(); ast.C.visit(this, new Frame(frame, extraSize)); if (extraSize > 0) emit(Machine.POPop, 0, 0, extraSize); return null; } @Override public Object visitSequentialCommand(SequentialCommand ast, Object o) { ast.C1.visit(this, o); ast.C2.visit(this, o); return null; } @Override public Object visitWhileCommand(WhileCommand ast, Object o) { Frame frame = (Frame) o; int jumpAddr, loopAddr; jumpAddr = nextInstrAddr; emit(Machine.JUMPop, 0, Machine.CBr, 0); loopAddr = nextInstrAddr; ast.C.visit(this, frame); patch(jumpAddr, nextInstrAddr); ast.E.visit(this, frame); emit(Machine.JUMPIFop, Machine.trueRep, Machine.CBr, loopAddr); return null; } // Expressions @Override public Object visitArrayExpression(ArrayExpression ast, Object o) { ast.type.visit(this, null); return ast.AA.visit(this, o); } @Override public Object visitBinaryExpression(BinaryExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); int valSize1 = ((Integer) ast.E1.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, valSize1); int valSize2 = ((Integer) ast.E2.visit(this, frame1)).intValue(); Frame frame2 = new Frame(frame.level, valSize1 + valSize2); ast.O.visit(this, frame2); return valSize; } @Override public Object visitCallExpression(CallExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); Integer argsSize = (Integer) ast.APS.visit(this, frame); ast.I.visit(this, new Frame(frame.level, argsSize)); return valSize; } @Override public Object visitCharacterExpression(CharacterExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); emit(Machine.LOADLop, 0, 0, ast.CL.spelling.charAt(1)); return valSize; } @Override public Object visitEmptyExpression(EmptyExpression ast, Object o) { return Integer.valueOf(0); } @Override public Object visitIfExpression(IfExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize; int jumpifAddr, jumpAddr; ast.type.visit(this, null); ast.E1.visit(this, frame); jumpifAddr = nextInstrAddr; emit(Machine.JUMPIFop, Machine.falseRep, Machine.CBr, 0); valSize = (Integer) ast.E2.visit(this, frame); jumpAddr = nextInstrAddr; emit(Machine.JUMPop, 0, Machine.CBr, 0); patch(jumpifAddr, nextInstrAddr); valSize = (Integer) ast.E3.visit(this, frame); patch(jumpAddr, nextInstrAddr); return valSize; } @Override public Object visitIntegerExpression(IntegerExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); emit(Machine.LOADLop, 0, 0, Integer.parseInt(ast.IL.spelling)); return valSize; } @Override public Object visitLetExpression(LetExpression ast, Object o) { Frame frame = (Frame) o; ast.type.visit(this, null); int extraSize = ((Integer) ast.D.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, extraSize); Integer valSize = (Integer) ast.E.visit(this, frame1); if (extraSize > 0) emit(Machine.POPop, valSize.intValue(), 0, extraSize); return valSize; } @Override public Object visitRecordExpression(RecordExpression ast, Object o) { ast.type.visit(this, null); return ast.RA.visit(this, o); } @Override public Object visitUnaryExpression(UnaryExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); ast.E.visit(this, frame); ast.O.visit(this, new Frame(frame.level, valSize.intValue())); return valSize; } @Override public Object visitVnameExpression(VnameExpression ast, Object o) { Frame frame = (Frame) o; Integer valSize = (Integer) ast.type.visit(this, null); encodeFetch(ast.V, frame, valSize.intValue()); return valSize; } // Declarations @Override public Object visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Object o) { return Integer.valueOf(0); } @Override public Object visitConstDeclaration(ConstDeclaration ast, Object o) { Frame frame = (Frame) o; int extraSize = 0; if (ast.E instanceof CharacterExpression) { CharacterLiteral CL = ((CharacterExpression) ast.E).CL; ast.entity = new KnownValue(Machine.characterSize, characterValuation(CL.spelling)); } else if (ast.E instanceof IntegerExpression) { IntegerLiteral IL = ((IntegerExpression) ast.E).IL; ast.entity = new KnownValue(Machine.integerSize, Integer.parseInt(IL.spelling)); } else { int valSize = ((Integer) ast.E.visit(this, frame)).intValue(); ast.entity = new UnknownValue(valSize, frame.level, frame.size); extraSize = valSize; } writeTableDetails(ast); return Integer.valueOf(extraSize); } @Override public Object visitFuncDeclaration(FuncDeclaration ast, Object o) { Frame frame = (Frame) o; int jumpAddr = nextInstrAddr; int argsSize = 0, valSize = 0; emit(Machine.JUMPop, 0, Machine.CBr, 0); ast.entity = new KnownRoutine(Machine.closureSize, frame.level, nextInstrAddr); writeTableDetails(ast); if (frame.level == Machine.maxRoutineLevel) reporter.reportRestriction("can't nest routines more than 7 deep"); else { Frame frame1 = new Frame(frame.level + 1, 0); argsSize = ((Integer) ast.FPS.visit(this, frame1)).intValue(); Frame frame2 = new Frame(frame.level + 1, Machine.linkDataSize); valSize = ((Integer) ast.E.visit(this, frame2)).intValue(); } emit(Machine.RETURNop, valSize, 0, argsSize); patch(jumpAddr, nextInstrAddr); return Integer.valueOf(0); } @Override public Object visitProcDeclaration(ProcDeclaration ast, Object o) { Frame frame = (Frame) o; int jumpAddr = nextInstrAddr; int argsSize = 0; emit(Machine.JUMPop, 0, Machine.CBr, 0); ast.entity = new KnownRoutine(Machine.closureSize, frame.level, nextInstrAddr); writeTableDetails(ast); if (frame.level == Machine.maxRoutineLevel) reporter.reportRestriction("can't nest routines so deeply"); else { Frame frame1 = new Frame(frame.level + 1, 0); argsSize = ((Integer) ast.FPS.visit(this, frame1)).intValue(); Frame frame2 = new Frame(frame.level + 1, Machine.linkDataSize); ast.C.visit(this, frame2); } emit(Machine.RETURNop, 0, 0, argsSize); patch(jumpAddr, nextInstrAddr); return Integer.valueOf(0); } @Override public Object visitSequentialDeclaration(SequentialDeclaration ast, Object o) { Frame frame = (Frame) o; int extraSize1, extraSize2; extraSize1 = ((Integer) ast.D1.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, extraSize1); extraSize2 = ((Integer) ast.D2.visit(this, frame1)).intValue(); return Integer.valueOf(extraSize1 + extraSize2); } @Override public Object visitTypeDeclaration(TypeDeclaration ast, Object o) { // just to ensure the type's representation is decided ast.T.visit(this, null); return Integer.valueOf(0); } @Override public Object visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Object o) { return Integer.valueOf(0); } @Override public Object visitVarDeclaration(VarDeclaration ast, Object o) { Frame frame = (Frame) o; int extraSize; extraSize = ((Integer) ast.T.visit(this, null)).intValue(); emit(Machine.PUSHop, 0, 0, extraSize); ast.entity = new KnownAddress(Machine.addressSize, frame.level, frame.size); writeTableDetails(ast); return Integer.valueOf(extraSize); } // Array Aggregates @Override public Object visitMultipleArrayAggregate(MultipleArrayAggregate ast, Object o) { Frame frame = (Frame) o; int elemSize = ((Integer) ast.E.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, elemSize); int arraySize = ((Integer) ast.AA.visit(this, frame1)).intValue(); return Integer.valueOf(elemSize + arraySize); } @Override public Object visitSingleArrayAggregate(SingleArrayAggregate ast, Object o) { return ast.E.visit(this, o); } // Record Aggregates @Override public Object visitMultipleRecordAggregate(MultipleRecordAggregate ast, Object o) { Frame frame = (Frame) o; int fieldSize = ((Integer) ast.E.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, fieldSize); int recordSize = ((Integer) ast.RA.visit(this, frame1)).intValue(); return Integer.valueOf(fieldSize + recordSize); } @Override public Object visitSingleRecordAggregate(SingleRecordAggregate ast, Object o) { return ast.E.visit(this, o); } // Formal Parameters @Override public Object visitConstFormalParameter(ConstFormalParameter ast, Object o) { Frame frame = (Frame) o; int valSize = ((Integer) ast.T.visit(this, null)).intValue(); ast.entity = new UnknownValue(valSize, frame.level, -frame.size - valSize); writeTableDetails(ast); return Integer.valueOf(valSize); } @Override public Object visitFuncFormalParameter(FuncFormalParameter ast, Object o) { Frame frame = (Frame) o; int argsSize = Machine.closureSize; ast.entity = new UnknownRoutine(Machine.closureSize, frame.level, -frame.size - argsSize); writeTableDetails(ast); return Integer.valueOf(argsSize); } @Override public Object visitProcFormalParameter(ProcFormalParameter ast, Object o) { Frame frame = (Frame) o; int argsSize = Machine.closureSize; ast.entity = new UnknownRoutine(Machine.closureSize, frame.level, -frame.size - argsSize); writeTableDetails(ast); return Integer.valueOf(argsSize); } @Override public Object visitVarFormalParameter(VarFormalParameter ast, Object o) { Frame frame = (Frame) o; ast.T.visit(this, null); ast.entity = new UnknownAddress(Machine.addressSize, frame.level, -frame.size - Machine.addressSize); writeTableDetails(ast); return Integer.valueOf(Machine.addressSize); } @Override public Object visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Object o) { return Integer.valueOf(0); } @Override public Object visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Object o) { Frame frame = (Frame) o; int argsSize1 = ((Integer) ast.FPS.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, argsSize1); int argsSize2 = ((Integer) ast.FP.visit(this, frame1)).intValue(); return Integer.valueOf(argsSize1 + argsSize2); } @Override public Object visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Object o) { return ast.FP.visit(this, o); } // Actual Parameters @Override public Object visitConstActualParameter(ConstActualParameter ast, Object o) { return ast.E.visit(this, o); } @Override public Object visitFuncActualParameter(FuncActualParameter ast, Object o) { Frame frame = (Frame) o; if (ast.I.decl.entity instanceof KnownRoutine) { ObjectAddress address = ((KnownRoutine) ast.I.decl.entity).address; // static link, code address emit(Machine.LOADAop, 0, displayRegister(frame.level, address.level), 0); emit(Machine.LOADAop, 0, Machine.CBr, address.displacement); } else if (ast.I.decl.entity instanceof UnknownRoutine) { ObjectAddress address = ((UnknownRoutine) ast.I.decl.entity).address; emit(Machine.LOADop, Machine.closureSize, displayRegister(frame.level, address.level), address.displacement); } else if (ast.I.decl.entity instanceof PrimitiveRoutine) { int displacement = ((PrimitiveRoutine) ast.I.decl.entity).displacement; // static link, code address emit(Machine.LOADAop, 0, Machine.SBr, 0); emit(Machine.LOADAop, 0, Machine.PBr, displacement); } return Integer.valueOf(Machine.closureSize); } @Override public Object visitProcActualParameter(ProcActualParameter ast, Object o) { Frame frame = (Frame) o; if (ast.I.decl.entity instanceof KnownRoutine) { ObjectAddress address = ((KnownRoutine) ast.I.decl.entity).address; // static link, code address emit(Machine.LOADAop, 0, displayRegister(frame.level, address.level), 0); emit(Machine.LOADAop, 0, Machine.CBr, address.displacement); } else if (ast.I.decl.entity instanceof UnknownRoutine) { ObjectAddress address = ((UnknownRoutine) ast.I.decl.entity).address; emit(Machine.LOADop, Machine.closureSize, displayRegister(frame.level, address.level), address.displacement); } else if (ast.I.decl.entity instanceof PrimitiveRoutine) { int displacement = ((PrimitiveRoutine) ast.I.decl.entity).displacement; // static link, code address emit(Machine.LOADAop, 0, Machine.SBr, 0); emit(Machine.LOADAop, 0, Machine.PBr, displacement); } return Integer.valueOf(Machine.closureSize); } @Override public Object visitVarActualParameter(VarActualParameter ast, Object o) { encodeFetchAddress(ast.V, (Frame) o); return Integer.valueOf(Machine.addressSize); } @Override public Object visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Object o) { return Integer.valueOf(0); } @Override public Object visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Object o) { Frame frame = (Frame) o; int argsSize1 = ((Integer) ast.AP.visit(this, frame)).intValue(); Frame frame1 = new Frame(frame, argsSize1); int argsSize2 = ((Integer) ast.APS.visit(this, frame1)).intValue(); return Integer.valueOf(argsSize1 + argsSize2); } @Override public Object visitSingleActualParameterSequence(SingleActualParameterSequence ast, Object o) { return ast.AP.visit(this, o); } // Type Denoters @Override public Object visitAnyTypeDenoter(AnyTypeDenoter ast, Object o) { return Integer.valueOf(0); } @Override public Object visitArrayTypeDenoter(ArrayTypeDenoter ast, Object o) { int typeSize; if (ast.entity == null) { int elemSize = ((Integer) ast.T.visit(this, null)).intValue(); typeSize = Integer.parseInt(ast.IL.spelling) * elemSize; ast.entity = new TypeRepresentation(typeSize); writeTableDetails(ast); } else typeSize = ast.entity.size; return Integer.valueOf(typeSize); } @Override public Object visitBoolTypeDenoter(BoolTypeDenoter ast, Object o) { if (ast.entity == null) { ast.entity = new TypeRepresentation(Machine.booleanSize); writeTableDetails(ast); } return Integer.valueOf(Machine.booleanSize); } @Override public Object visitCharTypeDenoter(CharTypeDenoter ast, Object o) { if (ast.entity == null) { ast.entity = new TypeRepresentation(Machine.characterSize); writeTableDetails(ast); } return Integer.valueOf(Machine.characterSize); } @Override public Object visitErrorTypeDenoter(ErrorTypeDenoter ast, Object o) { return Integer.valueOf(0); } @Override public Object visitSimpleTypeDenoter(SimpleTypeDenoter ast, Object o) { return Integer.valueOf(0); } @Override public Object visitIntTypeDenoter(IntTypeDenoter ast, Object o) { if (ast.entity == null) { ast.entity = new TypeRepresentation(Machine.integerSize); writeTableDetails(ast); } return Integer.valueOf(Machine.integerSize); } @Override public Object visitRecordTypeDenoter(RecordTypeDenoter ast, Object o) { int typeSize; if (ast.entity == null) { typeSize = ((Integer) ast.FT.visit(this, Integer.valueOf(0))).intValue(); ast.entity = new TypeRepresentation(typeSize); writeTableDetails(ast); } else typeSize = ast.entity.size; return Integer.valueOf(typeSize); } @Override public Object visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Object o) { int offset = ((Integer) o).intValue(); int fieldSize; if (ast.entity == null) { fieldSize = ((Integer) ast.T.visit(this, null)).intValue(); ast.entity = new Field(fieldSize, offset); writeTableDetails(ast); } else fieldSize = ast.entity.size; Integer offset1 = Integer.valueOf(offset + fieldSize); int recSize = ((Integer) ast.FT.visit(this, offset1)).intValue(); return Integer.valueOf(fieldSize + recSize); } @Override public Object visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Object o) { int offset = ((Integer) o).intValue(); int fieldSize; if (ast.entity == null) { fieldSize = ((Integer) ast.T.visit(this, null)).intValue(); ast.entity = new Field(fieldSize, offset); writeTableDetails(ast); } else fieldSize = ast.entity.size; return Integer.valueOf(fieldSize); } // Literals, Identifiers and Operators @Override public Object visitCharacterLiteral(CharacterLiteral ast, Object o) { return null; } @Override public Object visitIdentifier(Identifier ast, Object o) { Frame frame = (Frame) o; if (ast.decl.entity instanceof KnownRoutine) { ObjectAddress address = ((KnownRoutine) ast.decl.entity).address; emit(Machine.CALLop, displayRegister(frame.level, address.level), Machine.CBr, address.displacement); } else if (ast.decl.entity instanceof UnknownRoutine) { ObjectAddress address = ((UnknownRoutine) ast.decl.entity).address; emit(Machine.LOADop, Machine.closureSize, displayRegister(frame.level, address.level), address.displacement); emit(Machine.CALLIop, 0, 0, 0); } else if (ast.decl.entity instanceof PrimitiveRoutine) { int displacement = ((PrimitiveRoutine) ast.decl.entity).displacement; if (displacement != Machine.idDisplacement) emit(Machine.CALLop, Machine.SBr, Machine.PBr, displacement); } else if (ast.decl.entity instanceof EqualityRoutine) { // "=" or "\=" int displacement = ((EqualityRoutine) ast.decl.entity).displacement; emit(Machine.LOADLop, 0, 0, frame.size / 2); emit(Machine.CALLop, Machine.SBr, Machine.PBr, displacement); } return null; } @Override public Object visitIntegerLiteral(IntegerLiteral ast, Object o) { return null; } @Override public Object visitOperator(Operator ast, Object o) { Frame frame = (Frame) o; if (ast.decl.entity instanceof KnownRoutine) { ObjectAddress address = ((KnownRoutine) ast.decl.entity).address; emit(Machine.CALLop, displayRegister(frame.level, address.level), Machine.CBr, address.displacement); } else if (ast.decl.entity instanceof UnknownRoutine) { ObjectAddress address = ((UnknownRoutine) ast.decl.entity).address; emit(Machine.LOADop, Machine.closureSize, displayRegister(frame.level, address.level), address.displacement); emit(Machine.CALLIop, 0, 0, 0); } else if (ast.decl.entity instanceof PrimitiveRoutine) { int displacement = ((PrimitiveRoutine) ast.decl.entity).displacement; if (displacement != Machine.idDisplacement) emit(Machine.CALLop, Machine.SBr, Machine.PBr, displacement); } else if (ast.decl.entity instanceof EqualityRoutine) { // "=" or "\=" int displacement = ((EqualityRoutine) ast.decl.entity).displacement; emit(Machine.LOADLop, 0, 0, frame.size / 2); emit(Machine.CALLop, Machine.SBr, Machine.PBr, displacement); } return null; } // Value-or-variable names @Override public Object visitDotVname(DotVname ast, Object o) { Frame frame = (Frame) o; RuntimeEntity baseObject = (RuntimeEntity) ast.V.visit(this, frame); ast.offset = ast.V.offset + ((Field) ast.I.decl.entity).fieldOffset; // I.decl points to the appropriate record field ast.indexed = ast.V.indexed; return baseObject; } @Override public Object visitSimpleVname(SimpleVname ast, Object o) { ast.offset = 0; ast.indexed = false; return ast.I.decl.entity; } @Override public Object visitSubscriptVname(SubscriptVname ast, Object o) { Frame frame = (Frame) o; RuntimeEntity baseObject; int elemSize, indexSize; baseObject = (RuntimeEntity) ast.V.visit(this, frame); ast.offset = ast.V.offset; ast.indexed = ast.V.indexed; elemSize = ((Integer) ast.type.visit(this, null)).intValue(); if (ast.E instanceof IntegerExpression) { IntegerLiteral IL = ((IntegerExpression) ast.E).IL; ast.offset = ast.offset + Integer.parseInt(IL.spelling) * elemSize; } else { // v-name is indexed by a proper expression, not a literal if (ast.indexed) frame.size = frame.size + Machine.integerSize; indexSize = ((Integer) ast.E.visit(this, frame)).intValue(); if (elemSize != 1) { emit(Machine.LOADLop, 0, 0, elemSize); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.multDisplacement); } if (ast.indexed) emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); else ast.indexed = true; } return baseObject; } // Programs @Override public Object visitProgram(Program ast, Object o) { return ast.C.visit(this, o); } public Encoder(ErrorReporter reporter) { this.reporter = reporter; nextInstrAddr = Machine.CB; elaborateStdEnvironment(); } private ErrorReporter reporter; // Generates code to run a program. // showingTable is true iff entity description details // are to be displayed. public final void encodeRun(Program theAST, boolean showingTable) { tableDetailsReqd = showingTable; // startCodeGeneration(); theAST.visit(this, new Frame(0, 0)); emit(Machine.HALTop, 0, 0, 0); } // Decides run-time representation of a standard constant. private final void elaborateStdConst(Declaration constDeclaration, int value) { if (constDeclaration instanceof ConstDeclaration) { ConstDeclaration decl = (ConstDeclaration) constDeclaration; int typeSize = ((Integer) decl.E.type.visit(this, null)).intValue(); decl.entity = new KnownValue(typeSize, value); writeTableDetails(constDeclaration); } } // Decides run-time representation of a standard routine. private final void elaborateStdPrimRoutine(Declaration routineDeclaration, int routineOffset) { routineDeclaration.entity = new PrimitiveRoutine(Machine.closureSize, routineOffset); writeTableDetails(routineDeclaration); } private final void elaborateStdEqRoutine(Declaration routineDeclaration, int routineOffset) { routineDeclaration.entity = new EqualityRoutine(Machine.closureSize, routineOffset); writeTableDetails(routineDeclaration); } private final void elaborateStdRoutine(Declaration routineDeclaration, int routineOffset) { routineDeclaration.entity = new KnownRoutine(Machine.closureSize, 0, routineOffset); writeTableDetails(routineDeclaration); } private final void elaborateStdEnvironment() { tableDetailsReqd = false; elaborateStdConst(StdEnvironment.falseDecl, Machine.falseRep); elaborateStdConst(StdEnvironment.trueDecl, Machine.trueRep); elaborateStdPrimRoutine(StdEnvironment.notDecl, Machine.notDisplacement); elaborateStdPrimRoutine(StdEnvironment.andDecl, Machine.andDisplacement); elaborateStdPrimRoutine(StdEnvironment.orDecl, Machine.orDisplacement); elaborateStdConst(StdEnvironment.maxintDecl, Machine.maxintRep); elaborateStdPrimRoutine(StdEnvironment.addDecl, Machine.addDisplacement); elaborateStdPrimRoutine(StdEnvironment.subtractDecl, Machine.subDisplacement); elaborateStdPrimRoutine(StdEnvironment.multiplyDecl, Machine.multDisplacement); elaborateStdPrimRoutine(StdEnvironment.divideDecl, Machine.divDisplacement); elaborateStdPrimRoutine(StdEnvironment.moduloDecl, Machine.modDisplacement); elaborateStdPrimRoutine(StdEnvironment.lessDecl, Machine.ltDisplacement); elaborateStdPrimRoutine(StdEnvironment.notgreaterDecl, Machine.leDisplacement); elaborateStdPrimRoutine(StdEnvironment.greaterDecl, Machine.gtDisplacement); elaborateStdPrimRoutine(StdEnvironment.notlessDecl, Machine.geDisplacement); elaborateStdPrimRoutine(StdEnvironment.chrDecl, Machine.idDisplacement); elaborateStdPrimRoutine(StdEnvironment.ordDecl, Machine.idDisplacement); elaborateStdPrimRoutine(StdEnvironment.eolDecl, Machine.eolDisplacement); elaborateStdPrimRoutine(StdEnvironment.eofDecl, Machine.eofDisplacement); elaborateStdPrimRoutine(StdEnvironment.getDecl, Machine.getDisplacement); elaborateStdPrimRoutine(StdEnvironment.putDecl, Machine.putDisplacement); elaborateStdPrimRoutine(StdEnvironment.getintDecl, Machine.getintDisplacement); elaborateStdPrimRoutine(StdEnvironment.putintDecl, Machine.putintDisplacement); elaborateStdPrimRoutine(StdEnvironment.geteolDecl, Machine.geteolDisplacement); elaborateStdPrimRoutine(StdEnvironment.puteolDecl, Machine.puteolDisplacement); elaborateStdEqRoutine(StdEnvironment.equalDecl, Machine.eqDisplacement); elaborateStdEqRoutine(StdEnvironment.unequalDecl, Machine.neDisplacement); } // Saves the object program in the named file. public void saveObjectProgram(String objectName) { FileOutputStream objectFile = null; DataOutputStream objectStream = null; int addr; try { objectFile = new FileOutputStream(objectName); objectStream = new DataOutputStream(objectFile); addr = Machine.CB; for (addr = Machine.CB; addr < nextInstrAddr; addr++) Machine.code[addr].write(objectStream); objectFile.close(); } catch (FileNotFoundException s) { System.err.println("Error opening object file: " + s); } catch (IOException s) { System.err.println("Error writing object file: " + s); } } boolean tableDetailsReqd; public static void writeTableDetails(AST ast) { } // OBJECT CODE // Implementation notes: // Object code is generated directly into the TAM Code Store, starting at CB. // The address of the next instruction is held in nextInstrAddr. private int nextInstrAddr; // Appends an instruction, with the given fields, to the object code. private void emit(int op, int n, int r, int d) { Instruction nextInstr = new Instruction(); if (n > 255) { reporter.reportRestriction("length of operand can't exceed 255 words"); n = 255; // to allow code generation to continue } nextInstr.op = op; nextInstr.n = n; nextInstr.r = r; nextInstr.d = d; if (nextInstrAddr == Machine.PB) reporter.reportRestriction("too many instructions for code segment"); else { Machine.code[nextInstrAddr] = nextInstr; nextInstrAddr = nextInstrAddr + 1; } } // Patches the d-field of the instruction at address addr. private void patch(int addr, int d) { Machine.code[addr].d = d; } // DATA REPRESENTATION public int characterValuation(String spelling) { // Returns the machine representation of the given character literal. return spelling.charAt(1); // since the character literal is of the form 'x'} } // REGISTERS // Returns the register number appropriate for object code at currentLevel // to address a data object at objectLevel. private int displayRegister(int currentLevel, int objectLevel) { if (objectLevel == 0) return Machine.SBr; else if (currentLevel - objectLevel <= 6) return Machine.LBr + currentLevel - objectLevel; // LBr|L1r|...|L6r else { reporter.reportRestriction("can't access data more than 6 levels out"); return Machine.L6r; // to allow code generation to continue } } // Generates code to fetch the value of a named constant or variable // and push it on to the stack. // currentLevel is the routine level where the vname occurs. // frameSize is the anticipated size of the local stack frame when // the constant or variable is fetched at run-time. // valSize is the size of the constant or variable's value. private void encodeStore(Vname V, Frame frame, int valSize) { RuntimeEntity baseObject = (RuntimeEntity) V.visit(this, frame); // If indexed = true, code will have been generated to load an index value. if (valSize > 255) { reporter.reportRestriction("can't store values larger than 255 words"); valSize = 255; // to allow code generation to continue } if (baseObject instanceof KnownAddress) { ObjectAddress address = ((KnownAddress) baseObject).address; if (V.indexed) { emit(Machine.LOADAop, 0, displayRegister(frame.level, address.level), address.displacement + V.offset); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); emit(Machine.STOREIop, valSize, 0, 0); } else { emit(Machine.STOREop, valSize, displayRegister(frame.level, address.level), address.displacement + V.offset); } } else if (baseObject instanceof UnknownAddress) { ObjectAddress address = ((UnknownAddress) baseObject).address; emit(Machine.LOADop, Machine.addressSize, displayRegister(frame.level, address.level), address.displacement); if (V.indexed) emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); if (V.offset != 0) { emit(Machine.LOADLop, 0, 0, V.offset); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); } emit(Machine.STOREIop, valSize, 0, 0); } } // Generates code to fetch the value of a named constant or variable // and push it on to the stack. // currentLevel is the routine level where the vname occurs. // frameSize is the anticipated size of the local stack frame when // the constant or variable is fetched at run-time. // valSize is the size of the constant or variable's value. private void encodeFetch(Vname V, Frame frame, int valSize) { RuntimeEntity baseObject = (RuntimeEntity) V.visit(this, frame); // If indexed = true, code will have been generated to load an index value. if (valSize > 255) { reporter.reportRestriction("can't load values larger than 255 words"); valSize = 255; // to allow code generation to continue } if (baseObject instanceof KnownValue) { // presumably offset = 0 and indexed = false int value = ((KnownValue) baseObject).value; emit(Machine.LOADLop, 0, 0, value); } else if ((baseObject instanceof UnknownValue) || (baseObject instanceof KnownAddress)) { ObjectAddress address = (baseObject instanceof UnknownValue) ? ((UnknownValue) baseObject).address : ((KnownAddress) baseObject).address; if (V.indexed) { emit(Machine.LOADAop, 0, displayRegister(frame.level, address.level), address.displacement + V.offset); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); emit(Machine.LOADIop, valSize, 0, 0); } else emit(Machine.LOADop, valSize, displayRegister(frame.level, address.level), address.displacement + V.offset); } else if (baseObject instanceof UnknownAddress) { ObjectAddress address = ((UnknownAddress) baseObject).address; emit(Machine.LOADop, Machine.addressSize, displayRegister(frame.level, address.level), address.displacement); if (V.indexed) emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); if (V.offset != 0) { emit(Machine.LOADLop, 0, 0, V.offset); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); } emit(Machine.LOADIop, valSize, 0, 0); } } // Generates code to compute and push the address of a named variable. // vname is the program phrase that names this variable. // currentLevel is the routine level where the vname occurs. // frameSize is the anticipated size of the local stack frame when // the variable is addressed at run-time. private void encodeFetchAddress(Vname V, Frame frame) { RuntimeEntity baseObject = (RuntimeEntity) V.visit(this, frame); // If indexed = true, code will have been generated to load an index value. if (baseObject instanceof KnownAddress) { ObjectAddress address = ((KnownAddress) baseObject).address; emit(Machine.LOADAop, 0, displayRegister(frame.level, address.level), address.displacement + V.offset); if (V.indexed) emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); } else if (baseObject instanceof UnknownAddress) { ObjectAddress address = ((UnknownAddress) baseObject).address; emit(Machine.LOADop, Machine.addressSize, displayRegister(frame.level, address.level), address.displacement); if (V.indexed) emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); if (V.offset != 0) { emit(Machine.LOADLop, 0, 0, V.offset); emit(Machine.CALLop, Machine.SBr, Machine.PBr, Machine.addDisplacement); } } } }