Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-03 10:41:35 |
Commit | cc58a1d3fcd21571a5d231359a3acbbe5564d97d |
Parent | 3f9a543df8693f7ebeb7492e4077a716ed3cfdc0 |
Implement procedure arguments
Diffstat
M | README.md | | | 2 | +- |
M | examples/main.g | | | 10 | ++++++---- |
M | src/analyse.c | | | 8 | +++++++- |
M | src/lex.c | | | 9 | +++++---- |
M | src/lex.h | | | 2 | +- |
M | src/llvm.c | | | 42 | +++++++++++++++++++++++++++--------------- |
M | src/main.c | | | 8 | -------- |
M | src/parse.c | | | 38 | +++++++++++++++++++++++++++++--------- |
M | src/parse.h | | | 2 | +- |
M | src/symbol.c | | | 9 | +++++++++ |
10 files changed, 86 insertions, 44 deletions
diff --git a/README.md b/README.md index 03b583b..831a715 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ command. The second command will output an executable file, *a.out* by default. - [x] Implement procedure declarations - [x] Implement procedure calls -- [ ] Implement procedure arguments +- [x] Implement procedure arguments - [x] Implement variables - [x] Implement booleans - [x] Implement integers diff --git a/examples/main.g b/examples/main.g index b4c85f3..61553d8 100644 --- a/examples/main.g +++ b/examples/main.g @@ -1,5 +1,7 @@ +add3 :: proc(x: u8, y: u8, z: u8) -> u8 { + return x + y + z; +} + main :: proc() -> u8 { - var : [1]u8; - var[0] = 1; - return var[0]; + return add3(1, 2, 3); } diff --git a/src/analyse.c b/src/analyse.c index 4f2a4a9..ed071f4 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -173,6 +173,11 @@ static void analyse_expr(ast *a, syt *st) { static void analyse_expr_proc(ast *a, syt *st) { assert(A.k == AK_PROC); + /* Analyse the procedure arguments */ + for (UINT i = 0; i < CL - 1; i += 1) { + /* TODO */ + } + /* Analyse the procedure body */ - analyse_stmt_comp(C[0], st); + analyse_stmt_comp(C[CL - 1], st); } diff --git a/src/lex.c b/src/lex.c index 00352bc..2180e47 100644 --- a/src/lex.c +++ b/src/lex.c @@ -40,7 +40,7 @@ char *tok_ks[] = { #define is_digit_doz(c) ((c >= '0' && c <= '9') || (c == 'A' || c == 'B')) #define is_digit_hex(c) ((c >= '0' && c <= '9') || (c >= 'A' || c == 'F')) -static inline u128 parse_int(char *s); +static inline u64 parse_int(char *s); static inline f128 parse_flt(char *s); /* Push a token to a token array. */ @@ -138,6 +138,7 @@ tok lex_next(lex *l) { switch (T.k) { case TK_INT: { T.v_int = parse_int(T.s); } break; case TK_FLT: { T.v_flt = parse_flt(T.s); } break; + default: { /* Unreachable */ } break; } } @@ -307,8 +308,8 @@ void lex_debug(lex *l) { } /* Parse an integer string into a value. */ -static inline u128 parse_int(char *s) { - register u128 v = 0, c; register UINT b = 10; +static inline u64 parse_int(char *s) { + register u64 v = 0; u64 c; register UINT b = 10; if (s[0] == '0') switch (s[1]) { case 'b': { s += 2; b = 2; } break; case 'o': { s += 2; b = 8; } break; @@ -322,7 +323,7 @@ static inline u128 parse_int(char *s) { /* TODO better error handling */ if (c >= b) { errno = EDOM; return 0; } - if (v > (U128_MAX - c) / b) { errno = ERANGE; return 0; } + if (v > (U64_MAX - c) / b) { errno = ERANGE; return 0; } v = v * b + c; } diff --git a/src/lex.h b/src/lex.h index 770d35a..6592620 100644 --- a/src/lex.h +++ b/src/lex.h @@ -30,7 +30,7 @@ typedef enum { k : Kind, ln : Line, cl : Column, h : Hash, s : String, v_int : Int Value, v_flt : Flt Value */ -typedef struct { tok_k k; UINT ln, cl; u64 h; char *s; union { u128 v_int; f128 v_flt; }; } tok; +typedef struct { tok_k k; UINT ln, cl; u64 h; char *s; union { u64 v_int; f128 v_flt; }; } tok; typedef struct { tok *a; UINT al; } tok_a; /* diff --git a/src/llvm.c b/src/llvm.c index 77096a3..3be9794 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -30,7 +30,6 @@ static LLVMBuilderRef llvm_builder = NULL; static LLVMValueRef llvm_stmt(ast *a, syt *st); static LLVMValueRef llvm_stmt_compound(ast *a, syt *st); static LLVMValueRef llvm_stmt_decl(ast *a, syt *st); -static LLVMValueRef llvm_stmt_expr(ast *a, syt *st); static LLVMValueRef llvm_stmt_return(ast *a, syt *st); static LLVMValueRef llvm_stmt_if(ast *a, syt *st); static LLVMValueRef llvm_stmt_for(ast *a, syt *st); @@ -138,14 +137,23 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { assert(a->k == AK_DECL); if (CL && C[0]->k == AK_PROC) { - /* TODO handle procedure arguments if present */ - LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), NULL, 0, 0); + LLVMTypeRef art[C[0]->c.al - 1]; + for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { + art[i] = llvm_type(ast_type(C[0]->c.a[i], st)); + } + + LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), art, C[0]->c.al - 1, 0); LLVMValueRef f = LLVMAddFunction(llvm_module, A.s, ft); LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, "entry"); LLVMPositionBuilderAtEnd(llvm_builder, bb); - llvm_expr_proc(C[0], st); A.llvm_t = ft; A.llvm_v = f; + for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { + C[0]->c.a[i]->llvm_v = LLVMGetParam(f, i); + } + + A.llvm_t = ft; A.llvm_v = f; + llvm_expr_proc(C[0], st); } else { if (A.p->k == AK_PROG) { /* Global */ @@ -163,11 +171,6 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { return NULL; } -/* Generate IR for an expression statement. */ -static LLVMValueRef llvm_stmt_expr(ast *a, syt *st) { - -} - /* Generate IR for a return statement. */ static LLVMValueRef llvm_stmt_return(ast *a, syt *st) { return LLVMBuildRet(llvm_builder, a->c.al > 0 ? llvm_expr(C[0], st, true) : NULL); @@ -175,12 +178,12 @@ static LLVMValueRef llvm_stmt_return(ast *a, syt *st) { /* Generate IR for an if statement. */ static LLVMValueRef llvm_stmt_if(ast *a, syt *st) { - + return NULL; /* TODO */ } /* Generate IR for a for statement. */ static LLVMValueRef llvm_stmt_for(ast *a, syt *st) { - + return NULL; /* TODO */ } /* Generate IR for an expression. */ @@ -197,7 +200,9 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable \"%s\"", A.s); } if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); } - if (!load || sym->t->k == TY_ARR) { return sym->llvm_v; } + /* TODO fix procedure argument handling, should be assignable */ + /* TODO fix array variable handling */ + if (!load || sym->k == AK_ID || sym->t->k == TY_ARR) { return sym->llvm_v; } else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); } } break; case AK_CALL: { @@ -205,9 +210,12 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined procedure \"%s\" (llvm:llvm_expr)", C[0]->s); } if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Procedure \"%s\" follows (llvm:llvm_expr)", C[0]->s); } - /* TODO procedure call arguments */ + LLVMValueRef args[CL - 1]; + for (UINT i = 1; i < CL; i += 1) { + args[i - 1] = llvm_expr(C[i], st, true); + } - return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, NULL, 0, ""); + return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, args, CL - 1, ""); } break; case AK_SUBS: { ast *sym = syt_search_h(st, C[0]->h, C[0]->s); @@ -298,11 +306,13 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { } break; default: { note(file_name, A.ln, A.cl, -1, "Unhandled AST kind %s (llvm:llvm_expr)", ast_ks[a->k]); } break; } + + return NULL; } /* Generate IR for a procedure. */ static LLVMValueRef llvm_expr_proc(ast *a, syt *st) { - return llvm_stmt_compound(C[0], st); + return llvm_stmt_compound(C[CL - 1], st); } /* Generate IR for a type cast. */ @@ -356,6 +366,8 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { } note(file_name, A.ln, A.cl, -1, "Unhandled cast \"%s\" -> \"%s\" (llvm:llvm_expr_cast)", expr_type->s, A.t->s); + + return NULL; } /* Generate IR for an array. */ diff --git a/src/main.c b/src/main.c index 4aa5271..bfba797 100644 --- a/src/main.c +++ b/src/main.c @@ -23,10 +23,6 @@ static struct lop lops[] = { { NULL, 0, 0 } }; -static char *aw[] = { - "g", "/home/deus/Workspace/G/examples/main.g", NULL -}; - static bool bflag = false, Bflag = false, cflag = false; static bool Eflag = false, pflag = false, Pflag = false; static bool qflag = false; @@ -42,9 +38,6 @@ static void hlp(void); static void ver(void); int main(int ac, char *av[]) { A0 = av[0]; - /* DEBUG */ - if (ac == 1) { ac = (sizeof (aw) / sizeof (*aw)) - 1; av = aw; } - struct opt opt = OPTGET_INIT; opt.str = "bBcEf:O:pPqW:"; opt.lops = lops; for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { case 'b': { bflag = true; } break; /* Output LLVM IR files */ diff --git a/src/parse.c b/src/parse.c index 923ac7c..bf81581 100644 --- a/src/parse.c +++ b/src/parse.c @@ -96,10 +96,10 @@ void ast_displace(ast *a, ast *c) { type *ast_type(ast *a, syt *st) { /* Search the symbol table for a type first */ if (a->s) { - ast *v = syt_search(st, a->s); - if (v != NULL) { - if (v->c.al != 0 && v->c.a[0]->k == AK_PROC) { return v->c.a[0]->t; } - else { return v->t; } + ast *sym = syt_search(st, a->s); + if (sym != NULL) { + if (sym->c.al != 0 && sym->c.a[0]->k == AK_PROC) { return sym->c.a[0]->t; } + else { return sym->t; } } } @@ -315,6 +315,7 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { case TK_OP_DIV: { a = ast_init(AK_OP_DIV, T.ln, T.cl); } goto infix; case TK_OP_MOD: { a = ast_init(AK_OP_MOD, T.ln, T.cl); } goto infix; infix: { lex_next(l); ast_push(a, left); ast_push(a, parse_expr(l, st, ast_precedence(a->k))); } break; + default: { /* Ignored */ } break; } return left; @@ -339,10 +340,23 @@ static ast *parse_expr_proc(lex *l, syt *st) { assert(T.k == TK_PROC); ast *a = ast_init(AK_PROC, T.ln, T.cl); - lex_next(l); lex_kind(l, TK_LPAREN); + lex_next(l); lex_kind(l, TK_LPAREN); a->st.pt = st; /* Parse optional procedure parameter(s) */ - /* TODO */ lex_kind(l, TK_RPAREN); + if (T.k != TK_RPAREN) for (;;) { + ast *arg = ast_init(AK_ID, T.ln, T.cl); + arg->h = T.h; arg->s = strdup_or_fail(T.s); + + lex_kind(l, TK_ID); lex_kind(l, TK_COLON); + + ta_pair ta = parse_type(l, st); + arg->t = ta.t; /* TODO handle AST component */ + + ast_push(a, arg); syt_insert_h(&a->st, arg->h, arg->s, arg); + if (T.k == TK_COMMA) { lex_next(l); } else { break; } + } + + lex_kind(l, TK_RPAREN); /* Parse optional procedure return type */ if (T.k == TK_RARROW) { @@ -353,7 +367,7 @@ static ast *parse_expr_proc(lex *l, syt *st) { } else { a->t = &TYPE(TY_VOID); } - ast_push(a, parse_stmt_compound(l, st)); return a; + ast_push(a, parse_stmt_compound(l, &a->st)); return a; } /* Parse a type identifier. */ @@ -386,7 +400,7 @@ static inline ta_pair parse_type(lex *l, syt *st) { if (s == NULL) { note(l->n, t.ln, t.cl, 0, "Use of undeclared identifier \"%s\"", t.s); } else if (s->k != AK_TYPE) { note(l->n, t.ln, t.cl, 0, "Expected type identifier"); } - if (r == NULL) { (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; } + if (r == NULL) { return (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; } } /* Parse an integer. */ @@ -404,7 +418,7 @@ static ast *parse_int(lex *l, syt *st) { else if (a->v_int <= U16_MAX) { a->t = &TYPE(TY_U16); } else if (a->v_int <= U32_MAX) { a->t = &TYPE(TY_U32); } else if (a->v_int <= U64_MAX) { a->t = &TYPE(TY_U64); } - else if (a->v_int <= U128_MAX) { a->t = &TYPE(TY_U128); } + // else if (a->v_int <= U128_MAX) { a->t = &TYPE(TY_U128); } return a; } @@ -495,7 +509,8 @@ void ast_print(ast *a, UINT indent) { switch (a->k) { case AK_BOOL: { printf(a->v_bool ? " = true" : " = false"); } break; case AK_INT: { printf(" = %lu", a->v_int); } break; - case AK_FLT: { printf(" = %lf", a->v_flt); } break; + case AK_FLT: { printf(" = %Lf", a->v_flt); } break; + default: { /* Ignored */ } break; } /* Indicate if the AST node has no parent */ diff --git a/src/parse.h b/src/parse.h index d0f7da0..5b489f5 100644 --- a/src/parse.h +++ b/src/parse.h @@ -37,7 +37,7 @@ typedef enum { typedef struct ast_s { ast_k k; UINT ln, cl; u64 h; char *s; type *t; syt st; struct ast_s *p; struct { struct ast_s **a; UINT al; } c; - union { bool v_bool; u128 v_int; f128 v_flt; }; + union { bool v_bool; u64 v_int; f128 v_flt; }; LLVMTypeRef llvm_t; LLVMValueRef llvm_v; } ast; diff --git a/src/symbol.c b/src/symbol.c index 43838b7..8ef3b2d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -160,7 +160,15 @@ ast *syt_search_h(syt *st, u64 h, char *k) { /* Print a basic representation of a map to stdout. */ void syt_print(syt *st) { for (UINT i = 0; i < st->ac; i += 1) if (st->a[i].h != 0) { - fputs(st->a[i].k, stdout); + printf("%s %s", ast_ks[st->a[i].v->k], st->a[i].k); + + if (st->a[i].v->k == AK_DECL && st->a[i].v->c.al > 0 && st->a[i].v->c.a[0]->k == AK_PROC) { + fputc('(', stdout); + for (UINT j = 0; j < st->a[i].v->c.al - 1; j += 1) { + /* TODO */ + } + fputc(')', stdout); + } if (st->a[i].v->t != NULL) { fputs(" -> ", stdout); } for (type *t = st->a[i].v->t; t != NULL; t = t->base) switch (t->k) {