diff options
| author | Carson Fleming <[email protected]> | 2026-03-26 16:21:29 -0400 |
|---|---|---|
| committer | Carson Fleming <[email protected]> | 2026-03-26 16:22:00 -0400 |
| commit | 7d9fb2c733c8c64f6f74eefa0eea35b36be102cd (patch) | |
| tree | 16b6cded5f9611e0ff1948395578845c9688b926 /parser.c | |
| parent | 68db110d34611fc8bb79035d3a11bba07dea43f3 (diff) | |
| download | ccc-7d9fb2c733c8c64f6f74eefa0eea35b36be102cd.tar.gz | |
let's go we can parse return zero most useful program ever
Diffstat (limited to 'parser.c')
| -rw-r--r-- | parser.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..590ed2b --- /dev/null +++ b/parser.c @@ -0,0 +1,190 @@ +#include "parser.h" +#include "lexer.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define PARSER_PANIC(format, ...) {\ + fprintf(\ + stderr,\ + "ccc: parse error: %s: line %lu, column %lu: " format "\n",\ + tok.PATH,\ + tok.LINE,\ + tok.COL __VA_OPT__(,)\ + __VA_ARGS__);\ + exit(1);\ +} + +static struct token tok; + +static void* protected_alloc(size_t sz) { + void* ptr = calloc(1, sz); + if (ptr == NULL) { + fprintf(stderr, "ccc: out of memory\n"); + exit(1); + } + return ptr; +} + +static void unexpected_token(enum token_type expected) { + /* TODO: print what token was expected */ + PARSER_PANIC("unexpected token"); +} + +static void expect(enum token_type expected) { + if (!lexer_pop(&tok)) + PARSER_PANIC("unexpected EOF"); + + if (tok.type != expected) unexpected_token(expected); +} + +/* "handle" indicates that we've peeked already */ +static void handle_expr(struct expr_node* p_node); +static void handle_stmt(struct stmt_node* p_node); + +static void parse_type(struct type_node* p_node) { + expect(TK_IDENT); + /* TODO: maybe check that this type is real haha */ + p_node->type = tok.data.ident; +} + +static void parse_var_decl(struct var_decl_node* p_node) { + parse_type(&p_node->type); + expect(TK_IDENT); + p_node->ident = tok.data.ident; +} + +static void parse_group(struct group_node* p_node) { + expect(TK_LCURLY); + + struct stmt_node** pp_node = &p_node->body_head; + for (;;) { + if (!lexer_peek(&tok)) + PARSER_PANIC("unexpected EOF in statement group"); + + if (tok.type == TK_RCURLY) break; + + *pp_node = protected_alloc(sizeof(struct stmt_node)); + handle_stmt(*pp_node); + pp_node = &((*pp_node)->next); + } + + expect(TK_RCURLY); +} + +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); + } +} + +static void parse_arg_list(struct var_decl_node** pp_arg) { + for (;;) { + *pp_arg = protected_alloc(sizeof(struct var_decl_node)); + parse_var_decl(*pp_arg); + pp_arg = &((*pp_arg)->next); + + if (!lexer_peek(&tok)) + PARSER_PANIC("unexpected EOF in argument list"); + + if (tok.type == TK_RPAREN) break; + expect(TK_COMMA); + } +} + +static void parse_fn_decl(struct fn_decl_node* p_node) { + parse_type(&p_node->return_type); + + expect(TK_IDENT); + p_node->name = tok.data.ident; + + expect(TK_LPAREN); + + if (!lexer_peek(&tok)) + PARSER_PANIC("unexpected EOF in function declaration"); + + + if (tok.type != TK_RPAREN) parse_arg_list(&p_node->args_head); + + expect(TK_RPAREN); + + 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; + + p_node->type = ROOT_FN_DECL; + parse_fn_decl(&p_node->as._fn_decl); + return true; +} + +struct root_node* parse(const char* path) { + lexer_load(path); + + struct root_node* root; + struct root_node** p_node = &root; + + for (;;) { + *p_node = protected_alloc(sizeof(struct root_node)); + if (!parse_root(*p_node)) { + free(*p_node); + *p_node = NULL; + break; + } + p_node = &((*p_node)->next); + } + + lexer_close(); + return root; +} |
