spl

a Simple Programming Language
Log | Files | Refs

commit 4bfe58b997ed954fb9ed0d7681fea10a6e4f9fde
parent 9fd16cd66e2bb0908953a30acb648b1ca59825bd
Author: thing1 <thing1@seacrossedlovers.xyz>
Date:   Thu, 18 Dec 2025 12:34:29 +0000

added propper support for functions, returns and the like

Diffstat:
Mcback.c | 45++++++++++++++++++++++++++++++++++-----------
Mlexer.c | 6++++--
Mlexer.h | 1+
Dnote.md | 99-------------------------------------------------------------------------------
Mparse.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mparse.h | 2++
Mspl.c | 16+++++++++-------
Mtest.spl | 4+++-
8 files changed, 119 insertions(+), 125 deletions(-)

diff --git a/cback.c b/cback.c @@ -38,6 +38,10 @@ toctype(char *type) { strcpy(ret, "float"); else if (SAME(type, "f64")) strcpy(ret, "double"); + else if (SAME(type, "void")) + strcpy(ret, "void"); + else + return NULL; return ret; } @@ -53,15 +57,19 @@ compiletype_C(type *t, FILE *f) { int compilefcall_C(rexpr *r, FILE *f) { mctx *ctx = newctx(); - int i, *ids; + int i, *ids = NULL; for (i = 0; i < r->argc; i++) { ids = realloczctx(ctx, ids, i + 1); ids[i] = compilerexpr_C(&r->args[i], f); } - compiletype_C(r->type, f); - fprintf(f, " v%d = %s(", vid++, r->fname); - for (int j = 0; j < i; j++) - printf("v%d%s", ids[j], (j == i - 1) ? ");\n" : ", "); + if (!(r->type->type == BASIC && SAME(r->type->name, "void"))) { + compiletype_C(r->type, f); + fprintf(f, " v%d = %s(", vid++, r->fname); + } else fprintf(f, "%s(", r->fname); + if (!r->argc) fprintf(f, ");\n"); + else + for (int j = 0; j < i; j++) + printf("v%d%s", ids[j], (j == i - 1) ? ");\n" : ", "); freectx(ctx); return vid - 1; @@ -98,9 +106,12 @@ compilerexpr_C(rexpr *r, FILE *f) { fprintf(f, " v%d = v%d %c v%d;\n", vid++, left, r->op, right); } else if (r->op == OBRACE) { left = compilerexpr_C(r->expr[0], f); - compiletype_C(r->type, f); fprintf(f, " v%d = v%d;\n", vid++, left); + }else if (r->op == NEGATE) { + left = compilerexpr_C(r->expr[0], f); + compiletype_C(r->type, f); + fprintf(f, " v%d = -v%d;\n", vid++, left); } return vid - 1; } @@ -113,13 +124,16 @@ compilefunc_C(lexpr *l, FILE *f) { compiletype_C(l->args[i].type, f); fprintf(f, " %s%s", l->args[i].name, (i == l->argc - 1) ? "" : ", "); } - fprintf(f, ") {\n"); + if (l->bodyc) { + fprintf(f, ") {\n"); - for (int i = 0; i < l->bodyc; i++) { - compilelexpr_C(&l->body[i], f); - } + for (int i = 0; i < l->bodyc; i++) { + compilelexpr_C(&l->body[i], f); + } - fprintf(f, "}\n"); + fprintf(f, "}\n"); + } + else fprintf(f, ");\n"); } void @@ -153,5 +167,14 @@ compilelexpr_C(lexpr *l, FILE *f) { case LEXPR_REASSIGN: compilereassign_C(l, f); break; + case RETURN: + if (l->ret) + fprintf(f, "return v%d;\n", compilerexpr_C(l->ret, f)); + else + fprintf(f, "return;\n"); + break; + case LEXPR_FCALL: + compilefcall_C(l->rexpr, f); + break; } } diff --git a/lexer.c b/lexer.c @@ -78,8 +78,10 @@ next(lex *l) { if (memcmp(l->ptr, ":=", 2) == 0) { l->ptr += 2; t.op = WALRUS; - } - if (memcmp(l->ptr, "func", 4) == 0) { + } else if (memcmp(l->ptr, "return", 6) == 0) { + l->ptr += 6; + t.op = RETURN; + } else if (memcmp(l->ptr, "func", 4) == 0) { l->ptr += 4; t.op = FUNC; } else if (isdigit(*l->ptr)) { diff --git a/lexer.h b/lexer.h @@ -25,6 +25,7 @@ enum lex_ops { FLOAT, NAME, WALRUS, + RETURN, /* used by the parser, wont be assigned by the lexer */ FUNCALL, diff --git a/note.md b/note.md @@ -1,99 +0,0 @@ -pivot parser -============ - -a parser could work like so - -2 + 4 * 3 - 1 = 13 - -loop through all tokens and find the first token with the lowest presidence - -2 + 4 * 3 - 1 - ^ - -split the list - -2 -+ -4 * 3 - 1 - -repeat - -4 * 3 -- -1 - -4 -* -3 - -assemble the tree - - + - / \ - 2 - - / \ - * 1 - / \ - 4 3 - -2 + ((4 * 3) - 1) -2 + (12 - 1) -2 + 11 -13 - -another example - -4 * 2 + (4 - 1) = 11 - -4 * 2 -+ -(4 - 1) - -4 -* -2 - - + - / \ - * (4 - 1) - / \ - 4 2 - -4 - 1 - -4 -- -1 - - + - / \ - * \ - / \ \ - 4 2 \ - - - / \ - 4 1 - -(4 * 2) + (4 - 1) -8 + 3 -11 - - -func(a) * (10 - 4) - -func(a) -* -(10 - 4) - - * - / \ - func(a) \ - (10 - 4) - - * - / \ - func(a) - - / \ - 10 4 - -func(a) * (10 - 4) diff --git a/parse.c b/parse.c @@ -12,6 +12,16 @@ #define SAME(s1, s2) (strcmp(s1, s2) == 0) #define SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +char *builtintypes[] = { + "f32", + "f64", + "i8", + "i16", + "i32", + "i64", + "void", +}; + char *builtinfns[] = { "f32", "f64", @@ -168,6 +178,8 @@ parsefcall(tok *start, tok *end, mctx *ctx) { another: while (!isterm(*exprend)) { if (exprend->op == ')') + if (e->argc == 0) + goto noargs; break; exprend = &exprend[1]; } @@ -226,11 +238,13 @@ parsesimple(tok *start, tok *end, tok *lowest, mctx *ctx) { } break; case OBRACE: + e = alloczctx(ctx, sizeof(rexpr)); e->op = OBRACE; e->e = parserexpr(&lowest[1], &findend(lowest, end)[-1], ctx); e->type = e->e->type; break; case NEGATE: + e = alloczctx(ctx, sizeof(rexpr)); e->op = NEGATE; e->e = parserexpr(&lowest[1], end, ctx); e->type = e->e->type; @@ -256,7 +270,11 @@ parsebin(tok *start, tok *end, tok *lowest, mctx *ctx) { e->expr[0] = parserexpr(start, &lowest[-1], ctx); e->expr[1] = parserexpr(&lowest[1], end, ctx); - /* TODO make this check both sides */ + if (!isequaltype(e->expr[0]->type, e->expr[1]->type)) { + parserErr("Type missmatch"); + return NULL; + } + e->type = e->expr[0]->type; return e; @@ -274,10 +292,17 @@ parserexpr(tok *start, tok *end, mctx *ctx) { /* binary ops */ else e = parsebin(start, end, lowest, ctx); - /* TODO something here that sets the type of an rexpr */ return e; } +int +isbasictype(char *t) { + for (int i = 0; i < SIZE(builtintypes); i++) + if (SAME(t, builtintypes[i])) + return 1; + return 0; +} + type * parsetype(lex *l, mctx *ctx) { SAVE(l); @@ -287,6 +312,11 @@ parsetype(lex *l, mctx *ctx) { RESTORE(l); return NULL; } + if (!isbasictype(t.name)) { + parserErr("not a known type!"); + RESTORE(l); + return NULL; + } ty = alloczctx(ctx, sizeof(type)); ty->type = BASIC; ty->name = t.name; @@ -489,13 +519,29 @@ parselexpr(lex *l, mctx *ctx) { SAVE(l); lexpr *le; fn *f; - tok t = next(l); + tok t = next(l), *ts = NULL; + int tsc = 0; switch (t.op) { case NAME: - if (!(le = parseassign(l, t, ctx))) { - le = parsereassign(l, t, ctx); + if (*l->ptr == '(') { + ts = alloczctx(ctx, sizeof(tok)); + ts[tsc++] = t; + while ((t = next(l)).op != ';') { + ts = realloczctx(ctx, ts, ++tsc * sizeof(tok)); + ts[tsc - 1] = t; + } + + le = alloczctx(ctx, sizeof(lexpr)); + le->rexpr = parsefcall(ts, &ts[tsc - 1], ctx); + if (!le->rexpr) { + RESTORE(l); + return NULL; + } + le->op = LEXPR_FCALL; } + else if (!(le = parseassign(l, t, ctx))) + le = parsereassign(l, t, ctx); break; case FUNC: le = parsefunc(l, ctx); /* we can drop the FUNC token, as it doesnt hold any info */ @@ -519,6 +565,21 @@ parselexpr(lex *l, mctx *ctx) { } funcs = addmap(funcs, f, f->name, ctx); break; + case RETURN: + le = alloczctx(ctx, sizeof(lexpr)); + le->op = RETURN; + if (*l->ptr == ';') + break; + + while ((t = next(l)).op != ';') { + ts = realloczctx(ctx, ts, ++tsc * sizeof(tok)); + ts[tsc - 1] = t; + } + + le->ret = parserexpr(ts, &ts[tsc - 1], ctx); + break; + case LEOF: + return NULL; default: parserErr("unexpected tok type"); } diff --git a/parse.h b/parse.h @@ -8,6 +8,7 @@ enum lexpr_ops { LEXPR_ASSIGN, LEXPR_FUNC, LEXPR_REASSIGN, + LEXPR_FCALL, }; enum type_types { @@ -61,6 +62,7 @@ typedef struct lexpr { struct lexpr *body; int bodyc; }; + rexpr *ret; /* the return value for return statements */ }; } lexpr; diff --git a/spl.c b/spl.c @@ -21,14 +21,16 @@ main(int argc, char **argv) { lex l = mklexer(file); mctx *ctx = newctx(); - lexpr *e = parselexpr(&l, ctx); - if (!e) { - parserErr("failed to parse lexpr"); - goto cleanup; + lexpr *xs = NULL, *x; + int lexprc = 0; + while (x = parselexpr(&l, ctx)) { + xs = realloczctx(ctx, xs, ++lexprc * sizeof(lexpr)); + xs[lexprc - 1] = *x; } - - fprintf(stdout, "#include <stdint.h>\n"); - compilelexpr_C(e, stdout); + if (lexprc) + fprintf(stdout, "#include <stdint.h>\n"); + for (int i = 0; i < lexprc; i++) + compilelexpr_C(&xs[i], stdout); cleanup: free(file); diff --git a/test.spl b/test.spl @@ -1,3 +1,5 @@ +func foo() void; + func main() i32 { - a i64 = i32(30); + foo(); }