From 514ebfa25a3839d2fd751a543c1f6ccfdc2d97cb Mon Sep 17 00:00:00 2001 From: Thomas Lindner Date: Sat, 7 Jan 2023 09:56:27 +0100 Subject: [PATCH] add loop control statements --- bootstrap/emit.cc | 10 ++++++++++ bootstrap/emit.hh | 5 +++-- bootstrap/error.cc | 5 +++++ bootstrap/error.hh | 1 + bootstrap/typecheck.cc | 20 +++++++++++++++++++- bootstrap/typecheck.hh | 1 + bootstrap/xlang.g4 | 4 ++++ test/meson.build | 9 +++++++++ test/sieve.x | 19 +++++++++++++++++++ 9 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 test/sieve.x diff --git a/bootstrap/emit.cc b/bootstrap/emit.cc index 04aeff1..74cb7c9 100644 --- a/bootstrap/emit.cc +++ b/bootstrap/emit.cc @@ -62,6 +62,7 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) { if (ctx->While()) { int block = blockcount++; + loopstack.push_back(block); output << "@while" << block << "_expr" << std::endl; tmpcount = 0; visitCondition(ctx->condition()); @@ -71,8 +72,17 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) { visitBlock(ctx->block(0)); output << " jmp @while" << block << "_expr" << std::endl; output << "@while" << block << "_end" << std::endl; + loopstack.pop_back(); return {}; } + if (ctx->Break()) { + output << " jmp @while" << loopstack.back() << "_end" << std::endl; + output << "@dead" << blockcount++ << std::endl; + } + if (ctx->Continue()) { + output << " jmp @while" << loopstack.back() << "_expr" << std::endl; + output << "@dead" << blockcount++ << std::endl; + } if (ctx->Return()) { tmpcount = 0; visitValue(ctx->value()); diff --git a/bootstrap/emit.hh b/bootstrap/emit.hh index 889e4f8..40596c6 100644 --- a/bootstrap/emit.hh +++ b/bootstrap/emit.hh @@ -9,9 +9,10 @@ namespace xlang { class EmitVisitor : public xlangBaseVisitor { std::ofstream output; - int blockcount; - int tmpcount; + size_t blockcount; + size_t tmpcount; std::string last; + std::vector loopstack; std::string tmp(); diff --git a/bootstrap/error.cc b/bootstrap/error.cc index ebc6083..ac762de 100644 --- a/bootstrap/error.cc +++ b/bootstrap/error.cc @@ -29,6 +29,11 @@ void ErrorListener::duplicateFunction(antlr4::Token *token, "duplicate function '" + name + "'"); } +void ErrorListener::loopControlWithoutLoop(antlr4::Token *token) { + printError(token->getLine(), token->getCharPositionInLine(), + "loop control statement without loop"); +} + void ErrorListener::shadowedVariable(antlr4::Token *token, const std::string &name) { printError(token->getLine(), token->getCharPositionInLine(), diff --git a/bootstrap/error.hh b/bootstrap/error.hh index 661c176..06a78e9 100644 --- a/bootstrap/error.hh +++ b/bootstrap/error.hh @@ -19,6 +19,7 @@ class ErrorListener : public antlr4::BaseErrorListener { [[noreturn]] void compilerError(const std::string &file, size_t line); void duplicateFunction(antlr4::Token *token, const std::string &name); + void loopControlWithoutLoop(antlr4::Token *token); void shadowedVariable(antlr4::Token *token, const std::string &name); void syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *offendingSymbol, size_t line, diff --git a/bootstrap/typecheck.cc b/bootstrap/typecheck.cc index ab81f8c..e0fb063 100644 --- a/bootstrap/typecheck.cc +++ b/bootstrap/typecheck.cc @@ -14,7 +14,7 @@ std::string typeToString(Type type) { } TypeCheckVisitor::TypeCheckVisitor(ErrorListener &errorlistener) - : errorlistener{errorlistener} {} + : errorlistener{errorlistener}, loopcount{0} {} std::any TypeCheckVisitor::visitFile(xlangParser::FileContext *ctx) { for (auto function : ctx->function()) { @@ -103,12 +103,30 @@ std::any TypeCheckVisitor::visitStatement(xlangParser::StatementContext *ctx) { if (type != Type::Boolean) { errorlistener.typeMismatch(condition->getStart(), Type::Boolean, type); } + if (ctx->While()) { + loopcount++; + } visitBlock(ctx->block(0)); + if (ctx->While()) { + loopcount--; + } if (ctx->Else()) { visitBlock(ctx->block(1)); } return {}; } + if (ctx->Break()) { + if (!loopcount) { + errorlistener.loopControlWithoutLoop(ctx->Break()->getSymbol()); + } + return {}; + } + if (ctx->Continue()) { + if (!loopcount) { + errorlistener.loopControlWithoutLoop(ctx->Continue()->getSymbol()); + } + return {}; + } if (ctx->Return()) { auto type = std::any_cast(visitValue(ctx->value())); diff --git a/bootstrap/typecheck.hh b/bootstrap/typecheck.hh index 9dfffee..0d318be 100644 --- a/bootstrap/typecheck.hh +++ b/bootstrap/typecheck.hh @@ -28,6 +28,7 @@ class TypeCheckVisitor : public xlangBaseVisitor { std::unordered_map signatures; Type returntype; Scope scope; + size_t loopcount; public: TypeCheckVisitor(ErrorListener &errorlistener); diff --git a/bootstrap/xlang.g4 b/bootstrap/xlang.g4 index 201294c..4aa4bee 100644 --- a/bootstrap/xlang.g4 +++ b/bootstrap/xlang.g4 @@ -11,6 +11,8 @@ statement : Identifier Define value Semicolon | Identifier Assign value Semicolon | If condition block (Else block)? | While condition block + | Break Semicolon + | Continue Semicolon | Return value Semicolon | Print value Semicolon ; @@ -49,6 +51,8 @@ TypeBoolean : 'bool'; If : 'if'; Else : 'else'; While : 'while'; +Break : 'break'; +Continue : 'continue'; Return : 'return'; Print : 'print'; And : 'and'; diff --git a/test/meson.build b/test/meson.build index b30449d..7a8edc4 100644 --- a/test/meson.build +++ b/test/meson.build @@ -19,3 +19,12 @@ custom_target('fib.ssa', executable('fib', sources : qbe.process(xc.process('fib.x')), link_args : ['-static']) + +# XXX why is this needed? +custom_target('sieve.ssa', + command : ['cp', '@INPUT@', '@OUTPUT@'], + input : xc.process('sieve.x'), + output : '@BASENAME@.ssa') +executable('sieve', + sources : qbe.process(xc.process('sieve.x')), + link_args : ['-static']) diff --git a/test/sieve.x b/test/sieve.x new file mode 100644 index 0000000..751198b --- /dev/null +++ b/test/sieve.x @@ -0,0 +1,19 @@ +main() : int { + print 2; + i := 3; + while i < 100 { + composite := false; + j := 3; + while j < i { + if i % j == 0 { + composite = true; + break; + } + j = j + 2; + } + if not composite { + print i; + } + i = i + 2; + } +}