spl

a Simple Programming Language
Log | Files | Refs

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------------
MMakefile | 9++++-----
Acback.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acback.h | 11+++++++++++
Acheck.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acheck.h | 30++++++++++++++++++++++++++++++
Mlexer.c | 10++++++++--
Mlexer.h | 7+++++--
Aparse.c | 349+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparse.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mspl.c | 389++++---------------------------------------------------------------------------
Atest.spl | 6++++++
Mutil.c | 15+++++++++++++++
Mutil.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