aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--codegen.c15
-rw-r--r--parse.c54
-rw-r--r--tests/080.sh30
3 files changed, 99 insertions, 0 deletions
diff --git a/codegen.c b/codegen.c
index 1ee007a..d15fb4c 100644
--- a/codegen.c
+++ b/codegen.c
@@ -335,6 +335,19 @@ void codegen_gvar(CodeGen* g, AstNode* ast, GenMode gen_mode) {
printf(" push rax\n");
}
+void codegen_composite_expr(CodeGen* g, AstNode* ast) {
+ // Standard C does not have composite expression, but ducc internally has.
+ int i;
+ for (i = 0; i < ast->node_len; ++i) {
+ AstNode* expr = ast->node_items + i;
+ codegen_expr(g, expr, GenMode_rval);
+ if (i != ast->node_len - 1) {
+ // TODO: the expression on the stack can be more than 8 bytes.
+ printf(" pop rax\n");
+ }
+ }
+}
+
void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
if (ast->kind == AstNodeKind_int_expr) {
codegen_int_expr(g, ast);
@@ -358,6 +371,8 @@ void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
codegen_lvar(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_gvar) {
codegen_gvar(g, ast, gen_mode);
+ } else if (ast->kind == AstNodeKind_list) {
+ codegen_composite_expr(g, ast);
} else {
unreachable();
}
diff --git a/parse.c b/parse.c
index b8ad901..70cf9d0 100644
--- a/parse.c
+++ b/parse.c
@@ -120,6 +120,28 @@ int add_lvar(Parser* p, String* name, Type* ty, int is_param) {
return stack_offset;
}
+String* generate_temporary_lvar_name(Parser* p) {
+ String* ret = calloc(1, sizeof(String));
+ ret->data = calloc(256, sizeof(char));
+ int i;
+ for (i = 1;; ++i) {
+ ret->len = sprintf(ret->data, "__%d", i);
+ if (find_lvar(p, ret) == -1) {
+ return ret;
+ }
+ }
+}
+
+AstNode* generate_temporary_lvar(Parser* p, Type* ty) {
+ String* name = generate_temporary_lvar_name(p);
+ int stack_offset = add_lvar(p, name, ty, 0);
+ AstNode* lvar = ast_new(AstNodeKind_lvar);
+ lvar->name = *name;
+ lvar->node_stack_offset = stack_offset;
+ lvar->ty = ty;
+ return lvar;
+}
+
int find_gvar(Parser* p, const String* name) {
int i;
for (i = 0; i < p->n_gvars; ++i) {
@@ -272,6 +294,32 @@ AstNode* parse_arg_list(Parser* p) {
return list;
}
+// e++
+// tmp1 = &e; tmp2 = *tmp1; *tmp1 += 1; tmp2
+// e--
+// tmp1 = &e; tmp2 = *tmp1; *tmp1 -= 1; tmp2
+AstNode* create_new_postfix_inc_or_dec(Parser* p, AstNode* e, TokenKind op) {
+ AstNode* tmp1_lvar = generate_temporary_lvar(p, type_new_ptr(e->ty));
+ AstNode* tmp2_lvar = generate_temporary_lvar(p, e->ty);
+
+ AstNode* expr1 = ast_new_assign_expr(TokenKind_assign, tmp1_lvar, ast_new_ref_expr(e));
+ AstNode* expr2 = ast_new_assign_expr(TokenKind_assign, tmp2_lvar, ast_new_deref_expr(tmp1_lvar));
+ AstNode* expr3;
+ if (op == TokenKind_plusplus) {
+ expr3 = ast_new_assign_add_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1));
+ } else {
+ expr3 = ast_new_assign_sub_expr(ast_new_deref_expr(tmp1_lvar), ast_new_int(1));
+ }
+ AstNode* expr4 = tmp2_lvar;
+
+ AstNode* ret = ast_new_list(4);
+ ast_append(ret, expr1);
+ ast_append(ret, expr2);
+ ast_append(ret, expr3);
+ ast_append(ret, expr4);
+ return ret;
+}
+
AstNode* parse_postfix_expr(Parser* p) {
AstNode* ret = parse_primary_expr(p);
String* name;
@@ -296,6 +344,12 @@ AstNode* parse_postfix_expr(Parser* p) {
next_token(p);
name = parse_ident(p);
ret = ast_new_member_access_expr(ret, name);
+ } else if (tk == TokenKind_plusplus) {
+ next_token(p);
+ ret = create_new_postfix_inc_or_dec(p, ret, tk);
+ } else if (tk == TokenKind_minusminus) {
+ next_token(p);
+ ret = create_new_postfix_inc_or_dec(p, ret, tk);
} else {
break;
}
diff --git a/tests/080.sh b/tests/080.sh
new file mode 100644
index 0000000..ed649da
--- /dev/null
+++ b/tests/080.sh
@@ -0,0 +1,30 @@
+set -e
+
+cat <<'EOF' > expected
+44
+44
+46
+46
+44
+42
+42
+EOF
+
+bash ../../test_diff.sh <<'EOF'
+int printf();
+
+int main() {
+ int a = 42;
+ ++a;
+ a++;
+ printf("%d\n", a);
+ printf("%d\n", a++);
+ printf("%d\n", ++a);
+ printf("%d\n", a);
+ --a;
+ a--;
+ printf("%d\n", a--);
+ printf("%d\n", --a);
+ printf("%d\n", a);
+}
+EOF