diff options
| -rw-r--r-- | ast.c | 1 | ||||
| -rw-r--r-- | codegen.c | 16 | ||||
| -rw-r--r-- | parse.c | 27 | ||||
| -rw-r--r-- | tests/091.sh | 13 |
4 files changed, 53 insertions, 4 deletions
@@ -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, @@ -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) { @@ -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 |
