Skip to content

Commit

Permalink
feat: Allow linking with extern vars, fixes #58
Browse files Browse the repository at this point in the history
  • Loading branch information
keyvank committed Nov 25, 2024
1 parent f7b9979 commit 39506f4
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 3 deletions.
11 changes: 11 additions & 0 deletions examples/inp_extern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
void fprintf(void *, char *, ...);

extern void *stderr;
extern void *stdout;

int main()
{
fprintf(stdout, "This is stdout!\n");
fprintf(stderr, "This is stderr!\n");
return 0;
}
2 changes: 2 additions & 0 deletions lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ typed_token *next_keyword_or_identifier(char **inp_ptr)
return new_simp_tkn(TKN_CASE);
else if (strcmp(val, "default") == 0)
return new_simp_tkn(TKN_DEFAULT);
else if (strcmp(val, "extern") == 0)
return new_simp_tkn(TKN_EXTERN);
else
return new_tkn(TKN_ID, val, ident_tkn_debug);
}
Expand Down
1 change: 1 addition & 0 deletions lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typed_token *tokenize(char *inp);
#define TKN_SIZEOF 11
#define TKN_TYPEDEF 12
#define TKN_GOTO 13
#define TKN_EXTERN 14

// Single letter symbols
#define TKN_L_PAREN 16
Expand Down
53 changes: 53 additions & 0 deletions parser/extern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "extern.h"
#include <stdlib.h>
#include <string.h>
#include "../codegen/codegen.h"

#include "parser.h"
#include "var_decl.h"
#include "type.h"

void extern_debug(int depth, parser_node *node)
{
node_extern *ex = (node_extern *)node->data;
printtabs(depth);
printf("Extern:\n");
ex->var_decl->debug(depth + 1, ex->var_decl);
}

apply_result *extern_apply(parser_node *node, context *ctx)
{
node_extern *ex = (node_extern *)node->data;
node_var_decl *vd = ex->var_decl->data;
node_type *tp = vd->type->data;

add_text(ctx, "extern %s", vd->identity);
new_global_symbol(ctx, vd->identity, cc_asprintf("[%s]", vd->identity), tp->type);

return NULL;
}

parser_node *parse_extern(typed_token **tkns_ptr)
{
typed_token *tkn = *tkns_ptr;
if (tkn->type_id == TKN_EXTERN)
{
tkn = tkn->next;
parser_node *decl = parse_var_decl(&tkn);
if (decl)
{
*tkns_ptr = tkn;

parser_node *node = (parser_node *)malloc(sizeof(parser_node));
node->data = (void *)malloc(sizeof(node_extern));
node->debug = extern_debug;
node->apply = extern_apply;
node_extern *ex = (node_extern *)node->data;
ex->var_decl = decl;

return node;
}
}

return NULL;
}
14 changes: 14 additions & 0 deletions parser/extern.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef EXTERN_H
#define EXTERN_H

#include "../lexer.h"
#include "parser.h"

parser_node *parse_extern(typed_token **tkns_ptr);

typedef struct
{
parser_node *var_decl;
} node_extern;

#endif
22 changes: 19 additions & 3 deletions parser/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@
#include "../linked_list.h"
#include "struct_def.h"
#include "type.h"
#include "extern.h"

void program_debug(int depth, parser_node *node)
{
node_program *prog = (node_program *)node->data;
printtabs(depth);
printf("Program(\n");
for (int i = 0; i < prog->externs->total; i++)
{
parser_node *node = (parser_node *)get_vec(prog->externs, i);
node->debug(depth + 1, node);
}
for (int i = 0; i < prog->num_functions; i++)
{
parser_node *node = prog->functions[i];
Expand All @@ -35,6 +41,11 @@ void program_debug(int depth, parser_node *node)
apply_result *program_apply(parser_node *node, context *ctx)
{
node_program *prog = (node_program *)node->data;
for (int i = 0; i < prog->externs->total; i++)
{
parser_node *node = (parser_node *)get_vec(prog->externs, i);
node->apply(node, ctx);
}
for (int i = 0; i < prog->num_struct_defs; i++)
{
prog->struct_defs[i]->apply(prog->struct_defs[i], ctx);
Expand All @@ -61,7 +72,7 @@ apply_result *program_apply(parser_node *node, context *ctx)
int total = ctx->stack_size;
// 16 byte stack alignment
total = total + (16 - total % 16);
if(nfd->statements)
if (nfd->statements)
add_data(ctx, "__%s_size: equ %u", ((node_func_def *)node->data)->identity, total);
}
add_text(ctx, "extern exit");
Expand All @@ -86,7 +97,8 @@ parser_node *parse_program(typed_token **tkn_ptr)
int var_decl_count = 0;
parser_node **funcs = (parser_node **)malloc(sizeof(parser_node *) * 128);
parser_node **struct_defs = (parser_node **)malloc(sizeof(parser_node *) * 128);
vector* var_decls = initialize_vec(sizeof(parser_node*));
vector *externs = initialize_vec(sizeof(parser_node *));
vector *var_decls = initialize_vec(sizeof(parser_node *));
typed_token *tkn = *tkn_ptr;
while (tkn)
{
Expand All @@ -97,7 +109,7 @@ parser_node *parse_program(typed_token **tkn_ptr)
node->debug = program_debug;
node->apply = program_apply;
node_program *prog = (node_program *)node->data;

prog->externs = externs;
prog->num_functions = func_count;
prog->functions = funcs;
prog->num_struct_defs = struct_def_count;
Expand All @@ -118,6 +130,10 @@ parser_node *parse_program(typed_token **tkn_ptr)
{
push_vec(var_decls, f);
}
else if ((f = parse_extern(&tkn)))
{
push_vec(externs, f);
}
else
{
return NULL;
Expand Down
2 changes: 2 additions & 0 deletions parser/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "../lexer.h"
#include "parser.h"
#include "../vec.h"

parser_node *parse_program(typed_token **tkns_ptr);

Expand All @@ -12,6 +13,7 @@ typedef struct
parser_node **functions;
int num_struct_defs;
parser_node **struct_defs;
vector *externs;
} node_program;

#endif
1 change: 1 addition & 0 deletions scripts/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"./examples/inp_loop.c": [],
"./examples/lots_of_variables.c": [],
"./examples/inp_arg_macro.c": [],
"./examples/inp_extern.c": [],
}
C_PROGRAM_NAME = "./a.out"
OUTPUT_FOLDER = "tests/output"
Expand Down
56 changes: 56 additions & 0 deletions tests/output/inp_extern.c_asm_output.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
section .data
__temp_str_0 db `This is stdout!\n`, 0
__temp_str_1 db `This is stderr!\n`, 0
__main_size: equ 80
section .text
extern stderr
extern stdout
extern fprintf
global main
main:
push rbp
mov rbp, rsp
sub rsp, __main_size
mov rax, rsp
add rax, 0
mov [rsp+0], rax
mov rax, [stdout]
mov [rsp+8], rax
mov rax, __temp_str_0
mov [rsp+16], rax
mov rdi, [rsp+8]
mov rsi, [rsp+16]
mov rax, rsp
add rax, 0
mov [rsp+24], rax
call fprintf
mov rax, rsp
add rax, 0
mov [rsp+32], rax
mov rax, [stderr]
mov [rsp+40], rax
mov rax, __temp_str_1
mov [rsp+48], rax
mov rdi, [rsp+40]
mov rsi, [rsp+48]
mov rax, rsp
add rax, 0
mov [rsp+56], rax
call fprintf
mov rax, 0
mov rsp, rbp
pop rbp
ret
mov rsp, rbp
pop rbp
ret
extern exit
global _start
_start:
; Pass argc and argv
mov rdi, [rsp]
mov rsi, rsp
add rsi, 8
call main
mov rdi, rax
call exit
48 changes: 48 additions & 0 deletions tests/output/inp_extern.c_lex_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
TKN_VOID
TKN_ID(fprintf)
TKN_L_PAREN
TKN_VOID
TKN_STAR
TKN_COMMA
TKN_CHAR
TKN_STAR
TKN_COMMA
TKN_DOTS
TKN_R_PAREN
TKN_SEMICOLON
TKN_EXTERN
TKN_VOID
TKN_STAR
TKN_ID(stderr)
TKN_SEMICOLON
TKN_EXTERN
TKN_VOID
TKN_STAR
TKN_ID(stdout)
TKN_SEMICOLON
TKN_INT
TKN_ID(main)
TKN_L_PAREN
TKN_R_PAREN
TKN_L_BRACE
TKN_ID(fprintf)
TKN_L_PAREN
TKN_ID(stdout)
TKN_COMMA
TKN_LIT_STR(This is stdout!
)
TKN_R_PAREN
TKN_SEMICOLON
TKN_ID(fprintf)
TKN_L_PAREN
TKN_ID(stderr)
TKN_COMMA
TKN_LIT_STR(This is stderr!
)
TKN_R_PAREN
TKN_SEMICOLON
TKN_RETURN
TKN_LIT_INT(0)
TKN_SEMICOLON
TKN_R_BRACE
TKN_EOF
48 changes: 48 additions & 0 deletions tests/output/inp_extern.c_prep_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
TKN_VOID
TKN_ID(fprintf)
TKN_L_PAREN
TKN_VOID
TKN_STAR
TKN_COMMA
TKN_CHAR
TKN_STAR
TKN_COMMA
TKN_DOTS
TKN_R_PAREN
TKN_SEMICOLON
TKN_EXTERN
TKN_VOID
TKN_STAR
TKN_ID(stderr)
TKN_SEMICOLON
TKN_EXTERN
TKN_VOID
TKN_STAR
TKN_ID(stdout)
TKN_SEMICOLON
TKN_INT
TKN_ID(main)
TKN_L_PAREN
TKN_R_PAREN
TKN_L_BRACE
TKN_ID(fprintf)
TKN_L_PAREN
TKN_ID(stdout)
TKN_COMMA
TKN_LIT_STR(This is stdout!
)
TKN_R_PAREN
TKN_SEMICOLON
TKN_ID(fprintf)
TKN_L_PAREN
TKN_ID(stderr)
TKN_COMMA
TKN_LIT_STR(This is stderr!
)
TKN_R_PAREN
TKN_SEMICOLON
TKN_RETURN
TKN_LIT_INT(0)
TKN_SEMICOLON
TKN_R_BRACE
TKN_EOF
Loading

0 comments on commit 39506f4

Please sign in to comment.