From 3e8a45a156069a28bb8b916630e53c4599c94a8b Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Mon, 16 Feb 2026 13:49:15 -0500 Subject: [PATCH] parser+codegen: Add support for 'return' statement Signed-off-by: Ian Moffett --- core/codegen.c | 48 +++++++++++++++++++ core/parser.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ inc/rifle/ast.h | 9 +++- inc/rifle/mu.h | 33 +++++++++++++ 4 files changed, 212 insertions(+), 1 deletion(-) diff --git a/core/codegen.c b/core/codegen.c index b52e56c..015efce 100644 --- a/core/codegen.c +++ b/core/codegen.c @@ -25,6 +25,48 @@ resolve_func(struct rifle_state *state, struct ast_node *root) return mu_gen_label(state, symbol->name, symbol->pub); } +static int +resolve_return(struct rifle_state *state, struct ast_node *root) +{ + struct symbol *func_sym; + struct ast_node *rhs; + data_type_t type; + + if (state == NULL || root == NULL) { + return -1; + } + + if ((func_sym = state->cur_func) == NULL) { + return -1; + } + + if (root->type != AST_RETURN) { + return -1; + } + + if ((rhs = root->right) == NULL) { + trace_error(state, "internal: return has no rhs\n"); + return -1; + } + + type = data_raw_type(&func_sym->dtype) ; + switch (rhs->type) { + case AST_NUMBER: + mu_gen_retimm( + state, + rhs->v, + type_to_msize(type) + ); + + break; + default: + trace_error(state, "internal: bad ast node in return\n"); + return -1; + } + + return 0; +} + int cg_resolve_node(struct rifle_state *state, struct ast_node *root) { @@ -38,6 +80,12 @@ cg_resolve_node(struct rifle_state *state, struct ast_node *root) return -1; } + break; + case AST_RETURN: + if (resolve_return(state, root) < 0) { + return -1; + } + break; default: trace_error(state, "unknown ast node %d\n", root->type); diff --git a/core/parser.c b/core/parser.c index cf2acdc..49172c5 100644 --- a/core/parser.c +++ b/core/parser.c @@ -547,6 +547,123 @@ parse_rbrace(struct rifle_state *state, struct token *tok, struct ast_node **res return 0; } +/* + * Parse a value + * + * @state: Compiler state + * @tok: Last token + * @res: AST result + * + * Returns zero on success + */ +static int +parse_value(struct rifle_state *state, struct token *tok, struct ast_node **res) +{ + struct ast_node *root; + + if (state == NULL || tok == NULL) { + return -1; + } + + if (res == NULL) { + return -1; + } + + switch (tok->type) { + case TT_NUMBER: + if (ast_alloc_node(state, AST_NUMBER, &root) < 0) { + trace_error(state, "failed to allocate AST_NUMBER\n"); + return -1; + } + + root->v = tok->v; + *res = root; + return 0; + default: + utok(state, symtok("number"), tokstr(tok)); + break; + } + + return -1; +} + +/* + * Parse a binary expression + * + * @state: Compiler state + * @tok: Last token + * @res: AST result + * + * Returns zero on success + */ +static int +parse_binexpr(struct rifle_state *state, struct token *tok, struct ast_node **res) +{ + struct ast_node *root; + + if (state == NULL || tok == NULL) { + return -1; + } + + if (res == NULL) { + return -1; + } + + if (parse_value(state, tok, &root) < 0) { + return -1; + } + + /* TODO: Allow actual binary expressions */ + *res = root; + return 0; +} + +/* + * Parse a 'return' token + * + * @state: Compiler state + * @tok: Last token + * @res: AST result + * + * Returns zero on success + */ +static int +parse_return(struct rifle_state *state, struct token *tok, struct ast_node **res) +{ + struct ast_node *root, *rhs; + + if (state == NULL || tok == NULL) { + return -1; + } + + if (res == NULL) { + return -1; + } + + if (state->cur_func == NULL) { + trace_error(state, "'return' not in function\n"); + return -1; + } + + if (parse_scan(state, tok) < 0) { + ueof(state); + return -1; + } + + if (parse_binexpr(state, tok, &rhs) < 0) { + return -1; + } + + if (ast_alloc_node(state, AST_RETURN, &root) < 0) { + trace_error(state, "failed to allocate AST_RETURN\n"); + return -1; + } + + root->right = rhs; + *res = root; + return 0; +} + static int parse_begin(struct rifle_state *state) { @@ -566,6 +683,12 @@ parse_begin(struct rifle_state *state) return -1; } + break; + case TT_RETURN: + if (parse_return(state, &tok, &root) < 0) { + return -1; + } + break; case TT_PUB: break; diff --git a/inc/rifle/ast.h b/inc/rifle/ast.h index 7cae4d3..bc93c0f 100644 --- a/inc/rifle/ast.h +++ b/inc/rifle/ast.h @@ -11,10 +11,14 @@ * * @AST_NONE: This node has no associated type * @AST_FUNC: This node represents a function + * @AST_RETURN: This node represents a return statement + * @AST_NUMBER: This node represents a number */ typedef enum { AST_NONE, - AST_FUNC + AST_FUNC, + AST_RETURN, + AST_NUMBER } ast_type_t; /* @@ -32,6 +36,9 @@ struct ast_node { struct ast_node *right; struct symbol *symbol; uint8_t epilogue : 1; + union { + size_t v; + }; }; /* diff --git a/inc/rifle/mu.h b/inc/rifle/mu.h index d1a966e..338293c 100644 --- a/inc/rifle/mu.h +++ b/inc/rifle/mu.h @@ -5,10 +5,43 @@ #include #include #include "rifle/state.h" +#include "rifle/types.h" #define INST(inst) \ " " inst "\n" +/* + * Represents valid machine sizes + */ +typedef enum { + MSIZE_BYTE, + MSIZE_WORD, + MSIZE_DWORD, + MSIZE_QWORD, + MSIZE_MAX, + MSIZE_BAD +} msize_t; + +/* + * Convert a program data type into a machine size + * + * @type: Program data type to convert + */ +static inline msize_t +type_to_msize(data_type_t type) +{ + switch (type) { + case DATA_TYPE_U8: return MSIZE_BYTE; + case DATA_TYPE_U16: return MSIZE_WORD; + case DATA_TYPE_U32: return MSIZE_DWORD; + case DATA_TYPE_U64: return MSIZE_QWORD; + default: + return MSIZE_BAD; + } + + return MSIZE_BAD; +} + /* * Generate a named label *