commit 8407c770cc7d16e589d4544e664b34014fb2d6c6
parent cc2a1dcea09d79cd11950843ecc02456266adbdf
Author: thing1 <thing1@seacrossedlovers.xyz>
Date: Tue, 9 Dec 2025 15:24:13 +0000
added c backend
Diffstat:
| D | .clang-format | | | 12 | ------------ |
| M | Makefile | | | 9 | ++++----- |
| A | cback.c | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | cback.h | | | 11 | +++++++++++ |
| A | check.c | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | check.h | | | 30 | ++++++++++++++++++++++++++++++ |
| M | lexer.c | | | 10 | ++++++++-- |
| M | lexer.h | | | 7 | +++++-- |
| A | parse.c | | | 349 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | parse.h | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | spl.c | | | 389 | ++++--------------------------------------------------------------------------- |
| A | test.spl | | | 6 | ++++++ |
| M | util.c | | | 15 | +++++++++++++++ |
| M | util.h | | | 4 | ++++ |
14 files changed, 660 insertions(+), 393 deletions(-)
diff --git a/.clang-format b/.clang-format
@@ -1,12 +0,0 @@
-UseTab: Always
-IndentWidth: 8
-TabWidth: 8
-ColumnLimit: 79
-DerivePointerAlignment: false
-PointerAlignment: Right
-AlignAfterOpenBracket: true
-AlignArrayOfStructures: Right
-AlignEscapedNewlines: LeftWithLastLine
-AlignOperands: true
-IndentCaseBlocks: false
-BreakAfterReturnType: TopLevel
diff --git a/Makefile b/Makefile
@@ -2,16 +2,15 @@ CFLAGS = -ggdb -pedantic #-fsanitize=address
CPPFLAGS = -D_POSIX_C_SOURCE -D_XOPEN_SOURCE=500
LDFLAGS = #-fsanitize=address
-SRC = spl.c lexer.c util.c
+SRC = spl.c lexer.c parse.c util.c check.c cback.c
OBJ = ${SRC:.c=.o}
EXEC = spl
${EXEC}: ${OBJ}
-${OBJ}: ${SRC}
+.c.o:
+ ${CC} -c ${CFLAGS} $<
clean:
- rm -rf ${OBJ} ${EXEC}
-format:
- clang-format -i *.c
+ rm -rf ${OBJ} ${EXEC}
diff --git a/cback.c b/cback.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+
+#include "lexer.h"
+#include "parse.h"
+
+int vid = 0;
+int indent = 0;
+
+void compilelexpr_C(lexpr *l, FILE *f);
+
+void
+putindent(FILE *f) {
+ for (int i = 0; i < indent; i++)
+ fputc('\t', f);
+}
+
+int
+compilerexpr_C(rexpr *r, FILE *f) {
+ int left, right;
+ if (r->op == INT) {
+ putindent(f);
+ fprintf(f, "int v%d = %d;\n", vid++, r->n);
+ return vid - 1;
+ }
+ putindent(f);
+ left = compilerexpr_C(r->expr[0], f);
+ putindent(f);
+ right = compilerexpr_C(r->expr[1], f);
+ putindent(f);
+ fprintf(f, "int v%d = v%d %c v%d;\n", vid++, left, r->op, right);
+ return vid - 1;
+}
+
+void
+compilefunc_C(lexpr *l, FILE *f) {
+ fprintf(f, "%s %s(", l->rtype->name, l->fname);
+ for (int i = 0; i < l->argc; i++)
+ fprintf(f, "%s %s%s", l->args[i].type->name, l->args[i].name, (i == l->argc - 1) ? "" : ", ");
+ fprintf(f, ") {\n");
+
+ indent++;
+
+ for (int i = 0; i < l->bodyc; i++) {
+ compilelexpr_C(&l->body[i], f);
+ }
+
+ fprintf(f, "}\n");
+ indent--;
+}
+
+void
+compileassign_C(lexpr *l, FILE *f) {
+ int id;
+ if (l->rexpr)
+ id = compilerexpr_C(l->rexpr, f);
+ putindent(f);
+ fprintf(f, "%s %s", l->type->name, l->name);
+ if (l->rexpr)
+ fprintf(f, " = v%d;\n", id);
+}
+
+void
+compilelexpr_C(lexpr *l, FILE *f) {
+ switch (l->op) {
+ case LEXPR_FUNC:
+ compilefunc_C(l, f);
+ break;
+ case LEXPR_ASSIGN:
+ compileassign_C(l, f);
+ break;
+ }
+}
diff --git a/cback.h b/cback.h
@@ -0,0 +1,11 @@
+#ifndef __BACK_C_H_
+#define __BACK_C_H_
+#include <stdio.h>
+
+#include "lexer.h"
+#include "parse.h"
+
+void compilelexpr_C(lexpr *l, FILE *f);
+void compileassign_C(lexpr *l, FILE *f);
+void compilelexpr_C(lexpr *l, FILE *f);
+#endif
diff --git a/check.c b/check.c
@@ -0,0 +1,67 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "lexer.h"
+#include "parse.h"
+#include "check.h"
+
+map *funcs;
+map *vars;
+
+void
+addmap(map *m, void *data, char *id, mctx *ctx) {
+ if (!m)
+ m = alloczctx(ctx, sizeof(map));
+ if (m->next)
+ addmap(m->next, data, id, ctx);
+ else {
+ m->next = alloczctx(ctx, sizeof(map));
+ m->next->id = id;
+ m->next->data = data;
+ }
+}
+
+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;
+ addmap(funcs, f, l->fname, ctx);
+
+ for (int i = 0; i < l->bodyc; i++)
+ checklexpr(&l->body[i], l, 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
@@ -0,0 +1,30 @@
+#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;
+
+extern map *funcs;
+extern map *vars;
+
+void 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/lexer.c b/lexer.c
@@ -29,8 +29,14 @@ lexName(lex *l) {
return strdup(name); /* TODO need to cleanup this */
}
+char *
+unlex(lex *l) {
+ return (l->ptr = l->prev);
+}
+
tok
next(lex *l) {
+ l->prev = l->ptr;
tok t = {0};
switch (*l->ptr) {
case 0:
@@ -50,13 +56,13 @@ next(lex *l) {
case DIV:
case OBRACE:
case CBRACE:
+ case OCBRACE:
+ case CCBRACE:
case ASSIGN:
case SEMI:
case COMMA:
t.op = *l->ptr++;
return t;
-
-
}
if (memcmp(l->ptr, "func", 4) == 0) {
l->ptr += 4;
diff --git a/lexer.h b/lexer.h
@@ -14,11 +14,13 @@ enum lex_ops {
DIV = '/',
OBRACE = '(',
CBRACE = ')',
+ OCBRACE = '{',
+ CCBRACE = '}',
LEOF = '$',
ASSIGN = '=',
SEMI = ';',
COMMA = ',',
- FUNC,
+ FUNC = 256,
NEGATE,
NAME,
};
@@ -32,10 +34,11 @@ typedef struct tok {
} tok;
typedef struct lex {
- char *input, *ptr;
+ char *input, *ptr, *prev;
} lex;
void lexErr(lex *l);
+char *unlex(lex *l);
tok next(lex *l);
void printTok(tok *t);
lex mklexer(char *input);
diff --git a/parse.c b/parse.c
@@ -0,0 +1,349 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lexer.h"
+#include "parse.h"
+#include "util.h"
+
+void
+parserErr(const char *msg) {
+ fprintf(stderr, "%s\n", msg);
+}
+
+int
+getpres(tok t) {
+ switch (t.op) {
+ case LEOF:
+ return -1;
+
+ case ADD:
+ case SUB:
+ return 1;
+
+ case MUL:
+ case DIV:
+ return 4;
+
+ case INT:
+ return 6;
+ case OBRACE:
+ return 8;
+
+ case NEGATE:
+ return 5;
+ }
+ return -2;
+}
+
+int
+isop(tok t) {
+ return (t.op == ADD || t.op == SUB || t.op == MUL || t.op == DIV);
+}
+
+tok *
+findend(tok *start, tok *end) {
+ int d = 1;
+ tok *t;
+
+ if (start->op != OBRACE) {
+ parserErr("Expected a '('");
+ return NULL;
+ }
+
+ for (t = &start[1]; d != 0; t = &t[1]) {
+ if (end->op != CBRACE && t == end) {
+ parserErr("unclosed brace");
+ return NULL;
+ }
+
+ if (t->op == OBRACE) d++;
+ else if (t->op == CBRACE) d--;
+ }
+ return &t[-1];
+}
+
+tok *
+findlowest(tok *start, tok *end) {
+ tok *lowest = start, prev = {.op = LEOF};
+
+ for (tok *t = lowest ; t != end; t = &t[1]) {
+ /* re assign ops, this is for when an op has multiple meanings */
+ if (isop(prev) || prev.op == LEOF) {
+ switch (t->op) {
+ case SUB:
+ t->op = NEGATE;
+ break;
+ }
+ }
+ else if (getpres(*t) < getpres(*lowest)) lowest = t;
+
+ /* move to the end brace, we only process the contents when nothing else is left */
+ if (t->op == OBRACE) {
+ if (!(t = findend(t, end))) return NULL;
+ }
+
+ /* checks if any of our skips ahead have put us at the end of expr */
+ if (t == end) break;
+
+ prev = *t;
+ }
+
+ return lowest;
+}
+
+rexpr *
+parsesimple(tok *start, tok *end, tok *lowest, mctx *ctx) {
+ rexpr *e = alloczctx(ctx, sizeof(rexpr));
+ switch (lowest->op) {
+ case INT:
+ if (start != end) {
+ parserErr("Trailing expression");
+ return NULL;
+ }
+ e->op = INT;
+ e->n = lowest->n;
+ break;
+ case OBRACE:
+ e->op = OBRACE;
+ e->e = parserexpr(&lowest[1], &findend(lowest, end)[-1], ctx);
+ break;
+ case NEGATE:
+ e->op = NEGATE;
+ e->e = parserexpr(&lowest[1], end, ctx);
+ break;
+ default:
+ parserErr("Unexpected token type");
+ return NULL;
+ }
+
+ return e;
+}
+
+rexpr *
+parsebin(tok *start, tok *end, tok *lowest, mctx *ctx) {
+ rexpr *e = alloczctx(ctx, sizeof(rexpr));
+
+ if (!isop(*lowest)) {
+ parserErr("Expected op");
+ return NULL;
+ }
+
+ // I think this is the spot!
+
+ e->op = lowest->op;
+ e->expr[0] = parserexpr(start, &lowest[-1], ctx);
+ e->expr[1] = parserexpr(&lowest[1], end, ctx);
+
+ return e;
+}
+
+rexpr *
+parserexpr(tok *start, tok *end, mctx *ctx) {
+ rexpr *e;
+ tok *lowest;
+ if (!(lowest = findlowest(start, end))) return NULL;
+
+ /* simple 1 term expr ops */
+ if (lowest == start) e = parsesimple(start, end, lowest, ctx);
+
+ /* binary ops */
+ else e = parsebin(start, end, lowest, ctx);
+
+ return e;
+}
+
+int
+eval(rexpr *e) {
+ switch (e->op) {
+ case INT:
+ return e->n;
+ case OBRACE:
+ return eval(e->e);
+ case NEGATE:
+ return -eval(e->e);
+ case ADD:
+ return eval(e->expr[0]) + eval(e->expr[1]);
+ case SUB:
+ return eval(e->expr[0]) - eval(e->expr[1]);
+ case MUL:
+ return eval(e->expr[0]) * eval(e->expr[1]);
+ case DIV:
+ return eval(e->expr[0]) / eval(e->expr[1]);
+ }
+}
+
+type *
+parsetype(lex *l, mctx *ctx) {
+ SAVE(l);
+ type *ty;
+ tok t = next(l);
+ if (t.op != NAME) {
+ RESTORE(l);
+ return NULL;
+ }
+ ty = alloczctx(ctx, sizeof(type));
+ ty->type = BASIC;
+ ty->name = t.name;
+ return ty;
+}
+
+int
+isterm(tok t) {
+ return (t.op == SEMI || t.op == COMMA || t.op == CBRACE);
+}
+
+lexpr *
+parseassign(lex *l, tok name, mctx *ctx) {
+ SAVE(l);
+ lexpr *le;
+ type *ty;
+ rexpr *r = NULL;
+ tok *arr, t;
+ int count = 1;
+
+ if (!(ty = parsetype(l, ctx))) {
+ RESTORE(l);
+ return NULL;
+ }
+ if ((t = next(l)).op != ASSIGN) {
+ if (isterm(t)) {
+ if (t.op != SEMI)
+ unlex(l);
+ goto shortdec;
+ }
+ RESTORE(l);
+ return NULL;
+ }
+
+ arr = alloczctx(ctx, sizeof(tok));
+ while ((t = next(l)).op != LEOF && !isterm(t)) {
+ arr[count++ - 1] = t;
+ arr = realloczctx(ctx, arr, sizeof(tok) * count);
+ }
+ if (count == 1) {
+ RESTORE(l);
+ return NULL;
+ } else if (!(r = parserexpr(arr, &arr[count - 2], ctx))) {
+ RESTORE(l);
+ return NULL;
+ }
+
+shortdec:
+ le = alloczctx(ctx, sizeof(lexpr));
+ le->name = alloczctx(ctx, strlen(name.name) + 1);
+ strcpy(le->name, name.name);
+ le->op = LEXPR_ASSIGN;
+ le->type = ty;
+ le->rexpr = r;
+ return le;
+}
+
+lexpr *
+parsefunc(lex *l, mctx *ctx) {
+ SAVE(l);
+ tok name, t;
+ lexpr *args = NULL, *arg = NULL, *func = NULL, *body = NULL;
+ type *ty;
+ int argc = 0;
+
+ if ((name = next(l)).op != NAME) {
+ parserErr("function has no name");
+ RESTORE(l);
+ return NULL;
+ }
+ if (next(l).op != OBRACE) {
+ parserErr("expected '('");
+ RESTORE(l);
+ return NULL;
+ }
+ for (;;) {
+ t = next(l);
+ switch (t.op) {
+ case NAME:
+ if (!(arg = parseassign(l, t, ctx))) {
+ parserErr("malformed function arg");
+ RESTORE(l);
+ return NULL;
+ }
+ args = realloczctx(ctx, args, sizeof(lexpr) * ++argc);
+ args[argc - 1] = *arg;
+ break;
+ case COMMA:
+ continue;
+ case CBRACE:
+ goto done;
+ default:
+ parserErr("unexpected token");
+ RESTORE(l);
+ return NULL;
+ }
+ }
+done:
+ if (argc == 0) {
+ argc = 0;
+ args = NULL;
+ }
+
+ if (!(ty = parsetype(l, ctx))) {
+ parserErr("function has no type");
+ RESTORE(l);
+ return NULL;
+ }
+
+ if ((t = next(l)).op == ';')
+ goto prototype;
+ else if (t.op != '{') {
+ parserErr("expected function body, or ';'");
+ RESTORE(l);
+ return NULL;
+ }
+
+ func = alloczctx(ctx, sizeof(lexpr));
+ do {
+ func->body = realloczctx(ctx, func->body, sizeof(lexpr) * (func->bodyc + 1));
+ body = parselexpr(l, ctx);
+ if (!body) {
+ RESTORE(l);
+ return NULL;
+ }
+ func->body[func->bodyc++] = *body;
+ t = next(l);
+ } while (t.op != '}' && unlex(l));
+
+ goto fullbody;
+
+prototype:
+ func = alloczctx(ctx, sizeof(lexpr));
+fullbody:
+ func->op = LEXPR_FUNC;
+ func->rtype = ty;
+ func->name = name.name;
+ func->args = args;
+ func->argc = argc;
+ return func;
+}
+
+lexpr *
+parselexpr(lex *l, mctx *ctx) {
+ SAVE(l);
+ lexpr *le;
+ tok t = next(l);
+ switch (t.op) {
+ case NAME:
+ le = parseassign(l, t, ctx);
+ break;
+ case FUNC:
+ le = parsefunc(l, ctx); /* we can drop the FUNC token, as it doesnt hold any info */
+ break;
+ default:
+ parserErr("unexpected tok type");
+ }
+ if (!le) {
+ RESTORE(l);
+ return NULL;
+ }
+
+ return le;
+}
+
diff --git a/parse.h b/parse.h
@@ -0,0 +1,72 @@
+#ifndef __PARSE_H_
+#define __PARSE_H_
+#include "lexer.h"
+#include "util.h"
+
+enum lexpr_ops {
+ LEXPR_ASSIGN,
+ LEXPR_FUNC,
+};
+
+enum type_types {
+ BASIC,
+};
+
+typedef struct rexpr {
+ enum lex_ops op;
+ union {
+ struct { /* unary ops */
+ struct rexpr *e;
+ };
+ struct { /* operators */
+ struct rexpr *expr[2];
+ };
+ struct { /* litterals */
+ int n;
+ };
+ };
+} rexpr;
+
+typedef struct type {
+ enum type_types type;
+ union {
+ struct { /* basic types */
+ char *name;
+ };
+ };
+} type;
+
+typedef struct lexpr {
+ enum lexpr_ops op;
+ union {
+ struct { /* assignments */
+ type *type;
+ char *name;
+ rexpr *rexpr;
+ };
+ struct { /* function decs */
+ type *rtype;
+ char *fname;
+ struct lexpr *args; /* must be of type assign */
+ int argc;
+ struct lexpr *body;
+ int bodyc;
+ };
+ };
+} lexpr;
+
+void parserErr(const char *msg);
+int getpres(tok t);
+int isop(tok t);
+tok *findend(tok *start, tok *end);
+tok *findlowest(tok *start, tok *end);
+rexpr *parsesimple(tok *start, tok *end, tok *lowest, mctx *ctx);
+rexpr *parsebin(tok *start, tok *end, tok *lowest, mctx *ctx);
+rexpr *parserexpr(tok *start, tok *end, mctx *ctx);
+int eval(rexpr *e);
+type *parsetype(lex *l, mctx *ctx);
+int isterm(tok t);
+lexpr *parseassign(lex *l, tok name, mctx *ctx);
+lexpr *parsefunc(lex *l, mctx *ctx);
+lexpr *parselexpr(lex *l, mctx *ctx);
+#endif
diff --git a/spl.c b/spl.c
@@ -3,383 +3,21 @@
#include <stdlib.h>
#include "lexer.h"
+#include "parse.h"
#include "util.h"
-
-enum lexpr_ops {
- LEXPR_ASSIGN,
- LEXPR_FUNC,
-};
-
-enum type_types {
- BASIC,
-};
-
-typedef struct rexpr {
- enum lex_ops op;
- union {
- struct { /* unary ops */
- struct rexpr *e;
- };
- struct { /* operators */
- struct rexpr *expr[2];
- };
- struct { /* litterals */
- int n;
- };
- };
-} rexpr;
-
-typedef struct type {
- enum type_types type;
- union {
- struct { /* basic types */
- char *name;
- };
- };
-} type;
-
-typedef struct lexpr {
- enum lexpr_ops op;
- union {
- struct { /* assignments */
- type *type;
- char *name;
- rexpr *rexpr;
- };
- struct { /* function decs */
- type *rtype;
- char *fname;
- struct lexpr *args; /* must be of type assign */
- int argc;
- };
- };
-} lexpr;
-
-rexpr *parserexpr(tok *start, tok *end, mctx *ctx);
-
-void
-parserErr(const char *msg) {
- fprintf(stderr, "%s\n", msg);
-}
-
-int
-getpres(tok t) {
- switch (t.op) {
- case LEOF:
- return -1;
-
- case ADD:
- case SUB:
- return 1;
-
- case MUL:
- case DIV:
- return 4;
-
- case INT:
- return 6;
- case OBRACE:
- return 8;
-
- case NEGATE:
- return 5;
- }
- return -2;
-}
-
-int
-isop(tok t) {
- return (t.op == ADD || t.op == SUB || t.op == MUL || t.op == DIV);
-}
-
-tok *
-findend(tok *start, tok *end) {
- int d = 1;
- tok *t;
-
- if (start->op != OBRACE) {
- parserErr("Expected a '('");
- return NULL;
- }
-
- for (t = &start[1]; d != 0; t = &t[1]) {
- if (end->op != CBRACE && t == end) {
- parserErr("unclosed brace");
- return NULL;
- }
-
- if (t->op == OBRACE) d++;
- else if (t->op == CBRACE) d--;
- }
- return &t[-1];
-}
-
-tok *
-findlowest(tok *start, tok *end) {
- tok *lowest = start, prev = {.op = LEOF};
-
- for (tok *t = lowest ; t != end; t = &t[1]) {
- /* re assign ops, this is for when an op has multiple meanings */
- if (isop(prev) || prev.op == LEOF) {
- switch (t->op) {
- case SUB:
- t->op = NEGATE;
- break;
- }
- }
- else if (getpres(*t) < getpres(*lowest)) lowest = t;
-
- /* move to the end brace, we only process the contents when nothing else is left */
- if (t->op == OBRACE) {
- if (!(t = findend(t, end))) return NULL;
- }
-
- /* checks if any of our skips ahead have put us at the end of expr */
- if (t == end) break;
-
- prev = *t;
- }
-
- return lowest;
-}
-
-rexpr *
-parsesimple(tok *start, tok *end, tok *lowest, mctx *ctx) {
- rexpr *e = alloczctx(ctx, sizeof(rexpr));
- switch (lowest->op) {
- case INT:
- if (start != end) {
- parserErr("Trailing expression");
- return NULL;
- }
- e->op = INT;
- e->n = lowest->n;
- break;
- case OBRACE:
- e->op = OBRACE;
- e->e = parserexpr(&lowest[1], &findend(lowest, end)[-1], ctx);
- break;
- case NEGATE:
- e->op = NEGATE;
- e->e = parserexpr(&lowest[1], end, ctx);
- break;
- default:
- parserErr("Unexpected token type");
- return NULL;
- }
-
- return e;
-}
-
-rexpr *
-parsebin(tok *start, tok *end, tok *lowest, mctx *ctx) {
- rexpr *e = alloczctx(ctx, sizeof(rexpr));
-
- if (!isop(*lowest)) {
- parserErr("Expected op");
- return NULL;
- }
-
- // I think this is the spot!
-
- e->op = lowest->op;
- e->expr[0] = parserexpr(start, &lowest[-1], ctx);
- e->expr[1] = parserexpr(&lowest[1], end, ctx);
-
- return e;
-}
-
-rexpr *
-parserexpr(tok *start, tok *end, mctx *ctx) {
- rexpr *e;
- tok *lowest;
- if (!(lowest = findlowest(start, end))) return NULL;
-
- /* simple 1 term expr ops */
- if (lowest == start) e = parsesimple(start, end, lowest, ctx);
-
- /* binary ops */
- else e = parsebin(start, end, lowest, ctx);
-
- return e;
-}
-
-int
-eval(rexpr *e) {
- switch (e->op) {
- case INT:
- return e->n;
- case OBRACE:
- return eval(e->e);
- case NEGATE:
- return -eval(e->e);
- case ADD:
- return eval(e->expr[0]) + eval(e->expr[1]);
- case SUB:
- return eval(e->expr[0]) - eval(e->expr[1]);
- case MUL:
- return eval(e->expr[0]) * eval(e->expr[1]);
- case DIV:
- return eval(e->expr[0]) / eval(e->expr[1]);
- }
-}
-
-type *
-parsetype(lex *l, mctx *ctx) {
- SAVE(l);
- type *ty;
- tok t = next(l);
- if (t.op != NAME) {
- RESTORE(l);
- return NULL;
- }
- ty = alloczctx(ctx, sizeof(type));
- ty->type = BASIC;
- ty->name = t.name;
- return ty;
-}
+#include "check.h"
+#include "cback.h"
int
-isterm(tok t) {
- return (t.op == SEMI || t.op == COMMA || t.op == CBRACE);
-}
+main(int argc, char **argv) {
+ if (argc == 1)
+ exit(1);
-lexpr *
-parseassign(lex *l, tok name, mctx *ctx) {
- SAVE(l);
- lexpr *le;
- type *ty;
- rexpr *r = NULL;
- tok *arr, t;
- int count = 1;
+ FILE *f = fopen(argv[1], "r");
+ char *file = drainfile(f);
+ fclose(f);
- if (!(ty = parsetype(l, ctx))) {
- RESTORE(l);
- return NULL;
- }
- if ((t = next(l)).op != ASSIGN) {
- if (isterm(t)) {
- if (t.op != SEMI)
- l->ptr--;
- goto shortdec;
- }
- RESTORE(l);
- return NULL;
- }
-
- arr = alloczctx(ctx, sizeof(tok));
- while ((t = next(l)).op != LEOF && !isterm(t)) {
- arr[count++ - 1] = t;
- arr = realloczctx(ctx, arr, sizeof(tok) * count);
- }
- if (count == 1) {
- RESTORE(l);
- return NULL;
- } else if (!(r = parserexpr(arr, &arr[count - 2], ctx))) {
- RESTORE(l);
- return NULL;
- }
-
-shortdec:
- le = alloczctx(ctx, sizeof(lexpr));
- le->op = LEXPR_ASSIGN;
- le->name = name.name;
- le->type = ty;
- le->rexpr = r;
- return le;
-}
-
-lexpr *
-parsefunc(lex *l, mctx *ctx) {
- SAVE(l);
- tok name, t;
- lexpr *args, *arg, *func;
- type *ty;
- int argc = 1;
-
- if ((name = next(l)).op != NAME) {
- parserErr("function has no name");
- RESTORE(l);
- return NULL;
- }
- if (next(l).op != OBRACE) {
- parserErr("expected '('");
- RESTORE(l);
- return NULL;
- }
- args = alloczctx(ctx, sizeof(lexpr));
-
- for (;;) {
- t = next(l);
- switch (t.op) {
- case NAME:
- if (!(arg = parseassign(l, t, ctx))) {
- parserErr("malformed function arg");
- RESTORE(l);
- return NULL;
- }
- args[argc++ - 1] = *arg;
- args = realloczctx(ctx, args, sizeof(lexpr) * argc);
- case COMMA:
- continue;
- case CBRACE:
- goto done;
- default:
- parserErr("unexpected token");
- RESTORE(l);
- return NULL;
- }
- }
-done:
- argc--;
- if (argc ==0) {
- argc = 0;
- args = NULL;
- }
-
- if (!(ty = parsetype(l, ctx))) {
- parserErr("function has no type");
- RESTORE(l);
- return NULL;
- }
-
- func = alloczctx(ctx, sizeof(lexpr));
- func->op = LEXPR_FUNC;
- func->rtype = ty;
- func->name = name.name;
- func->args = args;
- func->argc = argc;
- return func;
-}
-
-lexpr *
-parselexpr(lex *l, mctx *ctx) {
- SAVE(l);
- lexpr *le;
- tok t = next(l);
- switch (t.op) {
- case NAME:
- le = parseassign(l, t, ctx);
- break;
- case FUNC:
- le = parsefunc(l, ctx); /* we can drop the FUNC token, as it doesnt hold any info */
- break;
- default:
- parserErr("unexpected tok type");
- }
- if (!le) {
- RESTORE(l);
- return NULL;
- }
-
- return le;
-}
-
-
-
-int
-main() {
- lex l = mklexer("func foo(n int, m int) int");
+ lex l = mklexer(file);
mctx *ctx = newctx();
lexpr *e = parselexpr(&l, ctx);
@@ -387,7 +25,14 @@ main() {
parserErr("failed to parse lexpr");
goto cleanup;
}
+
+ mctx *checkctx = newctx();
+ checklexpr(e, NULL, checkctx);
+ freectx(checkctx);
+
+ compilelexpr_C(e, stdout);
cleanup:
+ free(file);
freectx(ctx);
}
diff --git a/test.spl b/test.spl
@@ -0,0 +1,6 @@
+func main(arg1 int, arg2 int) int {
+ a int = 0;
+ func foo() int {
+ a int = 3;
+ }
+}
diff --git a/util.c b/util.c
@@ -68,3 +68,18 @@ strslice(char *s, int len) {
memcpy(slice, s, len);
return slice;
}
+
+char *
+drainfile(FILE *f) {
+ int l;
+ char *file;
+
+ fseek(f, 0, SEEK_END);
+ l = ftell(f);
+ rewind(f);
+
+ file = malloc(l + 1);
+ fread(file, 1, l, f);
+
+ return file;
+}
diff --git a/util.h b/util.h
@@ -1,3 +1,5 @@
+#ifndef __UTIL_H_
+#define __UTIL_H_
#define allocztn(type, n) allocz(sizeof(type) * n)
#define alloczt(type) allocz(sizeof(type))
@@ -15,3 +17,5 @@ void *allocz(const size_t size);
mctx *newctx();
void freectx(mctx *ctx);
char *strslice(char *s, int len);
+char *drainfile(FILE *f);
+#endif