aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-15 19:45:48 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 19:45:48 +0900
commit70f3db84bb3e2f4d85da7392a112f6f82ce97152 (patch)
tree7eff3177bbf6433c475da9f7f07460352d41c85f
parent4e784d3d5b757f1088d5774897898ca108e9d5d8 (diff)
downloadducc-70f3db84bb3e2f4d85da7392a112f6f82ce97152.tar.gz
ducc-70f3db84bb3e2f4d85da7392a112f6f82ce97152.tar.zst
ducc-70f3db84bb3e2f4d85da7392a112f6f82ce97152.zip
feat: implement conditional expression
-rw-r--r--ast.c1
-rw-r--r--codegen.c16
-rw-r--r--parse.c27
-rw-r--r--tests/091.sh13
4 files changed, 53 insertions, 4 deletions
diff --git a/ast.c b/ast.c
index 8562088..6473d46 100644
--- a/ast.c
+++ b/ast.c
@@ -163,6 +163,7 @@ enum AstNodeKind {
AstNodeKind_assign_expr,
AstNodeKind_binary_expr,
AstNodeKind_break_stmt,
+ AstNodeKind_cond_expr,
AstNodeKind_continue_stmt,
AstNodeKind_deref_expr,
AstNodeKind_do_while_stmt,
diff --git a/codegen.c b/codegen.c
index f717c25..d6f320a 100644
--- a/codegen.c
+++ b/codegen.c
@@ -203,6 +203,20 @@ void codegen_binary_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
printf(" push rax\n");
}
+void codegen_cond_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
+ int label = codegen_new_label(g);
+
+ codegen_expr(g, ast->node_cond, GenMode_rval);
+ printf(" pop rax\n");
+ printf(" cmp rax, 0\n");
+ printf(" je .Lelse%d\n", label);
+ codegen_expr(g, ast->node_then, gen_mode);
+ printf(" jmp .Lend%d\n", label);
+ printf(".Lelse%d:\n", label);
+ codegen_expr(g, ast->node_else, gen_mode);
+ printf(".Lend%d:\n", label);
+}
+
void codegen_assign_expr_helper(CodeGen* g, AstNode* ast) {
if (ast->node_op == TokenKind_assign) {
return;
@@ -379,6 +393,8 @@ void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
codegen_deref_expr(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_binary_expr) {
codegen_binary_expr(g, ast, gen_mode);
+ } else if (ast->kind == AstNodeKind_cond_expr) {
+ codegen_cond_expr(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_logical_expr) {
codegen_logical_expr(g, ast);
} else if (ast->kind == AstNodeKind_assign_expr) {
diff --git a/parse.c b/parse.c
index c9b2886..a185241 100644
--- a/parse.c
+++ b/parse.c
@@ -707,22 +707,41 @@ AstNode* parse_logical_or_expr(Parser* p) {
return lhs;
}
+AstNode* parse_conditional_expr(Parser* p) {
+ AstNode* e = parse_logical_or_expr(p);
+ if (peek_token(p)->kind == TokenKind_question) {
+ next_token(p);
+ AstNode* then_expr = parse_expr(p);
+ expect(p, TokenKind_colon);
+ AstNode* else_expr = parse_assignment_expr(p);
+ AstNode* ret = ast_new(AstNodeKind_cond_expr);
+ ret->node_cond = e;
+ ret->node_then = then_expr;
+ ret->node_else = else_expr;
+ ret->ty = then_expr->ty;
+ return ret;
+ } else {
+ return e;
+ }
+}
+
AstNode* parse_assignment_expr(Parser* p) {
- AstNode* lhs = parse_logical_or_expr(p);
+ AstNode* lhs = parse_conditional_expr(p);
while (1) {
TokenKind op = peek_token(p)->kind;
+ // TODO: check if the lhs is unary expression.
if (op == TokenKind_assign || op == TokenKind_assign_mul || op == TokenKind_assign_div ||
op == TokenKind_assign_mod) {
next_token(p);
- AstNode* rhs = parse_logical_or_expr(p);
+ AstNode* rhs = parse_assignment_expr(p);
lhs = ast_new_assign_expr(op, lhs, rhs);
} else if (op == TokenKind_assign_add) {
next_token(p);
- AstNode* rhs = parse_logical_or_expr(p);
+ AstNode* rhs = parse_assignment_expr(p);
lhs = ast_new_assign_add_expr(lhs, rhs);
} else if (op == TokenKind_assign_sub) {
next_token(p);
- AstNode* rhs = parse_logical_or_expr(p);
+ AstNode* rhs = parse_assignment_expr(p);
lhs = ast_new_assign_sub_expr(lhs, rhs);
} else {
break;
diff --git a/tests/091.sh b/tests/091.sh
new file mode 100644
index 0000000..9281811
--- /dev/null
+++ b/tests/091.sh
@@ -0,0 +1,13 @@
+set -e
+
+cat <<'EOF' > expected
+2 5
+EOF
+
+bash ../../test_diff.sh <<'EOF'
+int printf();
+
+int main() {
+ printf("%d %d\n", 1 ? 2 : 3, 0 ? 4 : 5);
+}
+EOF