void emit_expr(FILE *file, Ast *n) { switch (n->kind) { case AST_INT: { fprintf(file, " mov rax, %lu\n", n->u); } break; case AST_BINARY: { emit_expr(file, n->l); fprintf(file, " push rax\n"); emit_expr(file, n->r); fprintf(file, " pop rcx\n"); if (n->op == TOK_PLUS) { fprintf(file, " add rax, rcx\n"); } else if (n->op == TOK_STAR) { fprintf(file, " imul rax, rcx\n"); } else if (n->op == TOK_MINUS) { fprintf(file, " mov rdx, rax\n"); fprintf(file, " mov rax, rcx\n"); fprintf(file, " sub rax, rdx\n"); } else { panicf("error"); } } break; default: panicf("error"); } } void emit_program(FILE *file, Ast *n) { fprintf(file, ".intel_syntax noprefix\n"); fprintf(file, ".global main\n"); fprintf(file, "main:\n"); emit_expr(file, n); fprintf(file, " ret\n"); } void emit_expr_test(char *expr, int value) { Token_Array tokens = lex_file("expr", expr, strlen(expr)); Parser parser = {tokens.data, tokens.data + tokens.len}; Ast *ast = parse_expr(&parser, 0); FILE *file = fopen("out.s", "w"); emit_program(file, ast); fclose(file); int result = system("clang out.s -o out"); assert(result == 0); result = system("./out"); assert(WEXITSTATUS(result) == value); } void emit_x64_test(void) { emit_expr_test("10+5*2-10", 10+5*2-10); printf("x64 tests passed\n"); }