Author | Jakob Wakeling <[email protected]> |
Date | 2024-01-30 07:33:09 |
Commit | 753057649be967f0151bea80de863738a9d6879f |
Parent | ce98c7aaef741ab5cda0560f446e77a34f718822 |
Remove all trailing whitespace
Diffstat
M | README.md | | | 2 | +- |
M | doc/g.ebnf | | | 14 | +++++++------- |
M | examples/io.g | | | 4 | ++-- |
M | examples/loop.g | | | 2 | +- |
M | examples/map.g.theoretical | | | 20 | ++++++++++---------- |
M | src/analyse.c | | | 52 | +++++++++++++++++++++++++--------------------------- |
M | src/init.c | | | 16 | ++++++++-------- |
M | src/lex.c | | | 65 | ++++++++++++++++++++++++++++++++--------------------------------- |
M | src/lex.h | | | 10 | +++++----- |
M | src/llvm.c | | | 144 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | src/llvm/attr.c | | | 2 | +- |
M | src/log.c | | | 6 | +++--- |
M | src/main.c | | | 11 | ----------- |
M | src/parse.c | | | 164 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | src/parse.h | | | 18 | +++++++++--------- |
M | src/symbol.c | | | 48 | ++++++++++++++++++++++++------------------------ |
M | src/type.c | | | 25 | +------------------------ |
M | src/type.h | | | 22 | +++++++++++----------- |
M | src/util/optget.c | | | 20 | ++++++++++---------- |
19 files changed, 304 insertions, 341 deletions
diff --git a/README.md b/README.md index 2c8da9c..bd98461 100644 --- a/README.md +++ b/README.md @@ -96,5 +96,5 @@ command. The second command will output an executable file, *a.out* by default. ## Meta -Copyright (C) 2021, Jakob Wakeling +Copyright (C) 2024, Jakob Wakeling All rights reserved. diff --git a/doc/g.ebnf b/doc/g.ebnf index 7d9397b..9a5d36a 100644 --- a/doc/g.ebnf +++ b/doc/g.ebnf @@ -23,7 +23,7 @@ stmt_for = "for", "(", expr, [ ";", expr ], [ ";", expr ], ")", stmt ; (* Expressions *) expr = iden | literal | expr_proc - + | "(", expr, ")" | type, "(", expr, ")" (* Type cast *) | iden, "(", [ expr, { ",", expr } ], ")" (* Procedure call *) @@ -31,21 +31,21 @@ expr = iden | literal | "#", iden, [ "(", [ expr, { ",", expr } ], ")" ] (* Hash expression *) | "+", expr | "-", expr (* Unary POS and NEG *) | "!", expr | "~", expr (* Logical and bitwise NOT *) - + | expr, "*", expr | expr, "/", expr | expr, "%", expr | expr, "&", expr | expr, "<<", expr | expr, ">>", expr - + | expr, "+", expr | expr, "-", expr (* Binary ADD and SUB *) | expr, "|", expr | expr, "^", expr (* Bitwise OR and XOR *) - + | expr, "==", expr | expr, "!=", expr (* EQ and NEQ *) | expr, "<", expr | expr, "<=", expr (* LT and LTE *) | expr, ">", expr | expr, ">=", expr (* GT and GTE *) - + | expr, "&&", expr | expr, "||", expr (* Logical AND and OR *) - + | expr, "?", expr, ":", expr (* Ternary operator *) - + | iden, "=", expr | iden, "+=" expr | iden, "-=" expr | iden, "*=", expr | iden, "/=" expr | iden, "%=" expr | iden, "&=", expr | iden, "|=" expr | iden, "^=" expr diff --git a/examples/io.g b/examples/io.g index 6bbac3e..dd75f13 100644 --- a/examples/io.g +++ b/examples/io.g @@ -1,11 +1,11 @@ main :: proc() sint { file : string = "g.txt"; body : string = "Output\n"; - + /* Open file with O_WRONLY and O_CREAT flags */ fd : sint = #syscall(uint(2), cstring(file), s32(0b1000010), u16(0o644)); r : sint = #syscall(uint(1), fd, cstring(body), len(body)); #syscall(uint(3), fd); - + return r; } diff --git a/examples/loop.g b/examples/loop.g index c679822..6071de1 100644 --- a/examples/loop.g +++ b/examples/loop.g @@ -4,6 +4,6 @@ main :: proc() u8 { #syscall(uint(1), uint(1), &c, uint(1)); #syscall(uint(1), uint(1), &nl, uint(1)); } - + return 0; } diff --git a/examples/map.g.theoretical b/examples/map.g.theoretical index 1a8b1ea..47081f4 100644 --- a/examples/map.g.theoretical +++ b/examples/map.g.theoretical @@ -18,7 +18,7 @@ define LOAD_FACTOR 0.75; Hashmap struct where K is the key type, V is the value type, a is the array of key-value pairs, al is the number of items in the array, and ac is the array capacity. - + The hashmap will resize itself when a load factor of 0.75 is reached. It *will* also shadow values when a duplicate key is used. Entries *will* be inserted using a robin hood hashing technique. @@ -53,42 +53,42 @@ map :: struct($K: type, $V: type) { /*map.*/insert :: proc(m: &map($K, $V), k: K, v: V) -> ErrorOr() { if (m.ac == 0 || m.al >= (m.ac * LOAD_FACTOR)) { /* Resize the map. */ } h := hash(k); index: uint = h % m.ac; - + /* Find the next available empty bucket */ for (; m.a[index] /*is unset*/; index += 1) { if (index >= m.ac) { index = 0; } } - + m.a[index] = { h, k, v }; - + return ErrorOr(); /* ??? */ } /* - + */ /*map.*/lookup :: proc(m: &map($K, $V), k: K) -> ErrorOr(V) { index: uint = hash(k) % m.ac; - + for (start: uint = index; m.a[index].k != k; index += 1) { if (index >= m.ac) { index = 0; } /* This doesnt account for the start being at the array start */ if (index + 1 == start) { return Error(); /* ??? */ } } - + return ErrorOr(m.a[index].v); /* ??? */ } /* - + */ /*map.*/remove :: proc(m: &map($K, $V), k: K) -> ErrorOr() { index: uint = hash(k) % m.ac; - + for (start: uint = index; m.a[index].k != k; index += 1) { if (index >= m.ac) { index = 0; } /* This doesnt account for the start being at the array start */ if (index + 1 == start) { return Error(); /* ??? */ } } - + return ErrorOr(); /* ??? */ } diff --git a/src/analyse.c b/src/analyse.c index d4789e3..80170d5 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -47,7 +47,7 @@ static void analyse_stmt(ast *a, syt *st) { /* Analyse a compound statement. AK_COMP has a scope. */ static inline void analyse_stmt_comp(ast *a, syt *st) { assert(A.k == AK_COMP); - + for (uptr i = 0; i < CL; i += 1) { analyse_stmt(C[i], &A.st); } } @@ -55,10 +55,10 @@ static inline void analyse_stmt_comp(ast *a, syt *st) { static void analyse_stmt_decl(ast *a, syt *st) { assert(A.c.al == 0 || A.c.al == 1); if (A.c.al == 0) { assert(A.t != null); return; } - + analyse_expr(C[0], st); type *value_type = ast_type(C[0], st); - + if (C[0]->k == AK_PROC) { A.t = &TYPE(TY_PROC); return; /* TODO */ @@ -66,7 +66,7 @@ static void analyse_stmt_decl(ast *a, syt *st) { else if (is_bool(value_type)) { /* If a type has not been specified, set the type based on the value */ if (A.t == null) { A.t = C[0]->t; } - + /* If the type has been specified, check that the value is compatible */ else { /* TODO */ @@ -76,24 +76,24 @@ static void analyse_stmt_decl(ast *a, syt *st) { /* If a type has not been specified, set the type based on the value */ if (A.t == null) { A.t = C[0]->t; - + /* If the value type is smaller than 32 bit, upgrade it */ if (A.t->l < 4) { if (is_sign(A.t)) { A.t = &TYPE(TY_S32); } else { A.t = &TYPE(TY_U32); } - + /* Insert a type cast node between parent and child */ /* FIXME this behaviour is incorrect, should only implicitely cast for literals, not all expressions */ ast *cast = ast_init(AK_CAST, C[0]->ln, C[0]->cl); cast->t = A.t; - + ast *child = C[0]; - + ast_displace(a, child); ast_push(cast, child); ast_push(a, cast); } } - + /* If the type has been specified, check that the value is compatible */ else { /* TODO */ @@ -102,24 +102,24 @@ static void analyse_stmt_decl(ast *a, syt *st) { else if (is_flt(value_type)) { /* If a type has not been specified, set the type based on the value */ if (A.t == null) { A.t = A.c.a[0]->t; } - + /* If the type has been specified, check that the value is compatible */ else { /* TODO */ } } else if (value_type->k == TY_STRING) { if (A.t == null) { A.t = C[0]->t; } return; } - + else { note("TODO", A.ln, A.cl, -1, "Unhandled value kind %s", ast_ks[C[0]->k]); } } /* Analyse a return statement. */ static void analyse_stmt_return(ast *a, syt *st) { if (A.c.al == 1) { analyse_expr(C[0], st); } - + type *t = A.c.al != 0 ? ast_type(C[0], st) : &TYPE(TY_VOID); ast *p = A.p; for (; p->k != AK_PROC; p = p->p); - + if (is_equal(t, &TYPE(TY_VOID)) && !is_equal(p->t, &TYPE(TY_VOID))) { note("TODO", A.ln, A.cl, 0, "Non-void procedure \"%s\" should return a value", p->p->s); } @@ -137,7 +137,7 @@ static void analyse_stmt_return(ast *a, syt *st) { static void analyse_stmt_if(ast *a, syt *st) { assert(A.k == AK_IF); assert(CL == 3 || CL == 4); - + if (C[0]->k != AK_VOID) { analyse_stmt(C[0], &A.st); } analyse_expr(C[1], &A.st); analyse_stmt(C[2], &A.st); if (CL == 4) { analyse_stmt(C[3], &A.st); } @@ -147,7 +147,7 @@ static void analyse_stmt_if(ast *a, syt *st) { static void analyse_stmt_for(ast *a, syt *st) { assert(A.k == AK_FOR); assert(CL == 2 || CL == 4); - + for (uptr i = 0; i < CL; i += 1) { analyse_stmt(C[i], &A.st); } } @@ -166,20 +166,20 @@ static void analyse_expr(ast *a, syt *st) { assert(C[0]->k == AK_ID); assert(C[0]->h != 0); assert(C[0]->s != null); - + analyse_expr(C[0], st); type *t = C[0]->t; - + ast *sym = syt_search_h(st, C[0]->h, C[0]->s); if (sym == null) { note("TODO", A.ln, A.cl, 0, "Use of undeclared identifier \"%s\"", C[0]->s); } - + else if (sym->k == AK_TYPE) { A.k = AK_CAST; A.t = sym->t; if (CL > 2) { note("TODO", A.ln, A.cl, 0, "Type casts must only have a single argument"); } } else if (sym->k == AK_PROC) { A.k = AK_BUILTIN; A.t = sym->t; } - + for (uptr i = 1; i < CL; i += 1) { analyse_expr(C[i], st); } - + if (is_proc(t)) { register ast **av = sym->c.a[0]->c.a; register uptr ac = sym->c.a[0]->c.al; for (uptr i = 0; i < ac - 1; i += 1) { @@ -188,7 +188,7 @@ static void analyse_expr(ast *a, syt *st) { if (C[i + 1]->t->l <= av[i]->t->l) { ast *cast = ast_init(AK_CAST, C[i + 1]->ln, C[i + 1]->cl); cast->t = av[i]->t; ast *child = C[i + 1]; - + ast_wrap(a, child, cast); } else { @@ -210,7 +210,7 @@ static void analyse_expr(ast *a, syt *st) { } break; case AK_SUBS: { assert(CL == 2); - + if (!is_int(ast_type(C[1], st))) { note("TODO", A.ln, A.cl, 0, "Expression must have integral type"); } @@ -236,12 +236,12 @@ static void analyse_expr(ast *a, syt *st) { /* Analyse a procedure expression. AK_PROC has a scope. */ static void analyse_expr_proc(ast *a, syt *st) { assert(A.k == AK_PROC); - + /* Analyse the procedure arguments */ for (uptr i = 0; i < CL - 1; i += 1) { /* TODO */ } - + /* Analyse the procedure body */ analyse_stmt_comp(C[CL - 1], &A.st); } @@ -249,9 +249,9 @@ static void analyse_expr_proc(ast *a, syt *st) { /* Analyse a hash expression. */ static void analyse_expr_hash(ast *a, syt *st) { assert(A.k == AK_HASH); - + if (strcmp(A.s, "syscall") == 0) { A.k = AK_HASH_SYSCALL; A.t = &TYPE(TY_SINT); } else { note("TODO", A.ln, A.cl, 0, "Unrecognised hash expression \"%s\"", A.s); } - + for (uptr i = 0; i < CL; i += 1) { analyse_expr(C[i], st); } } diff --git a/src/init.c b/src/init.c index a555a61..c70417b 100644 --- a/src/init.c +++ b/src/init.c @@ -10,14 +10,14 @@ static ast kwds[] = { { AK_TYPE, 0, 0, 0, "ptr", &TYPE(TY_PTR), { 0 }, null }, - + /* Boolean Types */ { AK_TYPE, 0, 0, 0, "bool", &TYPE(TY_BOOL), { 0 }, null }, { AK_TYPE, 0, 0, 0, "b8", &TYPE(TY_B8), { 0 }, null }, { AK_TYPE, 0, 0, 0, "b16", &TYPE(TY_B16), { 0 }, null }, { AK_TYPE, 0, 0, 0, "b32", &TYPE(TY_B32), { 0 }, null }, { AK_TYPE, 0, 0, 0, "b64", &TYPE(TY_B64), { 0 }, null }, - + /* Integer Types */ { AK_TYPE, 0, 0, 0, "uint", &TYPE(TY_UINT), { 0 }, null }, { AK_TYPE, 0, 0, 0, "u8", &TYPE(TY_U8), { 0 }, null }, @@ -25,29 +25,29 @@ static ast kwds[] = { { AK_TYPE, 0, 0, 0, "u32", &TYPE(TY_U32), { 0 }, null }, { AK_TYPE, 0, 0, 0, "u64", &TYPE(TY_U64), { 0 }, null }, { AK_TYPE, 0, 0, 0, "u128", &TYPE(TY_U128), { 0 }, null }, - + { AK_TYPE, 0, 0, 0, "sint", &TYPE(TY_SINT), { 0 }, null }, { AK_TYPE, 0, 0, 0, "s8", &TYPE(TY_S8), { 0 }, null }, { AK_TYPE, 0, 0, 0, "s16", &TYPE(TY_S16), { 0 }, null }, { AK_TYPE, 0, 0, 0, "s32", &TYPE(TY_S32), { 0 }, null }, { AK_TYPE, 0, 0, 0, "s64", &TYPE(TY_S64), { 0 }, null }, { AK_TYPE, 0, 0, 0, "s128", &TYPE(TY_S128), { 0 }, null }, - + /* Floating Point Types */ { AK_TYPE, 0, 0, 0, "f16", &TYPE(TY_F32), { 0 }, null }, { AK_TYPE, 0, 0, 0, "f32", &TYPE(TY_F32), { 0 }, null }, { AK_TYPE, 0, 0, 0, "f64", &TYPE(TY_F64), { 0 }, null }, { AK_TYPE, 0, 0, 0, "f128", &TYPE(TY_F128), { 0 }, null }, - + /* Character and String Types */ { AK_TYPE, 0, 0, 0, "char", &TYPE(TY_CHAR), { 0 }, null }, { AK_TYPE, 0, 0, 0, "rune", &TYPE(TY_RUNE), { 0 }, null }, { AK_TYPE, 0, 0, 0, "string", &TYPE(TY_STRING), { 0 }, null }, - + /* Builtins */ { AK_PROC, 0, 0, 0, "cstring", &(type){ TY_PTR, TF_PTR, -1, "", &TYPE(TY_U8) }, { 0 }, null }, { AK_PROC, 0, 0, 0, "len", &TYPE(TY_UINT), { 0 }, null }, - + { AK_VOID, 0, 0, 0, null, null, { 0 }, null } }; @@ -57,7 +57,7 @@ void initialise(void) { kwds[i].h = syt_hash(kwds[i].s, strlen(kwds[i].s)); syt_insert_h(&kwt, kwds[i].h, kwds[i].s, &kwds[i]); } - + /* Set the size of word sized types */ /* TODO don't hardcode */ TYPE(TY_UINT).l = 8; diff --git a/src/lex.c b/src/lex.c index cb75290..d5af0e1 100644 --- a/src/lex.c +++ b/src/lex.c @@ -13,19 +13,19 @@ char *tok_ks[] = { "TK_VOID", "TK_EOF", "TK_ID", "TK_INT", "TK_FLT", "TK_STR", - + "TK_NULL", "TK_TRUE", "TK_FALSE", "TK_PROC", "TK_GOTO", "TK_RETURN", "TK_IF", "TK_ELSE", "TK_FOR", "TK_BREAK", "TK_CONTINUE", - + "TK_LPAREN", "TK_RPAREN", "TK_LBRACK", "TK_RBRACK", "TK_LBRACE", "TK_RBRACE", "TK_COLON", "TK_SCOLON", "TK_COMMA", "TK_PERIOD", "TK_QMARK", "TK_HASH", - + "TK_ADD", "TK_SUB", "TK_MUL", "TK_DIV", "TK_MOD", "TK_EQ", "TK_NE", "TK_LT", "TK_LE", "TK_GT", "TK_GE", - + "TK_EMARK", "TK_LO_AND", "TK_LO_OR", "TK_TILDE", "TK_BW_AND", "TK_BW_OR", "TK_BW_XOR", "TK_LSHIFT", "TK_RSHIFT", - + "TK_ASSIGN", "TK_AS_ADD", "TK_AS_SUB", "TK_AS_MUL", "TK_AS_DIV", "TK_AS_MOD", "TK_AS_NOT", "TK_AS_AND", "TK_AS_OR", "TK_AS_XOR", "TK_AS_LSHIFT", "TK_AS_RSHIFT", }; @@ -57,17 +57,17 @@ tok lex_peek(lex *l) { return T; } tok lex_next(lex *l) { reset:; if (T.k == TK_EOF) { return T; } tok t = T; T = (tok){ 0 }; - + /* Skip null characters and whitespace */ skip:; for (; P != Q && (!P[0] || is_space(P[0])); P += 1) switch (P[0]) { case '\0': { note(l->n, l->ln, l->cl, 1, "Null character ignored"); } break; case '\n': { LN += 1; CL = 0; } break; default: { CL += 1; } break; } - + /* Return the current token immediately if EOF is reached */ if (P == Q) { T = (tok){ TK_EOF, LN, CL, 0 }; return t; } - + /* Skip single-line and (potentially nested) multi-line comments */ if (P[0] == '/') switch (P[1]) { case '/': { for (P += 2; P != Q && P[0] != '\n'; P += 1); } goto skip; @@ -79,16 +79,16 @@ tok lex_next(lex *l) { } } goto skip; } - + T.ln = LN; T.cl = CL; - + /* Handle identifiers and keywords */ if (is_alpha(P[0]) || P[0] == '_') { char *s = P; uptr sl; - + for (P += 1; is_alpha(P[0]) || is_digit_dec(P[0]) || P[0] == '_'; P += 1); sl = P - s; CL += sl; T.h = syt_hash(s, sl); - + if (strncmp(s, "null", 4) == 0) { T.k = TK_NULL; } else if (strncmp(s, "true", 4) == 0) { T.k = TK_TRUE; } else if (strncmp(s, "false", 5) == 0) { T.k = TK_FALSE; } @@ -102,24 +102,24 @@ tok lex_next(lex *l) { else if (strncmp(s, "continue", 8) == 0) { T.k = TK_CONTINUE; } else { T.k = TK_ID; if (!(T.s = strndup(s, sl))) { panic(SERR); }} } - + /* Handle number literals */ else if (is_digit_dec(P[0])) { T.k = TK_INT; char *start = P; - + for (P += 1; is_alpha(P[0]) || is_digit_dec(P[0]) || P[0] == '.'; P += 1) { if (P[0] == '.') { T.k = TK_FLT; } if (P[0] == 'e' || P[0] == 'E') { T.k = TK_FLT; P += P[1] == '+' || P[1] == '-'; } } - + uptr sl = P - start; CL += sl; if (!(T.s = strndup(start, sl))) { panic(SERR); } - + switch (T.k) { case TK_INT: { char *s = T.s; register u64 v = 0; u64 c; register uptr b = 10; char *b_s; - + if (s[0] == '0') switch (s[1]) { case 'b': { s += 2; b = 2; b_s = "binary"; } break; case 'o': { s += 2; b = 8; b_s = "octal"; } break; @@ -128,32 +128,32 @@ tok lex_next(lex *l) { case 'x': { s += 2; b = 16; b_s = "hexadecimal"; } 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) { note(l->n, T.ln, T.cl, 0, "Invalid digit \'%c\' in %s constant", s[0], b_s); } if (v > (U64_MAX - c) / b) { note(l->n, T.ln, T.cl, 0, "Integer literal cannot be represented"); } - + v = v * b + c; } - + T.v_int = v; } break; case TK_FLT: { /* TODO reimplement */ char *s = T.s, *end; register f128 v = 0; - + v = strtold(s, &end); if (*end != '\0') { note(l->n, T.ln, T.cl, 0, "Invalid digit \'%c\' in floating-point constant", *end); } - + T.v_flt = v; } break; default: { /* Unreachable */ } break; } } - + /* Handle punctuators and operators */ else switch (P[0]) { case '(': { T.k = TK_LPAREN; P += 1; CL += 1; } break; @@ -230,15 +230,15 @@ tok lex_next(lex *l) { default: { T.k = TK_BW_XOR; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_XOR; P += 2; CL += 2; } break; } break; - + /* Handle character and string literals */ case '\'': case '\"': { char quote = P[0], *s = P += 1; CL += 1; register char *head = s; - + for (; P[0] != quote && P[0] != '\n' && P != Q;) { /* Non escape characters are not altered */ if (P[0] != '\\') { *head = P[0]; P += 1; head += 1; } - + /* Escape characters are processed and re-written to head */ else switch (P[1]) { case '0': { *head = 0x00; P += 2; head += 1; } break; @@ -262,20 +262,20 @@ tok lex_next(lex *l) { } break; } } - + uptr sl = head - s; CL += sl; if (P[0] != quote) { note(l->n, T.ln, T.cl, 0, "Missing closing quote"); } else if (P != Q) { P += 1; CL += 1; } - + if (quote == '\'') { T.k = TK_INT; if (!(T.s = strndup(s, sl))) { panic(SERR); } - + /* Numerical value of character literals is calculated and stored in T.v_int */ for (uptr i = 0; i < sl; i += 1) { if (T.v_int > (U32_MAX - s[i]) / 256) { note(l->n, T.ln, T.cl, 0, "Character literal cannot be represented"); break; } - + T.v_int = T.v_int * 256 + s[i]; } } @@ -284,11 +284,11 @@ tok lex_next(lex *l) { if (!(T.s = strndup(s, sl))) { panic(SERR); } } } break; - + /* Handle unknown characters */ default: { note(l->n, LN, CL, 1, "Unknown character: %X '%c'", P[0], P[0]); P += 1; CL += 1; } break; } - + return t; } diff --git a/src/lex.h b/src/lex.h index 98f8e56..c1ba1f4 100644 --- a/src/lex.h +++ b/src/lex.h @@ -9,19 +9,19 @@ /* Remember to update tok_ks in lex.c */ typedef enum { TK_VOID, TK_EOF, TK_ID, TK_INT, TK_FLT, TK_STR, - + TK_NULL, TK_TRUE, TK_FALSE, TK_PROC, TK_GOTO, TK_RETURN, TK_IF, TK_ELSE, TK_FOR, TK_BREAK, TK_CONTINUE, - + TK_LPAREN, TK_RPAREN, TK_LBRACK, TK_RBRACK, TK_LBRACE, TK_RBRACE, TK_COLON, TK_SCOLON, TK_COMMA, TK_PERIOD, TK_QMARK, TK_HASH, - + TK_ADD, TK_SUB, TK_MUL, TK_DIV, TK_MOD, TK_EQ, TK_NE, TK_LT, TK_LE, TK_GT, TK_GE, - + TK_EMARK, TK_LO_AND, TK_LO_OR, TK_TILDE, TK_BW_AND, TK_BW_OR, TK_BW_XOR, TK_LSHIFT, TK_RSHIFT, - + TK_ASSIGN, TK_AS_ADD, TK_AS_SUB, TK_AS_MUL, TK_AS_DIV, TK_AS_MOD, TK_AS_NOT, TK_AS_AND, TK_AS_OR, TK_AS_XOR, TK_AS_LSHIFT, TK_AS_RSHIFT, } tok_k; diff --git a/src/llvm.c b/src/llvm.c index e9245d3..153e3fa 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -55,48 +55,48 @@ void llvm(ast *a, char *file, llvm_action action) { llvm_context = LLVMGetGlobalContext(); llvm_module = LLVMModuleCreateWithName((file_name = file)); llvm_builder = LLVMCreateBuilder(); - + /* Generate IR for all child nodes */ for (uptr i = 0; i < a->c.al; i += 1) { llvm_stmt_decl(a->c.a[i], &a->st); } - + char *err = null; bool failed = false; - + failed = LLVMVerifyModule(llvm_module, LLVMPrintMessageAction, &err); LLVMDisposeMessage(err); err = null; - + switch (action) { case llvm_obj: case llvm_asm: { if (failed) { exit(2); } /* Don't compile after failure */ - + char *triple = LLVMGetDefaultTargetTriple(); printf("Target: %s\n", triple); LLVMSetTarget(llvm_module, triple); - + LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargets(); LLVMInitializeAllTargetMCs(); LLVMInitializeAllAsmParsers(); LLVMInitializeAllAsmPrinters(); - + LLVMTargetRef target = null; - + if (LLVMGetTargetFromTriple(triple, &target, &err)) { panic("LLVMGetTargetFromTriple: %s", err); } if (err != null) { panic("%s", err); } LLVMDisposeMessage(err); err = null; - + LLVMTargetMachineRef machine = LLVMCreateTargetMachine( target, triple, "generic", "", LLVMCodeGenLevelNone, LLVMRelocPIC, LLVMCodeModelDefault ); - + char *outfile = action == llvm_obj ? "llvm.o" : "llvm.s"; int outform = action == llvm_obj ? LLVMObjectFile : LLVMAssemblyFile; if (LLVMTargetMachineEmitToFile(machine, llvm_module, outfile, outform, &err)) { panic("LLVMTargetMachineEmitToFile: %s", err); } if (err != null) { panic("%s", err); } LLVMDisposeMessage(err); err = null; - + LLVMDisposeTargetMachine(machine); } break; case llvm_ir: { @@ -111,7 +111,7 @@ void llvm(ast *a, char *file, llvm_action action) { } } break; } - + LLVMDisposeBuilder(llvm_builder); LLVMDisposeModule(llvm_module); LLVMShutdown(); @@ -138,21 +138,21 @@ static LLVMValueRef llvm_stmt_compound(ast *a, syt *st) { /* Generate IR for a declaration statement. */ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { assert(a->k == AK_DECL); - + if (CL && C[0]->k == AK_PROC) /* AK_PROC has a scope */ { LLVMTypeRef art[C[0]->c.al - 1]; for (uptr i = 0; i < C[0]->c.al - 1; i += 1) { art[i] = llvm_type(ast_type(C[0]->c.a[i], &A.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, ""); LLVMPositionBuilderAtEnd(llvm_builder, bb); - + /* Allocate scoped procedure arguments */ for (uptr i = 0; i < C[0]->c.al - 1; i += 1) { C[0]->c.a[i]->llvm_v = LLVMBuildAlloca(llvm_builder, art[i], ""); } for (uptr i = 0; i < C[0]->c.al - 1; i += 1) { LLVMBuildStore(llvm_builder, LLVMGetParam(f, i), C[0]->c.a[i]->llvm_v); } - + A.llvm_t = ft; A.llvm_v = f; llvm_expr_proc(C[0], &A.st); } @@ -169,7 +169,7 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { A.llvm_v = v; } } - + return null; } @@ -183,27 +183,27 @@ static LLVMValueRef llvm_stmt_return(ast *a, syt *st) { static LLVMValueRef llvm_stmt_if(ast *a, syt *st) { assert(A.k == AK_IF); assert(CL == 3 || CL == 4); - + if (C[0]->k != AK_VOID) { llvm_stmt(C[0], &A.st); } - + ast *p = find_proc(a); assert(p->k == AK_DECL); - + LLVMBasicBlockRef b1 = LLVMAppendBasicBlock(p->llvm_v, ""), b2 = null; if (CL == 4) { b2 = LLVMAppendBasicBlock(p->llvm_v, ""); } LLVMBasicBlockRef b3 = LLVMAppendBasicBlock(p->llvm_v, ""); - + LLVMBuildCondBr(llvm_builder, llvm_expr(C[1], &A.st, true), b1, CL == 4 ? b2 : b3); - + LLVMPositionBuilderAtEnd(llvm_builder, b1); llvm_stmt(C[2], &A.st); LLVMBuildBr(llvm_builder, b3); - + if (CL == 4) { LLVMPositionBuilderAtEnd(llvm_builder, b2); llvm_stmt(C[3], &A.st); LLVMBuildBr(llvm_builder, b3); } - + LLVMPositionBuilderAtEnd(llvm_builder, b3); - + return null; } @@ -211,27 +211,27 @@ static LLVMValueRef llvm_stmt_if(ast *a, syt *st) { static LLVMValueRef llvm_stmt_for(ast *a, syt *st) { assert(A.k == AK_FOR); assert(CL == 2 || CL == 4); - + if (CL == 4) { llvm_stmt(C[0], &A.st); } - + ast *p = find_proc(a); assert(p->k == AK_DECL); - + LLVMBasicBlockRef b1 = LLVMAppendBasicBlock(p->llvm_v, ""); LLVMBasicBlockRef b2 = LLVMAppendBasicBlock(p->llvm_v, ""); LLVMBasicBlockRef b3 = LLVMAppendBasicBlock(p->llvm_v, ""); - + LLVMBuildBr(llvm_builder, b1); - + LLVMPositionBuilderAtEnd(llvm_builder, b1); LLVMBuildCondBr(llvm_builder, llvm_expr(CL == 4 ? C[1] : C[0], &A.st, true), b2, b3); - + LLVMPositionBuilderAtEnd(llvm_builder, b2); llvm_stmt(CL == 4 ? C[3] : C[1], &A.st); if (CL == 4) { llvm_stmt(C[2], &A.st); } LLVMBuildBr(llvm_builder, b1); - + LLVMPositionBuilderAtEnd(llvm_builder, b3); - + return null; } @@ -252,7 +252,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { ast *sym = syt_search(st, a->s); 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; } else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); } } break; @@ -260,7 +260,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { ast *sym = syt_search_h(st, C[0]->h, C[0]->s); 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); } - + LLVMValueRef args[CL - 1]; for (uptr 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, args, CL - 1, ""); } break; @@ -271,16 +271,16 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { /* FIXME subscripting does not work with pointers */ LLVMValueRef idc[1] = { llvm_expr(C[1], st, true) }; LLVMValueRef vr = LLVMBuildInBoundsGEP2(llvm_builder, llvm_type(ast_type(C[0], st)), llvm_expr(C[0], st, false), idc, 1, ""); - + if (!load) { return vr; } else { return LLVMBuildLoad2(llvm_builder, llvm_type(ast_type(C[0], st)->base), vr, ""); } } - + case AK_POS: { a = C[0]; goto reset; /* no-op */ } break; case AK_NEG: { type *t = ast_type(C[0], st); if (t == null) { note(file_name, A.ln, A.cl, -1, "Subtree is missing a type (llvm:llvm_expr)"); } - + if (is_int(t)) { return LLVMBuildNeg(llvm_builder, llvm_expr(C[0], st, true), "neg"); } else if (is_flt(t)) { return LLVMBuildFNeg(llvm_builder, llvm_expr(C[0], st, true), "neg"); } else { note(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (llvm:llvm_expr)"); } @@ -290,11 +290,11 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { type *t = ast_type(C[0], st); if (t == null) { note(file_name, A.ln, A.cl, -1, "Child is missing a type (llvm:llvm_expr)"); } if (t->base == null) { note(file_name, A.ln, A.cl, -1, "Cannot be dereferenced (llvm:llvm_expr)"); } - + if (!load) { return llvm_expr(C[0], st, true); } else { return LLVMBuildLoad2(llvm_builder, llvm_type(t->base), llvm_expr(C[0], st, true), ""); } } - + case AK_ADD: { if (is_int(ast_type(C[0], st))) { return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } @@ -323,7 +323,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { } else if (is_flt(t)) { return LLVMBuildFRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } } break; - + case AK_EQ: { if (is_int(ast_type(C[0], st))) { return BuildICmp(llvm_builder, LLVMIntEQ, C[0], C[1], st); } else if (is_flt(ast_type(C[0], st))) { return BuildFCmp(llvm_builder, LLVMRealOEQ, C[0], C[1], st); } @@ -360,15 +360,15 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { } else if (is_flt(ast_type(C[0], st))) { return BuildFCmp(llvm_builder, LLVMRealOGE, C[0], C[1], st); } } break; - + case AK_LO_NOT: { return LLVMBuildNot(llvm_builder, llvm_expr(C[0], st, true), ""); } break; case AK_LO_AND: { return LLVMBuildAnd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } break; case AK_LO_OR: { return LLVMBuildOr(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } break; - + case AK_BW_NOT: { type *t = ast_type(C[0], st); if (t == null) { note(file_name, A.ln, A.cl, -1, "Subtree is missing a type (llvm:llvm_expr)"); } - + if (is_int(t)) { return LLVMBuildXor(llvm_builder, llvm_expr(C[0], st, true), LLVMConstInt(llvm_type(t), -1, false), ""); } @@ -380,7 +380,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { } else { note(file_name, A.ln, A.cl, -1, "Expression cannot be inverted (llvm:llvm_expr)"); } } break; - + case AK_ASSIGN: { return LLVMBuildStore(llvm_builder, llvm_expr(C[1], st, true), llvm_expr(C[0], st, false)); } break; @@ -420,10 +420,10 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { else if (is_flt(t)) { v = LLVMBuildFRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false)); } break; - + default: { panic("Unhandled AST kind \"%s\" (llvm:llvm_expr)", ast_ks[a->k]); } break; } - + return null; } @@ -436,10 +436,10 @@ static LLVMValueRef llvm_expr_proc(ast *a, syt *st) { static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { assert(A.t != null); assert(CL == 1 || CL == 2); - + ast *c = CL == 1 ? C[0] : C[1]; type *expr_type = ast_type(c, st); - + if (is_ptr(expr_type)) { if (is_int(a->t)) { return LLVMBuildPtrToInt(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), ""); } } @@ -468,23 +468,23 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { return LLVMBuildBitCast(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), ""); } } - + panic("Unhandled cast \"%s\" -> \"%s\" (llvm:llvm_expr_cast)", expr_type->s, A.t->s); - + return null; } /* Generate IR for a builtin. */ static LLVMValueRef llvm_expr_builtin(ast *a, syt *st) { assert(A.k == AK_BUILTIN); - + ast *sym = syt_search_h(st, C[0]->h, C[0]->s); if (sym == null) { note(file_name, A.ln, A.cl, -1, "Undefined builtin \"%s\" (llvm:llvm_expr_builtin)", C[0]->s); } - + if (strncmp(sym->s, "cstring", 7) == 0) { assert(CL == 2); if (ast_type(C[1], st)->k != TY_STRING) { panic("cstring builtin only takes strings, not \"%s\"s", ast_type(C[1], st)->s); } - + LLVMValueRef idc[2] = { LLVMConstInt(LLVMIntType(32), 0, false), LLVMConstInt(LLVMIntType(32), 0, false) }; LLVMValueRef v = LLVMBuildInBoundsGEP2(llvm_builder, llvm_type(ast_type(C[1], st)), llvm_expr(C[1], st, false), idc, 2, ""); return LLVMBuildLoad2(llvm_builder, LLVMPointerType(LLVMIntType(8), 0), v, ""); @@ -492,67 +492,67 @@ static LLVMValueRef llvm_expr_builtin(ast *a, syt *st) { else if (strncmp(sym->s, "len", 3) == 0) { assert(CL == 2); if (ast_type(C[1], st)->k != TY_STRING) { panic("len builtin only takes strings, not \"%s\"s", ast_type(C[1], st)->s); } - + LLVMValueRef idc[2] = { LLVMConstInt(LLVMIntType(32), 0, false), LLVMConstInt(LLVMIntType(32), 1, false) }; LLVMValueRef v = LLVMBuildInBoundsGEP2(llvm_builder, llvm_type(ast_type(C[1], st)), llvm_expr(C[1], st, false), idc, 2, ""); return LLVMBuildLoad2(llvm_builder, LLVMIntType(64), v, ""); } - + return null; } /* Generate IR for a hash procedure. */ static LLVMValueRef llvm_expr_hash(ast *a, syt *st) { assert(A.k == AK_HASH_SYSCALL); - + LLVMValueRef args[CL]; LLVMTypeRef argt[CL]; for (uptr i = 0; i < CL; i += 1) { args[i] = llvm_expr(C[i], st, true); argt[i] = llvm_type(ast_type(C[i], st)); } - + LLVMTypeRef func_type = LLVMFunctionType(llvm_type(&TYPE(TY_SINT)), argt, CL, false); LLVMValueRef inline_asm = null; - + /* TODO check architecture */ /* x86-64 */ { assert(CL <= 7); - + char constraints[128] = "={rax}"; - + char const *registers[] = { "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9" }; for (uptr i = 0; i < CL; i += 1) { strcat(constraints, ",{"); strcat(constraints, registers[i]); strcat(constraints, "}"); } - + strcat(constraints, ",~{rcx},~{r11},~{memory}"); - + inline_asm = LLVMGetInlineAsm( func_type, "syscall", 7, constraints, strlen(constraints), true, false, LLVMInlineAsmDialectATT, false ); } - + return LLVMBuildCall2(llvm_builder, func_type, inline_asm, args, CL, ""); } /* Generate IR for a string constant. */ static LLVMValueRef llvm_str(ast *a, syt *st, bool load) { assert(A.k == AK_STR); - + LLVMValueRef va[2] = { LLVMBuildGlobalString(llvm_builder, A.s, "string"), LLVMConstInt(LLVMIntType(64), strlen(A.s), false) }; - + LLVMValueRef vs = LLVMAddGlobal(llvm_module, llvm_type(&TYPE(TY_STRING)), "string"); LLVMSetInitializer(vs, LLVMConstNamedStruct(llvm_type(&TYPE(TY_STRING)), va, 2)); LLVMSetGlobalConstant(vs, true); LLVMSetLinkage(vs, LLVMPrivateLinkage); LLVMSetUnnamedAddress(vs, LLVMGlobalUnnamedAddr); LLVMSetAlignment(vs, 8); - + if (!load) { return vs; } else { return LLVMBuildLoad2(llvm_builder, llvm_type(&TYPE(TY_STRING)), vs, ""); } } @@ -560,11 +560,11 @@ static LLVMValueRef llvm_str(ast *a, syt *st, bool load) { /* 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 (uptr i = 0; i < CL; i += 1) { va[i] = llvm_expr(C[i], st, true); } - + return LLVMConstArray(llvm_type(C[0]->t), va, CL); } @@ -634,7 +634,7 @@ static LLVMValueRef llvm_ival(type *t) { LLVMBuildGlobalString(llvm_builder, "", ""), LLVMConstInt(LLVMIntType(64), 0, false) }; - + vs = LLVMAddGlobal(llvm_module, llvm_type(&TYPE(TY_STRING)), ""); LLVMSetInitializer(vs, LLVMConstNamedStruct(llvm_type(&TYPE(TY_STRING)), va, 2)); LLVMSetGlobalConstant(vs, true); diff --git a/src/llvm/attr.c b/src/llvm/attr.c index 2e9a72d..8deaf52 100644 --- a/src/llvm/attr.c +++ b/src/llvm/attr.c @@ -20,7 +20,7 @@ static char *llvm_func_attr_s[] = { int LLVMAddFuncAttr(LLVMContextRef C, LLVMValueRef F, llvm_func_attr attr, unsigned index) { u32 ak = LLVMGetEnumAttributeKindForName(llvm_func_attr_s[attr], strlen(llvm_func_attr_s[attr])); if (ak == 0) { dprint(null, 0, 0, "Attribute \"%s\" does not exist", llvm_func_attr_s[attr]); return -1; } - + LLVMAttributeRef ar = LLVMCreateEnumAttribute(C, ak, 0); LLVMAddAttributeAtIndex(F, index, ar); return 0; } diff --git a/src/log.c b/src/log.c index 67232e5..bd7bfa6 100644 --- a/src/log.c +++ b/src/log.c @@ -17,16 +17,16 @@ static sptr log_count = 0; /* Log a compiler fatal (-1), error (0), warning (1-3), or note (4). */ void note(const char *file, uptr ln, uptr cl, sptr level, const char *format, ...) { if (file) { fprintf(stderr, "%s:%lu:%lu: ", file, ln + 1, cl + 1); } - + if (level <= -1) { fprintf(stderr, "fatal: "); } else if (level == 9) { fprintf(stderr, "debug: "); } else if (level == 0) { fprintf(stderr, "error: "); } else if (level <= 3) { fprintf(stderr, "warning: "); } else if (level >= 4) { fprintf(stderr, "note: "); } - + va_list va; va_start(va, format); vfprintf(stderr, format, va); va_end(va); fputc('\n', stderr); if (level <= -1) { exit(1); } - + if (level == 0 && (log_count += 1) == log_limit) { fprintf(stderr, "fatal: error limit reached"); exit(1); } } diff --git a/src/main.c b/src/main.c index 2de3fd6..dfe098d 100644 --- a/src/main.c +++ b/src/main.c @@ -39,7 +39,7 @@ int main(int ac, char *av[]) { A0 = av[0]; { "version", ARG_NUL, 257 }, { null, 0, 0 } }; - + for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { case 'b': { args.bflag = true; } break; /* Output LLVM IR files */ case 'B': { args.Bflag = true; } break; /* Output LLVM bitcode files */ @@ -58,45 +58,45 @@ int main(int ac, char *av[]) { A0 = av[0]; case 257: { fputs(version, stdout); } return 0; default: {} return 1; } - + if (opt.ind == ac) { error(1, "Missing operand"); } else for (char **p = &av[opt.ind]; *p; ++p) { compile_file(*p); } - + return 0; } static void compile(const char * file, char *src, uptr len) { initialise(); - + lex l = lex_init(file, src, len); if (args.Eflag) { lex_debug(&l); goto end; } - + ast *a = parse(&l); if (args.pflag) { if (!args.qflag) { ast_print(a, 0); } goto end; } if (has_error()) { exit(1); } - + assert(a->k == AK_PROG); analyse(a); if (args.Pflag) { if (!args.qflag) { ast_print(a, 0); } goto end; } if (has_error()) { exit(1); } - + if (args.bflag) { llvm(a, strdup(file), llvm_ir); } else if (args.Bflag) { llvm(a, strdup(file), llvm_bc); } else if (args.Sflag) { llvm(a, strdup(file), llvm_asm); } else { llvm(a, strdup(file), llvm_obj); } if (has_error()) { exit(1); } - + end:; return; } static void compile_file(const char *file) { FILE *fi; char *fb; size_t fl; - + if (!(fi = fopen(file, "r"))) { error(1, "%s: %s", file, SERR); } fseek(fi, 0, SEEK_END); fl = ftell(fi); rewind(fi); - + fb = malloc((fl + 1) * sizeof (*fb)); fread(fb, 1, fl, fi); fb[fl] = 0; fclose(fi); - + compile(file, fb, fl); free(fb); return; } diff --git a/src/parse.c b/src/parse.c index 3e71095..82c36f5 100644 --- a/src/parse.c +++ b/src/parse.c @@ -18,23 +18,23 @@ typedef struct { type *t; ast *a; } ta_pair; char *ast_ks[] = { "AK_VOID", "AK_PROG", "AK_ID", "AK_BOOL", "AK_INT", "AK_FLT", "AK_STR", - + "AK_PROC", "AK_TYPE", "AK_CAST", - + "AK_COMP", "AK_DECL", "AK_RETURN", "AK_IF", "AK_FOR", - + "AK_OP_POS", "AK_OP_NEG", "AK_OP_ADO", "AK_OP_DRF", "AK_OP_ADD", "AK_OP_SUB", "AK_OP_MUL", "AK_OP_DIV", "AK_OP_MOD", - + "AK_EQ", "AK_NE", "AK_LT", "AK_LE", "AK_GT", "AK_GE", - + "AK_LO_NOT", "AK_LO_AND", "AK_LO_OR", "AK_BW_NOT", "AK_BW_AND", "AK_BW_OR", "AK_BW_XOR", "AK_BW_SHL", "AK_BW_SHR", - + "AK_ASSIGN", "AK_AS_ADD", "AK_AS_SUB", "AK_AS_MUL", "AK_AS_DIV", "AK_AS_MOD", - + "AK_CALL", "AK_ARR", "AK_SUBS", - + "AK_HASH", "AK_HASH_SYSCALL", "AK_BUILTIN" }; @@ -77,10 +77,10 @@ inline void ast_free(ast **a) { /* Push a child AST node to an AST node. */ void ast_push(ast *a, ast *c) { assert(a != null); assert(c != null); - + ast **ca = realloc(a->c.a, (a->c.al += 1) * sizeof (ast *)); if (!ca) { panic(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; @@ -89,17 +89,17 @@ void ast_push(ast *a, ast *c) { /* Displace a child AST node from a parent AST node. */ void ast_displace(ast *a, ast *c) { ast **oa = a->c.a; uptr ol = a->c.al; bool found = false; - + for (uptr i = 0; i < ol; i += 1) { if (oa[i] == c) { found = true; break; }} if (!found) { return; } - + ast **ca = calloc((a->c.al -= 1), sizeof (ast *)); if (!ca) { panic(SERR); } else { a->c.a = ca; ca = null; } - + for (uptr i = 0, j = 0; i < ol && j < a->c.al; i += 1) { if (oa[i] == c) { continue; } a->c.a[j] = oa[i]; j += 1; } - + c->p = null; free(oa); } @@ -107,10 +107,10 @@ void ast_displace(ast *a, ast *c) { void ast_wrap(ast *const a, ast *const c, ast *const w) { assert(a != null); assert(c != null); assert(w != null); ast **oa = a->c.a; uptr ol = a->c.al, ifound; bool found = false; - + for (uptr i = 0; i < ol; i += 1) { if (oa[i] == c) { found = true; ifound = i; break; }} if (!found) { panic("ast_wrap called with an unrelated parent and child"); } - + w->p = a; a->c.a[ifound] = w; c->p = null; ast_push(w, c); } @@ -118,7 +118,7 @@ void ast_wrap(ast *const a, ast *const c, ast *const w) { type *ast_type(ast *a, syt *st) { /* If the given node has a type, then return that */ if (a->t && !is_proc(a->t)) { return a->t; } - + /* Search the symbol table for a type first */ if (a->s) { ast *sym = syt_search(st, a->s); @@ -127,14 +127,14 @@ type *ast_type(ast *a, syt *st) { else { return sym->t; } } } - + /* Otherwise recurse down the first child */ if (a->c.al) { type *rt = ast_type(a->c.a[0], st); if (a->k == AK_SUBS) { return rt->base; } else { return rt; } } - + /* If no type is found, return null */ return null; } @@ -157,13 +157,13 @@ ast *ast_a_pop(ast_a *aa) { /* Parse a program. */ ast *parse(lex *l) { ast *a = ast_init(AK_PROG, 0, 0); - + /* Parse and append all child nodes */ for (ast *c; T.k != TK_EOF;) { if ((c = parse_stmt_decl(l, &a->st, true)) != null) { ast_push(a, c); } else { note(l->n, T.ln, T.cl, -1, "null AST (parse:parse_stmt_decl)"); } } - + return a; } @@ -201,9 +201,9 @@ static ast *parse_stmt_init(lex *l, syt *st) { static ast *parse_stmt_compound(lex *l, syt *st) { ast *a = ast_init(AK_COMP, T.ln, T.cl); lex_kind(l, TK_LBRACE); a->st.pt = st; - + for (; T.k != TK_EOF && T.k != TK_RBRACE;) { ast_push(a, parse_stmt(l, &a->st)); } - + lex_kind(l, TK_RBRACE); return a; } @@ -211,20 +211,20 @@ static ast *parse_stmt_compound(lex *l, syt *st) { static ast *parse_stmt_decl(lex *l, syt *st, bool scolon) { ast *a = ast_init(AK_DECL, T.ln, T.cl); a->h = T.h; a->s = T.s; lex_kind(l, TK_ID); lex_kind(l, TK_COLON); - + /* Store the declaration's type if one is specified */ if (T.k == TK_ID || T.k == TK_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)); } - + /* Ensure that a type is known and consume a semicolon if one is required */ if (a->t == null && CL(a) == 0) { note(l->n, T.ln, T.cl, 0, "A declaration without a type is invalid"); } if (scolon && (CL(a) < 1 || C(a)[0]->k != AK_PROC)) { lex_kind(l, TK_SCOLON); } - + /* Insert the new symbol and return */ syt_insert_h(st, a->h, a->s, a); return a; } @@ -238,23 +238,23 @@ static ast *parse_stmt_expr(lex *l, syt *st) { /* Parse a return statement. */ static ast *parse_stmt_return(lex *l, syt *st) { assert(T.k == TK_RETURN); - + ast *a = ast_init(AK_RETURN, T.ln, T.cl); lex_next(l); if (T.k != TK_SCOLON) { ast_push(a, parse_expr(l, st, 0)); } - + lex_kind(l, TK_SCOLON); return a; } /* Parse an if statement. AK_IF has a scope. */ static ast *parse_stmt_if(lex *l, syt *st) { assert(T.k == TK_IF); - + ast *a = ast_init(AK_IF, T.ln, T.cl); lex_next(l); lex_kind(l, TK_LPAREN); a->st.pt = st; - + if (T.k != TK_RPAREN) { register ast *c1 = parse_stmt_init(l, &a->st); - + if (T.k == TK_SCOLON) { lex_next(l); ast_push(a, c1); ast_push(a, parse_expr(l, &a->st, 0)); @@ -265,32 +265,32 @@ static ast *parse_stmt_if(lex *l, syt *st) { } } else { note(l->n, T.ln, T.cl, 0, "Expected an expression"); } - + lex_kind(l, TK_RPAREN); - + /* Parse the if statement body */ ast_push(a, parse_stmt(l, &a->st)); - + /* Parse an else statement if present */ if (T.k == TK_ELSE) { lex_next(l); ast_push(a, parse_stmt(l, &a->st)); } - + return a; } /* Parse a for statement. AK_FOR has a scope. */ static ast *parse_stmt_for(lex *l, syt *st) { assert(T.k == TK_FOR); - + ast *a = ast_init(AK_FOR, T.ln, T.cl); lex_next(l); lex_kind(l, TK_LPAREN); a->st.pt = st; - + if (T.k != TK_RPAREN) { register ast *c1 = parse_stmt_init(l, &a->st); - + if (T.k == TK_SCOLON) { lex_next(l); ast_push(a, c1); ast_push(a, parse_expr(l, &a->st, 0)); - + lex_kind(l, TK_SCOLON); ast_push(a, parse_expr(l, &a->st, 0)); } @@ -300,12 +300,12 @@ static ast *parse_stmt_for(lex *l, syt *st) { } } else { note(l->n, T.ln, T.cl, 0, "Expected an expression"); } - + lex_kind(l, TK_RPAREN); - + /* Parse the for statement body */ ast_push(a, parse_stmt(l, &a->st)); - + return a; } @@ -346,27 +346,27 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { prefix: { lex_next(l); ast_push(left, parse_expr(l, st, ast_precedence(left->k))); } break; default: { note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting an expression", tok_ks[T.k]); } break; } - + /* Parse an infix expression if one is present */ for (ast *a = null; tok_precedence(T.k) > o; left = a) switch (T.k) { case TK_LPAREN: { if (left->k == AK_HASH) { a = left; } else { a = ast_init(AK_CALL, left->ln, left->cl); ast_push(a, left); } - + lex_next(l); - + /* Parse call arguments if present */ if (T.k != TK_RPAREN) for (;;) { ast_push(a, parse_expr(l, st, 0)); if (T.k == TK_COMMA) { lex_next(l); } else { break; } } - + lex_kind(l, TK_RPAREN); } break; case TK_LBRACK: { a = ast_init(AK_SUBS, T.ln, T.cl); lex_next(l); ast_push(a, left); - + ast_push(a, parse_expr(l, st, 0)); lex_kind(l, TK_RBRACK); } break; @@ -392,54 +392,54 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { 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; } /* 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. AK_PROC has a scope. */ 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); a->st.pt = st; - + /* Parse optional procedure parameter(s) */ 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_ID) { 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, &a->st)); return a; } @@ -447,13 +447,13 @@ static ast *parse_expr_proc(lex *l, syt *st) { 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) { case TK_MUL: { lex_next(l); t = type_ptr(null, 1); } goto store; case TK_LBRACK: { lex_next(l); - + /* TODO handle variable array length */ if (T.k != TK_RBRACK) { assert(T.k == TK_INT); @@ -461,56 +461,56 @@ static inline ta_pair parse_type(lex *l, syt *st) { t = type_arr(null, a->v_int); } else { t = type_arr(null, -1); } - + lex_kind(l, TK_RBRACK); } goto store; store: { if (r == null) { r = c = t; } else { c = (c->base = t); }} break; default: { goto escape; } } escape:; - + /* Parse the base type identifier */ tok t = lex_kind(l, TK_ID); ast *s = syt_search_h(st, t.h, t.s); 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 (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; } } /* Parse an integer. AK_INT is terminal. */ static inline ast *parse_int(lex *l, syt *st) { assert(T.k == TK_INT); - + tok t = lex_next(l); ast *a = ast_init(AK_INT, t.ln, t.cl); - + a->s = strdup_or_fail(t.s); a->v_int = t.v_int; - + /* Determine the minimum integer type */ 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 floating-point number. AK_FLT is terminal. */ static inline ast *parse_flt(lex *l, syt *st) { assert(T.k == TK_FLT); - + tok t = lex_next(l); ast *a = ast_init(AK_FLT, t.ln, t.cl); - + a->s = strdup_or_fail(t.s); a->v_flt = t.v_flt; - + /* Determine the minimum float type */ 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; } @@ -565,10 +565,10 @@ static inline char *strdup_or_fail(const char *s) { /* Recursively print an AST. */ void ast_print(ast *a, uptr indent) { for (uptr i = 0; i < indent; ++i) { printf(" "); } - + /* Print basic AST information (line:column: kind "string") */ printf("%zu:%zu: %s \"%s\"", a->ln + 1, a->cl + 1, ast_ks[a->k], a->s); - + /* Print type information if present */ if (a->t != null) { fputs(" -> ", stdout); } for (type *t = a->t; t != null; t = t->base) switch (t->k) { @@ -576,13 +576,13 @@ void ast_print(ast *a, uptr indent) { 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->st.a != null ? 's' : '-', stdout); fputc(']', stdout); - + /* Indicate if the AST node has a value */ switch (a->k) { case AK_BOOL: { printf(a->v_bool ? " = true" : " = false"); } break; @@ -590,21 +590,21 @@ void ast_print(ast *a, uptr indent) { case AK_FLT: { printf(" = %Lf", a->v_flt); } break; default: { /* Ignored */ } break; } - + /* Indicate if the AST node has no parent */ if (a->p == null) { printf(" NO PARENT"); } - + fputc('\n', stdout); - + /* Print AST children */ for (uptr i = 0; i < a->c.al; i += 1) { ast_print(a->c.a[i], indent + 1); } - + if (a->st.a != null) { printf("--- SYT for %s \"%s\"%s ---\n", ast_ks[a->k], a->s, a->st.pt == null ? " NO PARENT" : ""); syt_print(&a->st); printf("--- SYT for %s \"%s\"%s ---\n", ast_ks[a->k], a->s, a->st.pt == null ? " NO PARENT" : ""); } - + return; } diff --git a/src/parse.h b/src/parse.h index bc043a7..d321d26 100644 --- a/src/parse.h +++ b/src/parse.h @@ -14,23 +14,23 @@ /* Remember to update ast_ks in parse.c */ typedef enum { AK_VOID, AK_PROG, AK_ID, AK_BOOL, AK_INT, AK_FLT, AK_STR, - + AK_PROC, AK_TYPE, AK_CAST, - + AK_COMP, AK_DECL, AK_RETURN, AK_IF, AK_FOR, - + AK_POS, AK_NEG, AK_ADO, AK_DRF, AK_ADD, AK_SUB, AK_MUL, AK_DIV, AK_MOD, - + AK_EQ, AK_NE, AK_LT, AK_LE, AK_GT, AK_GE, - + AK_LO_NOT, AK_LO_AND, AK_LO_OR, AK_BW_NOT, AK_BW_AND, AK_BW_OR, AK_BW_XOR, AK_BW_SHL, AK_BW_SHR, - + AK_ASSIGN, AK_AS_ADD, AK_AS_SUB, AK_AS_MUL, AK_AS_DIV, AK_AS_MOD, - + AK_CALL, AK_ARR, AK_SUBS, - + AK_HASH, AK_HASH_SYSCALL, AK_BUILTIN } ast_k; @@ -43,7 +43,7 @@ typedef struct ast_s { ast_k k; uptr ln, cl; u64 h; char *s; type *t; syt st; struct ast_s *p; struct { struct ast_s **a; uptr al; } c; 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 21629c1..69bab3a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -25,12 +25,12 @@ syt *syt_aloc(void) { return calloc(1, sizeof (syt)); } /* Uninitialise a symbol table. */ void syt_free(syt *st) { if (st == null || st->a == null) { return; } - + for (uptr i = 0; i < st->ac; i += 1) { if (st->a[i].h == 0) { continue; } free(st->a[i].k); /*free(s->a[i].v)*/ } - + free(st->a); *st = (syt){ null, 0, 0 }; } @@ -68,22 +68,22 @@ ast *syt_search(syt *st, char *k) { void syt_insert_h(syt *st, u64 h, char *k, ast *v) { if (st->ac == 0 || st->al >= ((f64)st->ac * LOAD_FACTOR)) { syt_resize(st); } uptr i = h % st->ac; k = strdup(k); - + for (uptr dist = 0;; i = (i + 1) % st->ac, dist += 1) { if (st->a[i].h == 0) { /* If an empty bucket is found, insert here */ st->a[i] = (typeof (*st->a)){ h, k, v }; st->al += 1; return; } - + /* Calculate tsid, the DIB of the item at the current index */ uptr tsid = (i + st->ac - (st->a[i].h % st->ac)) % st->ac; - + if (dist > tsid) { SWAP(st->a[i].h, h); SWAP(st->a[i].k, k); SWAP(st->a[i].v, v); - + dist = tsid; } } @@ -92,12 +92,12 @@ void syt_insert_h(syt *st, u64 h, char *k, ast *v) { /* Lookup a key-value pair from a map using a precalculated hash. */ ast *syt_lookup_h(syt *st, u64 h, char *k) { if (st->a == null) { return null; } - + uptr i = h % st->ac; - + for (uptr dist = 0;; i = (i + 1) % st->ac, dist += 1) { if (st->a[i].h == 0) { return null; } - + if (dist > DIB(i)) { return null; /* ? */ } if ((st->a[i].h == h) && (strcmp(st->a[i].k, k) == 0)) { return st->a[i].v; @@ -108,27 +108,27 @@ ast *syt_lookup_h(syt *st, u64 h, char *k) { /* Remove a key-value pair from a map using a precalculated hash. */ void syt_remove_h(syt *st, u64 h, char *k) { if (st->a == null) { return; } - + uptr i = h % st->ac; - + for (uptr dist = 0;; i = (i + 1) % st->ac, dist += 1) { if (st->a[i].h == 0) { return; } - + if (dist > DIB(i)) { return; } if ((st->a[i].h == h) && (strcmp(st->a[i].k, k) == 0)) { /* If the element to be removed is found, then deallocate it */ free(st->a[i].k); st->a[i] = (typeof (*st->a)){ 0, null, null }; st->al -= 1; - + /* */ for (uptr j = (i + 1) % st->ac;; i = j, j = (j + 1) % st->ac) { if (st->a[j].h == 0 || DIB(j) == 0) { break; } - + SWAP(st->a[i].h, st->a[j].h); SWAP(st->a[i].k, st->a[j].k); SWAP(st->a[i].v, st->a[j].v); } - + return; } } @@ -138,12 +138,12 @@ void syt_remove_h(syt *st, u64 h, char *k) { ast *syt_search_h(syt *st, u64 h, char *k) { ast *sm = syt_lookup_h(&kwt, h, k); if (sm != null) { return sm; } - + for (; st != null; st = st->pt) { sm = syt_lookup_h(st, h, k); if (sm != null) { return sm; } } - + return null; } @@ -151,7 +151,7 @@ ast *syt_search_h(syt *st, u64 h, char *k) { void syt_print(syt *st) { for (uptr i = 0; i < st->ac; i += 1) if (st->a[i].h != 0) { 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 (uptr j = 0; j < st->a[i].v->c.al - 1; j += 1) { @@ -159,14 +159,14 @@ void syt_print(syt *st) { } 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) { 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); } } @@ -189,17 +189,17 @@ static void syt_resize(syt *st) { st->ac = INITIAL_CAPACITY; st->a = calloc(st->ac, sizeof (*st->a)); return; } - + /* Otherwise rehash every element into a new resized map */ syt old = *st; st->ac *= 2; st->al = 0; st->a = calloc(st->ac, sizeof (*st->a)); - + for (uptr i = 0; i < old.ac; i += 1) { if (old.a[i].h == 0) { continue; } - + syt_insert(st, old.a[i].k, old.a[i].v); free(old.a[i].k); } - + free(old.a); } diff --git a/src/type.c b/src/type.c index 40c37b7..f12616d 100644 --- a/src/type.c +++ b/src/type.c @@ -12,42 +12,42 @@ type types[] = { { TY_ARR, 0, -1, "arr" }, { TY_TYPE, 0, -1, "type" }, { TY_PROC, 0, -1, "proc" }, - + { TY_BOOL, TF_BOOL, 1, "bool" }, { TY_B8, TF_BOOL, 1, "b8" }, { TY_B16, TF_BOOL, 2, "b16" }, { TY_B32, TF_BOOL, 4, "b32" }, { TY_B64, TF_BOOL, 8, "b64" }, - + { TY_UINT, TF_INT, -2, "uint" }, { TY_U8, TF_INT, 1, "u8" }, { TY_U16, TF_INT, 2, "u16" }, { TY_U32, TF_INT, 4, "u32" }, { TY_U64, TF_INT, 8, "u64" }, { TY_U128, TF_INT, 16, "u128" }, - + { TY_SINT, TF_INT | TF_SIGN, -2, "sint" }, { TY_S8, TF_INT | TF_SIGN, 1, "s8" }, { TY_S16, TF_INT | TF_SIGN, 2, "s16" }, { TY_S32, TF_INT | TF_SIGN, 4, "s32" }, { TY_S64, TF_INT | TF_SIGN, 8, "s64" }, { TY_S128, TF_INT | TF_SIGN, 16, "s128" }, - + { TY_F16, TF_FLT | TF_SIGN, 2, "f16" }, { TY_F32, TF_FLT | TF_SIGN, 4, "f32" }, { TY_F64, TF_FLT | TF_SIGN, 8, "f64" }, { TY_F128, TF_FLT | TF_SIGN, 16, "f128" }, - + { TY_C32, TF_CLX | TF_SIGN, 4, "c32" }, { TY_C64, TF_CLX | TF_SIGN, 8, "c64" }, { TY_C128, TF_CLX | TF_SIGN, 16, "c128" }, { TY_C256, TF_CLX | TF_SIGN, 32, "c256" }, - + { TY_Q64, TF_QTN | TF_SIGN, 8, "q64" }, { TY_Q128, TF_QTN | TF_SIGN, 16, "q128" }, { TY_Q256, TF_QTN | TF_SIGN, 32, "q256" }, { TY_Q512, TF_QTN | TF_SIGN, 64, "q512" }, - + { TY_U16LE, TF_INT | TF_LE, 2, "u16le" }, { TY_U32LE, TF_INT | TF_LE, 4, "u32le" }, { TY_U64LE, TF_INT | TF_LE, 8, "u64le" }, @@ -56,7 +56,7 @@ type types[] = { { TY_U32BE, TF_INT | TF_BE, 4, "u32be" }, { TY_U64BE, TF_INT | TF_BE, 8, "u64be" }, { TY_U128BE, TF_INT | TF_BE, 16, "u128be" }, - + { TY_S16LE, TF_INT | TF_SIGN | TF_LE, 2, "s16le" }, { TY_S32LE, TF_INT | TF_SIGN | TF_LE, 4, "s32le" }, { TY_S64LE, TF_INT | TF_SIGN | TF_LE, 8, "s64le" }, @@ -65,7 +65,7 @@ type types[] = { { TY_S32BE, TF_INT | TF_SIGN | TF_BE, 4, "s32be" }, { TY_S64BE, TF_INT | TF_SIGN | TF_BE, 8, "s64be" }, { TY_S128BE, TF_INT | TF_SIGN | TF_BE, 16, "s128be" }, - + { TY_F16LE, TF_FLT | TF_SIGN | TF_LE, 2, "f16le" }, { TY_F32LE, TF_FLT | TF_SIGN | TF_LE, 4, "f32le" }, { TY_F64LE, TF_FLT | TF_SIGN | TF_LE, 8, "f64le" }, @@ -74,7 +74,7 @@ type types[] = { { TY_F32BE, TF_FLT | TF_SIGN | TF_BE, 4, "f32be" }, { TY_F64BE, TF_FLT | TF_SIGN | TF_BE, 8, "f64be" }, { TY_F128BE, TF_FLT | TF_SIGN | TF_BE, 16, "f128be" }, - + { TY_C32LE, TF_CLX | TF_SIGN | TF_LE, 4, "c32le" }, { TY_C64LE, TF_CLX | TF_SIGN | TF_LE, 8, "c64le" }, { TY_C128LE, TF_CLX | TF_SIGN | TF_LE, 16, "c128le" }, @@ -83,7 +83,7 @@ type types[] = { { TY_C64BE, TF_CLX | TF_SIGN | TF_BE, 8, "c64be" }, { TY_C128BE, TF_CLX | TF_SIGN | TF_BE, 16, "c128be" }, { TY_C256BE, TF_CLX | TF_SIGN | TF_BE, 32, "c256be" }, - + { TY_Q64LE, TF_CLX | TF_SIGN | TF_LE, 8, "q64le" }, { TY_Q128LE, TF_CLX | TF_SIGN | TF_LE, 16, "q128le" }, { TY_Q256LE, TF_CLX | TF_SIGN | TF_LE, 32, "q256le" }, @@ -92,7 +92,7 @@ type types[] = { { TY_Q128BE, TF_CLX | TF_SIGN | TF_BE, 16, "q128be" }, { TY_Q256BE, TF_CLX | TF_SIGN | TF_BE, 32, "q256be" }, { TY_Q512BE, TF_CLX | TF_SIGN | TF_BE, 4, "q512be" }, - + { TY_BYTE, TF_INT, 1, "byte" }, { TY_CHAR, TF_INT | TF_CHAR, 1, "char" }, { TY_RUNE, TF_INT | TF_CHAR, 4, "rune" }, @@ -107,10 +107,10 @@ static inline void types_alloc(type_a *ta, u64 min) { ta->ac = 128; ta->a = malloc(ta->ac * sizeof (type)); if (ta->a == null) { error(1, "types: %s", SERR); } } - + register u64 mul = 1, sp = ta->ac - ta->al; for (; sp < min; mul *= 2, sp = (ta->ac * mul) - ta->al); - + if (mul > 1) { ta->ac *= mul; ta->a = realloc(ta->a, ta->ac * sizeof (type)); if (ta->a == null) { error(1, "types: %s", SERR); } @@ -126,22 +126,22 @@ static inline type *types_next(type_a *ta) { /* Initialise a new pointer type. */ type *type_ptr(type *base, u64 n) { types_alloc(&types_a, n); type *r = base; - + for (u64 i = 0; i < n; i += 1) { register type *t = types_next(&types_a); *t = TYPE(TY_PTR); t->base = r; r = t; } - + return r; } /* Initialise a new array type. */ type *type_arr(type *base, u64 l) { types_alloc(&types_a, 1); - + type *t = types_next(&types_a); *t = TYPE(TY_ARR); t->l = l; t->base = base; - + return t; } @@ -167,21 +167,21 @@ inline bool is_sign(type *t) { return (t->f & TF_SIGN); } inline bool is_equal(type *t1, type *t2) { if (t1 == null || t2 == null) { return false; } if (t1 == t2) { return true; } - + if (t1->k != t2->k) { return false; } if (t1->f != t2->f) { return false; } if (t1->l != t2->l) { return false; } - + /* 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->k != b2->k) { return false; } if (b1->f != b2->f) { return false; } if (b1->l != b2->l) { return false; } } - + return true; } @@ -189,9 +189,9 @@ inline bool is_equal(type *t1, type *t2) { inline bool is_com(type *t1, type *t2) { if (t1 == null || t2 == null) { return false; } if (is_equal(t1, t2)) { return true; } - + if (is_int(t1) && is_int(t2)) { return true; } if (is_flt(t1) && is_flt(t2)) { return true; } - + return false; } diff --git a/src/type.h b/src/type.h index 67472a0..7f1647f 100644 --- a/src/type.h +++ b/src/type.h @@ -10,31 +10,31 @@ typedef enum { TY_VOID, TY_PTR, TY_ARR, TY_TYPE, TY_PROC, - + TY_BOOL, TY_B8, TY_B16, TY_B32, TY_B64, - + TY_UINT, TY_U8, TY_U16, TY_U32, TY_U64, TY_U128, TY_SINT, TY_S8, TY_S16, TY_S32, TY_S64, TY_S128, - + TY_F16, TY_F32, TY_F64, TY_F128, TY_C32, TY_C64, TY_C128, TY_C256, TY_Q64, TY_Q128, TY_Q256, TY_Q512, - + TY_U16LE, TY_U32LE, TY_U64LE, TY_U128LE, TY_U16BE, TY_U32BE, TY_U64BE, TY_U128BE, - + TY_S16LE, TY_S32LE, TY_S64LE, TY_S128LE, TY_S16BE, TY_S32BE, TY_S64BE, TY_S128BE, - + TY_F16LE, TY_F32LE, TY_F64LE, TY_F128LE, TY_F16BE, TY_F32BE, TY_F64BE, TY_F128BE, - + TY_C32LE, TY_C64LE, TY_C128LE, TY_C256LE, TY_C32BE, TY_C64BE, TY_C128BE, TY_C256BE, - + TY_Q64LE, TY_Q128LE, TY_Q256LE, TY_Q512LE, TY_Q64BE, TY_Q128BE, TY_Q256BE, TY_Q512BE, - + TY_BYTE, TY_CHAR, TY_RUNE, TY_STRING, } type_k; @@ -43,10 +43,10 @@ typedef enum { TF_BOOL = BIT(2), TF_INT = BIT(3), TF_FLT = BIT(4), TF_CLX = BIT(5), TF_QTN = BIT(6), TF_SIGN = BIT(7), - + TF_LE = BIT(14), TF_BE = BIT(15), TF_CHAR = BIT(16), TF_STRING = BIT(17), - + TF_NUM = TF_INT | TF_FLT | TF_CLX, } type_f; diff --git a/src/util/optget.c b/src/util/optget.c index 630a556..12f103d 100644 --- a/src/util/optget.c +++ b/src/util/optget.c @@ -20,20 +20,20 @@ int optget(struct opt *opt, char *av[], int flags) { if (!cur) { opt->ind -= opt->nop; opt->nop = 0; return -1; } } else if (!cur || (cur[0] != '-' || cur[1] == 0)) { return -1; } - + int optind = opt->ind, optret; - + if (cur[1] == '-') { if (cur[2] == 0) { if (opt->nop) { permute(av, opt->ind++, opt->nop); opt->ind -= opt->nop; opt->nop = 0; } else { ++opt->ind; } return -1; } - + int optend, lop; optret = '?'; opt->opt = 0; opt->lop = cur; if (!opt->lops) { goto nol; } for (optend = 2; cur[optend] != '=' && cur[optend] != 0; ++optend); - + for (lop = 0; opt->lops[lop].str; ++lop) { if (strncmp(&cur[2], opt->lops[lop].str, (size_t)optend - 2) == 0) { if (!opt->lops[lop].str[optend - 2]) { @@ -41,7 +41,7 @@ int optget(struct opt *opt, char *av[], int flags) { } } } - + if (opt->lops[lop].arg > ARG_NUL) { if (cur[optend]) { opt->arg = &cur[optend + 1]; } else if (av[opt->ind + 1]) { opt->arg = av[++opt->ind]; } @@ -51,13 +51,13 @@ int optget(struct opt *opt, char *av[], int flags) { } } else { opt->arg = NULL; } - + nol: opt->pos = 0; } else { optret = opt->opt = cur[opt->pos++]; opt->lop = NULL; const char *optchr = strchr(opt->str, opt->opt); - + if (!optchr) { optret = '?'; } else if (optchr[1] == ':') { if (cur[opt->pos]) { opt->arg = &cur[opt->pos]; } @@ -67,14 +67,14 @@ nol: opt->pos = 0; } else { opt->arg = NULL; } } - + if (!opt->pos || !cur[opt->pos]) { ++opt->ind; opt->pos = 1; if (opt->nop) for (; optind < opt->ind; ++optind) { permute(av, optind, opt->nop); } } - + if (optret == '?' && opt->str[0] != ':') { if (opt->opt) { warn("%c: invalid option", opt->opt); } else if (opt->lop) { warn("%s: invalid option", opt->lop); } @@ -83,7 +83,7 @@ nol: opt->pos = 0; if (opt->opt) { warn("%c: option requires argument", opt->opt); } else if (opt->lop) { warn("%s: option requires argument", opt->lop); } } - + return optret; }