Skip to content

Commit

Permalink
feat: support break and continue statement (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
kumachan-mis authored Oct 13, 2023
1 parent 66b71a9 commit f1d1468
Show file tree
Hide file tree
Showing 30 changed files with 801 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ typedef enum AstType {

// statement
AST_CMPD_STMT,
AST_CONTINUE_STMT,
AST_BREAK_STMT,
AST_RET_STMT,
AST_EXPR_STMT,
AST_NULL_STMT,
Expand Down
4 changes: 2 additions & 2 deletions src/ctoken/ctoken.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ BaseType t_ctoken = {

char* ctoken_types[] = {
// non-punctuators
"char", "else", "enum", "for", "if", "int", "long", "return", "sizeof", "struct", "typedef", "unsigned", "void",
"while", "identifier", "integer-constant", "character-constant", "string-literal",
"break", "char", "continue", "else", "enum", "for", "if", "int", "long", "return", "sizeof", "struct", "typedef",
"unsigned", "void", "while", "identifier", "integer-constant", "character-constant", "string-literal",
// punctuators
"[", "]", "(", ")", "{", "}", ".", "->", "++", "--", "&", "*", "+", "-", "~", "!", "/", "%", "<", ">",
"<=", ">=", "==", "!=", "^", "|", "&&", "||", "?", ":", ";", "=",
Expand Down
2 changes: 2 additions & 0 deletions src/ctoken/ctoken.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

typedef enum CTokenType {
// keyword
CTOKEN_KEYWORD_BREAK,
CTOKEN_KEYWORD_CHAR,
CTOKEN_KEYWORD_CONTINUE,
CTOKEN_KEYWORD_ELSE,
CTOKEN_KEYWORD_ENUM,
CTOKEN_KEYWORD_FOR,
Expand Down
8 changes: 8 additions & 0 deletions src/immcgen/immcgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Immcgen* new_immcgen(Srt* srt) {
immcgen->next_reg_id = -1;
immcgen->initialized_dtype = NULL;
immcgen->initialized_offset = -1;
immcgen->continue_label_id = -1;
immcgen->break_label_id = -1;
immcgen->return_label_id = -1;
immcgen->label_id = -1;
return immcgen;
Expand Down Expand Up @@ -58,6 +60,12 @@ Vector* immcgen_generate_immcode(Immcgen* immcgen) {
immcgen->tag_table = tagtable_exit_scope(immcgen->tag_table);
immcgen->symbol_table = symboltable_exit_scope(immcgen->symbol_table);
break;
case SRT_CONTINUE_STMT:
codes = gen_continue_stmt_immcode(immcgen);
break;
case SRT_BREAK_STMT:
codes = gen_break_stmt_immcode(immcgen);
break;
case SRT_RET_STMT:
codes = gen_return_stmt_immcode(immcgen);
break;
Expand Down
2 changes: 2 additions & 0 deletions src/immcgen/immcgen.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ typedef struct Immcgen {
int next_reg_id;
DType* initialized_dtype;
int initialized_offset;
int continue_label_id;
int break_label_id;
int return_label_id;
int label_id;
} Immcgen;
Expand Down
32 changes: 32 additions & 0 deletions src/immcgen/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ Vector* gen_compound_stmt_immcode(Immcgen* immcgen) {
return codes;
}

Vector* gen_continue_stmt_immcode(Immcgen* immcgen) {
Vector* codes = new_vector(&t_immc);
ImmcOpe* continue_label = new_label_immcope_from_id(immcgen->continue_label_id);
vector_push(codes, new_inst_immc(IMMC_INST_JMP, continue_label, NULL, NULL));
return codes;
}

Vector* gen_break_stmt_immcode(Immcgen* immcgen) {
Vector* codes = new_vector(&t_immc);
ImmcOpe* break_label = new_label_immcope_from_id(immcgen->break_label_id);
vector_push(codes, new_inst_immc(IMMC_INST_JMP, break_label, NULL, NULL));
return codes;
}

Vector* gen_return_stmt_immcode(Immcgen* immcgen) {
Vector* codes = new_vector(&t_immc);
Srt* srt = immcgen->srt;
Expand Down Expand Up @@ -125,7 +139,14 @@ Vector* gen_while_stmt_immcode(Immcgen* immcgen) {
ImmcOpe* end_label = new_label_immcope_from_id(end_label_id);
append_child_jmp_false_immcode(immcgen, codes, 0, end_label);

int original_continue_label_id = immcgen->continue_label_id;
int original_break_label_id = immcgen->break_label_id;

immcgen->continue_label_id = begin_label_id;
immcgen->break_label_id = end_label_id;
append_child_immcode(immcgen, codes, 1);
immcgen->continue_label_id = original_continue_label_id;
immcgen->break_label_id = original_break_label_id;

ImmcOpe* begin_label = new_label_immcope_from_id(begin_label_id);
vector_push(codes, new_inst_immc(IMMC_INST_JMP, begin_label, NULL, NULL));
Expand All @@ -141,6 +162,8 @@ Vector* gen_for_stmt_immcode(Immcgen* immcgen) {
immcgen->label_id++;
int begin_label_id = immcgen->label_id;
immcgen->label_id++;
int continue_label_id = immcgen->label_id;
immcgen->label_id++;
int end_label_id = immcgen->label_id;

append_child_immcode(immcgen, codes, 0);
Expand All @@ -156,7 +179,16 @@ Vector* gen_for_stmt_immcode(Immcgen* immcgen) {
immcgen->srt = srt;
}

int original_continue_label_id = immcgen->continue_label_id;
int original_break_label_id = immcgen->break_label_id;

immcgen->continue_label_id = continue_label_id;
immcgen->break_label_id = end_label_id;
append_child_immcode(immcgen, codes, 3);
immcgen->continue_label_id = original_continue_label_id;
immcgen->break_label_id = original_break_label_id;

vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, continue_label_id));

append_child_immcode(immcgen, codes, 2);

Expand Down
2 changes: 2 additions & 0 deletions src/immcgen/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "./immcgen.h"

Vector* gen_compound_stmt_immcode(Immcgen* immcgen);
Vector* gen_continue_stmt_immcode(Immcgen* immcgen);
Vector* gen_break_stmt_immcode(Immcgen* immcgen);
Vector* gen_return_stmt_immcode(Immcgen* immcgen);
Vector* gen_expression_stmt_immcode(Immcgen* immcgen);
Vector* gen_null_stmt_immcode(void);
Expand Down
2 changes: 2 additions & 0 deletions src/lexer/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ void ctoken_map_add(Map* ctoken_map, char* ctoken_str, CTokenType type);
Map* new_keyword_map(void) {
Map* keyword_map = new_map(&t_hashable_string, &t_integer);

ctoken_map_add(keyword_map, "break", CTOKEN_KEYWORD_BREAK);
ctoken_map_add(keyword_map, "char", CTOKEN_KEYWORD_CHAR);
ctoken_map_add(keyword_map, "continue", CTOKEN_KEYWORD_CONTINUE);
ctoken_map_add(keyword_map, "else", CTOKEN_KEYWORD_ELSE);
ctoken_map_add(keyword_map, "enum", CTOKEN_KEYWORD_ENUM);
ctoken_map_add(keyword_map, "for", CTOKEN_KEYWORD_FOR);
Expand Down
40 changes: 40 additions & 0 deletions src/parser/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ ParserReturn* parse_stmt(Parser* parser) {
switch (ctoken->type) {
case CTOKEN_LBRACE:
return parse_compound_stmt(parser);
case CTOKEN_KEYWORD_CONTINUE:
return parse_continue_stmt(parser);
case CTOKEN_KEYWORD_BREAK:
return parse_break_stmt(parser);
case CTOKEN_KEYWORD_RETURN:
return parse_return_stmt(parser);
case CTOKEN_KEYWORD_IF:
Expand Down Expand Up @@ -65,6 +69,42 @@ ParserReturn* parse_compound_stmt(Parser* parser) {
return new_parserret(ast);
}

ParserReturn* parse_continue_stmt(Parser* parser) {
Ast* ast = NULL;
Error* err = NULL;

err = consume_ctoken(parser, CTOKEN_KEYWORD_CONTINUE);
if (err != NULL) {
return new_parserret_error(err);
}

err = consume_ctoken(parser, CTOKEN_SEMICOLON);
if (err != NULL) {
return new_parserret_error(err);
}

ast = new_ast(AST_CONTINUE_STMT, 0);
return new_parserret(ast);
}

ParserReturn* parse_break_stmt(Parser* parser) {
Ast* ast = NULL;
Error* err = NULL;

err = consume_ctoken(parser, CTOKEN_KEYWORD_BREAK);
if (err != NULL) {
return new_parserret_error(err);
}

err = consume_ctoken(parser, CTOKEN_SEMICOLON);
if (err != NULL) {
return new_parserret_error(err);
}

ast = new_ast(AST_BREAK_STMT, 0);
return new_parserret(ast);
}

ParserReturn* parse_return_stmt(Parser* parser) {
Ast* ast = NULL;
Error* err = NULL;
Expand Down
2 changes: 2 additions & 0 deletions src/parser/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

ParserReturn* parse_stmt(Parser* parser);
ParserReturn* parse_compound_stmt(Parser* parser);
ParserReturn* parse_continue_stmt(Parser* parser);
ParserReturn* parse_break_stmt(Parser* parser);
ParserReturn* parse_return_stmt(Parser* parser);
ParserReturn* parse_expression_stmt(Parser* parser);
ParserReturn* parse_if_else_stmt(Parser* parser);
Expand Down
2 changes: 2 additions & 0 deletions src/resolver/resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Resolver* new_resolver(Ast* ast) {
resolver->scope_srt = NULL;
resolver->symbol_table = new_symboltable();
resolver->tag_table = new_tagtable();
resolver->continueable = 0;
resolver->breakable = 0;
resolver->return_dtype = NULL;
resolver->specifier_dtype = NULL;
resolver->default_enum_value = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/resolver/resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ typedef struct Resolver {
Srt* scope_srt;
SymbolTable* symbol_table;
TagTable* tag_table;
int continueable;
int breakable;
DType* return_dtype;
DType* specifier_dtype;
int default_enum_value;
Expand Down
46 changes: 46 additions & 0 deletions src/resolver/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ ResolverReturn* resolve_stmt(Resolver* resolver) {
resolver->tag_table = tagtable_exit_scope(resolver->tag_table);
resolver->symbol_table = symboltable_exit_scope(resolver->symbol_table);
break;
case AST_CONTINUE_STMT:
resolverret_assign(&srt, &errs, resolve_continue_stmt(resolver));
break;
case AST_BREAK_STMT:
resolverret_assign(&srt, &errs, resolve_break_stmt(resolver));
break;
case AST_RET_STMT:
resolverret_assign(&srt, &errs, resolve_return_stmt(resolver));
break;
Expand Down Expand Up @@ -147,6 +153,30 @@ ResolverReturn* resolve_return_stmt(Resolver* resolver) {
return new_resolverret(srt);
}

ResolverReturn* resolve_continue_stmt(Resolver* resolver) {
if (!resolver->continueable) {
Vector* errs = new_vector(&t_error);
Error* err = new_error("continue statement is not allowed here");
vector_push(errs, err);
return new_resolverret_errors(errs);
}

Srt* srt = new_srt(SRT_CONTINUE_STMT, 0);
return new_resolverret(srt);
}

ResolverReturn* resolve_break_stmt(Resolver* resolver) {
if (!resolver->breakable) {
Vector* errs = new_vector(&t_error);
Error* err = new_error("break statement is not allowed here");
vector_push(errs, err);
return new_resolverret_errors(errs);
}

Srt* srt = new_srt(SRT_BREAK_STMT, 0);
return new_resolverret(srt);
}

ResolverReturn* resolve_expression_stmt(Resolver* resolver) {
Srt* srt = NULL;
Vector* errs = NULL;
Expand Down Expand Up @@ -250,9 +280,17 @@ ResolverReturn* resolve_while_stmt(Resolver* resolver) {
return new_resolverret_errors(errs);
}

int original_continueable = resolver->continueable;
int original_breakable = resolver->breakable;

resolver->continueable = 1;
resolver->breakable = 1;
resolver->ast = vector_at(ast->children, 1);
resolverret_assign(&child_srt, &errs, resolve_stmt(resolver));
resolver->ast = ast;
resolver->continueable = original_continueable;
resolver->breakable = original_breakable;

if (errs != NULL) {
delete_srt(srt);
return new_resolverret_errors(errs);
Expand Down Expand Up @@ -332,9 +370,17 @@ ResolverReturn* resolve_for_stmt(Resolver* resolver) {

vector_push(srt->children, child_srt);

int original_continueable = resolver->continueable;
int original_breakable = resolver->breakable;

resolver->continueable = 1;
resolver->breakable = 1;
resolver->ast = vector_at(ast->children, 3);
resolverret_assign(&child_srt, &errs, resolve_stmt(resolver));
resolver->ast = ast;
resolver->continueable = original_continueable;
resolver->breakable = original_breakable;

if (errs != NULL) {
delete_srt(srt);
return new_resolverret_errors(errs);
Expand Down
2 changes: 2 additions & 0 deletions src/resolver/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

ResolverReturn* resolve_stmt(Resolver* resolver);
ResolverReturn* resolve_compound_stmt(Resolver* resolver);
ResolverReturn* resolve_continue_stmt(Resolver* resolver);
ResolverReturn* resolve_break_stmt(Resolver* resolver);
ResolverReturn* resolve_return_stmt(Resolver* resolver);
ResolverReturn* resolve_expression_stmt(Resolver* resolver);
ResolverReturn* resolve_null_stmt(void);
Expand Down
4 changes: 2 additions & 2 deletions src/resolver/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ void sort_ast_type(AstType* ast_types, int begin, int end) {
AstType pivot = ast_types[begin];

while (i < j) {
while (i < j && ast_types[j] >= pivot) {
while (i < j && ast_types[j] > pivot) {
j--;
}
ast_types[i] = ast_types[j];
Expand All @@ -23,7 +23,7 @@ void sort_ast_type(AstType* ast_types, int begin, int end) {
ast_types[i] = pivot;

sort_ast_type(ast_types, begin, i - 1);
sort_ast_type(ast_types, i + 1, end);
sort_ast_type(ast_types, j + 1, end);
}

int ast_is_void_parameter_list(Ast* ast) {
Expand Down
2 changes: 2 additions & 0 deletions src/srt/srt.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ typedef enum SrtType {

// statement
SRT_CMPD_STMT,
SRT_CONTINUE_STMT,
SRT_BREAK_STMT,
SRT_RET_STMT,
SRT_EXPR_STMT,
SRT_NULL_STMT,
Expand Down
13 changes: 13 additions & 0 deletions test-fixtures/for/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,16 @@
512
1024
2048

0
2
4
6
8
10

0
1
2
4

17 changes: 17 additions & 0 deletions test-fixtures/for/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ int main(void) {
z = 2 * z;
put_int(z);
}
put_blank_line();

for (int i = 0;; i += 2) {
if (i > 10) {
break;
}
put_int(i);
}
put_blank_line();

for (int i = 0; i < 5; i++) {
if (i == 3) {
continue;
}
put_int(i);
}
put_blank_line();

return 0;
}
Loading

0 comments on commit f1d1468

Please sign in to comment.