diff --git a/bootstrap/emit.cc b/bootstrap/emit.cc index fc358dd..32b94a4 100644 --- a/bootstrap/emit.cc +++ b/bootstrap/emit.cc @@ -91,12 +91,24 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) { return {}; } if (ctx->Break()) { - output << " jmp @loop" << loopstack.back() << "_end" << std::endl; + if (auto integer = ctx->Integer()) { + auto num = stoul(integer->getSymbol()->getText()); + output << " jmp @loop" << *(loopstack.end() - num) << "_end" + << std::endl; + } else { + output << " jmp @loop" << loopstack.back() << "_end" << std::endl; + } output << "@dead" << blockcount++ << std::endl; return {}; } if (ctx->Continue()) { - output << " jmp @loop" << loopstack.back() << "_expr" << std::endl; + if (auto integer = ctx->Integer()) { + auto num = stoul(integer->getSymbol()->getText()); + output << " jmp @loop" << *(loopstack.end() - num) << "_continue" + << std::endl; + } else { + output << " jmp @loop" << loopstack.back() << "_continue" << std::endl; + } output << "@dead" << blockcount++ << std::endl; return {}; } diff --git a/bootstrap/error.cc b/bootstrap/error.cc index ac762de..770bfb6 100644 --- a/bootstrap/error.cc +++ b/bootstrap/error.cc @@ -18,11 +18,34 @@ bool ErrorListener::hasError() { return has_error; } +void ErrorListener::breakTooMany(antlr4::Token *token, size_t num, size_t max) { + printError(token->getLine(), token->getCharPositionInLine(), + "tried to break " + std::to_string(num) + " loops, but only " + + std::to_string(max) + " surrounding loops"); +} + +void ErrorListener::breakZero(antlr4::Token *token) { + printError(token->getLine(), token->getCharPositionInLine(), + "tried to break zero loops"); +} + void ErrorListener::compilerError(const std::string &file, size_t line) { std::cerr << "compiler bug in " << file << ":" << line << std::endl; std::terminate(); } +void ErrorListener::continueTooMany(antlr4::Token *token, size_t num, + size_t max) { + printError(token->getLine(), token->getCharPositionInLine(), + "tried to continue " + std::to_string(num) + " loops, but only " + + std::to_string(max) + " surrounding loops"); +} + +void ErrorListener::continueZero(antlr4::Token *token) { + printError(token->getLine(), token->getCharPositionInLine(), + "tried to continue zero loops"); +} + void ErrorListener::duplicateFunction(antlr4::Token *token, const std::string &name) { printError(token->getLine(), token->getCharPositionInLine(), diff --git a/bootstrap/error.hh b/bootstrap/error.hh index 06a78e9..67fc9d0 100644 --- a/bootstrap/error.hh +++ b/bootstrap/error.hh @@ -17,7 +17,11 @@ class ErrorListener : public antlr4::BaseErrorListener { bool hasError(); + void breakTooMany(antlr4::Token *token, size_t num, size_t max); + void breakZero(antlr4::Token *token); [[noreturn]] void compilerError(const std::string &file, size_t line); + void continueTooMany(antlr4::Token *token, size_t num, size_t max); + void continueZero(antlr4::Token *token); void duplicateFunction(antlr4::Token *token, const std::string &name); void loopControlWithoutLoop(antlr4::Token *token); void shadowedVariable(antlr4::Token *token, const std::string &name); diff --git a/bootstrap/typecheck.cc b/bootstrap/typecheck.cc index 69e2f29..2a52e25 100644 --- a/bootstrap/typecheck.cc +++ b/bootstrap/typecheck.cc @@ -109,14 +109,35 @@ std::any TypeCheckVisitor::visitStatement(xlangParser::StatementContext *ctx) { return {}; } if (ctx->Break()) { - if (!loopcount) { - errorlistener.loopControlWithoutLoop(ctx->Break()->getSymbol()); + if (auto integer = ctx->Integer()) { + auto num = stoul(integer->getSymbol()->getText()); + if (!num) { + errorlistener.breakZero(ctx->Break()->getSymbol()); + } + if (num > loopcount) { + errorlistener.breakTooMany(ctx->Break()->getSymbol(), num, loopcount); + } + } else { + if (!loopcount) { + errorlistener.loopControlWithoutLoop(ctx->Break()->getSymbol()); + } } return {}; } if (ctx->Continue()) { - if (!loopcount) { - errorlistener.loopControlWithoutLoop(ctx->Continue()->getSymbol()); + if (auto integer = ctx->Integer()) { + auto num = stoul(integer->getSymbol()->getText()); + if (!num) { + errorlistener.continueZero(ctx->Break()->getSymbol()); + } + if (num > loopcount) { + errorlistener.continueTooMany(ctx->Break()->getSymbol(), num, + loopcount); + } + } else { + if (!loopcount) { + errorlistener.loopControlWithoutLoop(ctx->Continue()->getSymbol()); + } } return {}; } diff --git a/bootstrap/xlang.g4 b/bootstrap/xlang.g4 index 2eb22e8..325ccd5 100644 --- a/bootstrap/xlang.g4 +++ b/bootstrap/xlang.g4 @@ -10,8 +10,8 @@ block : LeftBrace statement* RightBrace; statement : If condition block (Else block)? | While condition block | For value Semicolon condition Semicolon value block - | Break Semicolon - | Continue Semicolon + | Break Integer? Semicolon + | Continue Integer? Semicolon | Return value Semicolon | Print value Semicolon | value Semicolon diff --git a/test/sieve.x b/test/sieve.x index eba644c..a7a6080 100644 --- a/test/sieve.x +++ b/test/sieve.x @@ -1,15 +1,11 @@ main() : int { print 2; for i := 3; i < 100; i =+ 2 { - composite := false; for j := 3; j < i; j =+ 2 { if i % j == 0 { - composite = true; - break; + continue 2; } } - if not composite { - print i; - } + print i; } }