Skip to content

Commit de67746

Browse files
committed
add EXIT statement
1 parent e9a66ab commit de67746

File tree

7 files changed

+114
-12
lines changed

7 files changed

+114
-12
lines changed

ast.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,9 +923,16 @@ class IfStatement: public Statement {
923923
IfStatement &operator=(const IfStatement &);
924924
};
925925

926-
class WhileStatement: public CompoundStatement {
926+
class LoopStatement: public CompoundStatement {
927927
public:
928-
WhileStatement(const Expression *condition, const std::vector<const Statement *> &statements): CompoundStatement(statements), condition(condition) {}
928+
LoopStatement(unsigned int loop_id, const std::vector<const Statement *> &statements): CompoundStatement(statements), loop_id(loop_id) {}
929+
930+
const unsigned int loop_id;
931+
};
932+
933+
class WhileStatement: public LoopStatement {
934+
public:
935+
WhileStatement(unsigned int loop_id, const Expression *condition, const std::vector<const Statement *> &statements): LoopStatement(loop_id, statements), condition(condition) {}
929936

930937
const Expression *condition;
931938

@@ -939,9 +946,9 @@ class WhileStatement: public CompoundStatement {
939946
WhileStatement &operator=(const WhileStatement &);
940947
};
941948

942-
class ForStatement: public CompoundStatement {
949+
class ForStatement: public LoopStatement {
943950
public:
944-
ForStatement(const VariableReference *var, const Expression *start, const Expression *end, const std::vector<const Statement *> &statements): CompoundStatement(statements), var(var), start(start), end(end) {
951+
ForStatement(unsigned int loop_id, const VariableReference *var, const Expression *start, const Expression *end, const std::vector<const Statement *> &statements): LoopStatement(loop_id, statements), var(var), start(start), end(end) {
945952
}
946953

947954
const VariableReference *var;
@@ -1003,6 +1010,20 @@ class CaseStatement: public Statement {
10031010
CaseStatement &operator=(const CaseStatement &);
10041011
};
10051012

1013+
class ExitStatement: public Statement {
1014+
public:
1015+
ExitStatement(unsigned int loop_id): loop_id(loop_id) {}
1016+
1017+
const unsigned int loop_id;
1018+
1019+
virtual void generate(Emitter &emitter) const;
1020+
1021+
virtual std::string text() const { return "ExitStatement(...)"; }
1022+
private:
1023+
ExitStatement(const ExitStatement &);
1024+
ExitStatement &operator=(const ExitStatement &);
1025+
};
1026+
10061027
class Function: public Variable {
10071028
public:
10081029
Function(const std::string &name, const Type *returntype, Scope *scope, const std::vector<FunctionParameter *> &params): Variable(name, makeFunctionType(returntype, params)), scope(scope), params(params), entry_label(-1), statements() {}

compiler.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Emitter {
1616
int target;
1717
};
1818
public:
19-
Emitter(): code(), strings(), globals(), functions() {}
19+
Emitter(): code(), strings(), globals(), functions(), exit_label() {}
2020
void emit(unsigned char b);
2121
void emit_int(int value);
2222
void emit(unsigned char b, int value);
@@ -29,11 +29,15 @@ class Emitter {
2929
Label create_label();
3030
void emit_jump(unsigned char b, Label &label);
3131
void jump_target(Label &label);
32+
void add_exit_label(unsigned int loop_id, Label &label);
33+
void remove_exit_label(unsigned int loop_id);
34+
Label &get_exit_label(unsigned int loop_id);
3235
private:
3336
std::vector<unsigned char> code;
3437
std::vector<std::string> strings;
3538
std::vector<std::string> globals;
3639
std::vector<Label> functions;
40+
std::map<size_t, Label *> exit_label;
3741
};
3842

3943
void Emitter::emit(unsigned char b)
@@ -121,7 +125,7 @@ void Emitter::emit_jump(unsigned char b, Label &label)
121125
emit_int(label.target);
122126
} else {
123127
label.fixups.push_back(static_cast<int>(code.size()));
124-
emit_int(0);
128+
emit_int(-1);
125129
}
126130
}
127131

@@ -137,6 +141,24 @@ void Emitter::jump_target(Label &label)
137141
}
138142
}
139143

144+
void Emitter::add_exit_label(unsigned int loop_id, Label &label)
145+
{
146+
exit_label[loop_id] = &label;
147+
}
148+
149+
void Emitter::remove_exit_label(unsigned int loop_id)
150+
{
151+
exit_label.erase(loop_id);
152+
}
153+
154+
Emitter::Label &Emitter::get_exit_label(unsigned int loop_id)
155+
{
156+
if (exit_label.find(loop_id) == exit_label.end()) {
157+
internal_error("loop_id not found");
158+
}
159+
return *exit_label[loop_id];
160+
}
161+
140162
void TypeBoolean::generate_load(Emitter &emitter) const
141163
{
142164
emitter.emit(LOADB);
@@ -664,12 +686,14 @@ void WhileStatement::generate(Emitter &emitter) const
664686
emitter.jump_target(top);
665687
condition->generate(emitter);
666688
auto skip = emitter.create_label();
689+
emitter.add_exit_label(loop_id, skip);
667690
emitter.emit_jump(JF, skip);
668691
for (auto stmt: statements) {
669692
stmt->generate(emitter);
670693
}
671694
emitter.emit_jump(JUMP, top);
672695
emitter.jump_target(skip);
696+
emitter.remove_exit_label(loop_id);
673697
}
674698

675699
void CaseStatement::generate(Emitter &emitter) const
@@ -746,6 +770,7 @@ void CaseStatement::RangeWhenCondition::generate(Emitter &emitter) const
746770
void ForStatement::generate(Emitter &emitter) const
747771
{
748772
auto skip = emitter.create_label();
773+
emitter.add_exit_label(loop_id, skip);
749774
auto loop = emitter.create_label();
750775

751776
start->generate(emitter);
@@ -771,6 +796,12 @@ void ForStatement::generate(Emitter &emitter) const
771796
emitter.emit_jump(JUMP, loop);
772797

773798
emitter.jump_target(skip);
799+
emitter.remove_exit_label(loop_id);
800+
}
801+
802+
void ExitStatement::generate(Emitter &emitter) const
803+
{
804+
emitter.emit_jump(JUMP, emitter.get_exit_label(loop_id));
774805
}
775806

776807
void Scope::predeclare(Emitter &emitter) const

lexer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ std::string Token::tostring() const
7171
case WHEN: s << "WHEN"; break;
7272
case DOTDOT: s << "DOTDOT"; break;
7373
case EXTERNAL: s << "EXTERNAL"; break;
74+
case EXIT: s << "EXIT"; break;
7475
}
7576
s << ">";
7677
return s.str();
@@ -190,6 +191,7 @@ std::vector<Token> tokenize(const std::string &source)
190191
else if (t.text == "CASE") t.type = CASE;
191192
else if (t.text == "WHEN") t.type = WHEN;
192193
else if (t.text == "EXTERNAL") t.type = EXTERNAL;
194+
else if (t.text == "EXIT") t.type = EXIT;
193195
} else if (isdigit(c)) {
194196
t.type = NUMBER;
195197
if (c == '0' && (i+1 < source.length()) && source.at(i+1) != '.' && tolower(source.at(i+1)) != 'e' && not isdigit(source.at(i+1))) {

lexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ enum TokenType {
6565
WHEN,
6666
DOTDOT,
6767
EXTERNAL,
68+
EXIT,
6869
};
6970

7071
class Token {

parser.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "parser.h"
22

33
#include <iso646.h>
4+
#include <list>
45

56
#include "ast.h"
67
#include "rtl.h"
@@ -14,6 +15,8 @@ class Parser {
1415
static Scope *global_scope; // TODO: static is a hack, used by StringReference constructor
1516
std::vector<Token>::size_type i;
1617

18+
std::stack<std::list<std::pair<TokenType, unsigned int>>> loops;
19+
1720
typedef std::pair<std::vector<std::string>, const Type *> VariableInfo;
1821

1922
const Type *parseArrayType(Scope *scope);
@@ -45,6 +48,7 @@ class Parser {
4548
const Statement *parseWhileStatement(Scope *scope);
4649
const Statement *parseCaseStatement(Scope *scope);
4750
const Statement *parseForStatement(Scope *scope);
51+
const Statement *parseExitStatement(Scope *scope);
4852
const Statement *parseImport(Scope *scope);
4953
const Statement *parseStatement(Scope *scope);
5054
const Program *parse();
@@ -57,7 +61,8 @@ Scope *Parser::global_scope;
5761

5862
Parser::Parser(const std::vector<Token> &tokens)
5963
: tokens(tokens),
60-
i(0)
64+
i(0),
65+
loops()
6166
{
6267
}
6368

@@ -841,6 +846,7 @@ const Statement *Parser::parseFunctionDefinition(Scope *scope)
841846
parseFunctionHeader(scope, name, returntype, newscope, args);
842847
Function *function = new Function(name, returntype, newscope, args);
843848
scope->addName(name, function);
849+
loops.push(std::list<std::pair<TokenType, unsigned int>>());
844850
while (tokens[i].type != END) {
845851
const Statement *s = parseStatement(newscope);
846852
if (s != nullptr) {
@@ -852,6 +858,7 @@ const Statement *Parser::parseFunctionDefinition(Scope *scope)
852858
error(2102, tokens[i], "'FUNCTION' expected");
853859
}
854860
++i;
861+
loops.pop();
855862
return nullptr;
856863
}
857864

@@ -1002,6 +1009,8 @@ const Statement *Parser::parseWhileStatement(Scope *scope)
10021009
error(2082, tokens[i], "DO expected");
10031010
}
10041011
++i;
1012+
auto loop_id = i;
1013+
loops.top().push_back(std::make_pair(WHILE, loop_id));
10051014
std::vector<const Statement *> statements;
10061015
while (tokens[i].type != END && tokens[i].type != END_OF_FILE) {
10071016
const Statement *s = parseStatement(scope);
@@ -1017,7 +1026,8 @@ const Statement *Parser::parseWhileStatement(Scope *scope)
10171026
error(2104, tokens[i], "WHILE expected");
10181027
}
10191028
++i;
1020-
return new WhileStatement(cond, statements);
1029+
loops.top().pop_back();
1030+
return new WhileStatement(loop_id, cond, statements);
10211031
}
10221032

10231033
const Statement *Parser::parseCaseStatement(Scope *scope)
@@ -1277,6 +1287,8 @@ const Statement *Parser::parseForStatement(Scope *scope)
12771287
error(2118, tokens[i], "'DO' expected");
12781288
}
12791289
++i;
1290+
auto loop_id = i;
1291+
loops.top().push_back(std::make_pair(FOR, loop_id));
12801292
std::vector<const Statement *> statements;
12811293
while (tokens[i].type != END && tokens[i].type != END_OF_FILE) {
12821294
const Statement *s = parseStatement(scope);
@@ -1292,7 +1304,27 @@ const Statement *Parser::parseForStatement(Scope *scope)
12921304
error(2120, tokens[i], "'END FOR' expected");
12931305
}
12941306
++i;
1295-
return new ForStatement(var, start, end, statements);
1307+
loops.top().pop_back();
1308+
return new ForStatement(loop_id, var, start, end, statements);
1309+
}
1310+
1311+
const Statement *Parser::parseExitStatement(Scope *)
1312+
{
1313+
++i;
1314+
if (tokens[i].type != WHILE
1315+
&& tokens[i].type != FOR) {
1316+
error(2136, tokens[i], "loop type expected");
1317+
}
1318+
TokenType type = tokens[i].type;
1319+
++i;
1320+
if (not loops.empty()) {
1321+
for (auto j = loops.top().rbegin(); j != loops.top().rend(); ++j) {
1322+
if (j->first == type) {
1323+
return new ExitStatement(j->second);
1324+
}
1325+
}
1326+
}
1327+
error(2137, tokens[i-1], "no matching loop found in current scope");
12961328
}
12971329

12981330
const Statement *Parser::parseImport(Scope *scope)
@@ -1330,6 +1362,8 @@ const Statement *Parser::parseStatement(Scope *scope)
13301362
return parseCaseStatement(scope);
13311363
} else if (tokens[i].type == FOR) {
13321364
return parseForStatement(scope);
1365+
} else if (tokens[i].type == EXIT) {
1366+
return parseExitStatement(scope);
13331367
} else if (tokens[i].type == IDENTIFIER) {
13341368
const VariableReference *ref = parseVariableReference(scope);
13351369
if (tokens[i].type == ASSIGN) {
@@ -1364,12 +1398,14 @@ const Program *Parser::parse()
13641398
{
13651399
Program *program = new Program();
13661400
global_scope = program->scope;
1401+
loops.push(std::list<std::pair<TokenType, unsigned int>>());
13671402
while (tokens[i].type != END_OF_FILE) {
13681403
const Statement *s = parseStatement(program->scope);
13691404
if (s != nullptr) {
13701405
program->statements.push_back(s);
13711406
}
13721407
}
1408+
loops.pop();
13731409
return program;
13741410
}
13751411

t/exit-for.simple

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
VAR a: Number
2+
FOR a IN 0 TO 5 DO
3+
print(str(a))
4+
IF a = 3 THEN
5+
EXIT FOR
6+
END IF
7+
END FOR
8+
9+
%= 0
10+
%= 1
11+
%= 2
12+
%= 3

t/break.simple renamed to t/exit-while.simple

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
% TODO
2-
31
VAR a: Number
42
a := 5
53
WHILE a > 0 DO
64
print(str(a))
75
IF a = 3 THEN
8-
BREAK
6+
EXIT WHILE
97
END IF
8+
a := a - 1
109
END WHILE
1110

1211
%= 5

0 commit comments

Comments
 (0)