diff options
| author | Carson Fleming <[email protected]> | 2026-03-26 16:01:27 -0700 |
|---|---|---|
| committer | Carson Fleming <[email protected]> | 2026-03-26 16:01:27 -0700 |
| commit | 2e4f713ede25fb6147571858779fde542144c76f (patch) | |
| tree | ff7989e0f5a985d7368feeb1d0f0a26142c5d7da | |
| parent | 7d9fb2c733c8c64f6f74eefa0eea35b36be102cd (diff) | |
| download | ccc-2e4f713ede25fb6147571858779fde542144c76f.tar.gz | |
start codegen work
| -rw-r--r-- | ast.c | 12 | ||||
| -rw-r--r-- | ast.h | 8 | ||||
| -rw-r--r-- | codegen.c | 108 | ||||
| -rw-r--r-- | parser.c | 106 |
4 files changed, 172 insertions, 62 deletions
@@ -52,12 +52,6 @@ static void expr_destroy(struct expr_node* node) { case EXPR_EMPTY: case EXPR_INT_LIT: break; - case EXPR_VAR_DECL: - var_decl_destroy(&node->as._var_decl); - break; - case EXPR_RETURN: - return_destroy(&node->as._return); - break; } } @@ -66,6 +60,12 @@ static void stmt_destroy(struct stmt_node* node) { case STMT_EXPR: expr_destroy(&node->as._expr); break; + case STMT_VAR_DECL: + var_decl_destroy(&node->as._var_decl); + break; + case STMT_RETURN: + return_destroy(&node->as._return); + break; case STMT_GROUP: group_destroy(&node->as._group); } @@ -37,13 +37,9 @@ struct int_lit_node { struct expr_node { enum { EXPR_EMPTY, - EXPR_VAR_DECL, - EXPR_RETURN, EXPR_INT_LIT, } type; union { - struct var_decl_node _var_decl; - struct return_node _return; struct int_lit_node _int_lit; } as; }; @@ -51,10 +47,14 @@ struct expr_node { struct stmt_node { enum { STMT_EXPR, + STMT_VAR_DECL, + STMT_RETURN, STMT_GROUP, } type; union { struct expr_node _expr; + struct var_decl_node _var_decl; + struct return_node _return; struct group_node _group; } as; diff --git a/codegen.c b/codegen.c new file mode 100644 index 0000000..37c7a91 --- /dev/null +++ b/codegen.c @@ -0,0 +1,108 @@ +#include "ccc.h" +#include "ast.h" +#include <stdlib.h> +#include <stdio.h> + +static void emit_stmt(FILE* outfile, const struct stmt_node* node); +static void emit_expr( + FILE* outfile, + const struct expr_node* node, + const char* reg); + +static void emit_int_lit( + FILE* outfile, + const struct int_lit_node* node, + const char* reg +) { + fprintf(outfile, "\tmov %s, %lld\n", reg, node->val); +} + +static void emit_expr( + FILE* outfile, + const struct expr_node* node, + const char* reg +) { + switch (node->type) { + case EXPR_EMPTY: + break; + case EXPR_INT_LIT: + emit_int_lit(outfile, &node->as._int_lit, reg); + break; + } +} + +static void emit_var_decl(FILE* outfile, const struct var_decl_node* node) { + /* TODO: make do smth */ +} + +static void emit_return(FILE* outfile, const struct return_node* node) { + if (node->ret_val != NULL) emit_expr(outfile, node->ret_val, "rax"); + fprintf(outfile, "\tret\n"); +} + +static void emit_group(FILE* outfile, const struct group_node* node) { + const struct stmt_node* body_node = node->body_head; + while (body_node != NULL) { + emit_stmt(outfile, body_node); + body_node = body_node->next; + } +} + +static void emit_stmt(FILE* outfile, const struct stmt_node* node) { + switch (node->type) { + case STMT_VAR_DECL: + emit_var_decl(outfile, &node->as._var_decl); + break; + case STMT_RETURN: + emit_return(outfile, &node->as._return); + break; + case STMT_EXPR: + emit_expr(outfile, &node->as._expr, NULL); + break; + case STMT_GROUP: + emit_group(outfile, &node->as._group); + break; + } +} + +static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { + fprintf(outfile, "%s:\n", node->name); + /* TODO: probably something to map the args to temporaries lol */ + emit_group(outfile, &node->body); +} + +static void emit_root_node(FILE* outfile, const struct root_node* node) { + switch (node->type) { + case ROOT_FN_DECL: + emit_fn_decl(outfile, &node->as._fn_decl); + break; + } +} + +void emit_code(const struct root_node* ast, const char* path) { + FILE* outfile = fopen(path, "w"); + if (outfile == NULL) CCC_PANIC; + + fprintf(outfile, "section .text\n"); + + /* output all non-static function declarations as globals */ + const struct root_node* node = ast; + while (node != NULL) { + if (node->type == ROOT_FN_DECL) + fprintf(outfile, "global %s\n", node->as._fn_decl.name); + + node = node->next; + } + + fprintf(outfile, "\n"); + + /* actual code body */ + node = ast; + while (node != NULL) { + emit_root_node(outfile, node); + fprintf(outfile, "\n"); + node = node->next; + } + + fclose(outfile); +} @@ -48,6 +48,42 @@ static void parse_type(struct type_node* p_node) { p_node->type = tok.data.ident; } +static void parse_return(struct return_node* p_node) { + expect(TK_IDENT); + if (strcmp(tok.data.ident, "return") != 0) + PARSER_PANIC("unexpected token %s; expected: return", tok.data.ident); + + if (!lexer_peek(&tok)) + PARSER_PANIC("unexpected EOF in return statement"); + + if (tok.type == TK_SEMI) { + p_node->ret_val = NULL; + return; + } + + p_node->ret_val = protected_alloc(sizeof(struct expr_node)); + handle_expr(p_node->ret_val); +} + +static void parse_int_lit(struct int_lit_node* p_node) { + expect(TK_INT_LIT); + p_node->val = tok.data.int_lit; +} + +static void handle_expr(struct expr_node* p_node) { + switch (tok.type) { + case TK_SEMI: + p_node->type = EXPR_EMPTY; + return; + case TK_INT_LIT: + p_node->type = EXPR_INT_LIT; + parse_int_lit(&p_node->as._int_lit); + return; + default: + PARSER_PANIC("expected expression"); + } +} + static void parse_var_decl(struct var_decl_node* p_node) { parse_type(&p_node->type); expect(TK_IDENT); @@ -73,14 +109,25 @@ static void parse_group(struct group_node* p_node) { } static void handle_stmt(struct stmt_node* p_node) { - if (tok.type == TK_LCURLY) { - p_node->type = STMT_GROUP; - parse_group(&p_node->as._group); - } else { - p_node->type = STMT_EXPR; - handle_expr(&p_node->as._expr); - expect(TK_SEMI); + switch (tok.type) { + case TK_LCURLY: + p_node->type = STMT_GROUP; + parse_group(&p_node->as._group); + return; + case TK_IDENT: + if (strcmp(tok.data.ident, "return") == 0) { + p_node->type = STMT_RETURN; + parse_return(&p_node->as._return); + } else { + p_node->type = STMT_VAR_DECL; + parse_var_decl(&p_node->as._var_decl); + } + break; + default: + p_node->type = STMT_EXPR; + handle_expr(&p_node->as._expr); } + expect(TK_SEMI); } static void parse_arg_list(struct var_decl_node** pp_arg) { @@ -116,51 +163,6 @@ static void parse_fn_decl(struct fn_decl_node* p_node) { parse_group(&p_node->body); } -static void parse_return(struct return_node* p_node) { - expect(TK_IDENT); - if (strcmp(tok.data.ident, "return") != 0) - PARSER_PANIC("unexpected token %s; expected: return", tok.data.ident); - - if (!lexer_peek(&tok)) - PARSER_PANIC("unexpected EOF in return statement"); - - if (tok.type == TK_SEMI) { - p_node->ret_val = NULL; - return; - } - - p_node->ret_val = protected_alloc(sizeof(struct expr_node)); - handle_expr(p_node->ret_val); -} - -static void parse_int_lit(struct int_lit_node* p_node) { - expect(TK_INT_LIT); - p_node->val = tok.data.int_lit; -} - -static void handle_expr(struct expr_node* p_node) { - switch (tok.type) { - case TK_SEMI: - p_node->type = EXPR_EMPTY; - return; - case TK_IDENT: - if (strcmp(tok.data.ident, "return") == 0) { - p_node->type = EXPR_RETURN; - parse_return(&p_node->as._return); - } else { - p_node->type = EXPR_VAR_DECL; - parse_var_decl(&p_node->as._var_decl); - } - return; - case TK_INT_LIT: - p_node->type = EXPR_INT_LIT; - parse_int_lit(&p_node->as._int_lit); - return; - default: - PARSER_PANIC("expected expression"); - } -} - static bool parse_root(struct root_node* p_node) { if (!lexer_peek(&tok)) return false; |
