From 4c3f2deb53045f91efd9a758b6208e0dda85d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=8Ddiohabara=E5=8D=8D?= Date: Wed, 26 Jul 2023 09:15:36 -0500 Subject: [PATCH] feat: add ternary operator(?) --- ccc.h | 1 + codegen.c | 12 ++++++++++++ parse.c | 20 ++++++++++++++++++-- tests | 3 +++ tokenize.c | 2 +- type.c | 3 +++ 6 files changed, 38 insertions(+), 3 deletions(-) diff --git a/ccc.h b/ccc.h index c1c480d..3bb3df9 100644 --- a/ccc.h +++ b/ccc.h @@ -122,6 +122,7 @@ typedef enum { ND_SHR, // >> ND_A_SHL, // <<= ND_A_SHR, // >>= + ND_TERNARY, // ? : } NodeKind; // AST node type typedef struct Node Node; diff --git a/codegen.c b/codegen.c index c30bb98..7c53aac 100644 --- a/codegen.c +++ b/codegen.c @@ -391,6 +391,18 @@ void gen(Node *node) { store(node->ty); inc(node); return; + case ND_TERNARY: + int seq = labelseq++; + gen(node->cond); + printf(" pop rax\n"); + printf(" cmp rax, 0\n"); + printf(" je .Lelse%d\n", seq); + gen(node->then); + printf(" jmp .Lend%d\n", seq); + printf(".Lelse%d:\n", seq); + gen(node->els); + printf(".Lend%d:\n", seq); + return; case ND_A_ADD: case ND_A_SUB: case ND_A_MUL: diff --git a/parse.c b/parse.c index a9dab99..8615360 100644 --- a/parse.c +++ b/parse.c @@ -161,6 +161,7 @@ bool is_typename(); Node *stmt(); Node *expr(); Node *assign(); +Node *conditional(); Node *bitand(); Node * bitor (); Node *bitxor(); @@ -820,10 +821,10 @@ Node *expr() { } return node; } -// assign = logor (assign-op assign)? +// assign = conditional (assign-op assign)? // assign-op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" Node *assign() { - Node *node = logor(); + Node *node = conditional(); Token *tok; if (tok = consume("=")) { node = new_binary(ND_ASSIGN, node, assign(), tok); @@ -852,6 +853,21 @@ Node *assign() { return node; } +// conditional = logor ("?" expr ":" condtional)? +Node *conditional() { + Node *node = logor(); + Token *tok = consume("?"); + while (!tok) { + return node; + } + Node *ternary = new_node(ND_TERNARY, tok); + ternary->cond = node; + ternary->then = expr(); + expect(":"); + ternary->els = conditional(); + return ternary; +} + // logor = logand ("||" logand)* Node *logor() { Node *node = logand(); diff --git a/tests b/tests index 049261d..83c7218 100644 --- a/tests +++ b/tests @@ -825,6 +825,9 @@ int main() { assert(-1, ({ int i=-1; i; }), "int i=-1; i;"); assert(-1, ({ int i=-1; i>>=1; i; }), "int i=1; i>>1;"); + assert(2, 0?1:2, "0?1:2"); + assert(1, 1?1:2, "0?1:2"); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 862dab0..688c912 100644 --- a/tokenize.c +++ b/tokenize.c @@ -285,7 +285,7 @@ Token *tokenize() { continue; } // Single-letter punctuator - if (strchr("+-*/()<>;={},&[].,!~|^:", *p)) { + if (strchr("+-*/()<>;={},&[].,!~|^:?", *p)) { cur = new_token(TK_RESERVED, cur, p++, 1); continue; } diff --git a/type.c b/type.c index a2ad22e..ef75572 100644 --- a/type.c +++ b/type.c @@ -165,6 +165,9 @@ void visit(Node* node) { case ND_BITNOT: node->ty = node->lhs->ty; return; + case ND_TERNARY: + node->ty = node->then->ty; + return; case ND_COMMA: node->ty = node->lhs->ty; return;