package de.fuberlin.projectF.CodeGenerator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.fuberlin.projectF.CodeGenerator.model.Token.Parameter;
import de.fuberlin.projectF.CodeGenerator.model.Array;
import de.fuberlin.projectF.CodeGenerator.model.ArrayPointer;
import de.fuberlin.projectF.CodeGenerator.model.MMXRegisterAddress;
import de.fuberlin.projectF.CodeGenerator.model.Record;
import de.fuberlin.projectF.CodeGenerator.model.Reference;
import de.fuberlin.projectF.CodeGenerator.model.RegisterAddress;
import de.fuberlin.projectF.CodeGenerator.model.StackAddress;
import de.fuberlin.projectF.CodeGenerator.model.Token;
import de.fuberlin.projectF.CodeGenerator.model.TokenType;
import de.fuberlin.projectF.CodeGenerator.model.Variable;
public class Translator {
private MemoryManager mem;
protected Assembler asm;
ArrayList<Token> code;
public Translator(String assembler) {
mem = new MemoryManager();
if(assembler.equals("gnu"))
asm = new GNUAssembler();
else if(assembler.equals("intel"))
asm = new IntelAssembler();
else
return;
}
public void translate(ArrayList<Token> code) {
this.code = code;
int tokenNumber = 0;
String lastComparism = "";
for (Token tok : code) {
String op1, op2;
RegisterAddress res;
MMXRegisterAddress mmxRes;
MMXRegisterAddress mmxRes2;
switch (tok.getType()) {
case Declare:
asm.declare(tok.getTarget().substring(1));
break;
case Definition:
// Neuen Variablenkontext anlegen
String name = tok.getTarget().substring(1);
mem.newContext(name);
mem.setContext(name);
// Deklaration
asm.funcDec(name, "0", "0");
// Parameterbehandlung
if (tok.getParameterCount() > 0) {
int stack = 8;
for (int i = 0; i < tok.getParameterCount(); i++) {
Parameter p = tok.getParameter(i);
int size = getSize(p.getType());
mem.addStackVar(p.getOperand(), p.getType(), stack + size);
stack += size;
}
}
break;
case Return:
// Kein Rückgabewert oder bereits in %eax
if (tok.getTypeOp1().equals("void") || mem.inReg(tok.getOp1(), 0)) {
asm.funcEnd();
break;
}
// Variable zurückgeben
if (tok.getOp1().startsWith("%")) {
if(tok.getTypeOp1().equals("double"))
asm.movsd(mem.getAddress(tok.getOp1()), mem.getMMXRegister(0).getFullName(), "Return value");
else
asm.mov(mem.getAddress(tok.getOp1()), mem.getRegister(0).getFullName(), "Return value");
}
// Fester Wert
else {
if(tok.getTypeOp1().equals("double"))
asm.mov(tok.getOp1(), mem.getMMXRegister(0).getFullName(), "Return Value");
else
asm.mov(tok.getOp1(), mem.getRegister(0).getFullName(), "Return Value");
}
asm.funcEnd();
break;
case DefinitionEnd:
asm.funcEnd();
break;
case Call:
String function = tok.getOp1().substring(1);
// Variablen, die nur in Registern sind, auf dem Stack speichern
saveRegisters();
// Alle Register sind nun frei und werden möglicherweise in der
// Aufgerufenen Funktion verwendet.
// Parameter auf den Stack legen
if (tok.getParameterCount() > 0) {
for (int i = tok.getParameterCount() - 1; i >= 0; i--) {
Parameter p = tok.getParameter(i);
String operand;
if (p.getOperand().startsWith("%"))
operand = mem.getAddress(p.getOperand());
else
operand = p.getOperand();
if (operand.charAt(0) == '@')
operand = mem.getContextName() + "." + operand.substring(2);
if(p.getType().equals("double")) {
if(p.getOperand().startsWith("%")) {
asm.push(mem.getAddress(p.getOperand(), 4), "Parameter " + p.getOperand());
} else {
asm.push(p.getOperand().substring(0,10),"Parameter " + p.getOperand());
operand = "0x" + p.getOperand().substring(10);
}
}
asm.push(operand, "Parameter " + p.getOperand());
}
}
// Funktionsaufruf
asm.call(function);
// Parameter löschen
for (int i = 0; i < tok.getParameterCount(); i++) {
Parameter p = tok.getParameter(i);
asm.add(String.valueOf(getSize(p.getType())), "esp", "Dismiss Parameter");
}
// Rückgabe speichern
if (tok.getTypeTarget().equals("i32")) {
mem.addRegVar(tok.getTarget(), tok.getTypeTarget(), mem.getRegister(0));
}
else if (tok.getTypeTarget().equals("double")) {
mmxRes = mem.getMMXRegister(0);
mem.addMMXRegVar(tok.getTarget(), tok.getTypeTarget(), mmxRes);
Variable tmp = mem.newStackVar(tok.getTarget(), tok.getTypeTarget());
String addr = mem.getAddress(tmp.getName());
asm.sub(String.valueOf(tmp.getSize()), "esp", "save return on stack");
asm.movsd(mmxRes.getFullName(), addr, "save a copy");
}
break;
case Allocation:
String tT = tok.getTypeTarget();
// Array
if (tT.startsWith("[")){
Array newArr = createArray(tok.getTypeTarget(), tok.getTarget());
asm.sub(String.valueOf(newArr.getSize()), "esp",
"Allocation " + tok.getTarget());
}
// Record
else if(tT.startsWith("%")) {
int result;
result = findToken(0, false, TokenType.TypeDefinition, tok.getTypeTarget(), null, null);
Record rec = createRecord(tok.getTarget(), code.get(result));
asm.sub(String.valueOf(rec.getSize()), "esp",
"Allocation " + tok.getTarget());
}
// Kein Record
else{
// Neue Variable anlegen
Variable newVar = mem.newStackVar(tok.getTarget(),
tT);
// Stackpointer verschieben
asm.sub(String.valueOf(newVar.getSize()), "esp",
"Allocation " + tok.getTarget());
}
break;
case Assignment:
String target = mem.getAddress(tok.getTarget());
String source;
// Zuweisung Variable = Zahl
if (!tok.getOp1().startsWith("%")) {
if(tok.getTypeTarget().equals("i32*"))
asm.mov(tok.getOp1(), target, "Assignment " + tok.getTarget());
else if(tok.getTypeTarget().equals("double*")) {
String target2 = mem.getAddress(tok.getTarget(), +4);
asm.mov(tok.getOp1().substring(0,10), target2, "Assignment " + tok.getTarget());
asm.mov("0x" + tok.getOp1().substring(10), target, "Assignment " + tok.getTarget());
}
}
// Variable (Stack) = Variable (Stack)
else if (mem.onStack(tok.getOp1()) && mem.onStack(tok.getTarget())) {
if(tok.getTypeOp1().equals("double")) {
MMXRegisterAddress tmp = mem.getFreeMMXRegister();
asm.movsd(mem.getAddress(tok.getOp1()), tmp.getFullName(), "Copy assignment");
asm.movsd(tmp.getFullName(), target, tok.getTarget() + tok.getOp1());
} else {
RegisterAddress tmp = mem.getFreeRegister();
asm.mov(mem.getAddress(tok.getOp1()), tmp.getFullName(), "Copy assignment");
asm.mov(tmp.getFullName(), target, tok.getTarget() + tok.getOp1());
mem.freeRegister(tmp);
}
// Variable = Variable (min. ein Register)
} else {
source = mem.getAddress(tok.getOp1());
if(tok.getTypeTarget().equals("double*"))
asm.movsd(source, target, "Assignment double " + tok.getTarget());
else
asm.mov(source, target, "Assignment i32 " + tok.getTarget());
}
// Falls Zuweisung auf Array Pointer, kann dieser nun freigegeben werden.
mem.freeArrayPointer(tok.getTarget());
break;
case Load:
// Pointer anlegen
mem.newReference(tok.getTarget(), tok.getOp1());
break;
case ExpressionInt:
res = mem.getFreeRegister();
if (res == null) {
if (!freeUnusedRegister(tokenNumber))
System.err.println("Could'nt free register");
res = mem.getFreeRegister();
}
if (tok.getOp1().startsWith("%")) {
op1 = mem.getAddress(tok.getOp1());
}
else
op1 = tok.getOp1();
if (tok.getOp2().startsWith("%"))
op2 = mem.getAddress(tok.getOp2());
else
op2 = tok.getOp2();
asm.mov(op1, res.getFullName(), "Expression");
if (tok.getTypeTarget().equals("or"))
asm.or(op2, res.getFullName(), tok.getOp1() + " + " + tok.getOp2());
else if (tok.getTypeTarget().equals("and"))
asm.and(op2, res.getFullName(), tok.getOp1() + " + " + tok.getOp2());
else if (tok.getTypeTarget().equals("xor"))
asm.xor(op2, res.getFullName(), tok.getOp1() + " ^ " + tok.getOp2());
else if (tok.getTypeTarget().equals("add"))
asm.add(op2, res.getFullName(), tok.getOp1() + " + " + tok.getOp2());
else if (tok.getTypeTarget().equals("sub"))
asm.sub(op2, res.getFullName(), tok.getOp1() + " - " + tok.getOp2());
else if (tok.getTypeTarget().equals("mul"))
asm.imul(op2, res.getFullName(), tok.getOp1() + " * " + tok.getOp2());
else if (tok.getTypeTarget().equals("shl"))
asm.shl(op2, res.getFullName(), tok.getOp1() + " << " + tok.getOp2());
else if (tok.getTypeTarget().equals("ashr"))
asm.sar(op2, res.getFullName(), tok.getOp1() + " >a> " + tok.getOp2());
else if (tok.getTypeTarget().equals("lshr"))
asm.shr(op2, res.getFullName(), tok.getOp1() + " >l> " + tok.getOp2());
else if (tok.getTypeTarget().equals("sdiv")) {
if (!mem.isFree(0)) {
saveRegisters();
}
if (!mem.isFree(3)) {
saveRegisters();
}
asm.mov(op1, mem.getRegister(0).getFullName(), "");
asm.mov(new String("0"),
mem.getRegister(3).getFullName(), "");
asm.idiv(op2);
res = mem.getRegister(0);
}
mem.addRegVar(tok.getTarget(), "i32*", res);
break;
case ExpressionDouble:
if (tok.getOp1().startsWith("%"))
op1 = mem.getAddress(tok.getOp1());
else {
op1 = tok.getOp1();
Variable tmp = mem.newStackVar(tok.getTarget(), "double");
String addr = mem.getAddress(tmp.getName());
asm.sub(String.valueOf(tmp.getSize()), "esp", "");
asm.mov("0x" + op1.substring(10), addr, "save a copy");
addr = mem.getAddress(tmp.getName(),4);
asm.mov(op1.substring(0,10), addr, "save a copy");
op1 = mem.getAddress(tmp.getName());
}
if (tok.getOp2().startsWith("%"))
op2 = mem.getAddress(tok.getOp2());
else {
op2 = tok.getOp2();
Variable tmp = mem.newStackVar(tok.getTarget(), "double");
String addr = mem.getAddress(tmp.getName());
asm.sub(String.valueOf(tmp.getSize()), "esp", "");
asm.mov("0x" + op2.substring(10), addr, "save a copy");
addr = mem.getAddress(tmp.getName(),4);
asm.mov(op2.substring(0,10), addr, "save a copy");
op2 = mem.getAddress(tmp.getName());
}
mmxRes = mem.getFreeMMXRegister();
if (mmxRes == null) {
if (!freeUnusedMMXRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
mmxRes = mem.getFreeMMXRegister();
}
mem.addMMXRegVar(tok.getOp1(), tok.getTypeOp1(), mmxRes);
asm.movsd(op1, mmxRes.getFullName(), "Expression");
mmxRes2 = mem.getFreeMMXRegister();
if (mmxRes2 == null) {
if (!freeUnusedMMXRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
mmxRes2 = mem.getFreeMMXRegister();
}
asm.movsd(op2, mmxRes2.getFullName(), "Expression");
mem.addMMXRegVar(tok.getOp2(), tok.getTypeOp2(), mmxRes2);
if (tok.getTypeTarget().equals("fadd"))
asm.addsd(mmxRes2.getFullName(), mmxRes.getFullName(), tok.getOp1() + " + " + tok.getOp2());
else if (tok.getTypeTarget().equals("fsub"))
asm.subsd(mmxRes2.getFullName(), mmxRes.getFullName(), tok.getOp1() + " - " + tok.getOp2());
else if (tok.getTypeTarget().equals("fmul"))
asm.mulsd(mmxRes2.getFullName(), mmxRes.getFullName(), tok.getOp1() + " * " + tok.getOp2());
else if (tok.getTypeTarget().equals("fdiv")) {
asm.divsd(mmxRes2.getFullName(), mmxRes.getFullName(), tok.getOp1() + " * " + tok.getOp2());
}
mem.addMMXRegVar(tok.getTarget(), "double*", mmxRes);
break;
case Cast:
if(tok.getTypeTarget().equals("i32") && tok.getTypeOp1().equals("double")) {
op1 = mem.getAddress(tok.getOp1());
if(!mem.inMMXReg(tok.getOp1())) {
mmxRes = mem.getFreeMMXRegister();
asm.movss(op1, mmxRes.getFullName(), "Convert to single precision");
op1 = mmxRes.getFullName();
} else {
asm.cvtsd2ss(op1,op1, "Convert to single precision");
}
res = mem.getFreeRegister();
if (res == null) {
if (!freeUnusedRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
res = mem.getFreeRegister();
}
asm.cvttss2si(op1,res.getFullName(), "Convert to integer");
mem.addRegVar(tok.getTarget(), "i32*", res);
} else if (tok.getTypeTarget().equals("double") && tok.getTypeOp1().equals("i32")) {
op1 = mem.getAddress(tok.getOp1());
mmxRes = mem.getFreeMMXRegister();
if (mmxRes == null) {
if (!freeUnusedMMXRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
mmxRes = mem.getFreeMMXRegister();
}
asm.cvtsi2sd(op1, mmxRes.getFullName(), "Cast");
mem.addMMXRegVar(tok.getTarget(), "double*", mmxRes);
} else {
System.err.println("Cast Error");
}
break;
case Label:
asm.label(mem.getContextName() + "" + tok.getTarget());
break;
case CompareInteger:
res = mem.getFreeRegister();
if (res == null) {
if (!freeUnusedRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
res = mem.getFreeRegister();
}
if (tok.getOp1().startsWith("%"))
op1 = mem.getAddress(tok.getOp1());
else
op1 = tok.getOp1();
if (tok.getOp2().startsWith("%"))
op2 = mem.getAddress(tok.getOp2());
else
op2 = tok.getOp2();
lastComparism = tok.getTypeTarget();
asm.mov(op1, res.getFullName(), "Compare");
asm.icmp(op2, res.getFullName());
mem.addRegVar(tok.getOp1(), tok.getTypeOp1(), res);
break;
case CompareDouble:
mmxRes2 = mem.getFreeMMXRegister();
if (mmxRes2 == null) {
if (!freeUnusedRegister(tokenNumber)) {
System.err.println("Could'nt free register");
}
mmxRes2 = mem.getFreeMMXRegister();
}
if (tok.getOp1().startsWith("%"))
op1 = mem.getAddress(tok.getOp1());
else
op1 = tok.getOp1();
if (tok.getOp2().startsWith("%"))
op2 = mem.getAddress(tok.getOp2());
else
op2 = tok.getOp2();
lastComparism = tok.getTypeTarget();
asm.movsd(op1, mmxRes2.getFullName(), "Compare");
asm.fcmp(op2, mmxRes2.getFullName());
mem.addMMXRegVar(tok.getOp1(), tok.getTypeOp1(), mmxRes2);
break;
case Branch:
op2 = "label_" + mem.getContextName() + "" + tok.getOp2().substring(1);
if (!tok.getOp1().isEmpty()) {
op1 = "label_" + mem.getContextName() + "" + tok.getOp1().substring(1);
if (lastComparism.equals("eq"))
asm.je(op1);
else if (lastComparism.equals("ne"))
asm.jne(op1);
else if (lastComparism.equals("slt"))
asm.jl(op1);
else if (lastComparism.equals("sgt"))
asm.jg(op1);
else if (lastComparism.equals("sle"))
asm.jle(op1);
else if (lastComparism.equals("sge"))
asm.jge(op1);
else if (lastComparism.equals("oeq"))
asm.je(op1);
else if (lastComparism.equals("une"))
asm.jne(op1);
else if (lastComparism.equals("olt"))
asm.jb(op1);
else if (lastComparism.equals("ogt"))
asm.ja(op1);
else if (lastComparism.equals("ole"))
asm.jbe(op1);
else if (lastComparism.equals("oge"))
asm.jae(op1);
}
asm.jmp(op2);
break;
case String:
mem.addGlobalVar(tok.getTarget().substring(2));
String tmp = mem.getAddress(tok.getTarget().substring(2));
asm.data(tmp, ".ascii", tok.getOp1());
break;
case Getelementptr:
if(tok.getTypeTarget().charAt(0) == '%') {
mem.newRecordPtr(tok.getTarget(), tok.getOp1(), tok.getOp2());
} else if(tok.getOp1().charAt(0) == '@') {
mem.newReference(tok.getTarget(), tok.getOp1().substring(2));
} else {
// Array Pointer basiert auf bestehendem Array Pointer (z.B. mehrdimensionales Array)
if (tok.getOp1().matches("%\\d+")) {
String offset = tok.getOp2();
ArrayPointer newPtr = mem.contArrayPtr(tok.getTarget(), tok.getOp1(), tok.getOp2(), tok.getTypeTarget());
RegisterAddress temp = mem.getFreeRegister();
if (offset.startsWith("%")){
offset = mem.getAddress(offset);
}
asm.mov("" + newPtr.getValue(), temp.getFullName(), "ArrayPointer " + tok.getTarget());
asm.imul("" + newPtr.getArray().getTypeSize(), temp.getFullName(), "Calculating offset");
asm.imul(offset, temp.getFullName(), "");
asm.add(temp.getFullName(), newPtr.getPtrAddress(), "Adding to last pointer");
mem.freeRegister(temp);
}
// Neuen Array Pointer anlegen
else{
RegisterAddress reg = mem.getFreeRegister();
if (reg == null){
saveRegisters();
reg = mem.getFreeRegister();
}
String offset = tok.getOp2();
ArrayPointer newPtr = mem.newArrayPtr(tok.getTarget(), tok.getOp1(), tok.getTypeTarget(), reg);
if (offset.startsWith("%")){
offset = mem.getAddress(offset);
}
Array array = mem.getArray(tok.getOp1());
String ptrName = tok.getTarget();
// Offset berechnen
asm.mov("" + newPtr.getValue(), reg.getFullName(), "ArrayPointer " + ptrName);
asm.imul("" + array.getTypeSize(), reg.getFullName(), "Calculating offset");
asm.imul(offset, reg.getFullName(), "");
// Array-Adresse zum Offset addieren
RegisterAddress temp = mem.getFreeRegister();
if (temp == null){
saveRegisters();
temp = mem.getFreeRegister();
}
asm.lea(array.getAddress(), temp.getFullName(), "Load array address");
asm.add(temp.getFullName(), reg.getFullName(), "Add array address");
mem.freeRegister(temp);
}
}
break;
default:
break;
}
tokenNumber++;
}
//erstelle Einstiegspunkt
asm.createEP();
}
private void saveRegisters(){
List<Variable> regVars = mem.getRegVariables();
RegisterAddress movedFrom;
StackAddress movedTo;
for (Variable var : regVars) {
movedFrom = var.getRegAddress();
movedTo = mem.regToStack(var);
// Stackpointer verschieben
asm.sub(String.valueOf(var.getSize()), "esp", "Move var to stack");
asm.mov(movedFrom.getFullName(), movedTo.getFullName(), var.getName());
}
}
private void saveMMXRegisters(){
List<Variable> regVars = mem.getMMXRegVariables();
MMXRegisterAddress movedFrom;
StackAddress movedTo;
for (Variable var : regVars) {
movedFrom = var.getMMXRegAddress();
movedTo = mem.mmxRegToStack(var);
// Stackpointer verschieben
asm.sub(String.valueOf(var.getSize()), "esp", "Move var to stack");
asm.mov(movedFrom.getFullName(), movedTo.getFullName(), var.getName());
}
}
private Array createArray(String targetType, String target) {
// Extrahieren der Array-Größen
ArrayList<Integer> numbers = new ArrayList<Integer>();
Pattern p = Pattern.compile("(\\d+)(\\sx)");
Matcher m = p.matcher(targetType);
while (m.find()) {
numbers.add(new Integer(m.group(1)));
}
// Extrahieren des Typs
p = Pattern.compile("(i\\d+)|double");
m = p.matcher(targetType);
m.find();
String type = m.group();
// Länge berechnen
int length = 1;
for (Integer i : numbers) {
length *= i;
}
return mem.newArray(target, type, length);
}
private Record createRecord(String name, Token tok) {
Record rec = new Record(name);
for( int i = 0; i < tok.getParameterCount(); i++) {
String type = tok.getParameter(i).getType();
if(type.charAt(0) == '%') {
int result = findToken(0, false, TokenType.TypeDefinition, type, null, null);
Record tmp = createRecord(String.valueOf(i), code.get(result));
rec.add(tmp);
} else {
rec.add(mem.newStackVar(String.valueOf(i),type));
}
}
mem.newRecord(rec);
return rec;
}
private boolean freeUnusedRegister(int tokenNumber) {
HashMap<RegisterAddress, Reference> usedRegisters = mem.getUsedRegisters();
ArrayList<RegisterAddress> toFree = new ArrayList<RegisterAddress>();
for (Entry<RegisterAddress, Reference> entry : usedRegisters.entrySet()) {
RegisterAddress k = entry.getKey();
Reference v = entry.getValue();
if (findToken(tokenNumber, false, null, null, v.getName(), v.getName()) == 0) {
toFree.add(k);
}
}
for (RegisterAddress r : toFree) {
mem.freeRegister(r);
}
return !toFree.isEmpty();
}
private boolean freeUnusedMMXRegister(int tokenNumber) {
HashMap<MMXRegisterAddress, Variable> usedRegisters = mem.getUsedMMXRegisters();
ArrayList<MMXRegisterAddress> toFree = new ArrayList<MMXRegisterAddress>();
for (Entry<MMXRegisterAddress, Variable> entry : usedRegisters.entrySet()) {
MMXRegisterAddress k = entry.getKey();
Reference v = entry.getValue();
if (findToken(tokenNumber, false, null, null, v.getName(), v.getName()) == 0) {
toFree.add(k);
}
}
for (MMXRegisterAddress r : toFree) {
mem.freeMMXRegister(r);
}
return !toFree.isEmpty();
}
private int findToken(int start, boolean backwards, TokenType type,
String target, String op1, String op2) {
for (int i = start; i < code.size() && i >= 0;) {
if (code.get(i).getType() == type || type == null)
if (code.get(i).getTarget().equals(target) || target == null)
if (code.get(i).getOp1().equals(op1) || op1 == null)
if (code.get(i).getOp2().equals(op2) || op2 == null)
return i;
if (backwards)
i--;
else
i++;
}
return 0;
}
public String getCode() {
return (asm.getSectionHead() + asm.getSectionData().toString() + asm.getSectionText().toString());
}
public void print() {
System.out.print(asm.getSectionHead());
System.out.print(asm.getSectionData());
System.out.print(asm.getSectionText());
System.out.println();
}
private static int getSize(String type) {
if (type.equals("double"))
return 8;
else
return 4;
}
}