add loop control statements
This commit is contained in:
parent
919a9f255b
commit
514ebfa25a
|
@ -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());
|
||||
|
|
|
@ -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<size_t> loopstack;
|
||||
|
||||
std::string tmp();
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<Type>(visitValue(ctx->value()));
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class TypeCheckVisitor : public xlangBaseVisitor {
|
|||
std::unordered_map<std::string, Signature> signatures;
|
||||
Type returntype;
|
||||
Scope<Type> scope;
|
||||
size_t loopcount;
|
||||
|
||||
public:
|
||||
TypeCheckVisitor(ErrorListener &errorlistener);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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'])
|
||||
|
|
19
test/sieve.x
Normal file
19
test/sieve.x
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue