parser+codegen: Add support for 'return' statement
Signed-off-by: Ian Moffett <ian@mirocom.org>
This commit is contained in:
@@ -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);
|
||||
|
||||
123
core/parser.c
123
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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,10 +5,43 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user