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:
parent
968f51343a
commit
62533afc6a
199
src/dk/camelot64/kickc/icl/AsmFragment.java
Normal file
199
src/dk/camelot64/kickc/icl/AsmFragment.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user