1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-18 08:30:18 +00:00

Refactored fragment handling

This commit is contained in:
jespergravgaard 2017-05-15 18:30:43 +02:00
parent 968f51343a
commit 62533afc6a
5 changed files with 208 additions and 221 deletions

View File

@ -0,0 +1,199 @@
package dk.camelot64.kickc.icl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Code Generation Fragment that can handle loading of fragment file and binding of values / registers */
public class AsmFragment {
/** The symbol table. */
private SymbolTable symbols;
/** Binding of named values in the fragment to values (constants, variables, ...) .*/
private Map<String, Value> bindings;
/** The string signature/name of the asm fragment. */
private String signature;
public AsmFragment(StatementConditionalJump conditionalJump, SymbolTable symbols) {
this.bindings = new HashMap<>();
this.symbols = symbols;
StringBuilder signature = new StringBuilder();
signature.append(bind(conditionalJump.getCondition()));
signature.append("?");
signature.append(bind(conditionalJump.getDestination()));
setSignature(signature.toString());
}
public AsmFragment(StatementAssignment assignment, SymbolTable symbols) {
this.bindings = new HashMap<>();
this.symbols = symbols;
setSignature(assignmentSignature(assignment.getLValue(), assignment.getRValue1(), assignment.getOperator(), assignment.getRValue2()));
}
public AsmFragment(LValue lValue, RValue rValue, SymbolTable symbols) {
this.bindings = new HashMap<>();
this.symbols = symbols;
setSignature(assignmentSignature(lValue, null, null, rValue));
}
private String assignmentSignature(LValue lValue, RValue rValue1, Operator operator, RValue rValue2) {
StringBuilder signature = new StringBuilder();
signature.append(bind(lValue));
signature.append("=");
if (rValue1 != null) {
signature.append(bind(rValue1));
}
if (operator != null) {
signature.append(operator.getOperator());
}
signature.append(bind(rValue2));
return signature.toString();
}
public Value getBinding(String name) {
return bindings.get(name);
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
/** Zero page byte register name indexing. */
private int nextZpByteIdx = 1;
/** Zero page bool register name indexing. */
private int nextZpBoolIdx = 1;
/** Constant byte indexing. */
private int nextConstByteIdx = 1;
/** Label indexing. */
private int nextLabelIdx = 1;
/**
* Add bindings of a value.
* @param value The value to bind.
* @return The bound name of the value. If the value has already been bound the existing bound name is returned.
*/
public String bind(Value value) {
// Find value if it is already bound
for (String name : bindings.keySet()) {
if (value.equals(bindings.get(name))) {
return name;
}
}
if (value instanceof Variable) {
RegisterAllocation.Register register = symbols.getRegister((Variable) value);
if (RegisterAllocation.RegisterType.ZP_BYTE.equals(register.getType())) {
String name = "zpby" + nextZpByteIdx++;
bindings.put(name, value);
return name;
} else if (RegisterAllocation.RegisterType.ZP_BOOL.equals(register.getType())) {
String name = "zpbo" + nextZpBoolIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of register type not supported " + register.getType());
}
} else if (value instanceof ConstantInteger) {
ConstantInteger intValue = (ConstantInteger) value;
if(intValue.getType().equals(SymbolType.BYTE)) {
String name = "coby"+ nextConstByteIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of word integers not supported " + intValue);
}
} else if (value instanceof Label) {
String name = "la"+ nextLabelIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of value type not supported " + value);
}
}
/**
* Get the value to replace a bound name with from the fragment signature
*
* @param name The name of the bound value in the fragment
* @return The bound value to use in the generated ASM code
*/
public String getValue(String name) {
Value boundValue = getBinding(name);
String bound;
if (boundValue instanceof Variable) {
RegisterAllocation.Register register = symbols.getRegister((Variable) boundValue);
if (register instanceof RegisterAllocation.RegisterZpByte) {
bound = Integer.toString(((RegisterAllocation.RegisterZpByte) register).getZp());
} else if (register instanceof RegisterAllocation.RegisterZpBool) {
bound = Integer.toString(((RegisterAllocation.RegisterZpBool) register).getZp());
} else {
throw new RuntimeException("Register Type not implemented " + register);
}
} else if (boundValue instanceof ConstantInteger) {
ConstantInteger boundInt = (ConstantInteger) boundValue;
if (boundInt.getType().equals(SymbolType.BYTE)) {
bound = Integer.toString(boundInt.getNumber());
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
} else if (boundValue instanceof Label) {
bound = ((Label) boundValue).getName().replace('@', 'B');
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
return bound;
}
/**
* Generate assembler code for the assembler fragment.
*
* @param asm The assembler sequence to generate into.
*/
public void generateAsm(AsmSequence asm) {
String signature = this.getSignature();
ClassLoader classLoader = this.getClass().getClassLoader();
URL fragmentResource = classLoader.getResource("dk/camelot64/kickc/icl/asm/" + signature + ".asm");
if (fragmentResource == null) {
System.out.println("Fragment not found " + fragmentResource);
asm.addAsm(" // Fragment not found: " + signature);
return;
}
Pattern bindPattern = Pattern.compile(".*\\{([^}]*)}.*");
try {
InputStream fragmentStream = fragmentResource.openStream();
BufferedReader fragmentReader = new BufferedReader(new InputStreamReader(fragmentStream));
String line;
while ((line = fragmentReader.readLine()) != null) {
Matcher matcher = bindPattern.matcher(line);
if (matcher.matches()) {
String name = matcher.group(1);
String bound = this.getValue(name);
line = line.replaceFirst("\\{[^}]*}", bound);
}
asm.addAsm(" " + line);
}
fragmentReader.close();
fragmentStream.close();
} catch (IOException e) {
throw new RuntimeException("Error reading code fragment " + fragmentResource);
}
}
}

View File

@ -1,90 +0,0 @@
package dk.camelot64.kickc.icl;
import java.util.HashMap;
import java.util.Map;
/** Signature and Binding for a Code Generation Fragment */
public abstract class AsmFragmentSignature {
/** The symbol table. */
private SymbolTable symbols;
/** Binding of named values in the fragment to values (constants, variables, ...) .*/
private Map<String, Value> bindings;
/** The string signature/name of the asm fragment. */
private String signature;
public AsmFragmentSignature(SymbolTable symbols) {
this.symbols = symbols;
this.bindings = new HashMap<>();
}
public Value getBinding(String name) {
return bindings.get(name);
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
/** Zero page byte register name indexing. */
private int nextZpByteIdx = 1;
/** Zero page bool register name indexing. */
private int nextZpBoolIdx = 1;
/** Constant byte indexing. */
private int nextConstByteIdx = 1;
/** Label indexing. */
private int nextLabelIdx = 1;
/**
* Add bindings of a value.
* @param value The value to bind.
* @return The bound name of the value. If the value has already been bound the existing bound name is returned.
*/
public String bind(Value value) {
// Find value if it is already bound
for (String name : bindings.keySet()) {
if (value.equals(bindings.get(name))) {
return name;
}
}
if (value instanceof Variable) {
RegisterAllocation.Register register = symbols.getRegister((Variable) value);
if (RegisterAllocation.RegisterType.ZP_BYTE.equals(register.getType())) {
String name = "zpby" + nextZpByteIdx++;
bindings.put(name, value);
return name;
} else if (RegisterAllocation.RegisterType.ZP_BOOL.equals(register.getType())) {
String name = "zpbo" + nextZpBoolIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of register type not supported " + register.getType());
}
} else if (value instanceof ConstantInteger) {
ConstantInteger intValue = (ConstantInteger) value;
if(intValue.getType().equals(SymbolType.BYTE)) {
String name = "coby"+ nextConstByteIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of word integers not supported " + intValue);
}
} else if (value instanceof Label) {
String name = "la"+ nextLabelIdx++;
bindings.put(name, value);
return name;
} else {
throw new RuntimeException("Binding of value type not supported " + value);
}
}
}

View File

@ -1,31 +0,0 @@
package dk.camelot64.kickc.icl;
/** Assembler Fragemnt Signature for an assignment */
public class AsmFragmentSignatureAssignment extends AsmFragmentSignature {
public AsmFragmentSignatureAssignment(StatementAssignment assignment, SymbolTable symbols) {
super(symbols);
setSignature(assignment.getLValue(), assignment.getRValue1(), assignment.getOperator(), assignment.getRValue2());
}
public AsmFragmentSignatureAssignment(LValue lValue, RValue rValue, SymbolTable symbols) {
super(symbols);
setSignature(lValue, null, null, rValue);
}
private void setSignature(LValue lValue, RValue rValue1, Operator operator, RValue rValue2) {
StringBuilder signature = new StringBuilder();
signature.append(bind(lValue));
signature.append("=");
if (rValue1 != null) {
signature.append(bind(rValue1));
}
if (operator != null) {
signature.append(operator.getOperator());
}
signature.append(bind(rValue2));
setSignature(signature.toString());
}
}

View File

@ -1,13 +0,0 @@
package dk.camelot64.kickc.icl;
/** Assembler Fragment Signature for a conditional jump */
public class AsmFragmentSignatureConditionalJump extends AsmFragmentSignature {
public AsmFragmentSignatureConditionalJump(StatementConditionalJump conditionalJump, SymbolTable symbols) {
super(symbols);
StringBuilder signature = new StringBuilder();
signature.append(bind(conditionalJump.getCondition()));
signature.append("?");
signature.append(bind(conditionalJump.getDestination()));
setSignature(signature.toString());
}
}

View File

@ -1,13 +1,6 @@
package dk.camelot64.kickc.icl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Code Generation of 6502 Assembler from ICL/SSA Control Flow Graph
@ -55,13 +48,13 @@ public class Pass4CodeGeneration {
private void genStatement(AsmSequence asm, Statement statement) {
if (statement instanceof StatementAssignment) {
AsmFragmentSignature asmFragmentSignature = new AsmFragmentSignatureAssignment((StatementAssignment) statement, symbols);
asm.addAsm(" // " + statement + " // " + asmFragmentSignature.getSignature());
genAsmFragment(asm, asmFragmentSignature);
AsmFragment asmFragment = new AsmFragment((StatementAssignment) statement, symbols);
asm.addAsm(" // " + statement + " // " + asmFragment.getSignature());
asmFragment.generateAsm(asm);
} else if (statement instanceof StatementConditionalJump) {
AsmFragmentSignature asmFragmentSignature = new AsmFragmentSignatureConditionalJump((StatementConditionalJump) statement, symbols);
asm.addAsm(" // " + statement + " // " + asmFragmentSignature.getSignature());
genAsmFragment(asm, asmFragmentSignature);
AsmFragment asmFragment = new AsmFragment((StatementConditionalJump) statement, symbols);
asm.addAsm(" // " + statement + " // " + asmFragment.getSignature());
asmFragment.generateAsm(asm);
} else {
asm.addAsm(" // TODO: " + statement);
}
@ -102,9 +95,9 @@ public class Pass4CodeGeneration {
* @param lValue The lValue
*/
private void genAsmMove(AsmSequence asm, RValue rValue, LValue lValue) {
AsmFragmentSignatureAssignment signature = new AsmFragmentSignatureAssignment(lValue, rValue, symbols);
asm.addAsm(" // " + rValue + " = " + lValue + " // " + signature.getSignature());
genAsmFragment(asm, signature);
AsmFragment asmFragment = new AsmFragment(lValue, rValue, symbols);
asm.addAsm(" // " + rValue + " = " + lValue + " // " + asmFragment.getSignature());
asmFragment.generateAsm(asm);
}
private void genAsmLabel(AsmSequence asm, Label label) {
@ -119,76 +112,5 @@ public class Pass4CodeGeneration {
asm.addAsm(" jmp " + label.replace('@', 'B'));
}
/**
* Generate assembler code for an assembler fragment.
*
* @param asm The assembler sequence to generate into.
* @param fragmentSignature Signature of the code fragment to generate
*/
private void genAsmFragment(AsmSequence asm, AsmFragmentSignature fragmentSignature) {
String signature = fragmentSignature.getSignature();
ClassLoader classLoader = this.getClass().getClassLoader();
URL fragmentResource = classLoader.getResource("dk/camelot64/kickc/icl/asm/" + signature + ".asm");
if (fragmentResource == null) {
System.out.println("Fragment not found " + fragmentResource);
asm.addAsm(" // Fragment not found: " + signature);
return;
}
Pattern bindPattern = Pattern.compile(".*\\{([^}]*)}.*");
try {
InputStream fragmentStream = fragmentResource.openStream();
BufferedReader fragmentReader = new BufferedReader(new InputStreamReader(fragmentStream));
String line;
while ((line = fragmentReader.readLine()) != null) {
Matcher matcher = bindPattern.matcher(line);
if (matcher.matches()) {
String name = matcher.group(1);
String bound = getFragmentBoundValue(name, fragmentSignature);
line = line.replaceFirst("\\{[^}]*}", bound);
}
asm.addAsm(" " + line);
}
fragmentReader.close();
fragmentStream.close();
} catch (IOException e) {
throw new RuntimeException("Error reading code fragment " + fragmentResource);
}
}
/**
* Get the value to replace a bound name with from the fragment signature
*
* @param boundName The name of the bound value in the fragment
* @param fragmentSignature The fragment signature containing the bindings
* @return The bound value to use in the generated ASM code
*/
private String getFragmentBoundValue(String boundName, AsmFragmentSignature fragmentSignature) {
Value boundValue = fragmentSignature.getBinding(boundName);
String bound;
if (boundValue instanceof Variable) {
RegisterAllocation.Register register = symbols.getRegister((Variable) boundValue);
if (register instanceof RegisterAllocation.RegisterZpByte) {
bound = Integer.toString(((RegisterAllocation.RegisterZpByte) register).getZp());
} else if (register instanceof RegisterAllocation.RegisterZpBool) {
bound = Integer.toString(((RegisterAllocation.RegisterZpBool) register).getZp());
} else {
throw new RuntimeException("Register Type not implemented " + register);
}
} else if (boundValue instanceof ConstantInteger) {
ConstantInteger boundInt = (ConstantInteger) boundValue;
if (boundInt.getType().equals(SymbolType.BYTE)) {
bound = Integer.toString(boundInt.getNumber());
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
} else if (boundValue instanceof Label) {
bound = ((Label) boundValue).getName().replace('@', 'B');
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}
return bound;
}
}