Archived
121 lines
3.2 KiB
Java
121 lines
3.2 KiB
Java
package Triangle.CodeGenerator;
|
|
|
|
import java.io.DataOutputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
|
|
import Triangle.ErrorReporter;
|
|
import Triangle.AbstractMachine.Instruction;
|
|
import Triangle.AbstractMachine.Machine;
|
|
import Triangle.AbstractMachine.OpCode;
|
|
import Triangle.AbstractMachine.Primitive;
|
|
import Triangle.AbstractMachine.Register;
|
|
|
|
public class Emitter {
|
|
|
|
// 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.
|
|
|
|
ErrorReporter errorReporter;
|
|
|
|
int nextInstrAddr;
|
|
|
|
public Emitter(ErrorReporter errorReporter) {
|
|
this.errorReporter = errorReporter;
|
|
nextInstrAddr = Machine.CB;
|
|
}
|
|
|
|
public int getNextInstrAddr() {
|
|
return nextInstrAddr;
|
|
}
|
|
|
|
public int emit(OpCode op) {
|
|
return emit(op, 0, Register.CB, 0);
|
|
}
|
|
|
|
public int emit(OpCode op, int operand) {
|
|
return emit(op, 0, Register.CB, operand);
|
|
}
|
|
|
|
public int emit(OpCode op, int length, int operand) {
|
|
return emit(op, length, Register.CB, operand);
|
|
}
|
|
|
|
public int emit(OpCode op, Register staticRegister, Register register, int operand) {
|
|
return emit(op, staticRegister.ordinal(), register, operand);
|
|
}
|
|
|
|
public int emit(OpCode op, Register register, int operand) {
|
|
return emit(op, 0, register, operand);
|
|
}
|
|
|
|
public int emit(OpCode op, Register register) {
|
|
return emit(op, 0, register, 0);
|
|
}
|
|
|
|
public int emit(OpCode op, int length, Register register) {
|
|
return emit(op, length, register, 0);
|
|
}
|
|
|
|
public int emit(OpCode op, Register register, Primitive primitive) {
|
|
return emit(op, 0, register, primitive.ordinal());
|
|
}
|
|
|
|
/**
|
|
* Appends an instruction, with the given fields, to the object code.
|
|
*
|
|
* @param op the opcode
|
|
* @param length the length field
|
|
* @param register the register field
|
|
* @param operand the operand field
|
|
* @return the code address of the new instruction
|
|
**/
|
|
public int emit(OpCode op, int length, Register register, int operand) {
|
|
|
|
if (length > 255) {
|
|
errorReporter.reportRestriction("length of operand can't exceed 255 words");
|
|
length = 255; // to allow code generation to continue
|
|
}
|
|
|
|
var nextInstr = new Instruction(op, register, length, operand);
|
|
|
|
var currentInstrAddr = nextInstrAddr;
|
|
if (nextInstrAddr == Machine.PB) {
|
|
errorReporter.reportRestriction("too many instructions for code segment");
|
|
} else {
|
|
Machine.code[nextInstrAddr++] = nextInstr;
|
|
}
|
|
return currentInstrAddr;
|
|
|
|
}
|
|
|
|
// Patches the d-field of the instruction at address addr with the next
|
|
// instruction address.
|
|
public void patch(int addr) {
|
|
Machine.code[addr].setOperand(nextInstrAddr);
|
|
}
|
|
|
|
/**
|
|
* Saves the object program in the given object file.
|
|
*
|
|
* @param objectFile the object file
|
|
*/
|
|
public void saveObjectProgram(String objectFileName) {
|
|
try (var objectFile = new FileOutputStream(objectFileName)) {
|
|
var objectStream = new DataOutputStream(objectFile);
|
|
for (var addr = Machine.CB; addr < nextInstrAddr; addr++) {
|
|
Machine.code[addr].write(objectStream);
|
|
}
|
|
} catch (FileNotFoundException fnfe) {
|
|
System.err.println("Error opening object file: " + fnfe);
|
|
} catch (IOException ioe) {
|
|
System.err.println("Error writing object file: " + ioe);
|
|
}
|
|
}
|
|
}
|