From 9c39311d6739cf059dd72f54e007ce997b03d1ee Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 2 Dec 2017 16:56:58 +0100 Subject: [PATCH] Preventing double imports. Closes #102 --- .../java/dk/camelot64/kickc/Compiler.java | 79 +-- .../dk/camelot64/kickc/model/Program.java | 27 +- .../dk/camelot64/kickc/test/TestPrograms.java | 4 + .../dk/camelot64/kickc/test/double-import.kc | 6 + .../kickc/test/ref/double-import.asm | 11 + .../kickc/test/ref/double-import.cfg | 15 + .../kickc/test/ref/double-import.log | 514 ++++++++++++++++++ .../kickc/test/ref/double-import.sym | 10 + 8 files changed, 612 insertions(+), 54 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/test/double-import.kc create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/double-import.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/double-import.cfg create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/double-import.log create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/double-import.sym diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 650dd15b8..ddbf1f428 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -19,10 +19,9 @@ public class Compiler { private Program program; public Compiler() { - this.program = new Program(new ProgramScope(), new CompileLog()); - this.program.setImportPaths(new ArrayList<>()); + this.program = new Program(); } - + public CompileLog getLog() { return program.getLog(); } @@ -57,45 +56,51 @@ public class Compiler { } public static void loadAndParseFile(String fileName, Program program, StatementSequenceGenerator statementSequenceGenerator) { - CharStream fileStream = loadFile(fileName, program); - program.getLog().append(fileStream.toString()); - KickCLexer lexer = new KickCLexer(fileStream); - KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); - parser.setBuildParseTree(true); - parser.addErrorListener(new BaseErrorListener() { - @Override - public void syntaxError( - Recognizer recognizer, - Object offendingSymbol, - int line, - int charPositionInLine, - String msg, - RecognitionException e) { - throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); - } - }); - statementSequenceGenerator.generate(parser.file()); - } - - private static CharStream loadFile(String fileName, Program program) { - if(!fileName.endsWith(".kc")) { - fileName += ".kc"; - } try { - List importPaths = program.getImportPaths(); - for (String importPath : importPaths) { - if(!importPath.endsWith("/")) { - importPath += "/"; - } - String filePath = importPath + fileName; - File file = new File(filePath); - if(file.exists()) { - return CharStreams.fromPath(file.toPath()); - } + File file = loadFile(fileName, program); + List imported = program.getImported(); + if (imported.contains(file.getAbsolutePath())) { + return; } + final CharStream fileStream = CharStreams.fromPath(file.toPath()); + imported.add(file.getAbsolutePath()); + program.getLog().append(fileStream.toString()); + KickCLexer lexer = new KickCLexer(fileStream); + KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); + parser.setBuildParseTree(true); + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { + throw new CompileError("Error parsing file " + fileStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg); + } + }); + statementSequenceGenerator.generate(parser.file()); } catch (IOException e) { throw new CompileError("Error loading file " + fileName, e); } + } + + private static File loadFile(String fileName, Program program) { + if (!fileName.endsWith(".kc")) { + fileName += ".kc"; + } + List importPaths = program.getImportPaths(); + for (String importPath : importPaths) { + if (!importPath.endsWith("/")) { + importPath += "/"; + } + String filePath = importPath + fileName; + File file = new File(filePath); + if (file.exists()) { + return file; + } + } throw new CompileError("File not found " + fileName); } diff --git a/src/main/java/dk/camelot64/kickc/model/Program.java b/src/main/java/dk/camelot64/kickc/model/Program.java index 6688724c2..6469f084d 100644 --- a/src/main/java/dk/camelot64/kickc/model/Program.java +++ b/src/main/java/dk/camelot64/kickc/model/Program.java @@ -1,10 +1,9 @@ package dk.camelot64.kickc.model; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; import dk.camelot64.kickc.CompileLog; import dk.camelot64.kickc.asm.AsmProgram; +import java.util.ArrayList; import java.util.List; /** A KickC Intermediate Compiler Language (ICL) Program */ @@ -12,6 +11,8 @@ public class Program { /** Paths used for importing files. */ private List importPaths; + /** Imported files. */ + private List imported; /** The initial statement sequence generated byt the parser. */ private StatementSequence statementSequence; /** The main scope. */ @@ -52,27 +53,19 @@ public class Program { /** Separation of live range equivalence classes into scopes - used for register uplift */ private RegisterUpliftProgram registerUpliftProgram; - @JsonCreator - public Program( - @JsonProperty("scope") ProgramScope scope, - @JsonProperty("graph") ControlFlowGraph graph, - @JsonProperty("asm") AsmProgram asm) { - this.scope = scope; - this.graph = graph; - this.asm = asm; - } - - public Program(ProgramScope programScope, CompileLog log) { - this.scope = programScope; - this.log = log; + public Program() { + this.scope = new ProgramScope(); + this.log = new CompileLog(); + this.importPaths = new ArrayList<>(); + this.imported = new ArrayList<>(); } public List getImportPaths() { return importPaths; } - public void setImportPaths(List importPaths) { - this.importPaths = importPaths; + public List getImported() { + return imported; } public StatementSequence getStatementSequence() { diff --git a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java index 75e176494..f06effafc 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java @@ -24,6 +24,10 @@ public class TestPrograms extends TestCase { helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); } + public void testDoubleImport() throws IOException, URISyntaxException { + compileAndCompare("double-import"); + } + public void testImporting() throws IOException, URISyntaxException { compileAndCompare("importing"); } diff --git a/src/main/java/dk/camelot64/kickc/test/double-import.kc b/src/main/java/dk/camelot64/kickc/test/double-import.kc new file mode 100644 index 000000000..7e7ea8617 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/double-import.kc @@ -0,0 +1,6 @@ +import "imported" +import "imported" + +void main() { + *BGCOL = RED; +} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/test/ref/double-import.asm b/src/main/java/dk/camelot64/kickc/test/ref/double-import.asm new file mode 100644 index 000000000..3e8eae581 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/double-import.asm @@ -0,0 +1,11 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .const BGCOL = $d021 + .const RED = 2 + jsr main +main: { + lda #RED + sta BGCOL + rts +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/double-import.cfg b/src/main/java/dk/camelot64/kickc/test/ref/double-import.cfg new file mode 100644 index 000000000..3d5c83dff --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/double-import.cfg @@ -0,0 +1,15 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [5] return [ ] ( main:2 [ ] ) + to:@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/double-import.log b/src/main/java/dk/camelot64/kickc/test/ref/double-import.log new file mode 100644 index 000000000..7c2dd50b2 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/double-import.log @@ -0,0 +1,514 @@ +import "imported" +import "imported" + +void main() { + *BGCOL = RED; +} +Importing imported +const byte *BGCOL = $d021; +const byte RED = 2; + +Importing imported +PROGRAM + (byte*) BGCOL ← (word) 53281 + (byte) RED ← (byte/signed byte/word/signed word) 2 +proc (void()) main() + *((byte*) BGCOL) ← (byte) RED +main::@return: + return +endproc // main() + call main + +SYMBOLS +(byte*) BGCOL +(byte) RED +(void()) main() +(label) main::@return + +Promoting word to byte* in BGCOL ← ((byte*)) 53281 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) BGCOL ← ((byte*)) (word) 53281 + (byte) RED ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from + *((byte*) BGCOL) ← (byte) RED + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) BGCOL ← ((byte*)) (word) 53281 + (byte) RED ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from + *((byte*) BGCOL) ← (byte) RED + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@begin: scope:[] from + (byte*) BGCOL ← ((byte*)) (word) 53281 + (byte) RED ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + *((byte*) BGCOL) ← (byte) RED + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +Completing Phi functions... +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (word) 53281 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + (byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + *((byte*) BGCOL#1) ← (byte) RED#1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + (byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (word) 53281 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + (byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + *((byte*) BGCOL#1) ← (byte) RED#1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + (byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +INITIAL SSA SYMBOL TABLE +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) BGCOL +(byte*) BGCOL#0 +(byte*) BGCOL#1 +(byte*) BGCOL#2 +(byte) RED +(byte) RED#0 +(byte) RED#1 +(byte) RED#2 +(void()) main() +(label) main::@return + +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (word) 53281 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + (byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#2 ) + (byte) RED#1 ← phi( @1/(byte) RED#2 ) + *((byte*) BGCOL#1) ← (byte) RED#1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + (byte*) BGCOL#2 ← phi( @begin/(byte*) BGCOL#0 ) + (byte) RED#2 ← phi( @begin/(byte) RED#0 ) + call main param-assignment + to:@end +@end: scope:[] from @1 + +Not aliassing across scopes: RED#1 RED#2 +Not aliassing across scopes: BGCOL#1 BGCOL#2 +Alias (byte) RED#0 = (byte) RED#2 +Alias (byte*) BGCOL#0 = (byte*) BGCOL#2 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (word) 53281 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + (byte*) BGCOL#1 ← phi( @1/(byte*) BGCOL#0 ) + (byte) RED#1 ← phi( @1/(byte) RED#0 ) + *((byte*) BGCOL#1) ← (byte) RED#1 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Not aliassing across scopes: RED#1 RED#0 +Not aliassing across scopes: BGCOL#1 BGCOL#0 +Redundant Phi (byte) RED#1 (byte) RED#0 +Redundant Phi (byte*) BGCOL#1 (byte*) BGCOL#0 +Succesful SSA optimization Pass2RedundantPhiElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (word) 53281 + (byte) RED#0 ← (byte/signed byte/word/signed word) 2 + to:@1 +main: scope:[main] from @1 + *((byte*) BGCOL#0) ← (byte) RED#0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const byte*) BGCOL#0 = ((byte*))53281 +Constant (const byte) RED#0 = 2 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + *((const byte*) BGCOL#0) ← (const byte) RED#0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 = ((byte*))(word) 53281 +(byte) RED +(const byte) RED#0 = (byte/signed byte/word/signed word) 2 +(void()) main() +(label) main::@return + +Block Sequence Planned @begin @1 @end main main::@return +Block Sequence Planned @begin @1 @end main main::@return +CONTROL FLOW GRAPH - PHI LIFTED +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + *((const byte*) BGCOL#0) ← (const byte) RED#0 + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +CALL GRAPH +Calls in [] to main:2 + +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES FOUND +@begin: scope:[] from + [0] phi() [ ] + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 + [3] phi() [ ] +main: scope:[main] from @1 + [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] + to:main::@return +main::@return: scope:[main] from main + [5] return [ ] + to:@return + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @1 @end main main::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Propagating live ranges... +CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES +@begin: scope:[] from + [0] phi() [ ] + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] + [2] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 + [3] phi() [ ] +main: scope:[main] from @1 + [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] + to:main::@return +main::@return: scope:[main] from main + [5] return [ ] + to:@return + +CONTROL FLOW GRAPH - PHI MEM COALESCED +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@1 +@1: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 + [3] phi() [ ] ( ) +main: scope:[main] from @1 + [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) + to:main::@return +main::@return: scope:[main] from main + [5] return [ ] ( main:2 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@return dominated by main::@return @1 @begin main + +NATURAL LOOPS + +Found 0 loops in scope [] +Found 0 loops in scope [main] +NATURAL LOOPS WITH DEPTH + + +VARIABLE REGISTER WEIGHTS +(byte*) BGCOL +(byte) RED +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const BGCOL = $d021 + .const RED = 2 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2 + lda #RED + sta BGCOL + jmp breturn + //SEG10 main::@return + breturn: + //SEG11 [5] return [ ] ( main:2 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 27 combination +Uplifting [] best 27 combination +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const BGCOL = $d021 + .const RED = 2 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2 + lda #RED + sta BGCOL + //SEG10 main::@return + breturn: + //SEG11 [5] return [ ] ( main:2 [ ] ) + rts +} + +Removing instruction bbegin: +Removing instruction b1_from_bbegin: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const BGCOL = $d021 + .const RED = 2 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +b1: +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2 + lda #RED + sta BGCOL + //SEG10 main::@return + breturn: + //SEG11 [5] return [ ] ( main:2 [ ] ) + rts +} + +Removing instruction b1: +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const BGCOL = $d021 + .const RED = 2 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2 + lda #RED + sta BGCOL + //SEG10 main::@return + //SEG11 [5] return [ ] ( main:2 [ ] ) + rts +} + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281 +(byte) RED +(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2 +(void()) main() +(label) main::@return + + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const BGCOL = $d021 + .const RED = 2 +//SEG2 @begin +//SEG3 [1] phi from @begin to @1 [phi:@begin->@1] +//SEG4 @1 +//SEG5 [2] call main param-assignment [ ] ( ) + jsr main +//SEG6 [3] phi from @1 to @end [phi:@1->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 [4] *((const byte*) BGCOL#0) ← (const byte) RED#0 [ ] ( main:2 [ ] ) -- _deref_cowo1=coby2 + lda #RED + sta BGCOL + //SEG10 main::@return + //SEG11 [5] return [ ] ( main:2 [ ] ) + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/double-import.sym b/src/main/java/dk/camelot64/kickc/test/ref/double-import.sym new file mode 100644 index 000000000..f3a4c6433 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/double-import.sym @@ -0,0 +1,10 @@ +(label) @1 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = ((byte*))(word) 53281 +(byte) RED +(const byte) RED#0 RED = (byte/signed byte/word/signed word) 2 +(void()) main() +(label) main::@return +