Author | Jakob Wakeling <[email protected]> |
Date | 2023-06-29 05:38:34 |
Commit | 6a79f8726e30559134fbd692dff366db7dd748d1 |
Parent | f718ad0837fb154deaacf843c679f8b6975d3e50 |
Implement arrays, integrate values into AST nodes
Diffstat
M | README.md | | | 6 | ++++-- |
M | examples/hello.g | | | 16 | +--------------- |
M | src/init.c | | | 2 | ++ |
M | src/lex.c | | | 19 | ++++++++++++++----- |
M | src/lex.h | | | 4 | ++-- |
M | src/llvm.c | | | 90 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | src/parse.c | | | 130 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
M | src/parse.h | | | 9 | +++++---- |
M | src/symbol.c | | | 11 | ++++++++++- |
M | src/symbol.h | | | 1 | - |
M | src/type.c | | | 12 | ++++++++---- |
M | src/type.h | | | 7 | ++----- |
D | src/value.c | | | 50 | -------------------------------------------------- |
D | src/value.h | | | 23 | ----------------------- |
14 files changed, 187 insertions, 193 deletions
diff --git a/README.md b/README.md index ca35bcf..164afd1 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,8 @@ command. The second command will output an executable file, *a.out* by default. ## Todo -> Not all todo items will necesarilly be implemented +> Not all todo items will necesarilly be implemented and sometimes I am pretty +> liberal with what justifies crossing something off - [x] Implement procedure declarations - [x] Implement procedure calls @@ -65,7 +66,8 @@ command. The second command will output an executable file, *a.out* by default. - [x] Implement integers - [x] Implement reals - [x] Implement pointers -- [ ] Implement arrays +- [x] Implement arrays +- [ ] Implement variable length arrays - [x] Implement expressions - [x] Implement type casting - [ ] Implement type casting to pointers and arrays diff --git a/examples/hello.g b/examples/hello.g index 70b57ac..3525d82 100644 --- a/examples/hello.g +++ b/examples/hello.g @@ -1,20 +1,5 @@ main :: proc() -> u64 { - c : u8; - - c = u8('H'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('e'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('l'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('l'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('o'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8(','); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8(' '); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('W'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('o'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('r'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('l'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('d'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('!'); #syscall(u64(1), u64(1), &c, u64(1)); - c = u8('\n'); #syscall(u64(1), u64(1), &c, u64(1)); - + hello : [14]u8 = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\n' }; + #syscall(u64(1), u64(1), hello, u64(14)); return u64(0); } diff --git a/src/init.c b/src/init.c index c9587b5..1b82d1d 100644 --- a/src/init.c +++ b/src/init.c @@ -11,6 +11,8 @@ #include <string.h> static ast kwds[] = { + { AK_TYPE, 0, 0, 0, "ptr", &TYPE(TY_PTR), { 0 }, NULL }, + /* Boolean Types */ { AK_TYPE, 0, 0, 0, "b8", &TYPE(TY_B8), { 0 }, NULL }, { AK_TYPE, 0, 0, 0, "b16", &TYPE(TY_B16), { 0 }, NULL }, diff --git a/src/lex.c b/src/lex.c index c27fc8c..00352bc 100644 --- a/src/lex.c +++ b/src/lex.c @@ -16,7 +16,7 @@ #include <stdio.h> char *tok_ks[] = { - "TK_VOID", "TK_EOF", "TK_ID", "TK_INT", "TK_NUM", "TK_STR", "TK_HASH", + "TK_VOID", "TK_EOF", "TK_ID", "TK_INT", "TK_FLT", "TK_STR", "TK_HASH", "TK_NULL", "TK_TRUE", "TK_FALSE", "TK_RETURN", "TK_IF", "TK_ELSE", "TK_FOR", "TK_PROC", @@ -128,13 +128,17 @@ tok lex_next(lex *l) { T.k = TK_INT; char *s = P; for (P += 1; is_alpha(C) || is_digit_dec(C); P += 1); - if (C == '.') { T.k = TK_NUM; P += 1; for (P += 1; is_digit_dec(C); P += 1); } + if (C == '.') { T.k = TK_FLT; P += 1; for (P += 1; is_digit_dec(C); P += 1); } /* TODO lex exponent part of real numbers */ UINT sl = P - s; CL += sl; if (!(T.s = strndup(s, sl))) { error(1, SERR); } - if (T.k == TK_INT) { T.v_int = parse_int(T.s); } + + 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; + } } /* Handle hash procedures */ @@ -327,5 +331,11 @@ static inline u128 parse_int(char *s) { } static inline f128 parse_flt(char *s) { - return 0.0; + register f128 v = 0; u64 c; char *endptr; + + v = strtold(s, &endptr); + /* TODO better error handling */ + if (*endptr != '\0') { return 0; } + + return v; } diff --git a/src/lex.h b/src/lex.h index 0f22a2e..770d35a 100644 --- a/src/lex.h +++ b/src/lex.h @@ -10,7 +10,7 @@ /* Remember to update tok_ks in lex.c */ typedef enum { - TK_VOID, TK_EOF, TK_ID, TK_INT, TK_NUM, TK_STR, TK_HASH, + TK_VOID, TK_EOF, TK_ID, TK_INT, TK_FLT, TK_STR, TK_HASH, TK_NULL, TK_TRUE, TK_FALSE, TK_RETURN, TK_IF, TK_ELSE, TK_FOR, TK_PROC, @@ -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 { u64 v_int; f128 v_flt; }; } tok; +typedef struct { tok_k k; UINT ln, cl; u64 h; char *s; union { u128 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 b3e5e02..852823b 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -40,9 +40,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st); static LLVMValueRef llvm_expr_proc(ast *a, syt *st); static LLVMValueRef llvm_expr_cast(ast *a, syt *st); -static LLVMValueRef llvm_bool(ast *a); -static LLVMValueRef llvm_int(ast *a); -static LLVMValueRef llvm_flt(ast *a); +static LLVMValueRef llvm_arr(ast *a, syt *st); static LLVMValueRef llvm_hash(ast *a, syt *st); @@ -143,26 +141,26 @@ static LLVMValueRef llvm_stmt_compound(ast *a, syt *st) { static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { assert(a->k == AK_DECL); - if (a->c.al && C[0]->k == AK_PROC) { + if (CL && C[0]->k == AK_PROC) { /* TODO handle procedure arguments if present */ LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), NULL, 0, 0); - LLVMValueRef f = LLVMAddFunction(llvm_module, a->s, ft); + 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; + llvm_expr_proc(C[0], st); A.llvm_t = ft; A.llvm_v = f; } else { - if (a->p->k == AK_PROG) { /* Global */ + if (A.p->k == AK_PROG) { /* Global */ LLVMValueRef v = LLVMAddGlobal(llvm_module, llvm_type(A.t), ""); - LLVMSetInitializer(v, a->c.al ? llvm_expr(C[0], st) : llvm_ival(a->t)); - a->llvm_v = v; + LLVMSetInitializer(v, CL ? llvm_expr(C[0], st) : llvm_ival(A.t)); + A.llvm_v = v; } else { /* Local */ LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), ""); - LLVMBuildStore(llvm_builder, a->c.al ? llvm_expr(C[0], st) : llvm_ival(a->t), v); - a->llvm_v = v; + LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st) : llvm_ival(A.t), v); + A.llvm_v = v; } } @@ -238,16 +236,19 @@ static LLVMValueRef llvm_stmt_for(ast *a, syt *st) { /* Generate IR for an expression. */ static LLVMValueRef llvm_expr(ast *a, syt *st) { reset:; switch (A.k) { + case AK_BOOL: { return LLVMConstInt(llvm_type(a->t), a->v_bool, false); } break; + case AK_INT: { return LLVMConstInt(llvm_type(a->t), a->v_int, false); } break; + case AK_FLT: { return LLVMConstReal(llvm_type(a->t), a->v_flt); } break; + case AK_ARR: { return llvm_arr(a, st); } break; case AK_PROC: { return llvm_expr_proc(a, st); } break; case AK_CAST: { return llvm_expr_cast(a, st); } break; - case AK_BOOL: { return llvm_bool(a); } break; - case AK_INT: { return llvm_int(a); } break; - case AK_FLT: { return llvm_flt(a); } break; case AK_ID_VAR: { - ast *v = syt_search(st, a->s); - if (v == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable %s", A.s); } + ast *sym = syt_search(st, a->s); + if (sym == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable %s", A.s); } + + if (sym->t->k == TY_ARR) { return sym->llvm_v; } - return LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, ""); + return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); } break; case AK_CALL: { ast *v = syt_search(st, a->s); @@ -360,23 +361,25 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { } } } + else if (expr_type->k == TY_ARR) { + if (is_ptr(a->t)) { + a->t->base = expr_type->base; + return LLVMBuildBitCast(llvm_builder, llvm_expr(C[0], st), llvm_type(a->t), ""); + } + } note(file_name, A.ln, A.cl, -1, "unhandled type %s or %s (llvm:llvm_expr_cast)", expr_type->s, a->t->s); } -/* Generate IR for a boolean. */ -static LLVMValueRef llvm_bool(ast *a) { - return LLVMConstInt(llvm_type(a->t), a->v.v_bool, false); -} - -/* Generate IR for an integer. */ -static LLVMValueRef llvm_int(ast *a) { - return LLVMConstInt(llvm_type(a->t), a->v.v_int, false); -} - -/* Generate IR for a real. */ -static LLVMValueRef llvm_flt(ast *a) { - return LLVMConstReal(llvm_type(a->t), a->v.v_flt); +/* Generate IR for an array. */ +static LLVMValueRef llvm_arr(ast *a, syt *st) { + assert(A.k == AK_ARR); + + LLVMValueRef *va = calloc(CL, sizeof (LLVMValueRef)); + + for (UINT i = 0; i < CL; i += 1) { va[i] = llvm_expr(C[i], st); } + + return LLVMConstArray(llvm_type(C[0]->t), va, CL); } /* Generate IR for a hash procedure. */ @@ -442,7 +445,8 @@ static inline void llvm_free(void) { static LLVMTypeRef llvm_type(type *t) { switch (t->k) { case TY_VOID: { return LLVMVoidType(); } break; - case TY_PTR: { return LLVMPointerType(llvm_type(t->base), 0); } break; + case TY_PTR: { return LLVMPointerType(llvm_type(t->base), 0); } break; + case TY_ARR: { return LLVMArrayType(llvm_type(t->base), t->l); } break; case TY_BOOL: { return LLVMIntType(8); } break; case TY_B8: { return LLVMIntType(8); } break; case TY_B16: { return LLVMIntType(16); } break; @@ -468,6 +472,14 @@ static LLVMTypeRef llvm_type(type *t) { static LLVMValueRef llvm_ival(type *t) { switch (t->k) { case TY_PTR: { return LLVMConstNull(llvm_type(t->base)); } break; + case TY_ARR: { + LLVMValueRef *va = calloc(t->l, sizeof (LLVMValueRef)); + LLVMValueRef bv = llvm_ival(t->base); + + for (UINT i = 0; i < t->l; i += 1) { va[i] = bv; } + + return LLVMConstArray(llvm_type(t->base), va, t->l); + } break; case TY_BOOL: { return LLVMConstInt(LLVMIntType(8), 0, false); } break; case TY_B8: { return LLVMConstInt(LLVMIntType(8), 0, false); } break; case TY_B16: { return LLVMConstInt(LLVMIntType(16), 0, false); } break; diff --git a/src/parse.c b/src/parse.c index 433a092..5d80fe5 100644 --- a/src/parse.c +++ b/src/parse.c @@ -10,12 +10,13 @@ #include "type.h" #include "util/error.h" #include "util/util.h" -#include "value.h" #include <stdio.h> #include <stdlib.h> #include <string.h> +typedef struct { type *t; ast *a; } ta_pair; + char *ast_ks[] = { "AK_VOID", "AK_PROG", "AK_PROC", "AK_TYPE", "AK_CAST", @@ -26,7 +27,7 @@ char *ast_ks[] = { "AK_ASSIGN", "AK_AS_ADD", "AK_AS_SUB", "AK_AS_MUL", "AK_AS_DIV", "AK_AS_MOD", - "AK_ID_VAR", "AK_CALL", "AK_INT", "AK_FLT", "AK_BOOL", + "AK_ID_VAR", "AK_CALL", "AK_BOOL", "AK_INT", "AK_FLT", "AK_ARR", "AK_HASH_SYSCALL" }; @@ -40,9 +41,10 @@ static ast *parse_stmt_if(lex *l, syt *st); static ast *parse_stmt_for(lex *l, syt *st); static ast *parse_expr(lex *l, syt *st, s32 o); +static ast *parse_expr_compound(lex *l, syt *st); static ast *parse_expr_proc(lex *l, syt *st); -static inline type *parse_type(lex *l, syt *st); +static inline ta_pair parse_type(lex *l, syt *st); static ast *parse_int(lex *l, syt *st); static ast *parse_flt(lex *l, syt *st); @@ -57,7 +59,9 @@ inline ast *ast_init(ast_k kind, UINT ln, UINT cl) { } inline void ast_free(ast **a) { - fprintf(stderr, "ast_free() NOT IMPLEMENTED\n"); /* TODO */ + if ((*a)->s != NULL) { free((*a)->s); } + if ((*a)->c.a != NULL) { free((*a)->c.a); } + free(*a); a = NULL; /* TODO free LLVM pointers? */ } /* Push a child AST node to an AST node. */ @@ -66,6 +70,7 @@ void ast_push(ast *a, ast *c) { if (!ca) { error(1, SERR); } else { a->c.a = ca; ca = NULL; } /* Store pointer from parent to child and vice versa */ + assert(c->p == NULL); c->p = a; a->c.a[a->c.al - 1] = c; } @@ -83,7 +88,7 @@ void ast_displace(ast *a, ast *c) { if (oa[i] == c) { continue; } a->c.a[j] = oa[i]; j += 1; } - free(oa); + c->p = NULL; free(oa); } type *ast_type(ast *a, syt *st) { @@ -165,7 +170,10 @@ static ast *parse_stmt_decl(lex *l, syt *st) { assert(T.k == TK_ID); lex_next(l); assert(T.k == TK_COLON); lex_next(l); /* Store the declaration's type if one is specified */ - if (T.k == TK_ID || T.k == TK_OP_MUL || T.k == TK_LBRACK) { a->t = parse_type(l, st); } + if (T.k == TK_ID || T.k == TK_OP_MUL || T.k == TK_LBRACK) { + ta_pair ta = parse_type(l, st); + a->t = ta.t; /* TODO keep the AST component */ + } /* Assign a constant or variable value if one is specified */ if (T.k == TK_COLON || T.k == TK_ASSIGN) { lex_next(l); ast_push(a, parse_expr(l, st, 0)); } @@ -253,12 +261,13 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { if (!(left->s = strdup(t.s))) { error(1, "%s", SERR); } } break; - case TK_TRUE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v = val_bool(true); } goto boolean; - case TK_FALSE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v = val_bool(false); } goto boolean; + case TK_TRUE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v_bool = true; } goto boolean; + case TK_FALSE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v_bool = false; } goto boolean; boolean: { left->t = &TYPE(TY_BOOL); lex_next(l); } break; - case TK_INT: { left = parse_int(l, st); } break; - case TK_NUM: { left = parse_flt(l, st); } break; - case TK_PROC: { return parse_expr_proc(l, st); } break; + case TK_INT: { left = parse_int(l, st); } break; + case TK_FLT: { left = parse_flt(l, st); } break; + case TK_LBRACE: { return parse_expr_compound(l, st); } break; + case TK_PROC: { return parse_expr_proc(l, st); } break; case TK_HASH: { tok t = lex_next(l); bool needs_args = false; left = ast_init(0, t.ln, t.cl); @@ -308,6 +317,20 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { return left; } +/* Parse a compound expression (arrays, structs, etc.). */ +static ast *parse_expr_compound(lex *l, syt *st) { + assert(T.k == TK_LBRACE); + + ast *a = ast_init(AK_ARR, T.ln, T.cl); lex_next(l); + + if (T.k != TK_RBRACE) for (;;) { + ast_push(a, parse_expr(l, st, 0)); + if (T.k == TK_COMMA) { lex_next(l); } else { break; } + } + + lex_kind(l, TK_RBRACE); return a; +} + /* Parse a procedure expression. */ static ast *parse_expr_proc(lex *l, syt *st) { assert(T.k == TK_PROC); @@ -319,15 +342,21 @@ static ast *parse_expr_proc(lex *l, syt *st) { /* TODO */ lex_kind(l, TK_RPAREN); /* Parse optional procedure return type */ - if (T.k == TK_RARROW) { lex_next(l); a->t = parse_type(l, st); } + if (T.k == TK_RARROW) { + lex_next(l); + + ta_pair ta = parse_type(l, st); + a->t = ta.t; /* TODO handle AST component */ + } else { a->t = &TYPE(TY_VOID); } ast_push(a, parse_stmt_compound(l, st)); return a; } /* Parse a type identifier. */ -static inline type *parse_type(lex *l, syt *st) { - type *r = NULL, *c; /* root and deepest child */ +static inline ta_pair parse_type(lex *l, syt *st) { + /* root, deepest child, and variable length */ + type *r = NULL, *c; ast *a = NULL; /* Parse optional pointer and array specifiers */ for (register type *t = NULL;;) switch (T.k) { @@ -335,7 +364,13 @@ static inline type *parse_type(lex *l, syt *st) { case TK_LBRACK: { lex_next(l); - /* TODO parse integer expression */ + /* TODO handle variable array length */ + if (T.k != TK_RBRACK) { + assert(T.k == TK_INT); + a = parse_expr(l, st, 0); + t = type_arr(NULL, a->v_int); + } + else { t = type_arr(NULL, -1); } lex_kind(l, TK_RBRACK); } goto store; @@ -348,7 +383,7 @@ static inline type *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) { return s->t; } else { c->base = s->t; return r; } + if (r == NULL) { (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; } } /* Parse an integer. */ @@ -360,34 +395,33 @@ static ast *parse_int(lex *l, syt *st) { if (!(a->s = strdup(t.s))) { error(1, "%s", SERR); } - a->v = val_u64(t.v_int); + a->v_int = t.v_int; /* Determine the minimum integer type */ - if (a->v.v_int <= U8_MAX) { a->t = &TYPE(TY_U8); } - else if (a->v.v_int <= U16_MAX) { a->t = &TYPE(TY_U16); } - else if (a->v.v_int <= U32_MAX) { a->t = &TYPE(TY_U32); } - else if (a->v.v_int <= U64_MAX) { a->t = &TYPE(TY_U64); } - else if (a->v.v_int <= U128_MAX) { a->t = &TYPE(TY_U128); } + if (a->v_int <= U8_MAX) { a->t = &TYPE(TY_U8); } + 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); } return a; } -/* Parse a real. */ +/* Parse a floating-point number. */ static ast *parse_flt(lex *l, syt *st) { - assert(T.k == TK_NUM); + assert(T.k == TK_FLT); tok t = lex_next(l); ast *a = ast_init(AK_FLT, t.ln, t.cl); if (!(a->s = strdup(t.s))) { error(1, "%s", SERR); } - if (!(a->v = val_parse_flt(t.s)).k) { - note(l->n, t.ln, t.cl, 0, "%s: %s", t.s, SERR); - } + + a->v_flt = t.v_flt; /* Determine the minimum float type */ - if (a->v.v_flt <= F32_MAX) { a->t = &TYPE(TY_F32); } - else if (a->v.v_flt <= F64_MAX) { a->t = &TYPE(TY_F64); } - else if (a->v.v_flt <= F128_MAX) { a->t = &TYPE(TY_F128); } + if (a->v_flt <= F32_MAX) { a->t = &TYPE(TY_F32); } + else if (a->v_flt <= F64_MAX) { a->t = &TYPE(TY_F64); } + else if (a->v_flt <= F128_MAX) { a->t = &TYPE(TY_F128); } return a; } @@ -396,7 +430,7 @@ static ast *parse_flt(lex *l, syt *st) { Expression operator precedence: 8 > expression group (parenthesis), function call 7 > - 6 > positive (prefix +), negative (prefix -), address-of (prefix &), dereference (prefix *) + 6 > positive (prefix +), negative (prefix -), bitwise not (prefix ~), address-of (prefix &), dereference (prefix *) 5 > 4 > multiplication (*), division (/), modulo (%) 3 > addition (+), subtraction (-) @@ -418,7 +452,7 @@ static s32 tok_precedence(tok_k tk) { /* Get the precedence of an AST kind. */ static s32 ast_precedence(ast_k ak) { switch (ak) { - case AK_OP_POS: case AK_OP_NEG: case AK_OP_ADO: case AK_OP_DRF: { return 6; } + case AK_OP_POS: case AK_OP_NEG: case AK_BW_NOT: case AK_OP_ADO: case AK_OP_DRF: { return 6; } case AK_OP_MUL: case AK_OP_DIV: case AK_OP_MOD: { return 4; } case AK_OP_ADD: case AK_OP_SUB: { return 3; } case AK_ASSIGN: case AK_AS_ADD: case AK_AS_SUB: case AK_AS_MUL: case AK_AS_DIV: case AK_AS_MOD: { return 1; } @@ -434,20 +468,25 @@ void ast_print(ast *a, UINT indent) { printf("%zu:%zu: %s \"%s\"", a->ln + 1, a->cl + 1, ast_ks[a->k], a->s); /* Print type information if present */ - for (type *t = a->t; t != NULL; t = t->base) { printf(" -> %s", t->s); } + if (a->t != NULL) { fputs(" -> ", stdout); } + for (type *t = a->t; t != NULL; t = t->base) switch (t->k) { + case TY_PTR: { printf("*"); } break; + case TY_ARR: { t->l != -1 ? printf("[%ld]", t->l) : printf("[]"); } break; + default: { printf("%s", t->s); } break; + } /* Indicate presence of various fields */ fputs(" [", stdout); fputc(a->h != 0 ? 'h' : '-', stdout); - fputc(a->v.k != VK_NULL ? 'v' : '-', stdout); + // fputc(a->v.k != VK_NULL ? 'v' : '-', stdout); fputc(a->st.a != NULL ? 's' : '-', stdout); fputc(']', stdout); /* Indicate if the AST node has a value */ - switch (a->v.k) { - case VK_BOOL: { printf(a->v.v_bool ? " = true" : " = false"); } break; - case VK_INT: { printf(" = %lu", a->v.v_int); } break; - case VK_FLT: { printf(" = %lf", a->v.v_flt); } break; + 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; } /* Indicate if the AST node has no parent */ diff --git a/src/parse.h b/src/parse.h index d0ad962..672346a 100644 --- a/src/parse.h +++ b/src/parse.h @@ -10,7 +10,6 @@ #include "symbol.h" #include "type.h" #include "util/util.h" -#include "value.h" #include <llvm-c/Types.h> @@ -25,18 +24,20 @@ typedef enum { AK_ASSIGN, AK_AS_ADD, AK_AS_SUB, AK_AS_MUL, AK_AS_DIV, AK_AS_MOD, - AK_ID_VAR, AK_CALL, AK_INT, AK_FLT, AK_BOOL, + AK_ID_VAR, AK_CALL, AK_BOOL, AK_INT, AK_FLT, AK_ARR, AK_HASH_SYSCALL } ast_k; /* - k : Kind, ln : Line, cl : Column, h : Hash, s : String, t : Type, v: Value + k : Kind, ln : Line, cl : Column, h : Hash, s : String, t : Type st : Symbol Table, p : Parent, c : Children + v_bool : Boolean Value, v_int : Integer Value, v_flt : Float Value */ typedef struct ast_s { - ast_k k; UINT ln, cl; u64 h; char *s; type *t; val v; syt st; + 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; }; LLVMTypeRef llvm_t; LLVMValueRef llvm_v; } ast; diff --git a/src/symbol.c b/src/symbol.c index 09ff20d..43838b7 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -160,8 +160,16 @@ 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) { - if (ast_type(st->a[i].v, st)) { printf("%s -> %s\n", st->a[i].k, ast_type(st->a[i].v, st)->s); } - else { printf("%s -> (null)\n", st->a[i].k); } + fputs(st->a[i].k, 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) { + case TY_PTR: { printf("*"); } break; + case TY_ARR: { t->l != -1 ? printf("[%ld]", t->l) : printf("[]"); } break; + default: { printf("%s", t->s); } break; + } + + fputc('\n', stdout); } } diff --git a/src/symbol.h b/src/symbol.h index d7b049e..5bc42f0 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -8,7 +8,6 @@ #include "type.h" #include "util/util.h" -#include "value.h" typedef struct ast_s ast; diff --git a/src/type.c b/src/type.c index 15b1293..8247b38 100644 --- a/src/type.c +++ b/src/type.c @@ -11,9 +11,9 @@ type types[] = { { TY_VOID, 0, 0, "void" }, { TY_PTR, TF_PTR, -1, "ptr" }, - { TY_ARR, TF_PTR, -1, "arr" }, + { TY_ARR, 0, -1, "arr" }, { TY_TYPE, 0, -1, "type" }, - { TY_AUTO, 0, -1, "auto" }, + { TY_ANY, 0, -1, "any" }, { TY_BOOL, TF_BOOL, 1, "bool" }, { TY_B8, TF_BOOL, 1, "b8" }, @@ -140,7 +140,11 @@ type *type_ptr(type *base, u64 n) { /* Initialise a new array type. */ type *type_arr(type *base, u64 l) { types_alloc(&types_a, 1); - return base; /* TODO */ + + type *t = types_next(&types_a); + *t = TYPE(TY_ARR); t->l = l; t->base = base; + + return t; } /* Check if a type is a pointer. */ @@ -173,7 +177,7 @@ inline bool is_equal(type *t1, type *t2) { /* Check if all base types match */ for (type *b1 = t1->base, *b2 = t2->base;; b1 = b1->base, b2 = b2->base) { if (b1 == NULL && b2 == NULL) { break; } - if (b1 == NULL != b2 == NULL) { return false; } + if ((b1 == NULL) != (b2 == NULL)) { return false; } if (b1->k != b2->k) { return false; } if (b1->f != b2->f) { return false; } diff --git a/src/type.h b/src/type.h index 313ecde..31f8b6f 100644 --- a/src/type.h +++ b/src/type.h @@ -11,7 +11,7 @@ #define TYPE(a) (types[a]) typedef enum { - TY_VOID, TY_PTR, TY_ARR, TY_TYPE, TY_AUTO, + TY_VOID, TY_PTR, TY_ARR, TY_TYPE, TY_ANY, TY_BOOL, TY_B8, TY_B16, TY_B32, TY_B64, @@ -53,11 +53,7 @@ typedef enum { } type_f; /* k : Kind, f : Flags, l : Length, s : String */ -typedef struct type_s { - type_k k; type_f f; s64 l; char *s; - struct type_s *base; -} type; - +typedef struct type_s { type_k k; type_f f; s64 l; char *s; struct type_s *base; } type; typedef struct { type *a; UINT al, ac; } type_a; extern type types[]; diff --git a/src/value.c b/src/value.c deleted file mode 100644 index 4c46d83..0000000 --- a/src/value.c +++ /dev/null @@ -1,50 +0,0 @@ -// value.c -// Value source file for G -// Copyright (C) 2021, Jakob Wakeling -// All rights reserved. - -#include "util/util.h" -#include "value.h" - -#include <errno.h> -#include <stdlib.h> - -const val val_null = { VK_NULL }; - -val val_bool(bool v) { return (val){ VK_BOOL, .v_bool = v }; } -val val_u64(u64 v) { return (val){ VK_INT, .v_int = v }; } -val val_f128(f128 v) { return (val){ VK_FLT, .v_flt = v }; } - -/* Parse an integer string into a value. */ -val val_parse_int(char *s) { - val v = { VK_INT, .v_int = 0 }; u64 c; UINT b = 10; - - if (s[0] == '0') switch (s[1]) { - case 'b': { s += 2; b = 2; } break; case 'o': { s += 2; b = 8; } break; - case 'd': { s += 2; b = 10; } break; case 'z': { s += 2; b = 12; } break; - case 'x': { s += 2; b = 16; } break; default: { s += 1; } break; - } - - for (; s[0]; ++s) { - if (s[0] >= '0' && s[0] <= '9') { c = *s - '0'; } - else if (s[0] >= 'A' && s[0] <= 'F') { c = *s - ('A' - 10); } - - if (c >= b) { errno = EDOM; return val_null; } - if (v.v_int > (U64_MAX - c) / b) { errno = ERANGE; return val_null; } - - v.v_int = v.v_int * b + c; - } - - return v; -} - -/* Parse a real string into a value. */ -/* TODO remove reliance on strtold(). */ -val val_parse_flt(char *s) { - val v = { VK_FLT, .v_flt = 0 }; u64 c; char *endptr; - - v.v_flt = strtold(s, &endptr); - if (*endptr != '\0') { return val_null; } - - return v; -} diff --git a/src/value.h b/src/value.h deleted file mode 100644 index 2c74007..0000000 --- a/src/value.h +++ /dev/null @@ -1,23 +0,0 @@ -// value.h -// Value header file for G -// Copyright (C) 2021, Jakob Wakeling -// All rights reserved. - -#ifndef G_VALUE_H_X2RKXBBA -#define G_VALUE_H_X2RKXBBA - -#include "util/util.h" - -typedef enum { VK_NULL, VK_BOOL, VK_INT, VK_FLT } val_k; -typedef struct { val_k k; union { bool v_bool; u64 v_int; f128 v_flt; }; } val; - -extern const val val_null; - -extern val val_bool(bool v); -extern val val_u64(u64 v); -extern val val_f128(f128 v); - -extern val val_parse_int(char *s); -extern val val_parse_flt(char *s); - -#endif // G_VALUE_H_X2RKXBBA