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()) {
|
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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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
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