From c951c59232f59f1e0235725103f8636fe2f580f7 Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Thu, 29 Oct 2009 15:04:27 -0700 Subject: [PATCH] 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!) --- libacc/acc.cpp | 24 +++++++++++++++++------- libacc/tests/data/continue.c | 13 +++++++++++++ libacc/tests/test.py | 4 ++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 libacc/tests/data/continue.c diff --git a/libacc/acc.cpp b/libacc/acc.cpp index d9cecdd6c..984019779 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -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(); diff --git a/libacc/tests/data/continue.c b/libacc/tests/data/continue.c new file mode 100644 index 000000000..d8b8e36ca --- /dev/null +++ b/libacc/tests/data/continue.c @@ -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; +} + diff --git a/libacc/tests/test.py b/libacc/tests/test.py index 6e0899cd8..d93af4686 100644 --- a/libacc/tests/test.py +++ b/libacc/tests/test.py @@ -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")