Add support for the continue statement
Add error check for a break statement that's not inside a loop. (We just generated bad code before. Oops!)
This commit is contained in:
parent
0163f77a83
commit
c951c59232
|
@ -5003,7 +5003,7 @@ class Compiler : public ErrorSink {
|
|||
return pGen->gtst(0, 0);
|
||||
}
|
||||
|
||||
void block(intptr_t l, bool outermostFunctionBlock) {
|
||||
void block(int* breakLabel, int continueAddress, bool outermostFunctionBlock) {
|
||||
intptr_t a, n, t;
|
||||
|
||||
Type* pBaseType;
|
||||
|
@ -5015,12 +5015,12 @@ class Compiler : public ErrorSink {
|
|||
skip('(');
|
||||
a = test_expr();
|
||||
skip(')');
|
||||
block(l, false);
|
||||
block(breakLabel, continueAddress, false);
|
||||
if (tok == TOK_ELSE) {
|
||||
next();
|
||||
n = pGen->gjmp(0); /* jmp */
|
||||
pGen->gsym(a);
|
||||
block(l, false);
|
||||
block(breakLabel, continueAddress, false);
|
||||
pGen->gsym(n); /* patch else jmp */
|
||||
} else {
|
||||
pGen->gsym(a); /* patch if test */
|
||||
|
@ -5050,7 +5050,7 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
skip(')');
|
||||
block((intptr_t) &a, false);
|
||||
block(&a, n, false);
|
||||
pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
|
||||
pGen->gsym(a);
|
||||
} else if (tok == '{') {
|
||||
|
@ -5059,7 +5059,7 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
next();
|
||||
while (tok != '}' && tok != EOF)
|
||||
block(l, false);
|
||||
block(breakLabel, continueAddress, false);
|
||||
skip('}');
|
||||
if (! outermostFunctionBlock) {
|
||||
mLocals.popLevel();
|
||||
|
@ -5081,7 +5081,17 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
rsym = pGen->gjmp(rsym); /* jmp */
|
||||
} else if (accept(TOK_BREAK)) {
|
||||
*(int *) l = pGen->gjmp(*(int *) l);
|
||||
if (breakLabel) {
|
||||
*breakLabel = pGen->gjmp(*breakLabel);
|
||||
} else {
|
||||
error("break statement must be within a for, do, while, or switch statement");
|
||||
}
|
||||
} else if (accept(TOK_CONTINUE)) {
|
||||
if (continueAddress) {
|
||||
pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
|
||||
} else {
|
||||
error("continue statement must be within a for, do, or while statement");
|
||||
}
|
||||
} else if (tok != ';')
|
||||
commaExpr();
|
||||
skip(';');
|
||||
|
@ -5907,7 +5917,7 @@ class Compiler : public ErrorSink {
|
|||
rsym = loc = 0;
|
||||
pReturnType = pDecl->pHead;
|
||||
a = pGen->functionEntry(pDecl);
|
||||
block(0, true);
|
||||
block(0, 0, true);
|
||||
pGen->gsym(rsym);
|
||||
pGen->functionExit(pDecl, a, loc);
|
||||
mLocals.popLevel();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
int main() {
|
||||
int i, j, sum;
|
||||
sum = 0;
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (i & 1) continue;
|
||||
for (j = 0; j < 10; j++) {
|
||||
if (j & 1) continue;
|
||||
sum += i * j;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
|
@ -187,6 +187,10 @@ class TestACC(unittest.TestCase):
|
|||
self.compileCheck(["-R", "data/returnval-ansi.c"],
|
||||
"Executing compiled code:\nresult: 42\n")
|
||||
|
||||
def testContinue(self):
|
||||
self.compileCheck(["-R", "data/continue.c"],
|
||||
"Executing compiled code:\nresult: 400\n")
|
||||
|
||||
def testStringLiteralConcatenation(self):
|
||||
self.compileCheck(["-R", "data/testStringConcat.c"],
|
||||
"Executing compiled code:\nresult: 13\n", "Hello, world\n")
|
||||
|
|
Loading…
Reference in New Issue