compiler-design-eth/src/cd/backend/codegen/Interrupts.java

98 lines
3.5 KiB
Java

package cd.backend.codegen;
import cd.backend.codegen.RegisterManager.Register;
import static cd.backend.codegen.Interrupts.Mem.BUFFER;
public class Interrupts {
protected static final int EXIT_OK = 0, EXIT_DIV_0 = 7, EXIT_INPUT_MISMATCH = 8;
protected static final int STDIN = 0, STDOUT = 1, STDERR = 2;
protected static final int I_EXIT = 1, I_READ = 3, I_WRITE = 4;
protected enum Mem {
BUFFER("io_buffer"), EAX("eax");
String pos;
Mem(String pos) {
this.pos = pos;
}
@Override
public String toString() {
return pos;
}
}
/**
* Write auxiliary data variables needed for I/O and division
* @param cg AstCodeGenerator to print instructions
*/
protected static void reserveMemory(AstCodeGenerator cg) {
for (Mem m : Mem.values()) {
cg.emit.emitLabel(m.pos);
cg.emit.emitConstantData("0");
}
}
/**
* Writes a single character passed as parameter
* @param cg AstCodeGenerator to print instructions
* @param i Character code in ASCII (or single casted character)
*/
protected static void printChar(AstCodeGenerator cg, int i) {
cg.emit.emitMove(AssemblyEmitter.constant(i), BUFFER.pos);
printChar(cg);
}
/**
* Writes a single character from the BUFFER memory pos to stdout
* @param cg AstCodeGenerator to print instructions
*/
protected static void printChar(AstCodeGenerator cg) {
Register[] needed = {Register.EAX, Register.EBX, Register.ECX, Register.EDX};
for (int i = 0; i < needed.length; i++)
if (cg.rm.isInUse(needed[i]))
cg.emit.emit("push", needed[i]);
cg.emit.emitMove(AssemblyEmitter.constant(I_WRITE), Register.EAX);
cg.emit.emitMove(AssemblyEmitter.constant(STDOUT), Register.EBX);
cg.emit.emitMove("$" + BUFFER.pos, Register.ECX);
cg.emit.emitMove(AssemblyEmitter.constant(1), Register.EDX);
cg.emit.emit("int", 0x80);
for (int i = needed.length - 1; i >= 0; i--)
if (cg.rm.isInUse(needed[i]))
cg.emit.emit("pop", needed[i]);
}
/**
* Reads a single character from stdin and places it in the
* memory pos BUFFER
*/
protected static void readChar(AstCodeGenerator cg, Register destination) {
Register[] needed = {Register.EAX, Register.EBX, Register.ECX, Register.EDX};
for (int i = 0; i < needed.length; i++)
if (cg.rm.isInUse(needed[i]))
cg.emit.emit("push", needed[i]);
cg.emit.emitMove(AssemblyEmitter.constant(I_READ), Register.EAX);
cg.emit.emitMove(AssemblyEmitter.constant(STDIN), Register.EBX);
cg.emit.emitMove("$" + BUFFER.pos, Register.ECX);
cg.emit.emitMove(AssemblyEmitter.constant(1), Register.EDX);
cg.emit.emit("int", 0x80);
for (int i = needed.length - 1; i >= 0; i--)
if (cg.rm.isInUse(needed[i]))
cg.emit.emit("pop", needed[i]);
cg.emit.emitMove(BUFFER.pos, destination);
}
/**
* Generates a exit interrupt with the code provided
* @param cg AstCodeGenerator to print instructions
* @param exitCode Number to use as exit code (can use constants in this class)
*/
protected static void exit(AstCodeGenerator cg, int exitCode) {
cg.emit.emitMove(AssemblyEmitter.constant(I_EXIT), Register.EAX);
cg.emit.emitMove(AssemblyEmitter.constant(exitCode), Register.EBX);
cg.emit.emit("int", 0x80);
}
}