From 05e907d2b8a94103d60148ce90e27ca191ad5446 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 13 Aug 2019 18:04:08 +0900 Subject: [PATCH] Add +=, -=, *= and /= operators --- chibi.h | 70 +++++++++++++++------------- codegen.c | 132 +++++++++++++++++++++++++++++++---------------------- parse.c | 29 +++++++++++- tests | 9 ++++ tokenize.c | 3 +- type.c | 6 +++ 6 files changed, 159 insertions(+), 90 deletions(-) diff --git a/chibi.h b/chibi.h index 97c3ceb..2601791 100644 --- a/chibi.h +++ b/chibi.h @@ -82,38 +82,44 @@ struct VarList { // AST node typedef enum { - ND_ADD, // num + num - ND_PTR_ADD, // ptr + num or num + ptr - ND_SUB, // num - num - ND_PTR_SUB, // ptr - num - ND_PTR_DIFF, // ptr - ptr - ND_MUL, // * - ND_DIV, // / - ND_EQ, // == - ND_NE, // != - ND_LT, // < - ND_LE, // <= - ND_ASSIGN, // = - ND_PRE_INC, // pre ++ - ND_PRE_DEC, // pre -- - ND_POST_INC, // post ++ - ND_POST_DEC, // post -- - ND_COMMA, // , - ND_MEMBER, // . (struct member access) - ND_ADDR, // unary & - ND_DEREF, // unary * - ND_RETURN, // "return" - ND_IF, // "if" - ND_WHILE, // "while" - ND_FOR, // "for" - ND_BLOCK, // { ... } - ND_FUNCALL, // Function call - ND_EXPR_STMT, // Expression statement - ND_STMT_EXPR, // Statement expression - ND_VAR, // Variable - ND_NUM, // Integer - ND_CAST, // Type cast - ND_NULL, // Empty statement + ND_ADD, // num + num + ND_PTR_ADD, // ptr + num or num + ptr + ND_SUB, // num - num + ND_PTR_SUB, // ptr - num + ND_PTR_DIFF, // ptr - ptr + ND_MUL, // * + ND_DIV, // / + ND_EQ, // == + ND_NE, // != + ND_LT, // < + ND_LE, // <= + ND_ASSIGN, // = + ND_PRE_INC, // pre ++ + ND_PRE_DEC, // pre -- + ND_POST_INC, // post ++ + ND_POST_DEC, // post -- + ND_ADD_EQ, // += + ND_PTR_ADD_EQ, // += + ND_SUB_EQ, // -= + ND_PTR_SUB_EQ, // -= + ND_MUL_EQ, // *= + ND_DIV_EQ, // /= + ND_COMMA, // , + ND_MEMBER, // . (struct member access) + ND_ADDR, // unary & + ND_DEREF, // unary * + ND_RETURN, // "return" + ND_IF, // "if" + ND_WHILE, // "while" + ND_FOR, // "for" + ND_BLOCK, // { ... } + ND_FUNCALL, // Function call + ND_EXPR_STMT, // Expression statement + ND_STMT_EXPR, // Statement expression + ND_VAR, // Variable + ND_NUM, // Integer + ND_CAST, // Type cast + ND_NULL, // Empty statement } NodeKind; // AST node type diff --git a/codegen.c b/codegen.c index ca99ef0..ffa88f4 100644 --- a/codegen.c +++ b/codegen.c @@ -114,6 +114,69 @@ static void dec(Type *ty) { printf(" push rax\n"); } +static void gen_binary(Node *node) { + printf(" pop rdi\n"); + printf(" pop rax\n"); + + switch (node->kind) { + case ND_ADD: + case ND_ADD_EQ: + printf(" add rax, rdi\n"); + break; + case ND_PTR_ADD: + case ND_PTR_ADD_EQ: + printf(" imul rdi, %d\n", node->ty->base->size); + printf(" add rax, rdi\n"); + break; + case ND_SUB: + case ND_SUB_EQ: + printf(" sub rax, rdi\n"); + break; + case ND_PTR_SUB: + case ND_PTR_SUB_EQ: + printf(" imul rdi, %d\n", node->ty->base->size); + printf(" sub rax, rdi\n"); + break; + case ND_PTR_DIFF: + printf(" sub rax, rdi\n"); + printf(" cqo\n"); + printf(" mov rdi, %d\n", node->lhs->ty->base->size); + printf(" idiv rdi\n"); + break; + case ND_MUL: + case ND_MUL_EQ: + printf(" imul rax, rdi\n"); + break; + case ND_DIV: + case ND_DIV_EQ: + printf(" cqo\n"); + printf(" idiv rdi\n"); + break; + case ND_EQ: + printf(" cmp rax, rdi\n"); + printf(" sete al\n"); + printf(" movzb rax, al\n"); + break; + case ND_NE: + printf(" cmp rax, rdi\n"); + printf(" setne al\n"); + printf(" movzb rax, al\n"); + break; + case ND_LT: + printf(" cmp rax, rdi\n"); + printf(" setl al\n"); + printf(" movzb rax, al\n"); + break; + case ND_LE: + printf(" cmp rax, rdi\n"); + printf(" setle al\n"); + printf(" movzb rax, al\n"); + break; + } + + printf(" push rax\n"); +} + // Generate code for a given node. static void gen(Node *node) { switch (node->kind) { @@ -172,6 +235,19 @@ static void gen(Node *node) { store(node->ty); inc(node->ty); return; + case ND_ADD_EQ: + case ND_PTR_ADD_EQ: + case ND_SUB_EQ: + case ND_PTR_SUB_EQ: + case ND_MUL_EQ: + case ND_DIV_EQ: + gen_lval(node->lhs); + printf(" push [rsp]\n"); + load(node->lhs->ty); + gen(node->rhs); + gen_binary(node); + store(node->ty); + return; case ND_COMMA: gen(node->lhs); gen(node->rhs); @@ -283,61 +359,7 @@ static void gen(Node *node) { gen(node->lhs); gen(node->rhs); - - printf(" pop rdi\n"); - printf(" pop rax\n"); - - switch (node->kind) { - case ND_ADD: - printf(" add rax, rdi\n"); - break; - case ND_PTR_ADD: - printf(" imul rdi, %d\n", node->ty->base->size); - printf(" add rax, rdi\n"); - break; - case ND_SUB: - printf(" sub rax, rdi\n"); - break; - case ND_PTR_SUB: - printf(" imul rdi, %d\n", node->ty->base->size); - printf(" sub rax, rdi\n"); - break; - case ND_PTR_DIFF: - printf(" sub rax, rdi\n"); - printf(" cqo\n"); - printf(" mov rdi, %d\n", node->lhs->ty->base->size); - printf(" idiv rdi\n"); - break; - case ND_MUL: - printf(" imul rax, rdi\n"); - break; - case ND_DIV: - printf(" cqo\n"); - printf(" idiv rdi\n"); - break; - case ND_EQ: - printf(" cmp rax, rdi\n"); - printf(" sete al\n"); - printf(" movzb rax, al\n"); - break; - case ND_NE: - printf(" cmp rax, rdi\n"); - printf(" setne al\n"); - printf(" movzb rax, al\n"); - break; - case ND_LT: - printf(" cmp rax, rdi\n"); - printf(" setl al\n"); - printf(" movzb rax, al\n"); - break; - case ND_LE: - printf(" cmp rax, rdi\n"); - printf(" setle al\n"); - printf(" movzb rax, al\n"); - break; - } - - printf(" push rax\n"); + gen_binary(node); } static void emit_data(Program *prog) { diff --git a/parse.c b/parse.c index cb255c7..f045e89 100644 --- a/parse.c +++ b/parse.c @@ -742,12 +742,37 @@ static Node *expr(void) { return node; } -// assign = equality ("=" assign)? +// assign = equality (assign-op assign)? +// assign-op = "=" | "+=" | "-=" | "*=" | "/=" static Node *assign(void) { Node *node = equality(); Token *tok; + if (tok = consume("=")) - node = new_binary(ND_ASSIGN, node, assign(), tok); + return new_binary(ND_ASSIGN, node, assign(), tok); + + if (tok = consume("*=")) + return new_binary(ND_MUL_EQ, node, assign(), tok); + + if (tok = consume("/=")) + return new_binary(ND_DIV_EQ, node, assign(), tok); + + if (tok = consume("+=")) { + add_type(node); + if (node->ty->base) + return new_binary(ND_PTR_ADD_EQ, node, assign(), tok); + else + return new_binary(ND_ADD_EQ, node, assign(), tok); + } + + if (tok = consume("-=")) { + add_type(node); + if (node->ty->base) + return new_binary(ND_PTR_SUB_EQ, node, assign(), tok); + else + return new_binary(ND_SUB_EQ, node, assign(), tok); + } + return node; } diff --git a/tests b/tests index 50f5ca1..ce756bc 100644 --- a/tests +++ b/tests @@ -369,6 +369,15 @@ int main() { assert(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[2]; }), "int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++); a[0];"); assert(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; *p; }), "int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++); a[0];"); + assert(7, ({ int i=2; i+=5; i; }), "int i=2; i+=5; i;"); + assert(7, ({ int i=2; i+=5; }), "int i=2; i+=5;"); + assert(3, ({ int i=5; i-=2; i; }), "int i=5; i-=2; i;"); + assert(3, ({ int i=5; i-=2; }), "int i=5; i-=2;"); + assert(6, ({ int i=3; i*=2; i; }), "int i=3; i*=2; i;"); + assert(6, ({ int i=3; i*=2; }), "int i=3; i*=2;"); + assert(3, ({ int i=6; i/=2; i; }), "int i=6; i/=2; i;"); + assert(3, ({ int i=6; i/=2; }), "int i=6; i/=2;"); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 5d4e3cb..0d17551 100644 --- a/tokenize.c +++ b/tokenize.c @@ -158,7 +158,8 @@ static char *starts_with_reserved(char *p) { } // Multi-letter punctuator - static char *ops[] = {"==", "!=", "<=", ">=", "->", "++", "--"}; + static char *ops[] = {"==", "!=", "<=", ">=", "->", "++", "--", + "+=", "-=", "*=", "/="}; for (int i = 0; i < sizeof(ops) / sizeof(*ops); i++) if (startswith(p, ops[i])) diff --git a/type.c b/type.c index 7055ac1..0bfcd9f 100644 --- a/type.c +++ b/type.c @@ -85,6 +85,12 @@ void add_type(Node *node) { case ND_PRE_DEC: case ND_POST_INC: case ND_POST_DEC: + case ND_ADD_EQ: + case ND_PTR_ADD_EQ: + case ND_SUB_EQ: + case ND_PTR_SUB_EQ: + case ND_MUL_EQ: + case ND_DIV_EQ: node->ty = node->lhs->ty; return; case ND_VAR: -- GitLab