mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-24 20:32:39 +00:00
Fixing #488. Still fails on for() with no condition and an increment.
This commit is contained in:
parent
1852630b16
commit
be54089089
@ -202,7 +202,7 @@ switchCase:
|
||||
;
|
||||
|
||||
forLoop
|
||||
: forClassicInit ';' commaExpr ';' commaExpr? #forClassic
|
||||
: forClassicInit ';' commaExpr? ';' commaExpr? #forClassic
|
||||
| (declType declPointer*)? NAME COLON expr RANGE expr #forRange
|
||||
;
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1521,12 +1521,23 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
StatementLabel repeatTarget = new StatementLabel(beginJumpLabel.getRef(), StatementSource.forClassic(ctx), comments);
|
||||
addStatement(repeatTarget);
|
||||
// Add condition
|
||||
RValue rValue = addCondition(ctx.commaExpr(0), StatementSource.forClassic(ctx));
|
||||
final KickCParser.CommaExprContext conditionCtx = ctx.commaExpr(0);
|
||||
RValue conditionRvalue = null;
|
||||
if(conditionCtx!=null) {
|
||||
conditionRvalue = addCondition(conditionCtx, StatementSource.forClassic(ctx));
|
||||
}
|
||||
// Add jump if condition was met
|
||||
StatementConditionalJump doJmpStmt = new StatementConditionalJump(rValue, doJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(doJmpStmt);
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(endJmpStmt);
|
||||
Statement doJmpStmt;
|
||||
if(conditionRvalue!=null) {
|
||||
doJmpStmt = new StatementConditionalJump(conditionRvalue, doJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(doJmpStmt);
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(endJmpStmt);
|
||||
} else {
|
||||
// No condition - loop forever
|
||||
doJmpStmt = new StatementJump( doJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(doJmpStmt);
|
||||
}
|
||||
StatementLabel doJumpTarget = new StatementLabel(doJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(doJumpTarget);
|
||||
// Add body
|
||||
@ -1544,7 +1555,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
addStatement(beginJmpStmt);
|
||||
StatementLabel endJumpTarget = new StatementLabel(endJumpLabel.getRef(), StatementSource.forClassic(ctx), Comment.NO_COMMENTS);
|
||||
addStatement(endJumpTarget);
|
||||
addDirectives(doJmpStmt, stmtForCtx.directive());
|
||||
if(doJmpStmt instanceof StatementConditionalJump)
|
||||
addDirectives((StatementConditionalJump) doJmpStmt, stmtForCtx.directive());
|
||||
addLoopBreakLabel(loopStack.pop(), ctx);
|
||||
scopeStack.pop();
|
||||
return null;
|
||||
|
@ -42,10 +42,15 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
//@Test
|
||||
//public void testForEver() throws IOException, URISyntaxException {
|
||||
// compileAndCompare("for-ever.c");
|
||||
//}
|
||||
@Test
|
||||
public void testForEver2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("for-ever-2.c", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEver() throws IOException, URISyntaxException {
|
||||
compileAndCompare("for-ever.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerToPointerProblem() throws IOException, URISyntaxException {
|
||||
|
@ -1,4 +1,10 @@
|
||||
// lazyNES balloon demo
|
||||
// lazyNES - As lazy as possible NES hardware support library for vbcc6502
|
||||
// (happily cooperates with Shiru's famitone2 replay code)
|
||||
// V1.0, 'Lazycow 2020
|
||||
|
||||
// Ported to KickC 2020 by Jesper Gravgaard
|
||||
// Original Source VBCC alpha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip
|
||||
|
||||
#pragma target(nes)
|
||||
#include "lazynes.h"
|
||||
|
145
src/test/kc/complex/lazynes/bubbles.c
Normal file
145
src/test/kc/complex/lazynes/bubbles.c
Normal file
@ -0,0 +1,145 @@
|
||||
// lazyNES bubbles demo
|
||||
// lazyNES - As lazy as possible NES hardware support library for vbcc6502
|
||||
// (happily cooperates with Shiru's famitone2 replay code)
|
||||
// V1.0, 'Lazycow 2020
|
||||
|
||||
// Ported to KickC 2020 by Jesper Gravgaard
|
||||
// Original Source VBCC alpha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip
|
||||
|
||||
#pragma target(nes)
|
||||
#include "lazynes.h"
|
||||
|
||||
enum {
|
||||
F=3, // pseudo floating point shift value
|
||||
maxDrawObjects=40,
|
||||
dfAlive=1
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ubyte
|
||||
f, // flags
|
||||
s; // sprite image offset into bubbles[] table
|
||||
sword
|
||||
x, y; // coordinates (shifted)
|
||||
sbyte
|
||||
vx, vy, // velocity
|
||||
ax, ay; // accelleration
|
||||
} DrawObject;
|
||||
|
||||
|
||||
DrawObject dTab[maxDrawObjects];
|
||||
|
||||
|
||||
// print some text in the static area
|
||||
//
|
||||
void Print(uword offset, ubyte value) {
|
||||
static ubyte b[]={0,0,10,'B','U','B','B','L','E','S',':',0,0,lfEnd};
|
||||
b[0]=(offset>>8)|lfHor; b[1]=offset&255; b[11]=b[12]='0';
|
||||
while (value>=10) { ++b[11]; value-=10; }
|
||||
while (value>=1) { ++b[12]; value-=1; }
|
||||
lnList(b);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
int lnMain() {
|
||||
|
||||
static const ubyte bgColors[]={45,33,2};
|
||||
static const ubyte bubblesPal[]={ 0, 37,22,5, 0, 42,26,10, 0, 33,18,3 };
|
||||
static const ubyte bubbles[]={ // x-offset, y-offset, tile, palette+flags
|
||||
0,0,7,0, 8,0,9,0, 128, // 16x16, red, offset 0
|
||||
0,0,7,1, 8,0,9,1, 128, // 16x16, green, offset 9
|
||||
0,0,7,2, 8,0,9,2, 128, // 16x16, blue, offest 18
|
||||
0,4,11,0,128, // 8x8, red, offset 27
|
||||
0,4,11,1,128, // 8x8, green, offset 32
|
||||
0,4,11,2,128, // 8x8, blue, offset 37
|
||||
},
|
||||
bubbleTab[]={0,27,9,32,18,37}; // start offsets in bubbles[]
|
||||
|
||||
ubyte
|
||||
i,
|
||||
type=0,
|
||||
stopIt=0,
|
||||
objects=0;
|
||||
uword
|
||||
hScroll=0,
|
||||
tics=0;
|
||||
sbyte
|
||||
hVel=0, hDir=1;
|
||||
|
||||
lnSync(lfBlank); // blank screen to enable lnPush() usage
|
||||
lnPush(lnBackCol,3,bgColors); // set background colors
|
||||
lnPush(lnSprPal0,3,&bubblesPal[1]); // set sprite colors
|
||||
lnPush(lnSprPal1,3,&bubblesPal[5]);
|
||||
lnPush(lnSprPal2,3,&bubblesPal[9]);
|
||||
lnPPUCTRL|=32; // Select 8x16 sprites; has to be set after calling lnSync()!
|
||||
|
||||
// draw some backgrounds
|
||||
{ //
|
||||
static const ubyte g1[]={1}, g2[]={2,3,4,5}, g3[]={6,7,8,9};
|
||||
ubyte x;
|
||||
// draw a line: Sprite #0 will be placed ontop later to trigger the split
|
||||
i=2; for (x=0;x<32;x+=1) lnPush(lnNameTab0+(i<<5)+x,1,g1);
|
||||
// draw some diamond shapes
|
||||
for (i=8;i<=24;i+=4) for (x=0;x<4;x+=1) {
|
||||
lnPush(lnNameTab0+(i<<5)+12+x*4,4,g2);
|
||||
lnPush(lnNameTab0+32+(i<<5)+12+x*4,4,g3);
|
||||
}
|
||||
}
|
||||
|
||||
// setup bubbles
|
||||
type=0;
|
||||
for (i=0;i<maxDrawObjects;i+=1) {
|
||||
DrawObject* d=&dTab[i];
|
||||
d->f=dfAlive;
|
||||
d->s=bubbleTab[type];
|
||||
type+=1; if (type>=6) type=0;
|
||||
d->x=80<<F; d->vx=i; d->ax=1;
|
||||
d->y=24<<F; d->vy=1<<F; d->ay=1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
DrawObject* d;
|
||||
|
||||
lnScroll(0,0); // reset scrolling offsets of area above split
|
||||
lnScroll(hScroll>>6,32); // set scrolling offsets of area below split
|
||||
hVel+=hDir; if (hVel>64 || hVel<-64) hDir=-hDir;
|
||||
hScroll+=hVel;
|
||||
|
||||
// add 1st sprite (SPR0) at a fixed position on top of background blocks
|
||||
// mandatory for the SPR0HIT check later with lnSync(lfSplit)
|
||||
lnAddSpr(&bubbles[bubbleTab[5]],16,16);
|
||||
lnSpr0Wait=55; // delay the set of scrolling registers a bit
|
||||
|
||||
// move bubbles
|
||||
for (i=0,d=dTab; i<objects ;i+=1,++d) if (d->f&dfAlive) {
|
||||
d->vx+=d->ax;
|
||||
if (d->vx<-32) d->ax=1; else if (d->vx>32) d->ax=-1;
|
||||
if (d->y>216<<F) d->vy=-1<<F; else if (d->y<24<<F) d->vy=1<<F;
|
||||
d->x+=d->vx;
|
||||
d->y+=d->vy;
|
||||
lnAddSpr(&bubbles[d->s],d->x>>F,d->y>>F);
|
||||
}
|
||||
|
||||
// activate new bubble?
|
||||
tics+=1; if (tics>8) {
|
||||
tics=0;
|
||||
if (0==stopIt && objects<maxDrawObjects) objects+=1;
|
||||
}
|
||||
|
||||
// display the amount of moving bubbles + spr0-bubble
|
||||
Print(lnNameTab0+32,objects+1);
|
||||
|
||||
i=lnSync(lfSplit)&31; // sync with vblank, activate SPR0HIT splitscreen
|
||||
|
||||
// lnSync() returns the number of vblank NMI's that have been triggered
|
||||
// since the last call of lnSync(). If the program code is too slow to
|
||||
// move all objects in one frame (i>1), then we reduce the amount of
|
||||
// objects (objects-=1) and everything moves with 60 fps again.
|
||||
if (i>1 && objects>0) { objects-=1; stopIt=1; } // stop adding objects?
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
// lazyNES lazyhello demo
|
||||
// lazyNES - As lazy as possible NES hardware support library for vbcc6502
|
||||
// (happily cooperates with Shiru's famitone2 replay code)
|
||||
// V1.0, 'Lazycow 2020
|
||||
|
||||
// Ported to KickC 2020 by Jesper Gravgaard
|
||||
// Original Source VBCC alpha 2 http://www.ibaug.de/vbcc/vbcc6502_2.zip
|
||||
|
@ -40,7 +40,7 @@ void lnPush(uword o, ubyte a, void* s);
|
||||
// updateList: Pointer to update list
|
||||
//
|
||||
// TODO: void lnList(void* updateList);
|
||||
// TODO: enum { lfHor=64, lfVer=128, lfEnd=255 };
|
||||
enum { lfHor=64, lfVer=128, lfEnd=255 };
|
||||
//
|
||||
// remarks:
|
||||
// - The format of the update list is an array of unsigned bytes.
|
||||
|
9
src/test/kc/for-ever-2.c
Normal file
9
src/test/kc/for-ever-2.c
Normal file
@ -0,0 +1,9 @@
|
||||
// Test a for() loop that runs forever
|
||||
|
||||
char * const SCREEN = 0x0400;
|
||||
|
||||
void main() {
|
||||
for (char i=0;;i++) {
|
||||
SCREEN[i]++;
|
||||
}
|
||||
}
|
11
src/test/ref/for-ever.asm
Normal file
11
src/test/ref/for-ever.asm
Normal file
@ -0,0 +1,11 @@
|
||||
// Test a for() loop that runs forever
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
__b1:
|
||||
// (*SCREEN)++;
|
||||
inc SCREEN
|
||||
jmp __b1
|
||||
}
|
8
src/test/ref/for-ever.cfg
Normal file
8
src/test/ref/for-ever.cfg
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[1] *((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN)
|
||||
to:main::@1
|
148
src/test/ref/for-ever.log
Normal file
148
src/test/ref/for-ever.log
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from __start
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
*((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN)
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from
|
||||
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
|
||||
(const nomodify byte*) SCREEN = (byte*)(number) $400
|
||||
(void()) __start()
|
||||
(label) __start::@1
|
||||
(label) __start::@return
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@return
|
||||
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Removing unused block main::@return
|
||||
Successful SSA optimization Pass2EliminateUnusedBlocks
|
||||
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
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@1
|
||||
[1] *((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN)
|
||||
to:main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
|
||||
Initial phi equivalence classes
|
||||
Complete equivalence classes
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is c64basic / MOS6502X
|
||||
// File Comments
|
||||
// Test a for() loop that runs forever
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [1] *((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc SCREEN
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 120 combination
|
||||
Uplifting [] best 120 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test a for() loop that runs forever
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [1] *((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc SCREEN
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 90
|
||||
|
||||
// File Comments
|
||||
// Test a for() loop that runs forever
|
||||
// Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
// main::@1
|
||||
__b1:
|
||||
// (*SCREEN)++;
|
||||
// [1] *((const nomodify byte*) SCREEN) ← ++ *((const nomodify byte*) SCREEN) -- _deref_pbuc1=_inc__deref_pbuc1
|
||||
inc SCREEN
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
4
src/test/ref/for-ever.sym
Normal file
4
src/test/ref/for-ever.sym
Normal file
@ -0,0 +1,4 @@
|
||||
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
|
Loading…
Reference in New Issue
Block a user