[See 
Adding Named Constants to Jack for another Jack language extension.]
As I was writing the 
Jack Jack Compiler I had to write rather 
tortured structure to achieve single exit point code to ensure that there were 
no leaking Strings.  For example:
['ok' is true coming into this code.]
let break = false;
while (ok & ( ~ break)) {
    do xml.writeToken(token);
    let ok = _expectIdentifier();
    if (ok) {
        // Add class variable to symbol table
        let ok = symbolTable.define(token.identifier(), type, kind);
        if ( ~ ok) {
            do _printDuplicateSymbol(token.identifier());
        }
    } if (ok) {
        do token.advance();
        do xml.writeToken(token);
        if (_isSymbol(44)) {    // ','
            do token.advance();
        } else {
            let break = true;
        }
    }
}
I was wishing that Jack had break statements for its while 
loops.  With break statements, this code could be rewritten:
while (true) {
    do xml.writeToken(token);
    let ok = _expectIdentifier();
    if ( ~ ok) {
        break;
    }
    // Add class variable to symbol table
    let ok = symbolTable.define(token.identifier(), type, kind);
    if ( ~ ok) {
        do _printDuplicateSymbol(token.identifier());
        break;
    }
    do token.advance();
    do xml.writeToken(token);
    if (_isSymbol(44)) {    // ','
        do token.advance(); }
    else {
        break;
    }
}
It's certainly clearer in this code that the loop exits on the first error that 
is encountered.
What would it take to add break and continue statements?
Grammatically, 
break and 
continue are trivial; the are just two 
more statement types in the 
statement rule:
| <statement> | 
	 ::=  | 
	<letStatement> | 
		<ifStatement> | 
		<whileStatement> | 
		<doStatement> | 
		<returnStatement> | 
		<breakStatement> | 
		<continueStatement> | 
Semantically, break and continue may only appear within the 
body of a while statement, or an element nested within the body.  The 
break or continue refers to the deepest while 
statement containing them. (The only nestable elements 
containing statements are if and while.)
In my compiler, compileWhile() starts by creating three unique labels 
(Strings) that will be used in the generated code:
continueLabel = uniqueLabel();  // Before conditional test
bodyLabel = uniqueLabel();      // Before statement body
breakLabel = uniqueLabel();     // After statement body
These are local variables that are destroyed at the end of compileWhile().
break and continue statements will need to generate code that 
jumps to either breakLabel or continueLabel.
How will compileBreak() access the breakLabel variable 
set in compileWhile()?
breakLabel and 
continueLabel will 
need to become class variables:
this.continueLabel = uniqueLabel();  // Before conditional test
bodyLabel = uniqueLabel();           // Before statement body
this.breakLabel = uniqueLabel();     // After statement body
These class variables will need to be initialized to NULL so that the 
compileBreak() and compileContinue() can know when these 
statements are illegal.
They also need to be reset to NULL at the end of compileWhile() 
so that break and continue statements will be invalid 
outside the loop.
What about nested while statements?
Nested 
while statements need to use different 
breakLabel and 
continueLabel values than their parent 
while loop(s).
while (...) {
    ...
    while (...) {
        ...
        if (...) {
            continue;   // Jump to the beginning of the inner while.
        }
        ...
    }
    if (...) {
        continue;       // Jump to the beginning of the outer while.
    }
}
compileWhile() is a recursive function.  When it is called for the nested 
while loop, it will overwrite the class variables when it allocates the 
new breakLabel and continueLabel.  All break and 
continue statements in its scope will jump to the right place.
The problem is what happens when this compileWhile() returns and the 
outer compileWhile() resumes.  The breakLabel and 
continueLabel are NULL.  The outer continue will be flagged as 
a "break outside of while" error.
Nested Scopes
Languages like C++ and Java allow variables to be defined inside any { } pair.  
This is called a nested scope.  Those variables are only accessible inside the 
{ } pair.  Also in the nested scope are things less visible to the programmer, 
for instance the 
break and 
continue information.  Adding nested 
scopes like this to the Jack compiler would be a lot of work.
Fortunately, all that needs to be saved is the context for any outer 
while statement; this is just the two class variables breakLabel 
and continueLabel.  They can be saved in local variables on the stack.
void compileWhile() {
    saveContinueLabel = this.continueLabel;
    saveBreakLabel = this.breakLabel;
    this.continueLabel = uniqueLabel();  // Before conditional test
    bodyLabel = uniqueLabel();           // Before statement body
    this.breakLabel = uniqueLabel();     // After statement body
    ...
    [Explicitly deallocate this.continueLabel and this.breakLabel
    if required by programming language.]
    this.continueLabel = saveContinueLabel;
    this.breakLabel = saveBreakLabel;
}
Since breakLabel and continueLabel were NULL on entry to the 
outermost while statement, they will be restored to NULL on exiting 
that loop.  Any break or continue statements outside of the 
outermost while loop will be flagged as errors.
Final Result
Main.jack:
class Main {
    function void main() {
        var int i, j;
        while (i < 10) {
            do Output.printInt(i);
            do Output.printChar(32);
            let j = 0;
            while (j < (i+1)) {
                if (j = 2) {        // Don't print when j = 2.
                    let j = j+1;
                    continue;
                }
                if (j > 5) {        // Don't print when j > 5.
                    break;
                }
                do Output.printInt(j);
                do Output.printChar(32);
                let j = j+1;
            }
            do Output.println();
            if (i < 4) {        // Count by 1 until i >= 4.
                let i = i+1;
                continue;       // Test restored continue address.
            }
            let i = i+2;        // Count by 2.
        }
        return;
    }
}
Here's Main.vm generated by my compiler.  The comments in the .vm file showing source lines, VM function command numbers, and variable names are controlled by a command line switch.  (As is this language extension.)
--Mark