Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support compound assignment expressions #128

Merged
merged 5 commits into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ typedef enum AstType {
// expression
// assignment-expression
AST_ASSIGN_EXPR,
AST_MUL_ASSIGN_EXPR,
AST_DIV_ASSIGN_EXPR,
AST_MOD_ASSIGN_EXPR,
AST_ADD_ASSIGN_EXPR,
AST_SUB_ASSIGN_EXPR,
AST_AND_ASSIGN_EXPR,
AST_XOR_ASSIGN_EXPR,
AST_OR_ASSIGN_EXPR,
// conditional-expression
AST_COND_EXPR,
// logical-OR-expression
Expand Down
3 changes: 2 additions & 1 deletion src/ctoken/ctoken.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ char* ctoken_types[] = {
"identifier", "integer-constant", "character-constant", "string-literal",
// punctuators
"[", "]", "(", ")", "{", "}", ".", "->", "++", "--", "&", "*", "+", "-", "~", "!", "/", "%", "<", ">",
"<=", ">=", "==", "!=", "^", "|", "&&", "||", "?", ":", ";", "=", ",", "EOF"};
"<=", ">=", "==", "!=", "^", "|", "&&", "||", "?", ":", ";", "=",
"*=", "/=", "%=", "+=", "-=", "&=", "^=", "|=", ",", "EOF"};

CToken* new_base_ctoken(CTokenType type);

Expand Down
8 changes: 8 additions & 0 deletions src/ctoken/ctoken.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ typedef enum CTokenType {
CTOKEN_COLON,
CTOKEN_SEMICOLON,
CTOKEN_EQUAL,
CTOKEN_ASTERISK_EQUAL,
CTOKEN_SLASH_EQUAL,
CTOKEN_PERCENT_EQUAL,
CTOKEN_PLUS_EQUAL,
CTOKEN_MINUS_EQUAL,
CTOKEN_AND_EQUAL,
CTOKEN_CARET_EQUAL,
CTOKEN_VBAR_EQUAL,
CTOKEN_COMMA,
CTOKEN_EOF,
} CTokenType;
Expand Down
10 changes: 1 addition & 9 deletions src/immcgen/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,11 @@

Vector* gen_assignment_expr_immcode(Immcgen* immcgen) {
Vector* codes = new_vector(&t_immc);
Srt* srt = immcgen->srt;

ImmcOpe* src = gen_child_reg_immcope(immcgen, codes, 1);
ImmcOpe* dst = gen_child_ptr_immcope(immcgen, codes, 0);

switch (srt->type) {
case SRT_ASSIGN_EXPR:
vector_push(codes, new_inst_immc(IMMC_INST_STORE, dst, src, NULL));
break;
default:
fprintf(stderr, "unexpected srt type %d\n", srt->type);
exit(1);
}
vector_push(codes, new_inst_immc(IMMC_INST_STORE, dst, src, NULL));

update_non_void_expr_register(immcgen, src);
return codes;
Expand Down
8 changes: 8 additions & 0 deletions src/lexer/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ Map* new_punctuator_map(void) {
ctoken_map_add(punctuator_map, ":", CTOKEN_COLON);
ctoken_map_add(punctuator_map, ";", CTOKEN_SEMICOLON);
ctoken_map_add(punctuator_map, "=", CTOKEN_EQUAL);
ctoken_map_add(punctuator_map, "*=", CTOKEN_ASTERISK_EQUAL);
ctoken_map_add(punctuator_map, "/=", CTOKEN_SLASH_EQUAL);
ctoken_map_add(punctuator_map, "%=", CTOKEN_PERCENT_EQUAL);
ctoken_map_add(punctuator_map, "+=", CTOKEN_PLUS_EQUAL);
ctoken_map_add(punctuator_map, "-=", CTOKEN_MINUS_EQUAL);
ctoken_map_add(punctuator_map, "&=", CTOKEN_AND_EQUAL);
ctoken_map_add(punctuator_map, "^=", CTOKEN_CARET_EQUAL);
ctoken_map_add(punctuator_map, "|=", CTOKEN_VBAR_EQUAL);
ctoken_map_add(punctuator_map, ",", CTOKEN_COMMA);

return punctuator_map;
Expand Down
32 changes: 32 additions & 0 deletions src/parser/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ ParserReturn* parse_assignment_expr(Parser* parser) {
parser->index++;
vector_push(stack, new_ast(AST_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_ASTERISK_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_MUL_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_SLASH_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_DIV_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_PERCENT_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_MOD_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_PLUS_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_ADD_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_MINUS_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_SUB_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_AND_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_AND_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_CARET_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_XOR_ASSIGN_EXPR, 1, ast));
break;
case CTOKEN_VBAR_EQUAL:
parser->index++;
vector_push(stack, new_ast(AST_OR_ASSIGN_EXPR, 1, ast));
break;
default:
parser->index = index;
delete_ast(ast);
Expand Down
76 changes: 70 additions & 6 deletions src/resolver/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ ResolverReturn* resolve_expr(Resolver* resolver) {
case AST_ASSIGN_EXPR:
resolverret_assign(&srt, &errs, resolve_assignment_expr(resolver));
break;
case AST_MUL_ASSIGN_EXPR:
case AST_DIV_ASSIGN_EXPR:
case AST_MOD_ASSIGN_EXPR:
case AST_ADD_ASSIGN_EXPR:
case AST_SUB_ASSIGN_EXPR:
case AST_OR_ASSIGN_EXPR:
case AST_XOR_ASSIGN_EXPR:
case AST_AND_ASSIGN_EXPR:
resolverret_assign(&srt, &errs, resolve_compound_assignment_expr(resolver));
break;
case AST_COND_EXPR:
resolverret_assign(&srt, &errs, resolve_conditional_expr(resolver));
break;
Expand Down Expand Up @@ -143,6 +153,60 @@ ResolverReturn* resolve_assignment_expr(Resolver* resolver) {
return new_resolverret(srt);
}

ResolverReturn* resolve_compound_assignment_expr(Resolver* resolver) {
Srt* srt = NULL;
Vector* errs = NULL;

Ast* ast = resolver->ast;
Ast* lhs_ast = vector_at(ast->children, 0);
Ast* rhs_ast = vector_at(ast->children, 1);

Ast* binop_ast = NULL;
switch (ast->type) {
case AST_MUL_ASSIGN_EXPR:
binop_ast = new_ast(AST_MUL_EXPR, 0);
break;
case AST_DIV_ASSIGN_EXPR:
binop_ast = new_ast(AST_DIV_EXPR, 0);
break;
case AST_MOD_ASSIGN_EXPR:
binop_ast = new_ast(AST_MOD_EXPR, 0);
break;
case AST_ADD_ASSIGN_EXPR:
binop_ast = new_ast(AST_ADD_EXPR, 0);
break;
case AST_SUB_ASSIGN_EXPR:
binop_ast = new_ast(AST_SUB_EXPR, 0);
break;
case AST_OR_ASSIGN_EXPR:
binop_ast = new_ast(AST_OR_EXPR, 0);
break;
case AST_XOR_ASSIGN_EXPR:
binop_ast = new_ast(AST_XOR_EXPR, 0);
break;
case AST_AND_ASSIGN_EXPR:
binop_ast = new_ast(AST_AND_EXPR, 0);
break;
default:
fprintf(stderr, "\x1b[1;31mfatal error\x1b[0m: "
"unreachable statement (in resolve_compound_assignment_expr)\n");
exit(1);
}

vector_push(binop_ast->children, ast_copy(lhs_ast));
vector_push(binop_ast->children, ast_copy(rhs_ast));

resolver->ast = new_ast(AST_ASSIGN_EXPR, 2, ast_copy(lhs_ast), binop_ast);
resolverret_assign(&srt, &errs, resolve_assignment_expr(resolver));
delete_ast(resolver->ast);
resolver->ast = ast;
if (errs != NULL) {
return new_resolverret_errors(errs);
}

return new_resolverret(srt);
}

ResolverReturn* resolve_conditional_expr(Resolver* resolver) {
Srt* srt = NULL;
Srt* condition_srt = NULL;
Expand Down Expand Up @@ -422,7 +486,7 @@ ResolverReturn* resolve_equality_expr(Resolver* resolver) {
err = new_error("operands of pointer == pointer are not compatible");
} else {
err = new_error("binary == expression should be "
"either arithmetic == arithmetic or pointer == pointer\n");
"either arithmetic == arithmetic or pointer == pointer");
}
vector_push(errs, err);
break;
Expand All @@ -436,7 +500,7 @@ ResolverReturn* resolve_equality_expr(Resolver* resolver) {
err = new_error("operands of pointer != pointer are not compatible");
} else {
err = new_error("binary != expression should be "
"either arithmetic != arithmetic or pointer != pointer\n");
"either arithmetic != arithmetic or pointer != pointer");
}
vector_push(errs, err);
break;
Expand All @@ -446,7 +510,7 @@ ResolverReturn* resolve_equality_expr(Resolver* resolver) {
break;
default:
fprintf(stderr, "\x1b[1;31mfatal error\x1b[0m: "
"unreachable statement (in resolve_equality_expr)\n");
"unreachable statement (in resolve_equality_expr)");
exit(1);
}

Expand Down Expand Up @@ -646,7 +710,7 @@ ResolverReturn* resolve_add_expr(Resolver* resolver) {

errs = new_vector(&t_error);
err = new_error("binary + expression should be either arithmetic + arithmetic, "
"pointer + integer, or integer + pointer\n");
"pointer + integer, or integer + pointer");
vector_push(errs, err);

delete_srt(lhs_srt);
Expand Down Expand Up @@ -706,7 +770,7 @@ ResolverReturn* resolve_subtract_expr(Resolver* resolver) {
err = new_error("operands of pointer - pointer are not compatible");
} else {
err = new_error("binary - expression should be either arithmetic - arithmetic, "
"pointer - integer, or pointer - pointer\n");
"pointer - integer, or pointer - pointer");
}
vector_push(errs, err);

Expand Down Expand Up @@ -901,7 +965,7 @@ ResolverReturn* resolve_address_expr(Resolver* resolver) {
(child_srt->type != SRT_IDENT_EXPR || !dtype_isobject(child_srt->dtype))) {
errs = new_vector(&t_error);
err = new_error("operand of unary & is neither a function designator, "
"a indirection, nor an object lvalue\n");
"a indirection, nor an object lvalue");
vector_push(errs, err);
delete_srt(child_srt);
return new_resolverret_errors(errs);
Expand Down
1 change: 1 addition & 0 deletions src/resolver/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

ResolverReturn* resolve_expr(Resolver* resolver);
ResolverReturn* resolve_assignment_expr(Resolver* resolver);
ResolverReturn* resolve_compound_assignment_expr(Resolver* resolver);
ResolverReturn* resolve_conditional_expr(Resolver* resolver);
ResolverReturn* resolve_logical_expr(Resolver* resolver);
ResolverReturn* resolve_bitwise_expr(Resolver* resolver);
Expand Down
33 changes: 33 additions & 0 deletions test-fixtures/assignment/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
3
2
6
5

9
1
8

5
5

2
2

6
6

1
1

0
0

1
1

3
3

2
2

73 changes: 73 additions & 0 deletions test-fixtures/assignment/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
void put_int(int x);
void put_blank_line(void);

void simple_assignment(void) {
int first, second, third;

first = 3;
second = first - 1;
third = first * second;

put_int(first);
put_int(second);
put_int(third);
put_int(third - (first - second));
put_blank_line();

third = (first = 9) - (second = 1);
put_int(first);
put_int(second);
put_int(third);
put_blank_line();
}

void compound_assignment(void) {
int x;

x = 3;
put_int(x += 2);
put_int(x);
put_blank_line();

x = 3;
put_int(x -= 1);
put_int(x);
put_blank_line();

x = 3;
put_int(x *= 2);
put_int(x);
put_blank_line();

x = 3;
put_int(x /= 2);
put_int(x);
put_blank_line();

x = 3;
put_int(x %= 3);
put_int(x);
put_blank_line();

x = 3;
put_int(x &= 1);
put_int(x);
put_blank_line();

x = 3;
put_int(x |= 1);
put_int(x);
put_blank_line();

x = 3;
put_int(x ^= 1);
put_int(x);
put_blank_line();
}

int main(void) {
simple_assignment();
compound_assignment();

return 0;
}
8 changes: 0 additions & 8 deletions test-fixtures/variable/expected.txt

This file was deleted.

23 changes: 0 additions & 23 deletions test-fixtures/variable/main.c

This file was deleted.

Loading