commit 9fd16cd66e2bb0908953a30acb648b1ca59825bd
parent 63c43210f409875968beaa5e20d19c2b1f406287
Author: thing1 <thing1@seacrossedlovers.xyz>
Date: Mon, 15 Dec 2025 15:50:43 +0000
added support for functions
Diffstat:
| M | Makefile | | | 2 | +- |
| M | cback.c | | | 23 | +++++++++++++++++++++++ |
| D | check.c | | | 77 | ----------------------------------------------------------------------------- |
| D | check.h | | | 35 | ----------------------------------- |
| A | maps.c | | | 33 | +++++++++++++++++++++++++++++++++ |
| A | maps.h | | | 32 | ++++++++++++++++++++++++++++++++ |
| M | parse.c | | | 62 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| M | spl.c | | | 7 | ++----- |
| M | test.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);
}