mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-18 22:30:05 +00:00
Added support for ASM .string directives through string initializer.
This commit is contained in:
parent
1a649008b9
commit
6fb5372f1b
@ -3,7 +3,7 @@ package dk.camelot64.kickc.asm;
|
||||
import java.util.List;
|
||||
|
||||
/** A labelled numeric data directive. */
|
||||
public class AsmData implements AsmLine {
|
||||
public class AsmDataNumeric implements AsmLine {
|
||||
|
||||
private String label;
|
||||
private Type type;
|
||||
@ -25,7 +25,7 @@ public class AsmData implements AsmLine {
|
||||
|
||||
}
|
||||
|
||||
public AsmData(String label, Type type, List<String> values) {
|
||||
public AsmDataNumeric(String label, Type type, List<String> values) {
|
||||
this.label = label;
|
||||
this.type = type;
|
||||
this.values = values;
|
44
src/main/java/dk/camelot64/kickc/asm/AsmDataString.java
Normal file
44
src/main/java/dk/camelot64/kickc/asm/AsmDataString.java
Normal file
@ -0,0 +1,44 @@
|
||||
package dk.camelot64.kickc.asm;
|
||||
|
||||
/** A labelled string data directive. */
|
||||
public class AsmDataString implements AsmLine {
|
||||
|
||||
private String label;
|
||||
private String value;
|
||||
private int index;
|
||||
|
||||
public AsmDataString(String label, String value) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineBytes() {
|
||||
return value.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLineCycles() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsm() {
|
||||
StringBuilder asm = new StringBuilder();
|
||||
asm.append(label+": ");
|
||||
asm.append(".text ");
|
||||
asm.append("\""+value+"\"");
|
||||
return asm.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
}
|
@ -91,10 +91,20 @@ public class AsmProgram {
|
||||
* @param type The type of the data
|
||||
* @param asmElements The value of the elements
|
||||
*/
|
||||
public void addData(String label, AsmData.Type type, List<String> asmElements) {
|
||||
addLine(new AsmData(label, type, asmElements));
|
||||
public void addDataNumeric(String label, AsmDataNumeric.Type type, List<String> asmElements) {
|
||||
addLine(new AsmDataNumeric(label, type, asmElements));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string data declaration tot the ASM
|
||||
* @param label The label of the data
|
||||
* @param value The value of the string
|
||||
*/
|
||||
public void addDataString(String label, String value) {
|
||||
addLine(new AsmDataString(label, value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of bytes the segment occupies in memory.
|
||||
* Calculated by adding up the bytes of each ASM segment in the program.
|
||||
|
@ -138,7 +138,7 @@ public class AsmSegment {
|
||||
printState.decIndent();
|
||||
}
|
||||
out.append(printState.getIndent());
|
||||
if (line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant || line instanceof AsmData ) {
|
||||
if (line instanceof AsmComment || line instanceof AsmInstruction || line instanceof AsmLabelDecl || line instanceof AsmConstant || line instanceof AsmDataNumeric|| line instanceof AsmDataString) {
|
||||
out.append(" ");
|
||||
}
|
||||
out.append(line.getAsm() + "\n");
|
||||
|
@ -16,6 +16,10 @@ public class ConstantString implements ConstantValue {
|
||||
return SymbolTypeBasic.STRING;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
@ -24,9 +28,9 @@ public class ConstantString implements ConstantValue {
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
if (program == null) {
|
||||
return "\\" + value + "\\";
|
||||
return "\"" + value + "\"";
|
||||
} else {
|
||||
return "(" + SymbolTypeBasic.STRING.getTypeName() + ") " + "\\" + value + "\\";
|
||||
return "(" + SymbolTypeBasic.STRING.getTypeName() + ") " + "\"" + value + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,7 +486,8 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public RValue visitExprString(KickCParser.ExprStringContext ctx) {
|
||||
return new ConstantString(ctx.getText());
|
||||
String text = ctx.getText();
|
||||
return new ConstantString(text.substring(1, text.length()-1));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,7 +92,7 @@ public class Pass4CodeGeneration {
|
||||
Collection<ConstantVar> scopeConstants = scope.getAllConstants(false);
|
||||
Set<String> added = new LinkedHashSet<>();
|
||||
for (ConstantVar constantVar : scopeConstants) {
|
||||
if(! (constantVar.getValue() instanceof ConstantArray)) {
|
||||
if(! (constantVar.getValue() instanceof ConstantArray || constantVar.getValue() instanceof ConstantString)) {
|
||||
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
|
||||
if (asmName != null && !added.contains(asmName)) {
|
||||
asm.addConstant(asmName.replace("#", "_").replace("$", "_"), AsmFragment.getAsmConstant(program, constantVar.getValue(), 99));
|
||||
@ -117,19 +117,23 @@ public class Pass4CodeGeneration {
|
||||
ConstantArray constantArray = (ConstantArray) constantVar.getValue();
|
||||
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
|
||||
if (asmName != null && !added.contains(asmName)) {
|
||||
|
||||
List<String> asmElements = new ArrayList<>();
|
||||
for (ConstantValue element : constantArray.getElements()) {
|
||||
String asmElement = AsmFragment.getAsmConstant(program, element, 99);
|
||||
asmElements.add(asmElement);
|
||||
}
|
||||
if(SymbolTypeBasic.BYTE.equals(constantArray.getElementType())) {
|
||||
asm.addData(asmName.replace("#", "_").replace("$", "_"), AsmData.Type.BYTE, asmElements);
|
||||
asm.addDataNumeric(asmName.replace("#", "_").replace("$", "_"), AsmDataNumeric.Type.BYTE, asmElements);
|
||||
added.add(asmName);
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled constant array element type "+constantArray.toString(program));
|
||||
}
|
||||
}
|
||||
} else if(constantVar.getValue() instanceof ConstantString) {
|
||||
ConstantString constantString = (ConstantString) constantVar.getValue();
|
||||
String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName();
|
||||
asm.addDataString(asmName.replace("#", "_").replace("$", "_"), constantString.getValue());
|
||||
added.add(asmName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ public class VariableReplacer {
|
||||
if(rValue instanceof SymbolRef) {
|
||||
RValue alias = aliases.get(rValue);
|
||||
if(alias!=null) {
|
||||
if(alias.equals(rValue)) {
|
||||
return alias;
|
||||
}
|
||||
RValue replacement = getReplacement(alias);
|
||||
if(replacement!=null) {
|
||||
return replacement;
|
||||
|
@ -40,6 +40,10 @@ public class TestCompilationOutput extends TestCase {
|
||||
compileAndCompare("inmemarray");
|
||||
}
|
||||
|
||||
public void testInMemString() throws IOException, URISyntaxException {
|
||||
compileAndCompare("inmemstring");
|
||||
}
|
||||
|
||||
public void testVoronoi() throws IOException, URISyntaxException {
|
||||
compileAndCompare("voronoi");
|
||||
}
|
||||
|
15
src/main/java/dk/camelot64/kickc/test/inmemstring.kc
Normal file
15
src/main/java/dk/camelot64/kickc/test/inmemstring.kc
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
byte* SCREEN = $0400;
|
||||
byte[] TEXT = "camelot ";
|
||||
|
||||
main();
|
||||
void main() {
|
||||
byte* cursor = SCREEN;
|
||||
byte i=0;
|
||||
do {
|
||||
(*cursor) = TEXT[i];
|
||||
if(++i>8) {
|
||||
i = 0;
|
||||
}
|
||||
} while(++cursor<SCREEN+1000)
|
||||
}
|
33
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.asm
Normal file
33
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.asm
Normal file
@ -0,0 +1,33 @@
|
||||
.const SCREEN = $400
|
||||
TEXT: .text "camelot "
|
||||
jsr main
|
||||
main: {
|
||||
.label cursor = 2
|
||||
lda #<SCREEN
|
||||
sta cursor
|
||||
lda #>SCREEN
|
||||
sta cursor+1
|
||||
ldx #0
|
||||
b1:
|
||||
lda TEXT,x
|
||||
ldy #0
|
||||
sta (cursor),y
|
||||
inx
|
||||
cpx #8
|
||||
bcc b2_from_b1
|
||||
ldx #0
|
||||
b2_from_b1:
|
||||
inc cursor
|
||||
bne !+
|
||||
inc cursor+1
|
||||
!:
|
||||
lda cursor+1
|
||||
cmp #>SCREEN+$3e8
|
||||
bcc b1
|
||||
bne !+
|
||||
lda cursor
|
||||
cmp #<SCREEN+$3e8
|
||||
bcc b1
|
||||
!:
|
||||
rts
|
||||
}
|
23
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.cfg
Normal file
23
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.cfg
Normal file
@ -0,0 +1,23 @@
|
||||
@begin: scope:[] from
|
||||
[0] call main param-assignment [ ]
|
||||
to:@end
|
||||
@end: scope:[] from @begin
|
||||
main: scope:[main] from @begin
|
||||
[1] phi() [ ]
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[2] (byte*) main::cursor#2 ← phi( main/(const byte*) SCREEN#0 main::@2/(byte*) main::cursor#1 ) [ main::i#3 main::cursor#2 ]
|
||||
[2] (byte) main::i#3 ← phi( main/(byte) 0 main::@2/(byte) main::i#4 ) [ main::i#3 main::cursor#2 ]
|
||||
[3] (byte~) main::$0 ← (const byte[]) TEXT#0 *idx (byte) main::i#3 [ main::i#3 main::cursor#2 main::$0 ]
|
||||
[4] *((byte*) main::cursor#2) ← (byte~) main::$0 [ main::i#3 main::cursor#2 ]
|
||||
[5] (byte) main::i#1 ← ++ (byte) main::i#3 [ main::cursor#2 main::i#1 ]
|
||||
[6] if((byte) main::i#1<=(byte) 8) goto main::@2 [ main::cursor#2 main::i#1 ]
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1 main::@1
|
||||
[7] (byte) main::i#4 ← phi( main::@1/(byte) main::i#1 main::@1/(byte) 0 ) [ main::cursor#2 main::i#4 ]
|
||||
[8] (byte*) main::cursor#1 ← ++ (byte*) main::cursor#2 [ main::i#4 main::cursor#1 ]
|
||||
[9] if((byte*) main::cursor#1<(const byte*) SCREEN#0+(word) 1000) goto main::@1 [ main::i#4 main::cursor#1 ]
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[10] return [ ]
|
||||
to:@return
|
1347
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.log
Normal file
1347
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.log
Normal file
File diff suppressed because it is too large
Load Diff
22
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.sym
Normal file
22
src/main/java/dk/camelot64/kickc/test/ref/inmemstring.sym
Normal file
@ -0,0 +1,22 @@
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) SCREEN
|
||||
(const byte*) SCREEN#0 SCREEN = (word) 1024
|
||||
(byte[]) TEXT
|
||||
(const byte[]) TEXT#0 TEXT = (string) "camelot "
|
||||
(void()) main()
|
||||
(byte~) main::$0 reg byte a 22.0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte*) main::cursor
|
||||
(byte*) main::cursor#1 cursor zp ZP_PTR_BYTE:2 16.5
|
||||
(byte*) main::cursor#2 cursor zp ZP_PTR_BYTE:2 5.5
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#3 reg byte x 11.0
|
||||
(byte) main::i#4 reg byte x 7.333333333333333
|
||||
|
||||
reg byte x [ main::i#3 main::i#4 main::i#1 ]
|
||||
zp ZP_PTR_BYTE:2 [ main::cursor#2 main::cursor#1 ]
|
||||
reg byte a [ main::$0 ]
|
Loading…
x
Reference in New Issue
Block a user