spl

a Simple Programming Language
Log | Files | Refs

commit 9fd16cd66e2bb0908953a30acb648b1ca59825bd
parent 63c43210f409875968beaa5e20d19c2b1f406287
Author: thing1 <thing1@seacrossedlovers.xyz>
Date:   Mon, 15 Dec 2025 15:50:43 +0000

added support for functions

Diffstat:
MMakefile | 2+-
Mcback.c | 23+++++++++++++++++++++++
Dcheck.c | 77-----------------------------------------------------------------------------
Dcheck.h | 35-----------------------------------
Amaps.c | 33+++++++++++++++++++++++++++++++++
Amaps.h | 32++++++++++++++++++++++++++++++++
Mparse.c | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mspl.c | 7++-----
Mtest.spl | 2+-
9 files changed, 151 insertions(+), 122 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,7 @@ CFLAGS = -ggdb -pedantic #-fsanitize=address CPPFLAGS = -D_POSIX_C_SOURCE -D_XOPEN_SOURCE=500 LDFLAGS = #-fsanitize=address -SRC = spl.c lexer.c parse.c util.c check.c cback.c +SRC = spl.c lexer.c parse.c util.c maps.c cback.c OBJ = ${SRC:.c=.o} EXEC = spl diff --git a/cback.c b/cback.c @@ -8,6 +8,7 @@ int vid = 0; void compilelexpr_C(lexpr *l, FILE *f); +int compilerexpr_C(rexpr *r, FILE *f); int isbin(rexpr *r) { @@ -50,6 +51,23 @@ compiletype_C(type *t, FILE *f) { } int +compilefcall_C(rexpr *r, FILE *f) { + mctx *ctx = newctx(); + int i, *ids; + 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" : ", "); + + freectx(ctx); + return vid - 1; +} + +int compilerexpr_C(rexpr *r, FILE *f) { int left, right; switch (r->op) { @@ -65,6 +83,11 @@ compilerexpr_C(rexpr *r, FILE *f) { compiletype_C(r->type, f); fprintf(f, " v%d = %s;\n", vid++, r->name); return vid - 1; + case FUNCALL: + right = compilefcall_C(r, f); + compiletype_C(r->type, f); + fprintf(f, " v%d = v%d;\n", vid++, right, r->name); + return vid - 1; } if (isbin(r)) { diff --git a/check.c b/check.c @@ -1,77 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> - -#include "util.h" -#include "lexer.h" -#include "parse.h" -#include "check.h" - -map *funcs; -map *vars; - -map * -addmap(map *m, void *data, char *id, mctx *ctx) { - if (!m) - m = alloczctx(ctx, sizeof(map)); - else if (m->next) - return addmap(m->next, data, id, ctx); - - m->id = id; - m->data = data; - return m; -} - -void * -lookupmap(map *m, char *id) { - if (!m) - return NULL; - if (strcmp(m->id, id) == 0) - return m->data; - if (!m->next) - return NULL; - return lookupmap(m->next, id); -} - -void -checkErr(const char *msg) { - fprintf(stderr, "%s\n", msg); -} - -void -checkfunc(lexpr *l, mctx *ctx) { - fn *f; - if (lookupmap(funcs, l->fname)) - checkErr("function with name already declared"); - f = alloczctx(ctx, sizeof(fn)); - f->name = l->fname; - f->rtype = l->rtype; - funcs = addmap(funcs, f, l->fname, ctx); - - for (int i = 0; i < l->bodyc; i++) - checklexpr(&l->body[i], l, ctx); -} - -void -checkassign(lexpr *l, mctx *ctx) { - var *v; - if (lookupmap(vars, l->name)) - checkErr("var with name already declared"); - v = alloczctx(ctx, sizeof(var)); - v->name = l->name; - v->type = l->type; - vars = addmap(vars, v, l->name, ctx); -} - -void -checklexpr(lexpr *l, lexpr *scope, mctx *ctx) { - switch (l->op) { - case LEXPR_FUNC: - if (scope) - checkErr("functions can't be declared inside other functions"); - checkfunc(l, ctx); - break; - case LEXPR_ASSIGN: - checkassign(l, ctx); - break; - } -} diff --git a/check.h b/check.h @@ -1,35 +0,0 @@ -#ifndef __CHECK_H_ -#define __CHECK_H_ -#include <stdlib.h> -#include <stdio.h> - -#include "util.h" -#include "lexer.h" -#include "parse.h" - -typedef struct map { - char *id; - void *data; - struct map *next; -} map; - -typedef struct fn { - char *name; - type *rtype, *args; - int argc; -} fn; - -typedef struct var { - char *name; - type *type; -} var; - -extern map *funcs; -extern map *vars; - -map *addmap(map *m, void *data, char *id, mctx *ctx); -void *lookupmap(map *m, char *id); -void checkErr(const char *msg); -void checkfunc(lexpr *l, mctx *ctx); -void checklexpr(lexpr *l, lexpr *scope, mctx *ctx); -#endif diff --git a/maps.c b/maps.c @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "util.h" +#include "lexer.h" +#include "parse.h" +#include "maps.h" + +map *funcs; +map *vars; + +map * +addmap(map *m, void *data, char *id, mctx *ctx) { + if (!m) + m = alloczctx(ctx, sizeof(map)); + else if (m->next) + return addmap(m->next, data, id, ctx); + + m->id = id; + m->data = data; + return m; +} + +void * +lookupmap(map *m, char *id) { + if (!m) + return NULL; + if (strcmp(m->id, id) == 0) + return m->data; + if (!m->next) + return NULL; + return lookupmap(m->next, id); +} diff --git a/maps.h b/maps.h @@ -0,0 +1,32 @@ +#ifndef __MAPS_H_ +#define __MAPS_H_ +#include <stdlib.h> +#include <stdio.h> + +#include "util.h" +#include "lexer.h" +#include "parse.h" + +typedef struct map { + char *id; + void *data; + struct map *next; +} map; + +typedef struct fn { + char *name; + type *rtype, *args; + int argc; +} fn; + +typedef struct var { + char *name; + type *type; +} var; + +extern map *funcs; +extern map *vars; + +map *addmap(map *m, void *data, char *id, mctx *ctx); +void *lookupmap(map *m, char *id); +#endif diff --git a/parse.c b/parse.c @@ -2,13 +2,26 @@ #include <stdio.h> #include <stdlib.h> #include <limits.h> +#include <stdbool.h> #include "lexer.h" #include "parse.h" #include "util.h" -#include "check.h" +#include "maps.h" -int funcargs = 0; +#define SAME(s1, s2) (strcmp(s1, s2) == 0) +#define SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +char *builtinfns[] = { + "f32", + "f64", + "i8", + "i16", + "i32", + "i64", +}; + +int funcargs = false; void parserErr(const char *msg) { @@ -118,13 +131,35 @@ isequaltype(type *t1, type *t2) { return 0; } +fn * +isbuiltin(char *name, mctx *ctx) { + fn *f = alloczctx(ctx, sizeof(fn)); + for (int i = 0; i < SIZE(builtinfns); i++) { + if (SAME(name, builtinfns[i])) { + f->name = name; + f->rtype = mkbasictype(name, ctx); + f->argc = 1; + return f; + } + } + return NULL; +} + rexpr * parsefcall(tok *start, tok *end, mctx *ctx) { rexpr *e = alloczctx(ctx, sizeof(rexpr)); tok *exprend; + fn *f; + + if (!(f = isbuiltin(start->name, ctx)) && !(f = (fn *)lookupmap(funcs, start->name))) { + parserErr("no such function"); + return NULL; + } + + e->fname = f->name; + e->type = f->rtype; e->op = FUNCALL; - /* TODO lookup the return type of the function and put it into e->type*/ if (start[1].op != '(') return NULL; start = &start[2]; @@ -453,7 +488,9 @@ lexpr * parselexpr(lex *l, mctx *ctx) { SAVE(l); lexpr *le; + fn *f; tok t = next(l); + switch (t.op) { case NAME: if (!(le = parseassign(l, t, ctx))) { @@ -462,6 +499,25 @@ parselexpr(lex *l, mctx *ctx) { break; case FUNC: le = parsefunc(l, ctx); /* we can drop the FUNC token, as it doesnt hold any info */ + if (!le) { + RESTORE(l); + return NULL; + } + + f = alloczctx(ctx, sizeof(fn)); + f->name = le->fname; + f->rtype = le->rtype; + f->argc = le->argc; + for (int i = 0; i < f->argc; i++) { + f->args = realloczctx(ctx, f->args, (i + 1) * sizeof(type)); + f->args[i] = *le->args[i].type; + } + if (lookupmap(funcs, f->name)) { + parserErr("function already exists"); + RESTORE(l); + return NULL; + } + funcs = addmap(funcs, f, f->name, ctx); break; default: parserErr("unexpected tok type"); diff --git a/spl.c b/spl.c @@ -5,9 +5,10 @@ #include "lexer.h" #include "parse.h" #include "util.h" -#include "check.h" +#include "maps.h" #include "cback.h" + int main(int argc, char **argv) { if (argc == 1) @@ -26,10 +27,6 @@ main(int argc, char **argv) { goto cleanup; } - mctx *checkctx = newctx(); - checklexpr(e, NULL, checkctx); - freectx(checkctx); - fprintf(stdout, "#include <stdint.h>\n"); compilelexpr_C(e, stdout); diff --git a/test.spl b/test.spl @@ -1,3 +1,3 @@ func main() i32 { - a f32 = f32(30); + a i64 = i32(30); }