Switch to generic visitor pattern.

This commit is contained in:
Deryck Brown
2022-05-22 13:59:44 +01:00
parent 1db90b20a8
commit 55f6b2d105
132 changed files with 2941 additions and 2349 deletions
@@ -0,0 +1,120 @@
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);
}
}
}