diff --git a/examples/inp_extern.c b/examples/inp_extern.c new file mode 100644 index 0000000..f204694 --- /dev/null +++ b/examples/inp_extern.c @@ -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; +} \ No newline at end of file diff --git a/lexer.c b/lexer.c index e3074f0..676a7d9 100644 --- a/lexer.c +++ b/lexer.c @@ -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); } diff --git a/lexer.h b/lexer.h index 5d3013c..2c4cc4c 100644 --- a/lexer.h +++ b/lexer.h @@ -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 diff --git a/parser/extern.c b/parser/extern.c new file mode 100644 index 0000000..9f2fbf7 --- /dev/null +++ b/parser/extern.c @@ -0,0 +1,53 @@ +#include "extern.h" +#include +#include +#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; +} \ No newline at end of file diff --git a/parser/extern.h b/parser/extern.h new file mode 100644 index 0000000..449d097 --- /dev/null +++ b/parser/extern.h @@ -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 diff --git a/parser/program.c b/parser/program.c index 72dd328..e7bb94d 100644 --- a/parser/program.c +++ b/parser/program.c @@ -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]; @@ -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); @@ -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"); @@ -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) { @@ -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; @@ -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; diff --git a/parser/program.h b/parser/program.h index cf26835..7870509 100644 --- a/parser/program.h +++ b/parser/program.h @@ -3,6 +3,7 @@ #include "../lexer.h" #include "parser.h" +#include "../vec.h" parser_node *parse_program(typed_token **tkns_ptr); @@ -12,6 +13,7 @@ typedef struct parser_node **functions; int num_struct_defs; parser_node **struct_defs; + vector *externs; } node_program; #endif diff --git a/scripts/test.py b/scripts/test.py index 38e57d3..63c25ad 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -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" diff --git a/tests/output/inp_extern.c_asm_output.asm b/tests/output/inp_extern.c_asm_output.asm new file mode 100644 index 0000000..d38d4da --- /dev/null +++ b/tests/output/inp_extern.c_asm_output.asm @@ -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 diff --git a/tests/output/inp_extern.c_lex_output.txt b/tests/output/inp_extern.c_lex_output.txt new file mode 100644 index 0000000..01ce4d4 --- /dev/null +++ b/tests/output/inp_extern.c_lex_output.txt @@ -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 diff --git a/tests/output/inp_extern.c_prep_output.txt b/tests/output/inp_extern.c_prep_output.txt new file mode 100644 index 0000000..01ce4d4 --- /dev/null +++ b/tests/output/inp_extern.c_prep_output.txt @@ -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 diff --git a/tests/output/inp_extern.c_tree_output.txt b/tests/output/inp_extern.c_tree_output.txt new file mode 100644 index 0000000..6e62b1a --- /dev/null +++ b/tests/output/inp_extern.c_tree_output.txt @@ -0,0 +1,51 @@ +Program( + Extern: + VarDecl(stderr): + Type(Name: stderr): + Pointer of: + TKN_VOID + Extern: + VarDecl(stdout): + Type(Name: stdout): + Pointer of: + TKN_VOID + FunctionDecl( + Name: + fprintf + Returns: + Type(Name: (null)): + TKN_VOID + Params: + Type(Name: (null)): + Pointer of: + TKN_VOID + Type(Name: (null)): + Pointer of: + TKN_CHAR + ) + Function( + Name: + main + Returns: + Type(Name: (null)): + TKN_INT + Params: + Statements: + FunctionCall: + Function: + Variable(fprintf) + Args: + Variable(stdout) + Literal(Type: 33, Value: This is stdout! +) + FunctionCall: + Function: + Variable(fprintf) + Args: + Variable(stderr) + Literal(Type: 33, Value: This is stderr! +) + Return: + Literal(Type: 34, Value: 0) + ) +)