add loop control statements

This commit is contained in:
Thomas Lindner 2023-01-07 09:56:27 +01:00
parent 919a9f255b
commit 514ebfa25a
9 changed files with 71 additions and 3 deletions

View file

@ -62,6 +62,7 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) {
if (ctx->While()) { if (ctx->While()) {
int block = blockcount++; int block = blockcount++;
loopstack.push_back(block);
output << "@while" << block << "_expr" << std::endl; output << "@while" << block << "_expr" << std::endl;
tmpcount = 0; tmpcount = 0;
visitCondition(ctx->condition()); visitCondition(ctx->condition());
@ -71,8 +72,17 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) {
visitBlock(ctx->block(0)); visitBlock(ctx->block(0));
output << " jmp @while" << block << "_expr" << std::endl; output << " jmp @while" << block << "_expr" << std::endl;
output << "@while" << block << "_end" << std::endl; output << "@while" << block << "_end" << std::endl;
loopstack.pop_back();
return {}; 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()) { if (ctx->Return()) {
tmpcount = 0; tmpcount = 0;
visitValue(ctx->value()); visitValue(ctx->value());

View file

@ -9,9 +9,10 @@ namespace xlang {
class EmitVisitor : public xlangBaseVisitor { class EmitVisitor : public xlangBaseVisitor {
std::ofstream output; std::ofstream output;
int blockcount; size_t blockcount;
int tmpcount; size_t tmpcount;
std::string last; std::string last;
std::vector<size_t> loopstack;
std::string tmp(); std::string tmp();

View file

@ -29,6 +29,11 @@ void ErrorListener::duplicateFunction(antlr4::Token *token,
"duplicate function '" + name + "'"); "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, void ErrorListener::shadowedVariable(antlr4::Token *token,
const std::string &name) { const std::string &name) {
printError(token->getLine(), token->getCharPositionInLine(), printError(token->getLine(), token->getCharPositionInLine(),

View file

@ -19,6 +19,7 @@ class ErrorListener : public antlr4::BaseErrorListener {
[[noreturn]] void compilerError(const std::string &file, size_t line); [[noreturn]] void compilerError(const std::string &file, size_t line);
void duplicateFunction(antlr4::Token *token, const std::string &name); void duplicateFunction(antlr4::Token *token, const std::string &name);
void loopControlWithoutLoop(antlr4::Token *token);
void shadowedVariable(antlr4::Token *token, const std::string &name); void shadowedVariable(antlr4::Token *token, const std::string &name);
void syntaxError(antlr4::Recognizer *recognizer, void syntaxError(antlr4::Recognizer *recognizer,
antlr4::Token *offendingSymbol, size_t line, antlr4::Token *offendingSymbol, size_t line,

View file

@ -14,7 +14,7 @@ std::string typeToString(Type type) {
} }
TypeCheckVisitor::TypeCheckVisitor(ErrorListener &errorlistener) TypeCheckVisitor::TypeCheckVisitor(ErrorListener &errorlistener)
: errorlistener{errorlistener} {} : errorlistener{errorlistener}, loopcount{0} {}
std::any TypeCheckVisitor::visitFile(xlangParser::FileContext *ctx) { std::any TypeCheckVisitor::visitFile(xlangParser::FileContext *ctx) {
for (auto function : ctx->function()) { for (auto function : ctx->function()) {
@ -103,12 +103,30 @@ std::any TypeCheckVisitor::visitStatement(xlangParser::StatementContext *ctx) {
if (type != Type::Boolean) { if (type != Type::Boolean) {
errorlistener.typeMismatch(condition->getStart(), Type::Boolean, type); errorlistener.typeMismatch(condition->getStart(), Type::Boolean, type);
} }
if (ctx->While()) {
loopcount++;
}
visitBlock(ctx->block(0)); visitBlock(ctx->block(0));
if (ctx->While()) {
loopcount--;
}
if (ctx->Else()) { if (ctx->Else()) {
visitBlock(ctx->block(1)); visitBlock(ctx->block(1));
} }
return {}; 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()) { if (ctx->Return()) {
auto type = std::any_cast<Type>(visitValue(ctx->value())); auto type = std::any_cast<Type>(visitValue(ctx->value()));

View file

@ -28,6 +28,7 @@ class TypeCheckVisitor : public xlangBaseVisitor {
std::unordered_map<std::string, Signature> signatures; std::unordered_map<std::string, Signature> signatures;
Type returntype; Type returntype;
Scope<Type> scope; Scope<Type> scope;
size_t loopcount;
public: public:
TypeCheckVisitor(ErrorListener &errorlistener); TypeCheckVisitor(ErrorListener &errorlistener);

View file

@ -11,6 +11,8 @@ statement : Identifier Define value Semicolon
| Identifier Assign value Semicolon | Identifier Assign value Semicolon
| If condition block (Else block)? | If condition block (Else block)?
| While condition block | While condition block
| Break Semicolon
| Continue Semicolon
| Return value Semicolon | Return value Semicolon
| Print value Semicolon | Print value Semicolon
; ;
@ -49,6 +51,8 @@ TypeBoolean : 'bool';
If : 'if'; If : 'if';
Else : 'else'; Else : 'else';
While : 'while'; While : 'while';
Break : 'break';
Continue : 'continue';
Return : 'return'; Return : 'return';
Print : 'print'; Print : 'print';
And : 'and'; And : 'and';

View file

@ -19,3 +19,12 @@ custom_target('fib.ssa',
executable('fib', executable('fib',
sources : qbe.process(xc.process('fib.x')), sources : qbe.process(xc.process('fib.x')),
link_args : ['-static']) 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'])

19
test/sieve.x Normal file
View file

@ -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;
}
}