8000 feat: Function pointers (Fixes #20) by keyvank · Pull Request #37 · keyvank/30cc · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: Function pointers (Fixes #20) #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ $(BIN): *.c parser/*.c parser/expr/*.c codegen/*.c
$(CC) $(CFLAGS) *.c parser/*.c codegen/*.c parser/expr/*.c

run:
./a.out examples/inp5.c --asm > out.asm
./a.out examples/inp_func_ptrs.c --asm > out.asm
nasm -f elf64 out.asm -o out.o
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -o out out.o
./out a b c
50 changes: 34 additions & 16 deletions codegen/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ int pointer_type_named_offset(general_type *self, context *ctx, char *idx)
return 0;
}

int func_pointer_type_named_offset(general_type *self, context *ctx, char *idx)
int func_type_named_offset(general_type *self, context *ctx, char *idx)
{
fprintf(stderr, "Cannot access fields within a function pointer type!\n");
exit(1);
Expand All @@ -211,11 +211,11 @@ int pointer_type_size(general_type *self, context *ctx)
return 8;
}

void func_pointer_type_debug(general_type *self, context *ctx, int depth)
void func_type_debug(general_type *self, context *ctx, int depth)
{
func_pointer_type *p = (func_pointer_type *)self->data;
func_type *p = (func_type *)self->data;
printtabs(depth);
printf("FuncPointer:\n");
printf("Func:\n");
printtabs(depth + 1);
printf("Returns:\n");
p->return_type->debug(p->return_type, ctx, depth + 2);
Expand All @@ -230,9 +230,10 @@ void func_pointer_type_debug(general_type *self, context *ctx, int depth)
}
}

int func_pointer_type_size(general_type *self, context *ctx)
int func_type_size(general_type *self, context *ctx)
{
return 8;
fprintf(stderr, "Function-type has no size!\n");
exit(1);
}

void struct_type_debug(general_type *self, context *ctx, int depth)
Expand Down Expand Up @@ -280,17 +281,17 @@ general_type *new_pointer_type(general_type *of)
return ret;
}

general_type *new_func_pointer_type(general_type *return_type, linked_list *arg_types)
general_type *new_func_type(general_type *return_type, linked_list *arg_types)
{
general_type *ret = (general_type *)malloc(sizeof(general_type));
func_pointer_type *data = (func_pointer_type *)malloc(sizeof(func_pointer_type));
func_type *data = (func_type *)malloc(sizeof(func_type));
data->return_type = return_type;
data->arg_types = arg_types;
ret->kind = TYPE_FUNC_POINTER;
ret->kind = TYPE_FUNC;
ret->data = data;
ret->debug = func_pointer_type_debug;
ret->size = func_pointer_type_size;
ret->named_offset = func_pointer_type_named_offset;
ret->debug = func_type_debug;
ret->size = func_type_size;
ret->named_offset = func_type_named_offset;
return ret;
}

Expand Down Expand Up @@ -337,11 +338,28 @@ int types_equal(general_type *a, general_type *b, context *ctx)
general_type *b_of = ((pointer_type *)b->data)->of;
return types_equal(a_of, b_of, ctx);
}
else if (a->size == func_pointer_type_size)
else if (a->size == func_type_size)
{
general_type *a_ret = ((func_pointer_type *)a->data)->return_type;
general_type *b_ret = ((func_pointer_type *)b->data)->return_type;
return types_equal(a_ret, b_ret, ctx);
general_type *a_ret = ((func_type *)a->data)->return_type;
general_type *b_ret = ((func_type *)b->data)->return_type;
if (!types_equal(a_ret, b_ret, ctx))
return 0;
linked_list *a_args = ((func_type *)a->data)->arg_types;
linked_list *b_args = ((func_type *)b->data)->arg_types;
if (a_args->count != b_args->count)
return 0;
list_node *a_curr = a_args->first;
list_node *b_curr = b_args->first;
for (int i = 0; i < a_args->count; i++)
{
general_type *a_arg = (general_type *)a_curr->value;
general_type *b_arg = (general_type *)b_curr->value;
if (!types_equal(a_arg, b_arg, ctx))
return 0;
a_curr = a_curr->next;
b_curr = b_curr->next;
}
return 1;
}
return 0;
}
6 changes: 3 additions & 3 deletions codegen/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef struct

#define TYPE_PRIMITIVE 0
#define TYPE_POINTER 1
#define TYPE_FUNC_POINTER 2
#define TYPE_FUNC 2
#define TYPE_STRUCT 3

typedef struct
Expand All @@ -57,12 +57,12 @@ typedef struct
{
general_type *return_type;
linked_list *arg_types;
} func_pointer_type;
} func_type;

general_type *new_primitive_type(char *type_name);
general_type *new_struct_type(char *struct_name);
general_type *new_pointer_type(general_type *of);
general_type *new_func_pointer_type(general_type *return_type, linked_list *arg_types);
general_type *new_func_type(general_type *return_type, linked_list *arg_types);
int types_equal(general_type *a, general_type *b, context *ctx);

context new_context();
Expand Down
30 changes: 30 additions & 0 deletions examples/inp_func_ptrs.c
< 8000 /div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
void printf(char *, ...);
void *malloc(int sz);

int sum(int a, int b)
{
return a + b;
}

int mul(int a, int b)
{
return a * b;
}

int handle(int a, int b, int (*f)(int, int))
{
return f(a, b);
}

int main()
{
int (**funcs)(int, int) = (int (**)(int, int))malloc(sizeof(int (*)(int, int)) * 2);
funcs[0] = sum;
funcs[1] = mul;

for (int i = 0; i < 2; i++)
{
int res = handle(10, 20, funcs[i]);
printf("Func #%u result: %u\n", i, res);
}
}
18 changes: 15 additions & 3 deletions parser/expr/func_call.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,22 @@ apply_result *func_call_apply(parser_node *node, context *ctx)
add_text(ctx, "mov %s, %s", regname, argvals[i]);
}

apply_result *fun = call->func->apply(call->func, ctx);
general_type *ret_type = ((func_pointer_type *)fun->type->data)->return_type;
apply_result *fun_obj = call->func->apply(call->func, ctx);
if (fun_obj->type->kind != TYPE_POINTER)
{
fprintf(stderr, "Expected a pointer to function!");
exit(1);
}
general_type *fun_type = ((pointer_type *)fun_obj->type->data)->of;

if (fun_type->kind != TYPE_FUNC)
{
fprintf(stderr, "Expected a pointer to function!");
exit(1);
}
general_type *ret_type = ((func_type *)fun_type->data)->return_type;

add_text(ctx, "call %s", fun->code);
add_text(ctx, "call %s", fun_obj->code);
symbol *tmp = new_temp_symbol(ctx, ret_type);
add_text(ctx, "mov %s, rax", tmp->repl);

Expand Down
2 changes: 1 addition & 1 deletion parser/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ apply_result *program_apply(parser_node *node, context *ctx)
//tp->debug(tp, ctx, 0);
add_to_list(arg_types, tp);
}
general_type *func_type = new_func_pointer_type(func_ret, arg_types);
general_type *func_type = new_pointer_type(new_func_type(func_ret, arg_types));
//func_type->debug(func_type, ctx, 0);
new_global_symbol(ctx, func_name, func_name, func_type);
node->apply(node, ctx);
Expand Down
67 changes: 66 additions & 1 deletion parser/type.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,79 @@ parser_node *parse_type(typed_token **tkns_ptr, int allow_naming)
par->type = new_pointer_type(par->type);
par->name = NULL;
}
*tkns_ptr = tkn;
}

if (node != NULL && tkn->type_id == TKN_L_PAREN)
{
int num_fun_ptr = 0;
char *fun_name = NULL;

tkn = tkn->next;
while (tkn->type_id == TKN_STAR)
{
num_fun_ptr++;
tkn = tkn->next;
}

if (allow_naming && tkn->type_id == TKN_ID)
{
fun_name = tkn->data;
tkn = tkn->next;
}

if (tkn->type_id == TKN_R_PAREN)
{
tkn = tkn->next;
if (tkn->type_id == TKN_L_PAREN)
{
tkn = tkn->next;
parser_node **arg_types = malloc(sizeof(parser_node *) * 128);
int arg_count = 0;
while (1)
{
parser_node *arg_type = parse_type(&tkn, 1);
if (arg_type)
{
arg_types[arg_count++] = arg_type;
}
if (tkn->type_id == TKN_R_PAREN)
{
tkn = tkn->next;
break;
}
else if (arg_type && tkn->type_id == TKN_COMMA)
{
tkn = tkn->next;
continue;
}
else
{
return NULL;
}
}
node_type *par = (node_type *)node->data;
linked_list *args = new_linked_list();
for (int i = 0; i < arg_count; i++)
{
add_to_list(args, ((node_type *)arg_types[i]->data)->type);
}
par->type = new_func_type(par->type, args);
for (int i = 0; i < num_fun_ptr; i++)
par->type = new_pointer_type(par->type);
par->name = fun_name;
}
}
}

if (allow_naming && tkn->type_id == TKN_ID)
{
node_type *par = (node_type *)node->data;
par->name = tkn->data;
tkn = tkn->next;
}

if (node)
{
*tkns_ptr = tkn;
}

Expand Down
1 change: 1 addition & 0 deletions scripts/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"./examples/inp_unary_op.c",
"./examples/lib_usage.c",
"./examples/inp_include.c",
"./examples/inp_func_ptrs.c",
]
C_PROGRAM_NAME = "./a.out"
OUTPUT_FOLDER = "tests/output"
Expand Down
Loading
0