From 9e127d92246d6577792122b013088466e3688da1 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sat, 22 Jun 2024 08:24:53 +0200 Subject: Store decl info in auxilliary data --- src/analyzer.c | 95 +++++++++++++++++++++++++--------------------------- src/analyzer.h | 4 +-- src/codegen.c | 59 ++++++++++++++++++++++++-------- src/main.c | 6 ++-- src/parser.c | 80 ++++++++++++++++++++++++------------------- src/parser.h | 32 +++++++++++------- src/primitives.gperf | 2 ++ 7 files changed, 163 insertions(+), 115 deletions(-) diff --git a/src/analyzer.c b/src/analyzer.c index 798b34c..e8d4c51 100644 --- a/src/analyzer.c +++ b/src/analyzer.c @@ -56,7 +56,7 @@ struct cfctx { idx_t_ si; }; -static void analyzeast(struct scope *, struct type *, struct ast, +static void analyzeast(struct scope *, struct type *, struct ast, struct aux, struct lexemes, arena *) __attribute__((nonnull)); static void constfold(mpq_t *, struct scope *, struct type *, struct ast, @@ -65,22 +65,27 @@ static void constfold(mpq_t *, struct scope *, struct type *, struct ast, /* Perform a pass over the entire AST and return an array of symbol tables, one for each scope in the program */ -static struct scope *gensymtabs(struct ast, struct lexemes, arena *) +static struct scope *gensymtabs(struct ast, struct aux, struct lexemes, arena *) __attribute__((returns_nonnull, nonnull)); /* Find all the unordered symbols in the scope delimited by the inclusive indicies BEG and END in the AST, and accumulate them into a symbol table appended to the symbol table list. UP is the index of the previous scopes symbol table in the symbol table list. */ -static void find_unordered_syms(struct scopes *, struct ast, struct lexemes, - idx_t_ up, idx_t_ beg, idx_t_ end, arena *) +static void find_unordered_syms(struct scopes *, struct ast, struct aux, + struct lexemes, idx_t_ up, idx_t_ beg, + idx_t_ end, arena *) __attribute__((nonnull)); typedef idx_t_ analyzer(struct azctx, struct scope *, struct type *, struct ast, - struct lexemes, idx_t_) + struct aux, struct lexemes, idx_t_) + __attribute__((nonnull)); +typedef idx_t_ constfolder(struct cfctx, mpq_t *, struct scope *, struct type *, + struct ast, struct lexemes, idx_t_) __attribute__((nonnull)); static analyzer analyzeblk, analyzedecl, analyzeexpr, analyzefn, analyzestmt; +static constfolder constfoldblk, constfolddecl, constfoldexpr, constfoldstmt; static const struct type *typegrab(struct ast, struct lexemes, idx_t_) __attribute__((returns_nonnull)); @@ -98,14 +103,14 @@ const struct type *typelookup(const uchar *, size_t) __attribute__((nonnull)); void -analyzeprog(struct ast ast, struct lexemes toks, arena *a, struct type **types, - struct scope **scps, mpq_t **folds) +analyzeprog(struct ast ast, struct aux aux, struct lexemes toks, arena *a, + struct type **types, struct scope **scps, mpq_t **folds) { *types = bufalloc(NULL, ast.len, sizeof(**types)); memset(*types, 0, ast.len * sizeof(**types)); - *scps = gensymtabs(ast, toks, a); - analyzeast(*scps, *types, ast, toks, a); + *scps = gensymtabs(ast, aux, toks, a); + analyzeast(*scps, *types, ast, aux, toks, a); *folds = bufalloc(NULL, ast.len, sizeof(**folds)); memset(*folds, 0, ast.len * sizeof(**folds)); @@ -113,17 +118,18 @@ analyzeprog(struct ast ast, struct lexemes toks, arena *a, struct type **types, } struct scope * -gensymtabs(struct ast ast, struct lexemes toks, arena *a) +gensymtabs(struct ast ast, struct aux aux, struct lexemes toks, arena *a) { struct scopes scps = {.cap = 32}; scps.buf = bufalloc(NULL, scps.cap, sizeof(*scps.buf)); - find_unordered_syms(&scps, ast, toks, 0, 0, ast.len - 1, a); + find_unordered_syms(&scps, ast, aux, toks, 0, 0, ast.len - 1, a); return scps.buf; } void -find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks, - idx_t_ up, idx_t_ beg, idx_t_ end, arena *a) +find_unordered_syms(struct scopes *scps, struct ast ast, struct aux aux, + struct lexemes toks, idx_t_ up, idx_t_ beg, idx_t_ end, + arena *a) { if (scps->len == scps->cap) { scps->cap *= 2; @@ -138,10 +144,11 @@ find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks, }; for (idx_t_ i = beg; likely(i <= end); i++) { - bool globl_var = ast.kinds[i] <= _AST_DECLS_END && beg == 0; - bool const_var = (ast.kinds[i] | 1) == ASTPCDECL; + bool isstatic = ast.kinds[i] <= _AST_DECLS_END + && aux.buf[ast.kids[i].lhs].decl.isstatic; + bool isconst = ast.kinds[i] == ASTCDECL; - if (globl_var || const_var) { + if (isstatic || isconst) { struct strview sv = toks.strs[ast.lexemes[i]]; idx_t_ *p = symtab_insert(&scp->map, sv, a); if (*p != 0) { @@ -151,7 +158,7 @@ find_unordered_syms(struct scopes *scps, struct ast ast, struct lexemes toks, *p = i; } else if (ast.kinds[i] == ASTBLK) { struct pair p = ast.kids[i]; - find_unordered_syms(scps, ast, toks, beg, p.lhs, p.rhs, a); + find_unordered_syms(scps, ast, aux, toks, beg, p.lhs, p.rhs, a); i = p.rhs; } } @@ -169,21 +176,21 @@ typegrab(struct ast ast, struct lexemes toks, idx_t_ i) void analyzeast(struct scope *scps, struct type *types, struct ast ast, - struct lexemes toks, arena *a) + struct aux aux, struct lexemes toks, arena *a) { struct azctx ctx = {.a = a}; for (idx_t_ i = 0; likely(i < ast.len); i = fwdnode(ast, i)) { assert(ast.kinds[i] <= _AST_DECLS_END); - analyzedecl(ctx, scps, types, ast, toks, i); + analyzedecl(ctx, scps, types, ast, aux, toks, i); } } idx_t_ analyzedecl(struct azctx ctx, struct scope *scps, struct type *types, - struct ast ast, struct lexemes toks, idx_t_ i) + struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i) { struct strview sv = toks.strs[ast.lexemes[i]]; - if (ctx.si > 0 && (ast.kinds[i] | 1) == ASTPDECL) { + if (ctx.si > 0 && ast.kinds[i] == ASTDECL) { idx_t_ *ip = symtab_insert(&scps[ctx.si].map, sv, ctx.a); if (*ip == 0) *ip = i; @@ -199,15 +206,17 @@ analyzedecl(struct azctx ctx, struct scope *scps, struct type *types, struct type ltype, rtype; ltype.kind = TYPE_UNSET; - assert(p.lhs != AST_EMPTY || p.rhs != AST_EMPTY); + idx_t_ typeidx = aux.buf[p.lhs].decl.type; + + assert(typeidx != AST_EMPTY || p.rhs != AST_EMPTY); idx_t_ ni; - if (p.lhs != AST_EMPTY) - ltype = *typegrab(ast, toks, p.lhs); + if (typeidx != AST_EMPTY) + ltype = *typegrab(ast, toks, typeidx); if (p.rhs != AST_EMPTY) { ctx.decl = sv; - ni = analyzeexpr(ctx, scps, types, ast, toks, p.rhs); + ni = analyzeexpr(ctx, scps, types, ast, aux, toks, p.rhs); rtype = types[p.rhs]; } else ni = fwdnode(ast, i); @@ -223,12 +232,12 @@ analyzedecl(struct azctx ctx, struct scope *scps, struct type *types, idx_t_ analyzestmt(struct azctx ctx, struct scope *scps, struct type *types, - struct ast ast, struct lexemes toks, idx_t_ i) + struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i) { switch (ast.kinds[i]) { case ASTDECL: case ASTCDECL: - return analyzedecl(ctx, scps, types, ast, toks, i); + return analyzedecl(ctx, scps, types, ast, aux, toks, i); case ASTRET: { idx_t_ expr = ast.kids[i].rhs; if (expr == AST_EMPTY) { @@ -238,7 +247,8 @@ analyzestmt(struct azctx ctx, struct scope *scps, struct type *types, } else if (ctx.fnret.kind == TYPE_UNSET) err("analyzer: Function has no return value"); - idx_t_ ni = analyzeexpr(ctx, scps, types, ast, toks, ast.kids[i].rhs); + idx_t_ ni = analyzeexpr(ctx, scps, types, ast, aux, toks, + ast.kids[i].rhs); if (!typecompat(ctx.fnret, types[ast.kids[i].rhs])) err("analyzer: Return type mismatch"); return ni; @@ -250,7 +260,7 @@ analyzestmt(struct azctx ctx, struct scope *scps, struct type *types, idx_t_ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types, - struct ast ast, struct lexemes toks, idx_t_ i) + struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i) { switch (ast.kinds[i]) { case ASTNUMLIT: @@ -277,7 +287,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types, switch (types[*ip].kind) { case TYPE_UNSET: ctx.si = lvl; - analyzedecl(ctx, scps, types, ast, toks, *ip); + analyzedecl(ctx, scps, types, ast, aux, toks, *ip); break; case TYPE_CHECKING: err("analyzer: Circular definition of ‘%.*s’", SV_PRI_ARGS(sv)); @@ -291,7 +301,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types, err("analyzer: Unknown symbol ‘%.*s’", SV_PRI_ARGS(sv)); } case ASTFN: - return analyzefn(ctx, scps, types, ast, toks, i); + return analyzefn(ctx, scps, types, ast, aux, toks, i); default: __builtin_unreachable(); } @@ -299,7 +309,7 @@ analyzeexpr(struct azctx ctx, struct scope *scps, struct type *types, idx_t_ analyzefn(struct azctx ctx, struct scope *scps, struct type *types, - struct ast ast, struct lexemes toks, idx_t_ i) + struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i) { struct type t = {.kind = TYPE_FN}; struct pair p = ast.kids[i]; @@ -312,12 +322,12 @@ analyzefn(struct azctx ctx, struct scope *scps, struct type *types, } else ctx.fnret.kind = TYPE_UNSET; types[i] = t; - return analyzeblk(ctx, scps, types, ast, toks, p.rhs); + return analyzeblk(ctx, scps, types, ast, aux, toks, p.rhs); } idx_t_ analyzeblk(struct azctx ctx, struct scope *scps, struct type *types, - struct ast ast, struct lexemes toks, idx_t_ i) + struct ast ast, struct aux aux, struct lexemes toks, idx_t_ i) { struct pair p = ast.kids[i]; @@ -330,7 +340,7 @@ analyzeblk(struct azctx ctx, struct scope *scps, struct type *types, for (i = p.lhs; i <= p.rhs;) { if (chkrets && returns(ast, i)) hasret = true; - i = analyzestmt(ctx, scps, types, ast, toks, i); + i = analyzestmt(ctx, scps, types, ast, aux, toks, i); } if (chkrets && !hasret) err("analyzer: Function doesn’t return on all paths"); @@ -338,13 +348,6 @@ analyzeblk(struct azctx ctx, struct scope *scps, struct type *types, return i; } -static idx_t_ -constfolddecl(struct cfctx ctx, mpq_t *folds, struct scope *scps, - struct type *types, struct ast ast, struct lexemes toks, idx_t_ i); -static idx_t_ -constfoldexpr(struct cfctx ctx, mpq_t *folds, struct scope *scps, - struct type *types, struct ast ast, struct lexemes toks, idx_t_ i); - idx_t_ constfoldstmt(struct cfctx ctx, mpq_t *folds, struct scope *scps, struct type *types, struct ast ast, struct lexemes toks, idx_t_ i) @@ -352,8 +355,6 @@ constfoldstmt(struct cfctx ctx, mpq_t *folds, struct scope *scps, switch (ast.kinds[i]) { case ASTDECL: case ASTCDECL: - case ASTPCDECL: - case ASTPDECL: return constfolddecl(ctx, folds, scps, types, ast, toks, i); case ASTRET: return constfoldexpr(ctx, folds, scps, types, ast, toks, @@ -425,10 +426,8 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, struct scope *scps, } else { switch (ast.kinds[*ip]) { case ASTDECL: - case ASTPDECL: break; - case ASTCDECL: - case ASTPCDECL: { + case ASTCDECL: { idx_t_ expr = ast.kids[*ip].rhs; assert(expr != AST_EMPTY); #if DEBUG @@ -493,9 +492,7 @@ returns(struct ast ast, idx_t_ i) { switch (ast.kinds[i]) { case ASTDECL: - case ASTPDECL: case ASTCDECL: - case ASTPCDECL: return false; case ASTRET: return true; diff --git a/src/analyzer.h b/src/analyzer.h index ec6089c..ceb4899 100644 --- a/src/analyzer.h +++ b/src/analyzer.h @@ -56,8 +56,8 @@ struct type { }; }; -void analyzeprog(struct ast, struct lexemes, arena *, struct type **, - struct scope **, mpq_t **) +void analyzeprog(struct ast, struct aux, struct lexemes, arena *, + struct type **, struct scope **, mpq_t **) __attribute__((nonnull)); #endif /* !ORYX_ANALYZER_H */ diff --git a/src/codegen.c b/src/codegen.c index 5b883b5..bbe7d5f 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -42,10 +42,7 @@ void codegen(const char *file, mpq_t *folds, struct scope *scps, struct type *types, struct ast ast, struct lexemes toks) { - (void)types; (void)scps; - (void)ast; - (void)toks; char *triple = LLVMGetDefaultTargetTriple(); struct cgctx ctx; @@ -74,20 +71,41 @@ codegen(const char *file, mpq_t *folds, struct scope *scps, struct type *types, LLVMContextDispose(ctx.ctx); } +idx_t_ +codegenfunc(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast, + struct lexemes toks, idx_t_ i, const char *name) +{ + LLVMTypeRef ret = type2llvm(ctx, types[ast.kids[i].rhs]); + LLVMTypeRef ft = LLVMFunctionType(ret, NULL, 0, false); + LLVMValueRef fn = LLVMAddFunction(ctx.mod, name, ft); + LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry"); + + struct pair p = ast.kids[i]; + // for (i = p.lhs; i <= p.rhs; i = codegenstmt(ctx, folds, types, ast, toks, i)) + // ; + return fwdnode(ast, p.rhs); +} + idx_t_ codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast, struct lexemes toks, idx_t_ i) { /* Constants are purely a compiler concept; they aren’t generated into anything */ - if ((ast.kinds[i] | 1) == ASTPCDECL) + if (ast.kinds[i] == ASTCDECL) return fwdnode(ast, i); struct pair p = ast.kids[i]; - switch (ast.kinds[p.rhs]) { - case ASTFN: - err("%s():%d: TODO", __func__, __LINE__); - default: { + if (ast.kinds[p.rhs] == ASTFN) { + struct strview sv = toks.strs[ast.lexemes[i]]; + /* TODO: Namespace the name */ + /* TODO: Temporary allocator */ + char *name = bufalloc(NULL, sv.len + 1, 1); + svtocstr(name, sv); + i = codegenfunc(ctx, folds, types, ast, toks, p.rhs, name); + free(name); + return i; + } else if (!types[i].isfloat) { struct strview sv = toks.strs[ast.lexemes[i]]; /* TODO: Namespace the name */ /* TODO: Temporary allocator */ @@ -96,7 +114,13 @@ codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast, LLVMValueRef globl = LLVMAddGlobal(ctx.mod, t, svtocstr(name, sv)); free(name); - /* TODO: Assert that the fold is an integer */ +#if DEBUG /* Assert that the fold is an integer */ + mpz_t den; + mpq_canonicalize(folds[p.rhs]); + mpq_get_den(den, folds[p.rhs]); + assert(mpz_cmp_si(den, 1) == 0); + mpz_clear(den); +#endif /* The max value of a u128 is length 39 */ char buf[40]; @@ -106,8 +130,8 @@ codegendecl(struct cgctx ctx, mpq_t *folds, struct type *types, struct ast ast, LLVMSetLinkage(globl, LLVMInternalLinkage); return fwdnode(ast, i); - } - } + } else /* && types[i].isfloat */ + err("%s():%d: TODO", __func__, __LINE__); } void @@ -126,9 +150,16 @@ type2llvm(struct cgctx ctx, struct type t) case TYPE_FN: err("codegen: %s: Not implemented for function types", __func__); case TYPE_NUM: - /* TODO: Floats */ - if (t.isfloat) - err("codegen: %s: Not implemented for floats", __func__); + if (t.isfloat) { + switch (t.size) { + case 2: return LLVMHalfTypeInContext(ctx.ctx); + case 4: return LLVMFloatTypeInContext(ctx.ctx); + case 0: + case 8: return LLVMDoubleTypeInContext(ctx.ctx); + case 16: return LLVMFP128TypeInContext(ctx.ctx); + default: __builtin_unreachable(); + } + } /* TODO: Arbitrary precision */ if (t.size == 0) return LLVMInt64TypeInContext(ctx.ctx); diff --git a/src/main.c b/src/main.c index 5bd30fe..86e8e54 100644 --- a/src/main.c +++ b/src/main.c @@ -31,12 +31,13 @@ main(int argc, char **argv) arena a = NULL; mpq_t *folds; + struct aux aux; struct type *types; struct scope *scps; struct lexemes toks = lexstring(src, srclen); - struct ast ast = parsetoks(toks); - analyzeprog(ast, toks, &a, &types, &scps, &folds); + struct ast ast = parsetoks(toks, &aux); + analyzeprog(ast, aux, toks, &a, &types, &scps, &folds); codegen(argv[1], folds, scps, types, ast, toks); #if DEBUG @@ -51,6 +52,7 @@ main(int argc, char **argv) free(types); lexemes_free(toks); ast_free(ast); + aux_free(aux); arena_free(&a); #endif return EXIT_SUCCESS; diff --git a/src/parser.c b/src/parser.c index 5d9bf9c..3f8195c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -14,15 +14,17 @@ #if DEBUG # define AST_DFLT_CAP (8) +# define AUX_DFLT_CAP (8) #else # define AST_DFLT_CAP (2048) +# define AUX_DFLT_CAP (128) #endif #define SIZE_WDTH (sizeof(size_t) * CHAR_BIT) -typedef idx_t_ parsefn(struct ast *, struct lexemes) +typedef idx_t_ parsefn(struct ast *, struct aux *, struct lexemes) __attribute__((nonnull)); static parsefn parseblk, parseexpr, parsefunc, parseproto, parsestmt, parsetype; -static idx_t_ parsedecl(struct ast *, struct lexemes, bool) +static idx_t_ parsedecl(struct ast *, struct aux *, struct lexemes, bool) __attribute__((nonnull)); static struct ast mkast(void); @@ -42,7 +44,6 @@ fwdnode(struct ast ast, idx_t_ i) i = ast.kids[i].lhs == AST_EMPTY ? i + 1 : ast.kids[i].rhs; break; case ASTDECL: - case ASTPDECL: i = ast.kids[i].rhs == AST_EMPTY ? ast.kids[i].lhs : ast.kids[i].rhs; break; @@ -54,7 +55,6 @@ fwdnode(struct ast ast, idx_t_ i) case ASTBINADD: case ASTBINSUB: case ASTCDECL: - case ASTPCDECL: case ASTFN: i = ast.kids[i].rhs; break; @@ -72,12 +72,13 @@ fwdnode(struct ast ast, idx_t_ i) } struct ast -parsetoks(struct lexemes toks) +parsetoks(struct lexemes toks, struct aux *aux) { struct ast ast = mkast(); + aux->buf = bufalloc(NULL, aux->cap = AUX_DFLT_CAP, sizeof(*aux->buf)); for (;;) { - (void)parsedecl(&ast, toks, true); + (void)parsedecl(&ast, aux, toks, true); if (toks.kinds[toksidx] == LEXEOF) break; } @@ -86,7 +87,7 @@ parsetoks(struct lexemes toks) } idx_t_ -parseblk(struct ast *ast, struct lexemes toks) +parseblk(struct ast *ast, struct aux *aux, struct lexemes toks) { idx_t_ i = astalloc(ast); ast->lexemes[i] = toksidx; @@ -98,12 +99,12 @@ parseblk(struct ast *ast, struct lexemes toks) err("parser: Expected left brace"); if (toks.kinds[toksidx] != LEXRBRACE) { - idx_t_ stmt = parsestmt(ast, toks); + idx_t_ stmt = parsestmt(ast, aux, toks); ast->kids[i].lhs = ast->kids[i].rhs = stmt; } while (toks.kinds[toksidx] != LEXRBRACE) { - idx_t_ stmt = parsestmt(ast, toks); + idx_t_ stmt = parsestmt(ast, aux, toks); ast->kids[i].rhs = stmt; } @@ -112,18 +113,23 @@ parseblk(struct ast *ast, struct lexemes toks) } idx_t_ -parsedecl(struct ast *ast, struct lexemes toks, bool toplvl) +parsedecl(struct ast *ast, struct aux *aux, struct lexemes toks, bool toplvl) { - idx_t_ i = astalloc(ast); + idx_t_ i = astalloc(ast), j = aux->len++; + + if (aux->len > aux->cap) { + aux->cap *= 2; + aux->buf = bufalloc(aux->buf, aux->cap, sizeof(*aux->buf)); + } - bool pub; + aux->buf[j].decl.isstatic = toplvl; if (toplvl && toks.kinds[toksidx] == LEXIDENT && strview_eq(SV("pub"), toks.strs[toksidx])) { - pub = true; + aux->buf[j].decl.ispub = true; ast->lexemes[i] = ++toksidx; } else { - pub = false; + aux->buf[j].decl.ispub = false; ast->lexemes[i] = toksidx; } @@ -132,32 +138,33 @@ parsedecl(struct ast *ast, struct lexemes toks, bool toplvl) if (toks.kinds[toksidx++] != LEXCOLON) err("parser: Expected colon"); - idx_t_ lhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, toks) - : AST_EMPTY; - ast->kids[i].lhs = lhs; + aux->buf[j].decl.type = toks.kinds[toksidx] == LEXIDENT + ? parsetype(ast, aux, toks) + : AST_EMPTY; + ast->kids[i].lhs = j; switch (toks.kinds[toksidx++]) { case LEXSEMI: - if (ast->kids[i].lhs == AST_EMPTY) + if (aux->buf[j].decl.type == AST_EMPTY) err("parser: No type provided in non-assigning declaration"); - ast->kinds[i] = ASTDECL + pub; + ast->kinds[i] = ASTDECL; ast->kids[i].rhs = AST_EMPTY; return i; case LEXCOLON: - ast->kinds[i] = ASTCDECL + pub; + ast->kinds[i] = ASTCDECL; break; case LEXEQ: - ast->kinds[i] = ASTDECL + pub; + ast->kinds[i] = ASTDECL; break; default: err("parser: Expected colon, equals, or semicolon"); } bool func = toks.kinds[toksidx] == LEXLPAR; - if (func && ast->kinds[i] - pub == ASTDECL) + if (func && ast->kinds[i] == ASTDECL) err("Cannot assign function to mutable variable"); - idx_t_ rhs = (func ? parsefunc : parseexpr)(ast, toks); + idx_t_ rhs = (func ? parsefunc : parseexpr)(ast, aux, toks); ast->kids[i].rhs = rhs; if (!func && toks.kinds[toksidx++] != LEXSEMI) err("parser: Expected semicolon"); @@ -166,7 +173,7 @@ parsedecl(struct ast *ast, struct lexemes toks, bool toplvl) } idx_t_ -parsefunc(struct ast *ast, struct lexemes toks) +parsefunc(struct ast *ast, struct aux *aux, struct lexemes toks) { idx_t_ i = astalloc(ast); ast->lexemes[i] = toksidx; @@ -174,8 +181,8 @@ parsefunc(struct ast *ast, struct lexemes toks) assert(toks.kinds[toksidx] == LEXLPAR); ast->kinds[i] = ASTFN; - idx_t_ lhs = parseproto(ast, toks); - idx_t_ rhs = parseblk(ast, toks); + idx_t_ lhs = parseproto(ast, aux, toks); + idx_t_ rhs = parseblk(ast, aux, toks); ast->kids[i].lhs = lhs; ast->kids[i].rhs = rhs; @@ -183,8 +190,9 @@ parsefunc(struct ast *ast, struct lexemes toks) } idx_t_ -parseexpr(struct ast *ast, struct lexemes toks) +parseexpr(struct ast *ast, struct aux *aux, struct lexemes toks) { + (void)aux; idx_t_ i = astalloc(ast); ast->lexemes[i] = toksidx; @@ -205,7 +213,7 @@ parseexpr(struct ast *ast, struct lexemes toks) } idx_t_ -parseproto(struct ast *ast, struct lexemes toks) +parseproto(struct ast *ast, struct aux *aux, struct lexemes toks) { idx_t_ i = astalloc(ast); ast->lexemes[i] = toksidx; @@ -217,14 +225,14 @@ parseproto(struct ast *ast, struct lexemes toks) if (toks.kinds[toksidx++] != LEXRPAR) err("parser: Expected right parenthesis"); - idx_t_ rhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, toks) + idx_t_ rhs = toks.kinds[toksidx] == LEXIDENT ? parsetype(ast, aux, toks) : AST_EMPTY; ast->kids[i].rhs = rhs; return i; } idx_t_ -parsestmt(struct ast *ast, struct lexemes toks) +parsestmt(struct ast *ast, struct aux *aux, struct lexemes toks) { idx_t_ i; @@ -237,22 +245,24 @@ parsestmt(struct ast *ast, struct lexemes toks) ast->lexemes[i] = toksidx++; ast->kinds[i] = ASTRET; - idx_t_ rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, toks) + idx_t_ rhs = toks.kinds[toksidx] != LEXSEMI ? parseexpr(ast, aux, toks) : AST_EMPTY; ast->kids[i].rhs = rhs; if (toks.kinds[toksidx++] != LEXSEMI) err("parser: Expected semicolon"); - } else if (toks.kinds[toksidx + 1] == LEXCOLON) - i = parsedecl(ast, toks, false); - else + } else if (toks.kinds[toksidx + 1] == LEXCOLON) { + i = parsedecl(ast, aux, toks, false); + } else { err("parser: Invalid statement"); + } return i; } idx_t_ -parsetype(struct ast *ast, struct lexemes toks) +parsetype(struct ast *ast, struct aux *aux, struct lexemes toks) { + (void)aux; idx_t_ i = astalloc(ast); ast->kinds[i] = ASTTYPE; ast->lexemes[i] = toksidx; diff --git a/src/parser.h b/src/parser.h index 1b91498..b4ce8c4 100644 --- a/src/parser.h +++ b/src/parser.h @@ -16,22 +16,14 @@ enum { public by if the LSB is set. */ /* Variable declaration, lhs and rhs may be unused - ‘x: lhs = rhs’ */ + ‘x := rhs’; aux[lhs].decl */ ASTDECL, - /* Public variable declaration, lhs and rhs may be unused - ‘pub x: lhs = rhs’ */ - ASTPDECL, - /* Constant declaration, lhs may be unused - ‘x: lhs : rhs’ */ + ‘x :: rhs’; aux[lhs].decl */ ASTCDECL, - /* Public constant declaration, lhs may be unused - ‘pub x: lhs : rhs’ */ - ASTPCDECL, - - _AST_DECLS_END = ASTPCDECL, + _AST_DECLS_END = ASTCDECL, /* Function prototype ‘(a: b, c: d) rhs’; aux[lhs].fnproto */ @@ -76,6 +68,17 @@ static_assert(_AST_LAST_ENT - 1 <= (ast_kind_t_)-1, #define AST_EMPTY ((idx_t_)-1) #define AST_SOA_BLKSZ (sizeof(ast_kind_t_) + sizeof(idx_t_) * 3) +struct aux { + union { + struct { + idx_t_ type; + bool ispub; + bool isstatic; + } decl; + } *buf; + size_t len, cap; +}; + struct ast { ast_kind_t_ *kinds; idx_t_ *lexemes; @@ -86,9 +89,12 @@ struct ast { }; #define ast_free(x) free((x).kinds) +#define aux_free(x) free((x).buf) -/* Parse the tokens in TOKS into an abstract syntax tree */ -struct ast parsetoks(struct lexemes toks); +/* Parse the tokens in TOKS into an abstract syntax tree, and store + auxilliary information in AUX */ +struct ast parsetoks(struct lexemes toks, struct aux *aux) + __attribute__((nonnull)); /* Starting from the node at indent I in AST, return the index of the next node in AST that is of the same nest-depth as I */ diff --git a/src/primitives.gperf b/src/primitives.gperf index 230413f..ca9b8c2 100644 --- a/src/primitives.gperf +++ b/src/primitives.gperf @@ -29,8 +29,10 @@ u64, { TYPE_NUM, {.size = 8, .issigned=false, .isfloat=false} } u128, { TYPE_NUM, {.size = 16, .issigned=false, .isfloat=false} } uint, { TYPE_NUM, {.size = 8, .issigned=false, .isfloat=false} } rune, { TYPE_NUM ,{.size = 4, .issigned=true, .isfloat=false} } +f16, { TYPE_NUM, {.size = 2, .issigned=true, .isfloat=true } } f32, { TYPE_NUM, {.size = 4, .issigned=true, .isfloat=true } } f64, { TYPE_NUM, {.size = 8, .issigned=true, .isfloat=true } } +f128, { TYPE_NUM, {.size = 16, .issigned=true, .isfloat=true } } %% const struct type * typelookup(const uchar *p, size_t len) -- cgit v1.2.3