diff --git a/src/main/antlr4/dk/camelot64/kickc/parser/KickCParser.g4 b/src/main/antlr4/dk/camelot64/kickc/parser/KickCParser.g4 index 1a7e70da2..574d23c4b 100644 --- a/src/main/antlr4/dk/camelot64/kickc/parser/KickCParser.g4 +++ b/src/main/antlr4/dk/camelot64/kickc/parser/KickCParser.g4 @@ -136,7 +136,7 @@ parameterDecl ; pragma - : PRAGMA NAME PAR_BEGIN pragmaParam (COMMA pragmaParam)* PAR_END + : PRAGMA NAME PAR_BEGIN (pragmaParam (COMMA pragmaParam)* )? PAR_END ; pragmaParam diff --git a/src/main/java/dk/camelot64/kickc/preprocessor/CPreprocessor.java b/src/main/java/dk/camelot64/kickc/preprocessor/CPreprocessor.java index 3b80d2e6d..1fe90dd54 100644 --- a/src/main/java/dk/camelot64/kickc/preprocessor/CPreprocessor.java +++ b/src/main/java/dk/camelot64/kickc/preprocessor/CPreprocessor.java @@ -223,10 +223,9 @@ public class CPreprocessor implements TokenSource { pragmaTokens.add(pragmaType); pragmaTokens.addAll(skipWhitespace(cTokenSource)); ArrayList pragmaBody = readBody(cTokenSource); - final Token pragmaBodyStart = pragmaBody.get(0); // Convert space-based pragma to parenthesis-based for easier parsing // #pragma NAME XXX YYY \n => #pragma NAME ( XXX , YYY ) \n - if(pragmaBodyStart.getType() != KickCLexer.PAR_BEGIN) { + if(pragmaBody.isEmpty() || pragmaBody.get(0).getType() != KickCLexer.PAR_BEGIN) { ArrayList parenthesizedBody = new ArrayList<>(); parenthesizedBody.add(new CommonToken(KickCLexer.PAR_BEGIN, "(")); // Parenthesize the parameter list diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index 90670856d..042f930e2 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -546,6 +546,11 @@ public class TestProgramsFast extends TestPrograms { compileAndCompare("pragma-unknown.c"); } + @Test + public void testPragmaNoParametersNoParenthesis() throws IOException { + compileAndCompare("pragma-noparam-noparen.c"); + } + @Test public void testErrorFormatter() throws IOException { // Error on a char diff --git a/src/test/kc/pragma-noparam-noparen.c b/src/test/kc/pragma-noparam-noparen.c new file mode 100644 index 000000000..2d9fe466b --- /dev/null +++ b/src/test/kc/pragma-noparam-noparen.c @@ -0,0 +1,8 @@ +// Test that #pragma works with no parenthesis and no parameters + +#pragma nobank + +void main() { + char * const SCREEN = (char*) 0x0400; + *SCREEN = 'a'; +} \ No newline at end of file diff --git a/src/test/ref/pragma-noparam-noparen.asm b/src/test/ref/pragma-noparam-noparen.asm new file mode 100644 index 000000000..7039561db --- /dev/null +++ b/src/test/ref/pragma-noparam-noparen.asm @@ -0,0 +1,18 @@ +// Test that #pragma works with no parenthesis and no parameters + // Commodore 64 PRG executable file +.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) +.segment Code +main: { + .label SCREEN = $400 + // *SCREEN = 'a' + lda #'a' + sta SCREEN + // } + rts +} diff --git a/src/test/ref/pragma-noparam-noparen.cfg b/src/test/ref/pragma-noparam-noparen.cfg new file mode 100644 index 000000000..134ce4314 --- /dev/null +++ b/src/test/ref/pragma-noparam-noparen.cfg @@ -0,0 +1,8 @@ + +void main() +main: scope:[main] from + [0] *main::SCREEN = 'a' + to:main::@return +main::@return: scope:[main] from main + [1] return + to:@return diff --git a/src/test/ref/pragma-noparam-noparen.log b/src/test/ref/pragma-noparam-noparen.log new file mode 100644 index 000000000..68ccb3b9d --- /dev/null +++ b/src/test/ref/pragma-noparam-noparen.log @@ -0,0 +1,135 @@ +Warning! Unknown #pragma nobank + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + *main::SCREEN = 'a' + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +void __start() +void main() +__constant char * const main::SCREEN = (char *)$400 + +Simplifying constant pointer cast (char *) 1024 +Successful SSA optimization PassNCastSimplification +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +CALL GRAPH + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] *main::SCREEN = 'a' + to:main::@return +main::@return: scope:[main] from main + [1] return + to:@return + + +VARIABLE REGISTER WEIGHTS +void main() + +Initial phi equivalence classes +Complete equivalence classes +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *main::SCREEN = 'a' [ ] ( [ ] { } ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 15 combination +Uplifting [] best 15 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test that #pragma works with no parenthesis and no parameters + // Upstart + // Commodore 64 PRG executable file +.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels +.segment Code + // main +main: { + .label SCREEN = $400 + // [0] *main::SCREEN = 'a' -- _deref_pbuc1=vbuc2 + lda #'a' + sta SCREEN + jmp __breturn + // main::@return + __breturn: + // [1] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +void main() +__constant char * const main::SCREEN = (char *) 1024 + + + +FINAL ASSEMBLER +Score: 12 + + // File Comments +// Test that #pragma works with no parenthesis and no parameters + // Upstart + // Commodore 64 PRG executable file +.file [name="pragma-noparam-noparen.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels +.segment Code + // main +main: { + .label SCREEN = $400 + // *SCREEN = 'a' + // [0] *main::SCREEN = 'a' -- _deref_pbuc1=vbuc2 + lda #'a' + sta SCREEN + // main::@return + // } + // [1] return + rts +} + // File Data + diff --git a/src/test/ref/pragma-noparam-noparen.sym b/src/test/ref/pragma-noparam-noparen.sym new file mode 100644 index 000000000..a2a8aef7f --- /dev/null +++ b/src/test/ref/pragma-noparam-noparen.sym @@ -0,0 +1,3 @@ +void main() +__constant char * const main::SCREEN = (char *) 1024 +