From b7052e17a426b22c1c48b0d50bf169c3c3bbdda0 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Sat, 5 Sep 2026 17:14:53 +0200 Subject: Move source to src/prc1 --- CMakeLists.txt | 42 +--- call.c | 488 ---------------------------------------- call.h | 37 --- cgen.c | 195 ---------------- cgen.h | 23 -- display.c | 142 ------------ display.h | 17 -- div.c | 89 -------- div.h | 11 - end.c | 80 ------- end.h | 18 -- errloc.c | 28 --- errloc.h | 9 - exit.c | 8 - exit.h | 16 -- fn.c | 273 ---------------------- fn.h | 22 -- from.c | 364 ------------------------------ from.h | 34 --- gl.c | 24 -- gl.h | 12 - im.c | 125 ----------- im.h | 11 - kw.c | 41 ---- lex.c | 249 -------------------- lex.h | 34 --- lit.c | 102 --------- lit.h | 12 - lk.c | 12 - lk.h | 9 - main.c | 53 ----- parse.c | 183 --------------- parse.h | 138 ------------ pop.c | 37 --- pr.c | 375 ------------------------------- pr.h | 11 - print.c | 103 --------- print.h | 26 --- prv.h | 51 ----- push.c | 27 --- sdup.c | 16 -- set.c | 552 --------------------------------------------- set.h | 29 --- src/CMakeLists.txt | 2 + src/prc1/CMakeLists.txt | 39 ++++ src/prc1/call.c | 488 ++++++++++++++++++++++++++++++++++++++++ src/prc1/call.h | 37 +++ src/prc1/cgen.c | 195 ++++++++++++++++ src/prc1/cgen.h | 23 ++ src/prc1/display.c | 142 ++++++++++++ src/prc1/display.h | 17 ++ src/prc1/div.c | 89 ++++++++ src/prc1/div.h | 11 + src/prc1/end.c | 80 +++++++ src/prc1/end.h | 18 ++ src/prc1/errloc.c | 28 +++ src/prc1/errloc.h | 9 + src/prc1/exit.c | 8 + src/prc1/exit.h | 16 ++ src/prc1/fn.c | 273 ++++++++++++++++++++++ src/prc1/fn.h | 22 ++ src/prc1/from.c | 364 ++++++++++++++++++++++++++++++ src/prc1/from.h | 34 +++ src/prc1/gl.c | 24 ++ src/prc1/gl.h | 12 + src/prc1/im.c | 125 +++++++++++ src/prc1/im.h | 11 + src/prc1/kw.c | 41 ++++ src/prc1/lex.c | 249 ++++++++++++++++++++ src/prc1/lex.h | 34 +++ src/prc1/lit.c | 102 +++++++++ src/prc1/lit.h | 12 + src/prc1/lk.c | 12 + src/prc1/lk.h | 9 + src/prc1/parse.c | 183 +++++++++++++++ src/prc1/parse.h | 138 ++++++++++++ src/prc1/pop.c | 37 +++ src/prc1/pr.c | 375 +++++++++++++++++++++++++++++++ src/prc1/pr.h | 11 + src/prc1/prc1.c | 53 +++++ src/prc1/print.c | 103 +++++++++ src/prc1/print.h | 26 +++ src/prc1/prv.h | 51 +++++ src/prc1/push.c | 27 +++ src/prc1/sdup.c | 16 ++ src/prc1/set.c | 552 +++++++++++++++++++++++++++++++++++++++++++++ src/prc1/set.h | 29 +++ src/prc1/stmt.c | 92 ++++++++ src/prc1/stmt.h | 44 ++++ src/prc1/storage.c | 219 ++++++++++++++++++ src/prc1/storage.h | 29 +++ src/prc1/td.c | 587 ++++++++++++++++++++++++++++++++++++++++++++++++ src/prc1/td.h | 22 ++ src/prc1/tmp.c | 69 ++++++ src/prc1/tmp.h | 9 + src/prc1/type.c | 459 +++++++++++++++++++++++++++++++++++++ src/prc1/type.h | 16 ++ src/prc1/warn.c | 146 ++++++++++++ src/prc1/warn.h | 17 ++ src/prc1/ws.c | 29 +++ src/prc1/ws.h | 12 + stmt.c | 92 -------- stmt.h | 44 ---- storage.c | 219 ------------------ storage.h | 29 --- td.c | 587 ------------------------------------------------ td.h | 22 -- tmp.c | 69 ------ tmp.h | 9 - type.c | 459 ------------------------------------- type.h | 16 -- warn.c | 146 ------------ warn.h | 17 -- ws.c | 29 --- ws.h | 12 - 115 files changed, 5878 insertions(+), 5877 deletions(-) delete mode 100644 call.c delete mode 100644 call.h delete mode 100644 cgen.c delete mode 100644 cgen.h delete mode 100644 display.c delete mode 100644 display.h delete mode 100644 div.c delete mode 100644 div.h delete mode 100644 end.c delete mode 100644 end.h delete mode 100644 errloc.c delete mode 100644 errloc.h delete mode 100644 exit.c delete mode 100644 exit.h delete mode 100644 fn.c delete mode 100644 fn.h delete mode 100644 from.c delete mode 100644 from.h delete mode 100644 gl.c delete mode 100644 gl.h delete mode 100644 im.c delete mode 100644 im.h delete mode 100644 kw.c delete mode 100644 lex.c delete mode 100644 lex.h delete mode 100644 lit.c delete mode 100644 lit.h delete mode 100644 lk.c delete mode 100644 lk.h delete mode 100644 main.c delete mode 100644 parse.c delete mode 100644 parse.h delete mode 100644 pop.c delete mode 100644 pr.c delete mode 100644 pr.h delete mode 100644 print.c delete mode 100644 print.h delete mode 100644 prv.h delete mode 100644 push.c delete mode 100644 sdup.c delete mode 100644 set.c delete mode 100644 set.h create mode 100644 src/CMakeLists.txt create mode 100644 src/prc1/CMakeLists.txt create mode 100644 src/prc1/call.c create mode 100644 src/prc1/call.h create mode 100644 src/prc1/cgen.c create mode 100644 src/prc1/cgen.h create mode 100644 src/prc1/display.c create mode 100644 src/prc1/display.h create mode 100644 src/prc1/div.c create mode 100644 src/prc1/div.h create mode 100644 src/prc1/end.c create mode 100644 src/prc1/end.h create mode 100644 src/prc1/errloc.c create mode 100644 src/prc1/errloc.h create mode 100644 src/prc1/exit.c create mode 100644 src/prc1/exit.h create mode 100644 src/prc1/fn.c create mode 100644 src/prc1/fn.h create mode 100644 src/prc1/from.c create mode 100644 src/prc1/from.h create mode 100644 src/prc1/gl.c create mode 100644 src/prc1/gl.h create mode 100644 src/prc1/im.c create mode 100644 src/prc1/im.h create mode 100644 src/prc1/kw.c create mode 100644 src/prc1/lex.c create mode 100644 src/prc1/lex.h create mode 100644 src/prc1/lit.c create mode 100644 src/prc1/lit.h create mode 100644 src/prc1/lk.c create mode 100644 src/prc1/lk.h create mode 100644 src/prc1/parse.c create mode 100644 src/prc1/parse.h create mode 100644 src/prc1/pop.c create mode 100644 src/prc1/pr.c create mode 100644 src/prc1/pr.h create mode 100644 src/prc1/prc1.c create mode 100644 src/prc1/print.c create mode 100644 src/prc1/print.h create mode 100644 src/prc1/prv.h create mode 100644 src/prc1/push.c create mode 100644 src/prc1/sdup.c create mode 100644 src/prc1/set.c create mode 100644 src/prc1/set.h create mode 100644 src/prc1/stmt.c create mode 100644 src/prc1/stmt.h create mode 100644 src/prc1/storage.c create mode 100644 src/prc1/storage.h create mode 100644 src/prc1/td.c create mode 100644 src/prc1/td.h create mode 100644 src/prc1/tmp.c create mode 100644 src/prc1/tmp.h create mode 100644 src/prc1/type.c create mode 100644 src/prc1/type.h create mode 100644 src/prc1/warn.c create mode 100644 src/prc1/warn.h create mode 100644 src/prc1/ws.c create mode 100644 src/prc1/ws.h delete mode 100644 stmt.c delete mode 100644 stmt.h delete mode 100644 storage.c delete mode 100644 storage.h delete mode 100644 td.c delete mode 100644 td.h delete mode 100644 tmp.c delete mode 100644 tmp.h delete mode 100644 type.c delete mode 100644 type.h delete mode 100644 warn.c delete mode 100644 warn.h delete mode 100644 ws.c delete mode 100644 ws.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 899e223..8ff5c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,43 +1,3 @@ cmake_minimum_required(VERSION 3.5) project(prc C) -add_executable(${PROJECT_NAME} - call.c - cgen.c - display.c - div.c - end.c - errloc.c - exit.c - fn.c - from.c - gl.c - im.c - kw.c - lex.c - lit.c - lk.c - main.c - set.c - parse.c - pop.c - pr.c - print.c - push.c - sdup.c - stmt.c - storage.c - td.c - tmp.c - type.c - warn.c - ws.c -) - -target_compile_options(${PROJECT_NAME} PRIVATE -g -Wall -pedantic) -set_target_properties(${PROJECT_NAME} PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF) - -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - target_compile_options(${PROJECT_NAME} PRIVATE -Og) -endif() - -install(TARGETS ${PROJECT_NAME}) +add_subdirectory(src) diff --git a/call.c b/call.c deleted file mode 100644 index 8140eba..0000000 --- a/call.c +++ /dev/null @@ -1,488 +0,0 @@ -#include "call.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "lit.h" -#include "parse.h" -#include "prv.h" -#include "stmt.h" -#include "type.h" -#include -#include -#include -#include - -static int callpr(const struct lex *l, struct prv *p); -static int callp(const struct lex *l, struct prv *p); -static int callr(const struct lex *l, struct prv *p); -static int callv(const struct lex *l, struct prv *p); - -static const struct seq seqs[] = -{ - {(struct step[]){ - {ID}, - {ID, "using"}, - {ANY, NULL, 1}, - {ID, "returning"}, - {ID}, - {0}}, .fn = callpr}, - {(struct step[]){ - {ID}, - {ID, "using"}, - {ANY, NULL, 1}, - {0}}, .fn = callp}, - {(struct step[]){ - {ID}, - {ID, "returning"}, - {ID}, - {0}}, .fn = callr}, - {(struct step[]){ - {ID}, - {0}}, .fn = callv}, - {0} -}; - -static int param(const struct lex *l, struct prv *p, const struct tk *tk, - struct call *c) -{ - const struct fn *fn = fn_cur(p); - size_t n = c->nparams + 1; - struct callparam *params; - const struct lit *lit = NULL; - const struct stentry *e = NULL; - const struct type *t = NULL; - int sign = 0; - union callv u = {0}; - - if (tk->type == LIT) - { - if (!(lit = lit_push(tk, p))) - return -1; - } - else if (tk->type == NUM) - { - if ((sign = *tk->s == '-')) - u.v = strtoll(tk->s, NULL, 0); - else - u.uv = strtoull(tk->s, NULL, 0); - } - else if ((t = type_find(fn, tk->s))) - { - if (t->type != C) - { - errloc(tk, "type \"%s\" not a constant", tk->s); - return -1; - } - } - else if (!(e = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to parameter \"%s\"", tk->s); - return -1; - } - - if (!(params = realloc(c->params, n * sizeof *params))) - { - perror("realloc(3)"); - return -1; - } - - c->params = params; - c->params[c->nparams++] = (struct callparam) - { - .entry = e, - .lit = lit, - .t = t, - .u = u - }; - - return 0; -} - -static int callpr(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk + 2; - struct call *c = &stmt_cur(p)->u.call; - const struct pr *pr = c->pr; - const struct stentry *e; - size_t n = 0; - - while (!lex_eof(l, tk) && !kw((tk++)->s)) - n++; - - if (pr->variadic) - { - if (n < pr->nparams) - { - errloc(tk, "function \"%s\" expects at least %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); - return -1; - } - } - else if (n != pr->nparams) - { - tk -= 2; - errloc(tk, "function \"%s\" expects %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); - return -1; - } - - if (!pr->ret) - { - errloc(tk, "function \"%s\" does not expect any return variable", - c->tk->s); - return -1; - } - - tk = p->stk + 2; - - for (size_t i = 0; i < n; i++) - if (param(l, p, tk++, c)) - return -1; - - if (!(e = fn_var(fn_cur(p), ++tk))) - { - errloc(tk, "undefined reference to return variable \"%s\"", - tk->s); - return -1; - } - else if (pop(l, p)) - return -1; - - fprintf(stderr, "\t\tadding call to %s using %zu params " - "and %s as return variable\n", c->tk->s, n, tk->s); - c->ret = e; - c->nparams = n; - p->stk = ++tk; - return 1; -} - -static int callr(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk + 2; - const struct fn *fn = fn_cur(p); - const struct stentry *e; - struct call *c = &stmt_cur(p)->u.call; - const struct pr *pr = c->pr; - - if (!pr->ret) - { - errloc(tk, "function \"%s\" does not expect any return variable", - c->tk->s); - return -1; - } - else if (pr->nparams) - { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but none were given", c->tk->s, pr->nparams); - return -1; - } - else if (!(e = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to return variable \"%s\"", tk->s); - return -1; - } - else if (pop(l, p)) - return -1; - - fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", - c->tk->s, tk->s); - c->ret = e; - p->stk = ++tk; - return 1; -} - -static int callp(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk + 2; - struct call *c = &stmt_cur(p)->u.call; - const struct pr *pr = c->pr; - size_t n = 0; - - while (!lex_eof(l, tk) && !kw((tk++)->s)) - n++; - - if (lex_eof(l, tk)) - tk--; - - if (pr->variadic) - { - if (n < pr->nparams) - { - errloc(tk, "function \"%s\" expects at least %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); - return -1; - } - } - else if (pr->nparams != n) - { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but %zu were given", c->tk->s, pr->nparams, n); - return -1; - } - - tk = p->stk + 2; - - for (size_t i = 0; i < n; i++) - if (param(l, p, tk++, c)) - return -1; - - if (pop(l, p)) - return -1; - - fprintf(stderr, "\t\tadding call to %s with 1 param\n", c->tk->s); - p->stk = tk; - return 1; -} - -static int callv(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - struct call *c = &stmt_cur(p)->u.call; - const struct pr *pr = c->pr; - - if (pr->nparams) - { - errloc(tk, "function \"%s\" expects %zu parameters, " - "but none were given", c->tk->s, pr->nparams); - return -1; - } - else if (pop(l, p)) - return -1; - - fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", - c->tk->s, tk->s); - p->stk = ++tk; - return 1; -} - -static const struct pr *find_proto(const struct fn *fn, const char *s) -{ - const struct type *t = type_find(fn, s); - - if (t && t->type == P) - return t->u.p.fn->pr; - - return NULL; -} - -static const struct pr *find(const struct ast *ast, const char *s) -{ - for (size_t i = 0; i < ast->nfns; i++) - { - const struct fn *fn = &ast->fns[i]; - const struct pr *pr; - - if ((pr = find_proto(fn, s))) - return pr; - else if (!strcmp(fn->tk->s, s)) - return fn->pr; - } - - return NULL; -} - -static int gettmp(char *tmp, size_t n) -{ - size_t j; - - for (j = 0; j < n; j++) - { - char c = tmp[j]; - - if (!c) - return tmp[j] = 'a'; - else if (c != 'z') - return ++(tmp[j]); - } - - return EOF; -} - -static int param_lit(const struct lit *lit, struct cgen *c) -{ - printf("l $%s", lit->name); - return 0; -} - -static int param_id(const struct stentry *e, struct cgen *c, char *tmp, - size_t n) -{ - const char *name = e->tk->s; - const struct type *t = e->t; - - printf("%s ", cgen_sz(t->sz)); - - if (cgen_global(c->fn, e)) - printf("$%s", name); - else if (cgen_abity(t)) - { - if (gettmp(tmp, n) == EOF) - return -1; - - printf("%%%s", tmp); - } - else - printf("%%%s_", name); - - return 0; -} - -static int param_c(const struct type *t, struct cgen *cg) -{ - const union c *c = &t->u.c; - - /* TODO: adapt type to expected param size */ - fputs("l ", stdout); - - if (t->sign) - printf("%lld", c->v); - else - printf("%llu", c->uv); - - return 0; -} - -static int param_num(const struct callparam *cp, struct cgen *c) -{ - const union callv *u = &cp->u; - - /* TODO: adapt type to expected param size */ - fputs("w ", stdout); - - if (cp->sign) - printf("%lld", u->v); - else - printf("%llu", u->uv); - - return 0; -} - -static int param_load(const struct call *m, struct cgen *c) -{ - char tmp[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; - - for (size_t i = 0; i < m->nparams; i++) - { - const struct callparam *cp = &m->params[i]; - const struct stentry *e = cp->entry; - - if (!e || cgen_global(c->fn, e) || !cgen_abity(e->t)) - continue; - else if (gettmp(tmp, sizeof tmp - 1) == EOF) - { - fprintf(stderr, "%s: exhausted temporaries\n", __func__); - return -1; - } - - printf("%%%s =%s load%s %%%s_\n", tmp, cgen_sz(e->t->sz), - cgen_load(e->t), e->tk->s); - } - - return 0; -} - -int call_cgen(const struct call *m, struct cgen *c) -{ - char tmps[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; - const struct stentry *ret = m->ret; - const char *tmp; - size_t sz; - - if (param_load(m, c)) - return -1; - else if (ret) - { - tmp = cgen_tmp((sz = ret->t->sz)); - printf("%%%s =%s ", tmp, cgen_sz(sz)); - } - - printf("call $%s(", m->tk->s); - - for (size_t i = 0; i < m->nparams; i++) - { - const struct callparam *cp = &m->params[i]; - int var = m->pr->variadic; - - if (cp->lit) - param_lit(cp->lit, c); - else if (cp->entry) - param_id(cp->entry, c, tmps, sizeof tmps - 1); - else if (cp->t) - param_c(cp->t, c); - else - param_num(cp, c); - - if (var && i + 1 == var - 1) - fputs(", ...", stdout); - - if (i + 1 < m->nparams) - fputs(", ", stdout); - } - - puts(")"); - - if (ret) - { - printf("store%s %%%s, ", cgen_sz(sz), tmp); - cgen_printvar(c->fn, ret); - putchar('\n'); - } - - return 0; -} - -void call_free(struct call *c) -{ - if (c) - free(c->params); -} - -int call(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->tk; - const struct pr *pr; - struct fn *fn = fn_cur(p); - size_t n = fn->nstmts +1; - struct stmt *stmts; - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - /* TODO: function pointers */ - - if (lex_eof(l, tk)) - { - errloc(tk - 1, "incomplete call statement"); - return -1; - } - else if (!(pr = find(p->ast, tk->s))) - { - errloc(tk, "undefined reference to function \"%s\"", tk->s); - return -1; - } - else if (!(stmts = realloc(fn->stmts, n * sizeof *stmts))) - { - perror("realloc(3)"); - return -1; - } - - fn->stmts = stmts; - fn->stmts[fn->nstmts++] = (struct stmt) - { - .type = CALL, - .u.call = - { - .tk = tk, - .pr = pr - } - }; - - if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} diff --git a/call.h b/call.h deleted file mode 100644 index 0126e7f..0000000 --- a/call.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CALL_H -#define CALL_H - -#include "cgen.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include - -struct callparam -{ - const struct lit *lit; - const struct type *t; - const struct stentry *entry; - int sign; - - union callv - { - long long v; - unsigned long long uv; - } u; -}; - -struct call -{ - const struct tk *tk; - const struct pr *pr; - const struct stentry *ret; - struct callparam *params; - size_t nparams; -}; - -int call(const struct lex *l, struct prv *p); -int call_cgen(const struct call *m, struct cgen *c); -void call_free(struct call *c); - -#endif diff --git a/cgen.c b/cgen.c deleted file mode 100644 index 44e9d24..0000000 --- a/cgen.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "cgen.h" -#include "fn.h" -#include "lex.h" -#include "lit.h" -#include "parse.h" -#include "storage.h" -#include -#include -#include - -void cgen_free(struct cgen *c) -{ -} - -const char *cgen_sz(const size_t sz) -{ - switch (sz) - { - case 1: - return "b"; - case 2: - return "h"; - case 4: - return "w"; - case 8: - return "l"; - default: - break; - } - - return NULL; -} - -const char *cgen_tmp(const size_t sz) -{ - switch (sz) - { - case 1: - return "vb"; - case 2: - return "vh"; - case 4: - return "vw"; - case 8: - return "vl"; - default: - break; - } - - return "v"; -} - -const char *cgen_type(const struct type *t) -{ - switch (t->sz) - { - case 1: - return t->sign ? "b" : "ub"; - case 2: - return t->sign ? "h" : "uh"; - case 4: - return t->sign ? "w" : "uw"; - case 8: - return t->sign ? "l" : "ul"; - - default: - break; - } - - return NULL; -} - -const char *cgen_abity(const struct type *t) -{ - switch (t->sz) - { - case 1: - return t->sign ? "b" : "ub"; - case 2: - return t->sign ? "h" : "uh"; - case 4: - return "w"; - case 8: - return "l"; - - default: - break; - } - - return NULL; -} - -const char *cgen_load(const struct type *t) -{ - switch (t->sz) - { - case 1: - return t->sign ? "sb" : "ub"; - case 2: - return t->sign ? "sh" : "uh"; - case 4: - return t->sign ? "sw" : "uw"; - case 8: - return "l"; - - default: - break; - } - - return NULL; -} - -int cgen_param(const struct fn *fn, const struct stentry *e) -{ - const struct pr *pr = fn->pr; - const char *name = e->tk->s; - - for (size_t i = 0; i < pr->nparams; i++) - if (!strcmp(pr->params[i].tk->s, name)) - return 1; - - return 0; -} - -void cgen_printvar(const struct fn *fn, const struct stentry *e) -{ - const char *name = e->tk->s; - - if (cgen_global(fn, e)) - printf("$%s", name); - else - printf("%%%s_", name); -} - -int cgen_global(const struct fn *fn, const struct stentry *e) -{ - const struct storage *ws = fn->ws, *gl = fn->gl; - const struct pr *pr = fn->pr; - const struct param *ret = pr->ret; - const char *name = e->tk->s; - - /* A variable is only global if it is defined inside the global - * variables section ("gl"), or if it is not listed on the working - * storage section ("ws"), as a function parameter or a return value. */ - - if (gl) - for (size_t i = 0; i < gl->nentries; i++) - if (!strcmp(gl->entries[i].tk->s, name)) - return 1; - - if (cgen_param(fn, e) || (ret && !strcmp(ret->tk->s, name))) - return 0; - else if (ws) - for (size_t i = 0; i < ws->nentries; i++) - if (!strcmp(ws->entries[i].tk->s, name)) - return 0; - - for (const struct tmp *t = fn->tmps; t; t = t->next) - if (!strcmp(t->tk.s, name)) - return 0; - - return 1; -} - -static void pushfmt(const char *type, const char *fmt) -{ - printf("data $____fmt%s = { b \"%s\" , b 0 }\n", type, fmt); -} - -int cgen(const struct ast *ast, struct cgen *c) -{ - /* generate literals to use with printf(3) */ - pushfmt("b", "%hhd"); - pushfmt("h", "%hd"); - pushfmt("w", "%d"); - pushfmt("l", "%ld"); - pushfmt("ub", "%hhu"); - pushfmt("uh", "%hu"); - pushfmt("uw", "%u"); - pushfmt("ul", "%lu"); - pushfmt("bx", "%#hhx"); - pushfmt("hx", "%#hx"); - pushfmt("wx", "%#x"); - pushfmt("lx", "%#lx"); - - for (const struct lit *l = ast->lits; l; l = l->next) - if (lit_cgen(l)) - return-1; - - for (size_t i = 0; i < ast->nfns; i++) - if (fn_cgen((c->fn = &ast->fns[i]), c)) - return -1; - - return 0; -} diff --git a/cgen.h b/cgen.h deleted file mode 100644 index 0a30138..0000000 --- a/cgen.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CGEN_H -#define CGEN_H - -#include "parse.h" -#include "storage.h" - -struct cgen -{ - const struct fn *fn; -}; - -int cgen(const struct ast *ast, struct cgen *c); -int cgen_param(const struct fn *fn, const struct stentry *e); -int cgen_global(const struct fn *fn, const struct stentry *e); -void cgen_printvar(const struct fn *fn, const struct stentry *e); -const char *cgen_sz(const size_t sz); -const char *cgen_tmp(const size_t sz); -const char *cgen_type(const struct type *t); -const char *cgen_abity(const struct type *t); -const char *cgen_load(const struct type *t); -void cgen_free(struct cgen *c); - -#endif diff --git a/display.c b/display.c deleted file mode 100644 index 885fbe7..0000000 --- a/display.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "display.h" -#include "cgen.h" -#include "parse.h" -#include "prv.h" -#include "stmt.h" -#include "storage.h" -#include -#include -#include - -static int finalize(const struct lex *l, const struct prv *p, - const struct print *pr) -{ - const struct ast *ast = p->ast; - struct fn *fn = &ast->fns[ast->nfns - 1]; - size_t n = fn->nstmts + 1; - struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); - - if (!stmts) - { - perror("realloc(3)"); - return -1; - } - - fn->stmts = stmts; - fn->stmts[fn->nstmts++] = (struct stmt) - { - .type = DISPLAY, - .u.display.p = *pr - }; - - fprintf(stderr, "\t\tadding display statement with %zu entries%s\n", - pr->nentries, pr->println ? "" : ", no lf"); - return 0; -} - -static int cg_val(const struct tk *tk) -{ - const char *num = tk->s; - int neg = *num == '-'; - unsigned long long uv; - char *end; - - fputs("call $printf(l $____fmt", stdout); - errno = 0; - uv = strtoull(num, &end, 16); - - if (!neg && !errno && !*end) - printf("lx, ..., l %llu )\n", uv); - else - { - errno = 0; - uv = strtoull(num, &end, 0); - - if (neg || errno || *end) - { - long long v = strtoll(num, NULL, 0); - printf("l, ..., l %lld )\n", v); - } - else - printf("l, ..., l %llu )\n", uv); - } - - return 0; -} - -static int cg_lit(const struct prientry *e) -{ - const struct lit *l = e->lit; - const char *tmp; - - if (!l) - { - fprintf(stderr, "%s: unexpected null literal\n", __func__); - return -1; - } - - printf("%%%s =l loadl $stdout\n", (tmp = cgen_tmp(sizeof (void *)))); - printf("call $fputs(l $%s, w %%%s)\n", l->name, tmp); - return 0; -} - -static int cg_id(const struct prientry *de, const struct fn *fn) -{ - const struct stentry *e = de->entry; - const struct type *t = e->t; - const char *id = e->tk->s; - int global = cgen_global(fn, e); - size_t sz = t->sz; - const char *asz = cgen_sz(sz < 4 ? 4 : sz), *tmp = cgen_tmp(sz); - - if (global) - printf("%%%s =%s load%s $%s\n", tmp, asz, cgen_load(t), id); - else - printf("%%%s =%s load%s %%%s_\n", tmp, asz, cgen_load(t), id); - - fputs("call $printf(l $____fmt", stdout); - - if (t->type == PTR) - fputs("lx, ..., l ", stdout); - else - printf("%s, ..., %s ", cgen_type(t), asz); - - printf("%%%s)\n", tmp); - - return 0; -} - -int display_cgen(const struct display *d, struct cgen *c) -{ - const struct print *p = &d->p; - - for (size_t i = 0; i < p->nentries; i++) - { - const struct prientry *e = &p->entries[i]; - const struct tk *tk = e->tk; - - if (tk->type == LIT && cg_lit(e)) - return -1; - else if (tk->type == NUM && cg_val(tk)) - return -1; - else if (tk->type == ID && e->entry && cg_id(e, c->fn)) - return -1; - else if (tk->type == ID && e->lit && cg_lit(e)) - return -1; - } - - if (p->println) - puts("call $putchar(l 10)"); - - return 0; -} - -void display_free(struct display *d) -{ - print_free(&d->p); -} - -int display(const struct lex *l, struct prv *p) -{ - return print(l, p, finalize); -} diff --git a/display.h b/display.h deleted file mode 100644 index 9b073b1..0000000 --- a/display.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DISPLAY_H -#define DISPLAY_H - -#include "lex.h" -#include "print.h" -#include "prv.h" - -struct display -{ - struct print p; -}; - -int display(const struct lex *l, struct prv *p); -int display_cgen(const struct display *d, struct cgen *c); -void display_free(struct display *d); - -#endif diff --git a/div.c b/div.c deleted file mode 100644 index 9061ac6..0000000 --- a/div.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "div.h" -#include "gl.h" -#include "im.h" -#include "lk.h" -#include "pr.h" -#include "td.h" -#include "ws.h" - -static const struct seq linkage = - {(struct step[]){{ID, "linkage"}, {0}}, .fn = lk}, - types = {(struct step[]){{ID, "types"}, {0}}, .fn = td}, - imports = {(struct step[]){{ID, "imports"}, {0}}, .fn = im}, - procedure = {(struct step[]){{ID, "procedure"}, {0}}, .fn = pr}; - -static const struct seq fnseq[] = -{ - linkage, - types, - imports, - procedure, - {(struct step[]){{ID, "storage"}, {0}}, .fn = ws}, - {(struct step[]){{ID, "globals"}, {0}}, .fn = gl}, - {0} -}; - -static const struct seq imseq[] = -{ - linkage, - types, - imports, - {0} -}; - -static const struct seq pseq[] = -{ - linkage, - procedure, - {0} -}; - -int div_fn(const struct lex *l, struct prv *p) -{ - struct pos init = - { - .seq = fnseq, - .stseq = fnseq, - .step = fnseq->steps - }; - - if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 0; -} - -int div_im(const struct lex *l, struct prv *p) -{ - struct pos init = - { - .seq = imseq, - .stseq = imseq, - .step = imseq->steps - }; - - if (lex_eof(l, p->stk)) - return 0; - else if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} - -int div_p(const struct lex *l, struct prv *p) -{ - struct pos init = - { - .seq = pseq, - .stseq = pseq, - .step = pseq->steps - }; - - if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} diff --git a/div.h b/div.h deleted file mode 100644 index 8a0df6d..0000000 --- a/div.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef DIV_H -#define DIV_H - -#include "lex.h" -#include "prv.h" - -int div_fn(const struct lex *l, struct prv *p); -int div_im(const struct lex *l, struct prv *p); -int div_p(const struct lex *l, struct prv *p); - -#endif diff --git a/end.c b/end.c deleted file mode 100644 index b9ad790..0000000 --- a/end.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "end.h" -#include "errloc.h" -#include "fn.h" -#include "stmt.h" -#include -#include -#include - -void end_free(struct end *e) -{ -} - -int end_cgen(const struct end *e, struct cgen *c) -{ - const struct stmt *s = &c->fn->stmts[e->block_i]; - - if (!s->end) - { - fprintf(stderr, "%s: unreachable\n", __func__); - return -1; - } - else if (s->end(s, c)) - return -1; - - printf("@__end%zu\n", e->block_i); - return 0; -} - -int end(const struct lex *l, struct prv *p) -{ - struct pos *pos = &p->pos[p->i]; - struct fn *fn = fn_cur(p); - size_t nst = fn->nstmts + 1, *bl, bl_i; - struct stmt *s; - - if (!fn->nblocks) - { - errloc(p->stk, "unexpected \"end\" statement"); - return -1; - } - - bl_i = fn->blocks[fn->nblocks - 1]; - - if (fn->nblocks > 1) - { - if (!(bl = realloc(fn->blocks, (fn->nblocks - 1) * sizeof *bl))) - { - perror("realloc(3)"); - return -1; - } - - fn->blocks = bl; - } - else - { - free(fn->blocks); - fn->blocks = NULL; - } - - fn->nblocks--; - - if (!(s = realloc(fn->stmts, nst * sizeof *s))) - { - perror("realloc(3)"); - return -1; - } - - s[fn->nstmts++] = (struct stmt) - { - .type = END, - .u.end.block_i = bl_i - }; - - fn->stmts = s; - pos->seq = pos->stseq = stmts; - pos->step = stmts->steps; - p->stk = p->tk; - fprintf(stderr, "\t\tadding end statement, block index %zu\n", bl_i); - return 1; -} diff --git a/end.h b/end.h deleted file mode 100644 index 5286f4f..0000000 --- a/end.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef END_H -#define END_H - -#include "cgen.h" -#include "lex.h" -#include "prv.h" -#include - -struct end -{ - size_t block_i; -}; - -int end(const struct lex *l, struct prv *p); -int end_cgen(const struct end *e, struct cgen *c); -void end_free(struct end *e); - -#endif diff --git a/errloc.c b/errloc.c deleted file mode 100644 index 1f3e224..0000000 --- a/errloc.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "errloc.h" -#include "lex.h" -#include -#include - -void errcloc(const struct lex *l, const char *fmt, ...) -{ - const struct loc *loc = &l->loc; - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "%s:%d:%d: error: ", loc->f, loc->line, loc->col); - vfprintf(stderr, fmt, ap); - fputc('\n', stderr); - va_end(ap); -} - -void errloc(const struct tk *tk, const char *fmt, ...) -{ - const struct loc *loc = &tk->loc; - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "%s:%d:%d: error: ", loc->f, loc->line, loc->col); - vfprintf(stderr, fmt, ap); - fputc('\n', stderr); - va_end(ap); -} diff --git a/errloc.h b/errloc.h deleted file mode 100644 index 127caa7..0000000 --- a/errloc.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ERRLOC_H -#define ERRLOC_H - -#include "lex.h" - -void errloc(const struct tk *tk, const char *fmt, ...); -void errcloc(const struct lex *l, const char *fmt, ...); - -#endif diff --git a/exit.c b/exit.c deleted file mode 100644 index 0438b66..0000000 --- a/exit.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "exit.h" -#include "prv.h" - -int s_exit(const struct lex *l, struct prv *p) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} diff --git a/exit.h b/exit.h deleted file mode 100644 index 24b1292..0000000 --- a/exit.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef EXIT_H -#define EXIT_H - -#include "lex.h" -#include "prv.h" -#include - -struct exit -{ - int dummy; -}; - -int s_exit(const struct lex *l, struct prv *p); -void exit_free(struct exit *d); - -#endif diff --git a/fn.c b/fn.c deleted file mode 100644 index c2d3b4f..0000000 --- a/fn.c +++ /dev/null @@ -1,273 +0,0 @@ -#include "fn.h" -#include "div.h" -#include "errloc.h" -#include "gl.h" -#include "im.h" -#include "parse.h" -#include "prv.h" -#include "pr.h" -#include "stmt.h" -#include "storage.h" -#include "td.h" -#include "ws.h" -#include -#include -#include - -static int pubfn(const struct lex *l, struct prv *p); -static int prvfn(const struct lex *l, struct prv *p); - -static const struct seq fnseq[] = -{ - {(struct step[]) - {{ID, "public"}, {ID, "function"}, {ID}, {0}}, .fn = pubfn, - .end = fn_end}, - {(struct step[]) - {{ID, "function"}, {ID}, {0}}, .fn = prvfn, .end = fn_end}, - {0} -}; - -int fn_end(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - - if (!fn->pr) - { - const struct tk *tk = fn->tk; - const char *s = p->proto ? "prototype" : "function"; - - errloc(p->stk - 1, "%s \"%s\" has no procedure", s, tk->s); - return -1; - } - else if (fn->nblocks) - { - const struct tk *tk = lex_eof(l, p->stk) ? p->tk - 1 : p->stk; - - errloc(tk, "missing \"end\" in function \"%s\"", fn->tk->s); - return -1; - } - - return 0; -} - -static const struct tk *findfn(const char *s, const struct ast *ast) -{ - for (size_t i = 0; i < ast->nfns; i++) - { - const struct tk *tk = ast->fns[i].tk; - - if (!strcmp(tk->s, s)) - return tk; - } - - return NULL; -} - -static int pushfn(const struct tk *tk, const struct lex *lex, struct prv *p, - enum linkage l) -{ - const struct tk *def; - struct ast *ast = p->ast; - size_t n = ast->nfns + 1; - struct fn *fns; - - if ((def = findfn(tk->s, ast))) - { - const struct loc *loc = &def->loc; - - errloc(tk, "function \"%s\" already defined at %s:%d:%d", tk->s, - loc->f, loc->line, loc->col); - return -1; - } - else if (!(fns = realloc(ast->fns, n * sizeof *fns))) - { - perror("realloc(3)"); - return -1; - } - - fns[ast->nfns++] = (struct fn){.linkage = l, .tk = tk}; - ast->fns = fns; - - if (div_fn(lex, p)) - return -1; - - fprintf(stderr, "adding %s function %s\n", - l == STATIC ? "private" : "public", tk->s); - return 1; -} - -static int pubfn(const struct lex *l, struct prv *p) -{ - return pushfn(p->stk + 2, l, p, EXTERNAL); -} - -static int prvfn(const struct lex *l, struct prv *p) -{ - return pushfn(p->stk + 1, l, p, STATIC); -} - -const struct stentry *fn_var(const struct fn *fn, const struct tk *tk) -{ - const struct storage *lk = fn->lk, *ws = fn->ws, *gl = fn->gl; - const struct stentry *e; - - if ((lk && (e = storage_find(tk->s, lk))) - || (ws && (e = storage_find(tk->s, ws))) - || (gl && (e = storage_find(tk->s, gl)))) - return e; - - for (size_t i = 0; i < fn->nimps; i++) - if ((e = fn_var(fn->imps[i].ast.fns, tk))) - return e; - - return NULL; -} - -int fn_cgen(const struct fn *fn, struct cgen *c) -{ - const struct pr *pr = fn->pr; - const struct param *ret = pr->ret; - const struct type *rt = NULL; - const char *s = NULL; - - if (fn->gl && gl_cgen(fn->gl, c)) - return -1; - - switch (fn->linkage) - { - case STATIC: - printf("function "); - break; - case EXTERNAL: - printf("export function "); - break; - } - - if (ret) - { - rt = ret->entry->t; - s = ret->entry->tk->s; - printf("%s ", cgen_abity(ret->entry->t)); - } - - printf("$%s(", fn->tk->s); - - for (size_t i = 0; i < pr->nparams; i++) - { - const struct param *p = &pr->params[i]; - - printf(" %s", cgen_abity(p->entry->t)); - printf(" %%__param_%s ", p->tk->s); - - if (i + 1 < pr->nparams) - fputs(", ", stdout); - } - - puts(") {\n@start"); - - for (size_t i = 0; i < pr->nparams; i++) - { - const struct param *p = &pr->params[i]; - const struct type *t = p->entry->t; - const char *s = p->tk->s; - - printf("%%%s_ =l alloc%zu %zu\n", s, t->align, t->sz); - printf("store%s %%__param_%s, %%%s_\n", cgen_sz(t->sz), s, s); - } - - if (ret) - printf("%%%s_ =l alloc%zu %zu\n", s, rt->align, rt->sz); - - if (fn->ws && ws_cgen(fn->ws, c)) - return -1; - - for (const struct tmp *tmp = fn->tmps; tmp; tmp = tmp->next) - { - const struct stentry *e = &tmp->e; - const struct type *t = tmp->e.t; - - printf("%%%s_ =l alloc%zu %zu\n", e->tk->s, t->align, t->sz); - } - - for (size_t i = 0; i < fn->nstmts; i++) - if (stmt_cgen(&fn->stmts[i], c)) - return -1; - - if (ret) - { - const char *t = cgen_tmp(rt->sz); - - printf("%%%s =%s load%s %%%s_\n", t, cgen_sz(rt->sz), cgen_load(rt), s); - printf("ret %%%s", t); - } - else - fputs("ret", stdout); - - puts("\n}"); - return 0; -} - -void fn_cgen_free(struct fn_cgen *c) -{ - free(c); -} - -void fn_free(struct fn *fn) -{ - for (size_t i = 0; i < fn->nimps; i++) - im_free(&fn->imps[i]); - - for (size_t i = 0; i < fn->nstmts; i++) - stmt_free(&fn->stmts[i]); - - for (struct tmp *t = fn->tmps; t;) - { - struct tmp *next = t->next; - - free(t->tk.s); - free(t); - t = next; - } - - storage_free(fn->lk); - storage_free(fn->ws); - storage_free(fn->gl); - pr_free(fn->pr); - td_free(fn->td); - free(fn->imps); - free(fn->stmts); - free(fn->blocks); -} - -struct fn *fn_cur(const struct prv *p) -{ - struct ast *ast = p->ast; - - if (p->proto) - return p->proto; - - return &ast->fns[p->ast->nfns - 1]; -} - -int fn(const struct lex *l, struct prv *p) -{ - struct pos init = - { - .seq = fnseq, - .stseq = fnseq, - .step = fnseq->steps - }; - - if (lex_eof(l, p->stk)) - return 0; - else if (lex_eof(l, p->stk + 1)) - { - errloc(p->stk, "incomplete function statement"); - return -1; - } - else if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} diff --git a/fn.h b/fn.h deleted file mode 100644 index 6c65ae5..0000000 --- a/fn.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FN_H -#define FN_H - -#include "cgen.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" - -struct fn_cgen -{ - int dummy; -}; - -int fn(const struct lex *l, struct prv *p); -struct fn *fn_cur(const struct prv *p); -int fn_cgen(const struct fn *fn, struct cgen *c); -const struct stentry *fn_var(const struct fn *fn, const struct tk *tk); -int fn_end(const struct lex *l, struct prv *p); -void fn_free(struct fn *fn); -void fn_cgen_free(struct fn_cgen *c); - -#endif diff --git a/from.c b/from.c deleted file mode 100644 index b9cb99e..0000000 --- a/from.c +++ /dev/null @@ -1,364 +0,0 @@ -#include "from.h" -#include "cgen.h" -#include "fn.h" -#include "errloc.h" -#include "stmt.h" -#include "storage.h" -#include "tmp.h" -#include "type.h" -#include -#include -#include -#include -#include - -void from_free(struct from *fr) -{ -} - -static int loadvar(const struct from_it *st, struct cgen *c) -{ - const struct stentry *e = st->u.e; - size_t sz = e->t->sz; - const char *tmp = cgen_tmp(sz); - - printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(e->t)); - cgen_printvar(c->fn, e); - putchar('\n'); - return 0; -} - -/* TODO: de-duplicate function */ -static unsigned long long tonum(const char *s) -{ - unsigned long long v; - char *end; - - errno = 0; - v = strtoull(s, &end, 0); - - if (*s == '-' || errno || *end) - return strtoll(s, NULL, 0); - - return v; -} - -static int loadval(const struct from *fr, struct cgen *c) -{ - const struct stentry *dst = fr->var; - const struct from_it *st = &fr->start; - unsigned long long v = tonum(st->u.tk->s); - - printf("store%s %llu, ", cgen_sz(dst->t->sz), v); - cgen_printvar(c->fn, dst); - putchar('\n'); - return 0; -} - -static int endvar(const struct from *fr, struct cgen *c) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} - -static int endval(const struct from *fr, struct cgen *c) -{ - const struct stentry *src = fr->var; - size_t sz = src->t->sz; - const char *tmp = cgen_tmp(sz); - const struct from_it *end = &fr->end; - const struct tk *tk = end->u.tk; - int neg = *tk->s == '-'; - size_t bl = fr->block_i; - - printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(src->t)); - cgen_printvar(c->fn, src); - putchar('\n'); - printf("%%%s =%s c", tmp, cgen_sz(sz)); - fputs(neg ? "sge" : "uge", stdout); - printf("%s ", cgen_sz(sz)); - printf("%%%s, %s\n", tmp, tk->s); - printf("jnz %%%s, @__end%zu, @__blockbody%zu\n", tmp, bl, bl); - printf("@__blockbody%zu\n", bl); - return 0; -} - -static int from_var(const struct from *fr, struct cgen *c) -{ - const struct from_it *st = &fr->start; - - switch (st->type) - { - case FR_VAR: - if (loadvar(st, c)) - return -1; - break; - - case FR_VAL: - if (loadval(fr, c)) - return -1; - break; - } - - printf("@__block%zu\n", fr->block_i); - - switch (fr->end.type) - { - case FR_VAR: - if (endvar(fr, c)) - return -1; - break; - - case FR_VAL: - if (endval(fr, c)) - return -1; - break; - } - - return 0; -} - -int from_cgen(const struct from *fr, struct cgen *c) -{ - return from_var(fr, c); -} - -static int from_end(const struct stmt *s, struct cgen *c) -{ - const struct from *fr = &s->u.from; - const struct stentry *src = fr->var; - const struct type *t = src->t; - size_t sz = t->sz; - const char *tmp = cgen_tmp(sz); - const struct fn *fn = c->fn; - - printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(t)); - cgen_printvar(fn, src); - putchar('\n'); - printf("%%%s =%s add %%%s, 1\n", tmp, cgen_sz(sz), tmp); - printf("store%s %%%s, ", cgen_sz(sz), tmp); - cgen_printvar(fn, src); - putchar('\n'); - printf("jmp @__block%zu\n", fr->block_i); - return 0; -} - -static int checksym(const struct fn *fn, const struct tk *tk, - struct from_it *fr) -{ - const struct stentry *e = fn_var(fn, tk); - - if (!e) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - - switch (e->t->type) - { - case C: - case BUILTIN: - break; - case U: - case S: - case P: - case T: - case PTR: - case ARY: - { - char *s = type_name(e->t); - - if (s) - errloc(tk, "\"%s\" (\"%s\") cannot be used in \"from\" loop", - tk->s, s); - - free(s); - return -1; - } - } - - fr->type = FR_VAR; - fr->u.e = e; - return 0; -} - -static int check(const struct fn *fn, const struct tk *tk, struct from_it *fr) -{ - switch (tk->type) - { - case NUM: - fr->type = FR_VAL; - fr->u.tk = tk; - break; - case ID: - return checksym(fn, tk, fr); - case LIT: - errloc(tk, "unexpected literal"); - return -1; - case UNDEF: - case ANY: - fprintf(stderr, "%s: unreachable\n", __func__); - return -1; - } - - return 0; -} - -static int finalize(struct prv *p, struct fn *fn, struct from *fr) -{ - struct stmt *s; - struct pos *pos = &p->pos[p->i]; - size_t nst = fn->nstmts + 1, nbl = fn->nblocks + 1, - *bl = realloc(fn->blocks, nbl * sizeof *bl); - - if (!bl) - { - perror("realloc(3)"); - return -1; - } - - fr->block_i = bl[fn->nblocks++] = fn->nstmts; - fn->blocks = bl; - - if (!(s = realloc(fn->stmts, nst * sizeof *s))) - { - perror("realloc(3)"); - return -1; - } - - s[fn->nstmts++] = (struct stmt) - { - .type = FROM, - .u.from = *fr, - .end = from_end - }; - - fn->stmts = s; - pos->seq = pos->stseq = stmts; - pos->step = stmts->steps; - fprintf(stderr, ", iterator %s, block index %zu\n", fr->var->tk->s, - bl[fn->nblocks - 1]); - return 0; -} - -static const struct type *valtype(const struct fn *fn, const struct tk *tk) -{ - char *end; - - errno = 0; - strtol(tk->s, &end, 0); - - if (errno || *end) - { - errno = 0; - strtoll(tk->s, &end, 0); - - if (errno || *end) - return type_find(fn, "ulong"); - - return type_find(fn, "long"); - } - - return type_find(fn, "word"); -} - -static const struct type *ittype(const struct fn *fn, const struct from_it *it) -{ - switch (it->type) - { - case FR_VAL: - return valtype(fn, it->u.tk); - case FR_VAR: - return it->u.e->t; - } - - fprintf(stderr, "%s: unreachable\n", __func__); - return NULL; -} - -static const struct type *gettype(const struct fn *fn, - const struct from_it *a, const struct from_it *b) -{ - const struct type *ta = ittype(fn, a), *tb = ittype(fn, b); - - return ta->sz > tb->sz ? ta : tb; -} - -int from(const struct lex *l, struct prv *p) -{ - const struct tk *start = p->stk + 1, *end = p->stk + 3; - struct fn *fn = fn_cur(p); - struct from fr = {0}; - const struct type *t; - - if (check(fn, start, &fr.start) - || check(fn, end, &fr.end) - || !(t = gettype(fn, &fr.start, &fr.end)) - || !(fr.var = tmp_create(fn, t))) - return -1; - - fprintf(stderr, "\t\tadding from statement [%s, %s]", start->s, end->s); - - if (finalize(p, fn, &fr)) - return -1; - - p->stk = ++end; - return 1; -} - -static int checkvar(const struct fn *fn, const struct tk *tk, struct from *fr) -{ - const struct stentry *e; - - if (tk->type != ID) - { - errloc(tk, "\"%s\" not a variable", tk->s); - return -1; - } - else if (!(e = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - else if (e->t->type != BUILTIN) - { - errloc(tk, "variable \"%s\" not an integer", tk->s); - return -1; - } - - fr->var = e; - return 0; -} - -int from_id(const struct lex *l, struct prv *p) -{ - const struct tk *start = p->stk + 1, *end = p->stk + 3, *var = p->stk + 5; - struct fn *fn = fn_cur(p); - struct from fr = {0}; - - if (check(fn, start, &fr.start) - || check(fn, end, &fr.end) - || checkvar(fn, var, &fr)) - return -1; - - fprintf(stderr, "\t\tadding from statement [%s, %s] using %s", - start->s, end->s, var->s); - - if (finalize(p, fn, &fr)) - return -1; - - p->stk = ++var; - return 1; -} - -int from_by(const struct lex *l, struct prv *p) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} - -int from_idby(const struct lex *l, struct prv *p) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} diff --git a/from.h b/from.h deleted file mode 100644 index 8a77629..0000000 --- a/from.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef FROM_H -#define FROM_H - -#include "cgen.h" -#include "lex.h" -#include "storage.h" -#include "prv.h" -#include - -struct from -{ - struct from_it - { - enum {FR_VAL, FR_VAR} type; - - union - { - const struct tk *tk; - const struct stentry *e; - } u; - } start, end; - - size_t block_i; - const struct stentry *var; -}; - -int from(const struct lex *l, struct prv *p); -int from_id(const struct lex *l, struct prv *p); -int from_by(const struct lex *l, struct prv *p); -int from_idby(const struct lex *l, struct prv *p); -int from_cgen(const struct from *m, struct cgen *c); -void from_free(struct from *fr); - -#endif diff --git a/gl.c b/gl.c deleted file mode 100644 index de0293f..0000000 --- a/gl.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "gl.h" -#include "fn.h" -#include "prv.h" -#include "parse.h" -#include "storage.h" - -int gl_cgen(const struct storage *gl, struct cgen *c) -{ - for (size_t i = 0; i < gl->nentries; i++) - { - const struct stentry *e = &gl->entries[i]; - - printf("export data $%s = { z %zu }\n", e->tk->s, e->t->sz); - } - - return 0; -} - -int gl(const struct lex *l, struct prv *p) -{ - struct fn *fn = fn_cur(p); - - return storage(l, p, "globals section", 1, &fn->gl); -} diff --git a/gl.h b/gl.h deleted file mode 100644 index d8aaaaf..0000000 --- a/gl.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef GL_H -#define GL_H - -#include "cgen.h" -#include "lex.h" -#include "prv.h" -#include "storage.h" - -int gl(const struct lex *l, struct prv *p); -int gl_cgen(const struct storage *gl, struct cgen *c); - -#endif diff --git a/im.c b/im.c deleted file mode 100644 index e9a208c..0000000 --- a/im.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "im.h" -#include "errloc.h" -#include "fn.h" -#include "prv.h" -#include "parse.h" -#include -#include -#include -#include -#include - -static int imlit(const struct lex *, struct prv *); - -static const struct seq seqs[] = -{ - {(struct step[]){{LIT, NULL, 1}, {0}}, .fn = imlit}, - {0} -}; - -void im_free(struct im *im) -{ - ast_free(&im->ast); - lex_free(&im->l); -} - -static int doim(const struct lex *l, const struct tk *tk, struct prv *p) -{ - int ret = -1; - FILE *f = NULL; - struct im *im; - struct fn *fn = fn_cur(p); - struct ast *ast; - size_t n = fn->nimps + 1; - const char *path = tk->s; - - if (!strcmp(l->loc.f, path)) - { - errloc(tk, "detected recursive import \"%s\"", path); - goto end; - } - /* TODO: honor -I flags */ - if (!(f = fopen(path, "rb"))) - { - errloc(tk, "failed to open import \"%s\": %s", path, strerror(errno)); - goto end; - } - else if (!(im = realloc(fn->imps, n * sizeof *im))) - { - perror("realloc(3)"); - goto end; - } - - fn->imps = im; - im = &fn->imps[fn->nimps++]; - *im = (struct im){.l.loc.f = path}; - ast = &im->ast; - - if (!(ast->fns = malloc(sizeof *ast->fns))) - { - perror("malloc(3)"); - goto end; - } - - *ast->fns = (struct fn){.tk = tk}; - /* hack: treat imports as a function */ - ast->nfns = 1; - - if (lex(&im->l, f) || parse_im(&im->l, ast)) - goto end; - - ret = 0; - -end: - - if (f && fclose(f)) - { - fprintf(stderr, "fclose(3) %s: %s\n", path, strerror(errno)); - ret = -1; - } - - return ret; -} - -static int imlit(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - - while (!lex_eof(l, tk) && !kw(tk->s)) - if (doim(l, tk++, p)) - return -1; - - if (pop(l, p)) - return -1; - - p->stk = p->tk; - return 1; -} - -int im(const struct lex *l, struct prv *p) -{ - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - struct fn *fn = fn_cur(p); - - if (fn->im) - { - const struct loc *loc = &fn->im->loc; - - errloc(p->stk, "imports section already defined at %s:%d:%d", - loc->f, loc->line, loc->col); - return -1; - } - - if (push(&init, p)) - return -1; - - fn->im = p->stk; - p->stk = p->tk; - return 1; -} diff --git a/im.h b/im.h deleted file mode 100644 index 30382ed..0000000 --- a/im.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef IM_H -#define IM_H - -#include "lex.h" -#include "parse.h" -#include "prv.h" - -int im(const struct lex *l, struct prv *p); -void im_free(struct im *im); - -#endif diff --git a/kw.c b/kw.c deleted file mode 100644 index d5e22ca..0000000 --- a/kw.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "prv.h" -#include -#include - -static const char *kws[] = -{ - /* headers */ - "public", "function", - /* sections */ - "types", "storage", "linkage", "procedure", "locals", "globals", "imports", - /* types */ - "union", "struct", "constant", "alias", "prototype", - /* operators */ - "add", "subtract", "multiply", "divide", "xor", "bitor", "bitand", - "leftshift", "rightshift", "address", "size", "call", "set", - /* procedures */ - "using", "returning", - /* built-in functions */ - "display", "warn", - /* flow control */ - "while", "if", "else", "end", "return", "go", "label", "default", - /* prepositions */ - "by", "from", "to", "than", "of", "etc", - /* comparators */ - "is", "not", "equal", "greater", "smaller", "and", "or", - /* built-in types */ - "void", "array", "pointer", - /* built-in signed types */ - "byte", "halfword", "word", "long", - /* built-in unsigned types */ - "ubyte", "uhalfword", "uword", "ulong" -}; - -int kw(const char *s) -{ - for (size_t i = 0; i < sizeof kws / sizeof *kws; i++) - if (!strcmp(s, kws[i])) - return 1; - - return 0; -} diff --git a/lex.c b/lex.c deleted file mode 100644 index 736ebdd..0000000 --- a/lex.c +++ /dev/null @@ -1,249 +0,0 @@ -#include "lex.h" -#include "errloc.h" -#include -#include -#include -#include -#include - -static void free_tk(struct tk *tk) -{ - free(tk->s); -} - -static int invnum(const struct tk *tk, char *end) -{ - if (errno) - errloc(tk, "invalid number: %s (%s)", tk->s, strerror(errno)); - else if (*end) - errloc(tk, "invalid number: %s", tk->s); - - return -1; -} - -static int fintok(struct lex *lex) -{ - struct tk *tk = &lex->tk, *tokens; - const struct tk empty = {.loc = tk->loc}; - size_t ntk = lex->ntok + 1; - char *s; - - if (tk->type == UNDEF) - return 0; - else if (!(s = realloc(tk->s, lex->len + 1))) - { - perror("realloc(3)"); - return -1; - } - - tk->s = s; - tk->s[lex->len] = '\0'; - - switch (tk->type) - { - case UNDEF: - break; - - case ANY: - errloc(tk, "%s: unreachable", __func__); - return -1; - - case LIT: - case ID: - break; - - case NUM: - { - int neg = *tk->s == '-'; - char *end; - - errno = 0; - strtoll(tk->s, &end, 0); - - if (errno || *end) - { - if (neg) - return invnum(tk, end); - - errno = 0; - strtoull(tk->s, &end, 0); - - if (errno || *end) - return invnum(tk, end); - } - } - } - - if (!(tokens = realloc(lex->tokens, ntk * sizeof *tokens))) - { - perror("realloc(3)"); - return -1; - } - - tokens[lex->ntok++] = lex->tk; - lex->tokens = tokens; - lex->tk = empty; - lex->len = 0; - return 0; -} - -static int printable(char c) -{ - return c >= '!' && c <= '~'; -} - -static void invch(const struct lex *l, char c) -{ - if (printable(c)) - errcloc(l, "invalid character: %c", c); - else - errcloc(l, "invalid character: (%#hhx)", c); -} - -static int ch(char c, struct lex *lex) -{ - struct tk *tk = &lex->tk; - char *s; - - switch (tk->type) - { - case UNDEF: - tk->loc = lex->loc; - - if (c == '\"') - { - tk->type = LIT; - return 0; - } - else if (c == '-' || c == '+' - || (c >= '0' && c <= '9')) - tk->type = NUM; - else if (c == '_' - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z')) - tk->type = ID; - else - { - invch(lex, c); - return -1; - } - - break; - - case LIT: - if (c == '\"') - return fintok(lex); - - break; - - case NUM: - if (c == '\"') - { - invch(lex, c); - return -1; - } - - break; - - case ID: - if (c == '\"' || c == '-' || c == '+') - { - invch(lex, c); - return -1; - } - else if (!(c == '_' - || (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z'))) - { - invch(lex, c); - return -1; - } - - break; - case ANY: - errcloc(lex, "%s: unreachable", __func__); - return -1; - } - - if (!(s = realloc(tk->s, lex->len + 1))) - { - perror("realloc(3)"); - return -1; - } - - s[lex->len++] = c; - tk->s = s; - return 0; -} - -static int clex(char c, struct lex *lex) -{ - struct tk *tk = &lex->tk; - struct loc *loc = &lex->loc; - - ++loc->col; - - switch (c) - { - case '*': - lex->comment = 1; - return fintok(lex); - - case '\n': - if (tk->type == LIT) - { - errcloc(lex, "unterminated literal"); - return -1; - } - else if (fintok(lex)) - return -1; - - loc->line++; - loc->col = lex->comment = 0; - return 0; - - case '\t': - /* assume columns as 8-space width */ - loc->col += 7; - case ' ': - if (tk->type != LIT) - return lex->comment ? 0 : fintok(lex); - default: - return lex->comment ? 0 : ch(c, lex); - } - - invch(lex, c); - return -1; -} - -void lex_free(struct lex *lex) -{ - for (size_t i = 0; i < lex->ntok; i++) - free_tk(&lex->tokens[i]); - - free(lex->tokens); - free_tk(&lex->tk); -} - -int lex_eof(const struct lex *lex, const struct tk *tk) -{ - return tk - lex->tokens >= lex->ntok; -} - -int lex(struct lex *l, FILE *f) -{ - l->loc.line = 1; - - for (;;) - { - int c = fgetc(f); - - if (c == EOF) - break; - else if (clex(c, l)) - return -1; - } - - return 0; -} diff --git a/lex.h b/lex.h deleted file mode 100644 index 6e836ac..0000000 --- a/lex.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef LEX_H -#define LEX_H - -#include -#include - -enum tktype {UNDEF, ID, LIT, NUM, ANY}; - -struct loc -{ - const char *f; - int line, col; -}; - -struct tk -{ - enum tktype type; - struct loc loc; - char *s; -}; - -struct lex -{ - struct loc loc; - struct tk *tokens, tk; - size_t ntok, len; - int comment; -}; - -int lex(struct lex *lex, FILE *f); -int lex_eof(const struct lex *lex, const struct tk *tk); -void lex_free(struct lex *lex); - -#endif diff --git a/lit.c b/lit.c deleted file mode 100644 index 09528a2..0000000 --- a/lit.c +++ /dev/null @@ -1,102 +0,0 @@ -#include "lit.h" -#include "fn.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include -#include -#include -#include - -void lit_free(struct lit *l) -{ - free(l->name); -} - -static char *gen(struct ast *ast, struct fn *fn) -{ - static const char fmt[] = "__str_%zu"; - int n = snprintf(NULL, 0, fmt, ast->litcnt); - char *ret = NULL; - size_t sz; - - if (n < 0) - { - fprintf(stderr, "%s: snprintf(3) failed\n", __func__); - goto failure; - } - else if (!(ret = malloc((sz = n + 1)))) - { - perror("malloc(3)"); - goto failure; - } - - n = snprintf(ret, sz, fmt, ast->litcnt); - - if (n < 0 || n >= sz) - { - fprintf(stderr, "%s: snprintf(3) failed with %d\n", __func__, n); - goto failure; - } - - ast->litcnt++; - return ret; - -failure: - free(ret); - return NULL; -} - -static const struct lit *find(const struct tk *tk, const struct ast *ast) -{ - for (const struct lit *l = ast->lits; l; l = l->next) - if (!strcmp(l->tk->s, tk->s)) - return l; - - return NULL; -} - -int lit_cgen(const struct lit *l) -{ - printf("data $%s = { b \"%s\", b 0 }\n", l->name, l->tk->s); - return 0; -} - -const struct lit *lit_push(const struct tk *tk, struct prv *p) -{ - char *name = NULL; - struct fn *fn = fn_cur(p); - struct ast *ast = p->ast; - const struct lit *prev = find(tk, ast); - struct lit *l; - - if (prev) - return prev; - else if (!(name = gen(ast, fn))) - goto failure; - else if (!(l = malloc(sizeof *l))) - { - perror("malloc(3)"); - goto failure; - } - - *l = (struct lit) - { - .name = name, - .fn = fn, - .tk = tk - }; - - if (!ast->lits) - ast->lits = l; - else if (ast->lastlit) - ast->lastlit->next = l; - - ast->lastlit = l; - fprintf(stderr, "adding literal \"%s\"\n", name); - return l; - -failure: - free(name); - return NULL; -} diff --git a/lit.h b/lit.h deleted file mode 100644 index e94263c..0000000 --- a/lit.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef LIT_H -#define LIT_H - -#include "lex.h" -#include "parse.h" -#include "prv.h" - -const struct lit *lit_push(const struct tk *tk, struct prv *p); -int lit_cgen(const struct lit *l); -void lit_free(struct lit *l); - -#endif diff --git a/lk.c b/lk.c deleted file mode 100644 index 8bfb738..0000000 --- a/lk.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "lk.h" -#include "fn.h" -#include "prv.h" -#include "parse.h" -#include "storage.h" - -int lk(const struct lex *l, struct prv *p) -{ - struct fn *fn = fn_cur(p); - - return storage(l, p, "linkage section", 1, &fn->lk); -} diff --git a/lk.h b/lk.h deleted file mode 100644 index 35df205..0000000 --- a/lk.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef LK_H -#define LK_H - -#include "lex.h" -#include "prv.h" - -int lk(const struct lex *l, struct prv *p); - -#endif diff --git a/main.c b/main.c deleted file mode 100644 index 69165ba..0000000 --- a/main.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "cgen.h" -#include "lex.h" -#include "parse.h" -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - struct lex l = {0}; - struct ast a = {0}; - struct cgen c = {0}; - FILE *f = stdin; - int opened = 0, ret = EXIT_FAILURE; - - if (argc != 2) - { - fprintf(stderr, "%s: error: missing input file\n", *argv); - goto end; - } - else if (strcmp(argv[1], "-")) - { - if (!(f = fopen(argv[1], "rb"))) - { - fprintf(stderr, "failed to open %s: %s\n", argv[1], - strerror(errno)); - goto end; - } - - opened = 1; - l.loc.f = argv[1]; - } - else - l.loc.f = "stdin"; - - if (lex(&l, f) || parse(&l, &a) || cgen(&a, &c)) - goto end; - - ret = EXIT_SUCCESS; - -end: - if (opened && fclose(f)) - { - perror("fclose(3)"); - ret = EXIT_FAILURE; - } - - cgen_free(&c); - ast_free(&a); - lex_free(&l); - return ret; -} diff --git a/parse.c b/parse.c deleted file mode 100644 index 1c3aba2..0000000 --- a/parse.c +++ /dev/null @@ -1,183 +0,0 @@ -#include "parse.h" -#include "div.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "lit.h" -#include "prv.h" -#include "type.h" -#include -#include -#include - -void ast_free(struct ast *ast) -{ - struct type *t = ast->types; - - while (t) - { - struct type *next = t->next; - - type_lfree(t); - t = next; - } - - for (struct lit *l = ast->lits, *next; l; l = next) - { - next = l->next; - lit_free(l); - free(l); - } - - for (size_t i = 0; i < ast->nfns; i++) - fn_free(&ast->fns[i]); - - free(ast->fns); -} - -static const char *expected(const struct step *s) -{ - static const char *tmap[] = - { - [ID] = "identifier", [LIT] = "literal", [NUM] = "number" - }; - - return s->id ? s->id : tmap[s->type]; -} - -static int iter(const struct lex *l, struct prv *p) -{ - struct pos *pos = p->pos; - const struct step *s; - const struct tk *tk = p->tk; - - if (!pos) - return p->entry(l, p); - - pos = &p->pos[p->i]; - - if (!(s = pos->step)) - { - if (lex_eof(l, tk)) - return 0; - else if (p->n > 1) - return pop(l, p) ? -1 : 1; - else - { - switch (tk->type) - { - case LIT: - errloc(tk, "unexpected literal \"%s\"", tk->s); - break; - case NUM: - errloc(tk, "unexpected number %s", tk->s); - break; - case ID: - errloc(tk, "unexpected %s %s", kw(tk->s) ? - "keyword" : "identifier", tk->s); - break; - case ANY: - case UNDEF: - errloc(tk, "%s: unreachable", __func__); - break; - } - - return -1; - } - } - else if (lex_eof(l, tk)) - { - if (p->stk == p->tk) - return pop(l, p) ? -1 : 1; - else if (s->type) - { - tk--; - - if (lex_eof(l, p->stk)) - { - errloc(tk, "expected %s", expected(pos->step)); - return -1; - } - } - } - - if (!s->type) - return pos->seq->fn(l, p); - else if ((s->type == ID || s->type == ANY) && !s->id && kw(tk->s) - && !s->chain) - { - if (tk != p->stk || !p->n) - { - errloc(tk, "unexpected keyword %s", tk->s); - return -1; - } - else if (pop(l, p)) - return -1; - - pos = &p->pos[p->i]; - } - else if ((s->type != tk->type && s->type != ANY) - || (s->type == ID && s->id && strcmp(s->id, tk->s)) - || (s->type == ID && kw(tk->s) && s->chain)) - { - pos->step = (++pos->seq)->steps; - p->tk = p->stk; - } - else - { - const struct tk *next = tk + 1; - - if (!s->chain) - pos->step++; - else if (!lex_eof(l, next)) - { - if (s->chain && kw(next->s)) - pos->step++; - } - else - pos->step++; - - if (!lex_eof(l, p->tk)) - p->tk++; - } - - return 1; -} - -static void free_prv(struct prv *p) -{ - free(p->tdc); - free(p->pos); -} - -static int comm(const struct lex *l, struct ast *ast, - int (*entry)(const struct lex *, struct prv *)) -{ - int ret; - struct prv prv = - { - .ast = ast, - .tk = l->tokens, - .stk = l->tokens, - .entry = entry - }; - - if (!prv.stk) - return 0; - - while ((ret = iter(l, &prv)) > 0) - ; - - free_prv(&prv); - return ret; -} - -int parse(const struct lex *l, struct ast *ast) -{ - return comm(l, ast, fn); -} - -int parse_im(const struct lex *l, struct ast *ast) -{ - return comm(l, ast, div_im); -} diff --git a/parse.h b/parse.h deleted file mode 100644 index b85d618..0000000 --- a/parse.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef PARSE_H -#define PARSE_H - -#include "lex.h" -#include "storage.h" - -struct u -{ - struct storage *storage; -}; - -struct s -{ - struct storage *storage; -}; - -union c -{ - unsigned long long uv; - long long v; -}; - -struct p -{ - struct fn *fn; -}; - -struct t -{ - const struct type *alias; -}; - -struct ptr -{ - const struct type *t; -}; - -struct ary -{ - unsigned long long n; - int etc; -}; - -struct builtin -{ - const char *name; -}; - -struct type -{ - enum {U, S, C, P, T, PTR, ARY, BUILTIN} type; - const struct tk *tk; - size_t sz, align; - int sign; - struct type *child, *next; - - union - { - struct u u; - struct s s; - union c c; - struct p p; - struct t t; - struct ptr ptr; - struct ary ary; - struct builtin b; - } u; -}; - -struct param -{ - const struct tk *tk; - const struct stentry *entry; -}; - -struct pr -{ - const struct tk *tk; - struct param *params, *ret; - size_t nparams; - int variadic; -}; - -struct td -{ - const struct tk *tk; - struct type *types; - size_t ntypes; -}; - -struct tmp -{ - struct tk tk; - struct stentry e; - struct tmp *next; -}; - -struct fn -{ - const struct tk *tk, *im; - const struct fn *parent; - enum linkage {EXTERNAL, STATIC} linkage; - struct storage *lk, *ws, *gl; - struct stmt *stmts; - struct tmp *tmps; - struct im *imps; - struct pr *pr; - struct td *td; - size_t nstmts, nimps, nblocks, ntmps, *blocks; -}; - -struct lit -{ - char *name; - const struct tk *tk; - const struct fn *fn; - struct lit *next; -}; - -struct ast -{ - struct fn *fns; - struct lit *lits, *lastlit; - struct type *types; - size_t nfns, litcnt; -}; - -struct im -{ - struct lex l; - struct ast ast; -}; - -int parse(const struct lex *l, struct ast *ast); -int parse_im(const struct lex *l, struct ast *ast); -void ast_free(struct ast *ast); - -#endif diff --git a/pop.c b/pop.c deleted file mode 100644 index ba2f3a1..0000000 --- a/pop.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "prv.h" -#include - -int pop(const struct lex *l, struct prv *p) -{ - size_t n; - struct pos *pos = NULL; - - if (!p->n) - { - fprintf(stderr, "%s: underflow\n", __func__); - return -1; - } - else if (!(n = p->n - 1)) - { - free(p->pos); - p->pos = NULL; - } - else if (!(pos = realloc(p->pos, n * sizeof *pos))) - { - perror("realloc(3)"); - return -1; - } - - p->pos = pos; - p->n = n; - - if (p->n) - { - const struct pos *old = &p->pos[--p->i]; - - if (old->end && old->end(l, p)) - return -1; - } - - return 0; -} diff --git a/pr.c b/pr.c deleted file mode 100644 index a171554..0000000 --- a/pr.c +++ /dev/null @@ -1,375 +0,0 @@ -#include "pr.h" -#include "errloc.h" -#include "fn.h" -#include "prv.h" -#include "parse.h" -#include "stmt.h" -#include "storage.h" -#include -#include -#include - -static int prey(const struct lex *l, struct prv *p); -static int pren(const struct lex *l, struct prv *p); -static int pryy(const struct lex *l, struct prv *p); -static int pryn(const struct lex *l, struct prv *p); -static int prny(const struct lex *l, struct prv *p); -static int prnn(const struct lex *l, struct prv *p); - -static const struct seq seqs[] = -{ - /* function definition with variadic parameters and return variable */ - { - (struct step[]) - { - {ID, "using"}, - {ID, NULL, 1}, - {ID, "etc",}, - {ID, "returning"}, - {ID}, - {0} - }, - .fn = prey - }, - - /* function definition with variadic parameters and no return variable */ - { - (struct step[]) - { - {ID, "using"}, - {ID, NULL, 1}, - {ID, "etc",}, - {0} - }, - .fn = pren - }, - - /* function definition with parameters and return variable */ - { - (struct step[]) - { - {ID, "using"}, - {ID, NULL, 1}, - {ID, "returning"}, - {ID}, - {0} - }, - .fn = pryy - }, - - /* function definition with parameters, no return variable */ - { - (struct step[]) - { - {ID, "using"}, - {ID, NULL, 1}, - {0} - }, - - .fn = pryn - }, - - /* function definition with no parameters, with return variable */ - { - (struct step[]) - { - {ID, "returning"}, - {ID}, - {0} - }, - - .fn = prny - }, - - {0} -}; - -static const struct tk *findparam(const char *s, const struct pr *pr) -{ - for (size_t i = 0; i < pr->nparams; i++) - { - const struct param *p = &pr->params[i]; - const struct tk *tk = p->tk; - - if (!strcmp(tk->s, s)) - return tk; - } - - return NULL; -} - -static int param(const struct tk *tk, const struct stentry *e, struct pr *pr) -{ - size_t n = pr->nparams + 1; - struct param *params = realloc(pr->params, n * sizeof *params); - - if (!params) - { - perror("realloc(3)"); - return -1; - } - - pr->params = params; - pr->params[pr->nparams++] = (struct param){.tk = tk, .entry = e}; - return 0; -} - -static int setret(const struct tk *tk, const struct stentry *e, struct pr *pr) -{ - if (!(pr->ret = malloc(sizeof *pr->ret))) - { - perror("malloc(3)"); - return -1; - } - - *pr->ret = (struct param){.tk = tk, .entry = e}; - return 0; -} - -static int finalize(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - const struct pr *pr = fn->pr; - struct pos init = - { - .seq = stmts, - .stseq = stmts, - .step = stmts->steps - }; - - if (p->proto) - { - if (pop(l, p)) - return -1; - - fputc('\t', stderr); - } - else if (push(&init, p)) - return -1; - - fprintf(stderr, "\tadding procedure using %zu%s parameters " - "and%s return value\n", pr->nparams, pr->variadic ? " variadic" : "", - pr->ret ? "" : " no"); - p->stk = p->tk; - return 1; -} - -static int prret(const struct lex *l, const struct tk *tk, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - struct pr *pr = fn->pr; - const char *s = tk->s; - const struct storage *lk = fn->lk, *gl = fn->gl; - const struct stentry *e, *gle; - const struct tk *prm; - - if (!lk || !(e = storage_find(s, lk))) - { - errloc(tk, "return value \"%s\" not in %s", s, tk->s); - return -1; - } - else if (gl && (gle = storage_find(s, gl))) - { - const struct loc *loc = &gle->tk->loc; - - errloc(tk, "return value \"%s\" also in %s at %s:%d:%d", s, gl->name, - loc->f, loc->line, loc->col); - return -1; - } - else if ((prm = findparam(s, pr))) - { - const struct loc *loc = &prm->loc; - - errloc(tk, "return value \"%s\" already listed as " - "parameter at %s:%d:%d", tk->s, loc->f, loc->line, loc->col); - return -1; - } - else if (setret(tk, e, pr)) - return -1; - - return finalize(l, p); -} - -static const struct tk *prparams(const struct lex *l, struct prv *p, int *ret) -{ - const struct tk *tk = p->stk + 1; - const struct fn *fn = fn_cur(p); - struct pr *pr = fn->pr; - - if (ret) - *ret = 0; - - for (;;) - { - const struct storage *lk = fn->lk, *gl = fn->gl; - const struct stentry *e, *gle; - const struct tk *prm; - const char *s; - - if (lex_eof(l, tk)) - return tk; - else if (!strcmp((s = tk->s), "returning") && ret) - { - *ret = 1; - return ++tk; - } - else if (!strcmp(s, "etc")) - { - if (pr->variadic) - { - errloc(tk, "keyword \"etc\" may only appear once as a " - "parameter"); - return NULL; - } - - pr->variadic = tk++ - p->stk; - } - else if (kw(s)) - return tk; - else if (pr->variadic) - { - errloc(tk, "keyword \"etc\" must appear as the last parameter"); - return NULL; - } - else if ((prm = findparam(s, pr))) - { - const struct loc *loc = &prm->loc; - - errloc(tk, "parameter \"%s\" already listed at %d:%d", s, - loc->line, loc->col); - return NULL; - } - else if (!lk || !(e = storage_find(s, lk))) - { - if (p->proto) - { - /* ambiguous syntax: param might be confused - * with next custom type. */ - p->tk = p->stk + pr->nparams + 1; - return tk; - } - else - { - errloc(tk, "parameter \"%s\" not in %s", s, tk->s); - return NULL; - } - } - else if (gl && (gle = storage_find(s, gl))) - { - const struct loc *loc = &gle->tk->loc; - - errloc(tk, "parameter \"%s\" also in %s at %d:%d", s, gl->name, - loc->line, loc->col); - return NULL; - } - else if (param(tk, e, pr)) - return NULL; - else - tk++; - } - - return tk; -} - -static int prey(const struct lex *l, struct prv *p) -{ - int ret; - const struct tk *tk = prparams(l, p, &ret); - - if (!tk) - return -1; - else if (ret) - return prret(l, tk, p); - - return finalize(l, p); -} - -static int pren(const struct lex *l, struct prv *p) -{ - const struct tk *tk = prparams(l, p, NULL); - - if (!tk) - return -1; - - return finalize(l, p); -} - -static int pryy(const struct lex *l, struct prv *p) -{ - int ret; - const struct tk *tk = prparams(l, p, &ret); - - if (!tk) - return -1; - else if (ret) - return prret(l, tk, p); - - return finalize(l, p); -} - -static int pryn(const struct lex *l, struct prv *p) -{ - if (!prparams(l, p, NULL)) - return -1; - - return finalize(l, p); -} - -static int prny(const struct lex *l, struct prv *p) -{ - return prret(l, p->stk + 1, p); -} - -static int prnn(const struct lex *l, struct prv *p) -{ - return finalize(l, p); -} - -void pr_free(struct pr *pr) -{ - if (pr) - { - free(pr->params); - free(pr->ret); - } - - free(pr); -} - -int pr(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->tk - 1, *next = p->tk; - struct fn *fn = fn_cur(p); - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - if (fn->pr) - { - const struct loc *loc = &fn->pr->tk->loc; - - errloc(tk, "procedure already defined at %s:%d:%d", loc->f, loc->line, - loc->col); - return -1; - } - else if (!(fn->pr = malloc(sizeof *fn->pr))) - { - perror("malloc(3)"); - return -1; - } - - *fn->pr = (struct pr){.tk = tk}; - - /* on no parameters or return values, go directly to next sequences list. */ - if (lex_eof(l, next) - || (strcmp(next->s, "using") && strcmp(next->s, "returning"))) - return prnn(l, p); - else if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} diff --git a/pr.h b/pr.h deleted file mode 100644 index e3d8bf8..0000000 --- a/pr.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PR_H -#define PR_H - -#include "lex.h" -#include "parse.h" -#include "prv.h" - -int pr(const struct lex *l, struct prv *p); -void pr_free(struct pr *pr); - -#endif diff --git a/print.c b/print.c deleted file mode 100644 index abdb149..0000000 --- a/print.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "print.h" -#include "errloc.h" -#include "fn.h" -#include "lit.h" -#include "parse.h" -#include "prv.h" -#include "stmt.h" -#include "storage.h" -#include "type.h" -#include -#include - -static int entry(const struct lex *l, const struct tk *tk, struct print *pr, - struct prv *p) -{ - size_t n = pr->nentries + 1; - struct prientry *entries; - const struct stentry *stentry = NULL; - const struct fn *fn = fn_cur(p); - const struct lit *lit = NULL; - - if (tk->type == ID) - { - const struct type *t = NULL; - - if ((t = type_find(fn, tk->s))) - { - if (t->type != C) - { - errloc(tk, "type \"%s\" not a constant", tk->s); - return -1; - } - else if (!(lit = lit_push(t->tk, p))) - return -1; - } - else if (!(stentry = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - } - else if (tk->type == LIT && !(lit = lit_push(tk, p))) - return -1; - - if (!(entries = realloc(pr->entries, n * sizeof *entries))) - { - perror("realloc(3)"); - return -1; - } - - pr->entries = entries; - pr->entries[pr->nentries++] = (struct prientry) - { - .tk = tk, - .lit = lit, - .entry = stentry - }; - - return 0; -} - -void print_free(struct print *pr) -{ - free(pr->entries); -} - -int print(const struct lex *l, struct prv *p, - int (*fn)(const struct lex *, const struct prv *, const struct print *)) -{ - const struct tk *tk = p->stk + 1; - struct print pr = {0}; - struct pos *pos = &p->pos[p->i]; - int eof; - - if (lex_eof(l, tk)) - { - errloc(tk - 1, "incomplete %s statement", p->stk->s); - return -1; - } - - for (;;) - if (entry(l, tk, &pr, p)) - goto failure; - else if ((eof = lex_eof(l, ++tk)) || kw(tk->s)) - break; - - if (eof || strcmp(tk->s, "etc")) - pr.println = 1; - else if (!eof) - tk++; - - if (fn(l, p, &pr)) - goto failure; - - pos->seq = pos->stseq = stmts; - pos->step = stmts->steps; - p->stk = tk; - return 1; - -failure: - print_free(&pr); - return -1; -} diff --git a/print.h b/print.h deleted file mode 100644 index 950e0bc..0000000 --- a/print.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PRINT_H -#define PRINT_H - -#include "cgen.h" -#include "lex.h" -#include - -struct prientry -{ - const struct tk *tk; - const struct lit *lit; - const struct stentry *entry; -}; - -struct print -{ - struct prientry *entries; - size_t nentries; - int println; -}; - -int print(const struct lex *l, struct prv *p, - int (*fn)(const struct lex *, const struct prv *, const struct print *)); -void print_free(struct print *p); - -#endif diff --git a/prv.h b/prv.h deleted file mode 100644 index c0c8930..0000000 --- a/prv.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef PRV_H -#define PRV_H - -#include "lex.h" -#include - -struct prv; - -struct step -{ - enum tktype type; - const char *id; - int chain; -}; - -struct pos -{ - const struct seq *seq, *stseq; - const struct step *step; - int (*end)(const struct lex *, struct prv *); -}; - -struct prv -{ - const struct tk *tk, *stk, *id; - struct tdconstant *tdc; - struct storage *st; - struct pos *pos; - struct ast *ast; - struct type *ag, *t; - struct fn *proto; - size_t n, i, block; - int (*entry)(const struct lex *, struct prv *); - int (*type)(const struct lex *, struct prv *p, const struct type *t); -}; - -struct seq -{ - const struct step *steps; - int (*fn)(const struct lex *l, struct prv *p); - int (*end)(const struct lex *l, struct prv *p); - const char *chain; -}; - -int kw(const char *s); -int prev(const struct prv *p); -int push(const struct pos *pos, struct prv *p); -int pop(const struct lex *l, struct prv *p); -char *sdup(const char *s); - -#endif diff --git a/push.c b/push.c deleted file mode 100644 index 1a9056d..0000000 --- a/push.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "prv.h" -#include - -int push(const struct pos *pos, struct prv *p) -{ - size_t n = p->n + 1; - struct pos *npos = realloc(p->pos, n * sizeof *npos); - - if (!npos) - { - perror("realloc(3)"); - return -1; - } - else if (p->n) - { - struct pos *prev = &npos[p->n - 1]; - - prev->end = prev->seq->end; - prev->seq = prev->stseq; - prev->step = prev->seq->steps; - p->i++; - } - - npos[p->n++] = *pos; - p->pos = npos; - return 0; -} diff --git a/sdup.c b/sdup.c deleted file mode 100644 index e990744..0000000 --- a/sdup.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "prv.h" -#include -#include -#include - -char *sdup(const char *s) -{ - char *n = malloc(strlen(s) + 1); - - if (n) - strcpy(n, s); - else - perror("malloc(3)"); - - return n; -} diff --git a/set.c b/set.c deleted file mode 100644 index 3058040..0000000 --- a/set.c +++ /dev/null @@ -1,552 +0,0 @@ -#include "set.h" -#include "cgen.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include "stmt.h" -#include "storage.h" -#include "type.h" -#include -#include -#include -#include - -static int mv(const struct lex *l, struct prv *p); -static int maddr(const struct lex *l, struct prv *p); -static int msz(const struct lex *l, struct prv *p); -static int mimb(const struct lex *l, struct prv *p); - -static const struct seq seqs[] = -{ - /* size of elementary data types */ - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "void"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "byte"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "halfword"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "word"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "long"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "ubyte"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "uhalfword"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "uword"}, - {0}}, .fn = msz}, - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ID, "ulong"}, - {0}}, .fn = msz}, - - /* address of variable */ - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "address"}, - {ID, "of"}, - {ID}, - {0}}, .fn = maddr}, - - /* size of variable or type alias */ - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ID, "size"}, - {ID, "of"}, - {ANY}, - {0}}, .fn = msz}, - - /* array index or aggregate member */ - {(struct step[]){ - {ID, NULL, 1}, - {ID, "to"}, - {ANY}, - {ID, "of"}, - {ID}, - {0}}, .fn = mimb}, - - /* simple set */ - {(struct step[]){{ID, NULL, 1}, {ID, "to"}, {ANY}, {0}}, .fn = mv}, - {0} -}; - -static unsigned long long tonum(const char *s) -{ - unsigned long long v; - char *end; - - errno = 0; - v = strtoull(s, &end, 0); - - if (*s == '-' || errno || *end) - return strtoll(s, NULL, 0); - - return v; -} - -static int dst(const struct lex *l, const struct tk *tk, struct set *s, - struct prv *p) -{ - const struct stentry *e = fn_var(fn_cur(p), tk); - size_t n = s->ndsts + 1; - struct setdst *dsts; - - if (!e) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - else if (!(dsts = realloc(s->dsts, n * sizeof *dsts))) - { - perror("realloc(3)"); - return -1; - } - - s->dsts = dsts; - s->dsts[s->ndsts++] = (struct setdst){.entry = e}; - return 0; -} - -static int checkzero(const struct tk *tk, const struct set *s, - unsigned long long v) -{ - if (!s->srcv) - return 0; - - for (size_t i = 0; i < s->ndsts; i++) - { - const struct stentry *dst = s->dsts[i].entry; - - if (dst->t->type != BUILTIN) - { - errloc(tk, "destination \"%s\" cannot be set to \"%s\"", - dst->tk->s, tk->s); - return -1; - } - } - - return 0; -} - - -static int checkcompat(const struct tk *tk, const struct set *s) -{ - for (size_t i = 0; i < s->ndsts; i++) - { - const struct stentry *dst = s->dsts[i].entry; - const struct type *st = s->src->t, *dt = dst->t; - - /* TODO: integer promotions */ - if (st->type != dt->type - || st->sz != dt->sz - || st->sign != dt->sign) - { - errloc(tk, "destination \"%s\" cannot be set to \"%s\"", - dst->tk->s, tk->s); - return -1; - } - } - - return 0; -} - -static int mv(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - const struct stentry *e; - struct stmt *stmt = stmt_cur(p); - struct set *s = &stmt->u.set; - - while (!lex_eof(l, tk) && !kw((tk)->s)) - if (dst(l, tk++, s, p)) - return -1; - - /* skip "to" */ - tk++; - - if (tk->type == LIT) - { - /* this can only be applied to arrays of/pointers to chars */ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; - } - else if (tk->type == NUM) - { - s->type = SET_VAL; - s->srcv = tonum(tk->s); - - if (checkzero(tk, s, s->srcv)) - return -1; - } - else if (tk->type == ID) - { - const struct fn *fn = fn_cur(p); - const struct type *t = type_find(fn, tk->s); - - if (t) - { - if (t->type != C) - { - errloc(tk, "type \"%s\" not a constant", tk->s); - return -1; - } - - s->type = SET_VAL; - s->srcv = t->u.c.v; - - if (checkzero(tk, s, s->srcv)) - return -1; - } - else if ((e = fn_var(fn_cur(p), tk))) - { - s->type = SET_VAR; - s->src = e; - - if (checkcompat(tk, s)) - return -1; - } - else - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - } - - fputs("\t\tadding set ", stderr); - - for (size_t i = 0; i < s->ndsts; i++) - fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); - - fprintf(stderr, "to %s\n", tk->s); - - if (pop(l, p)) - return -1; - - p->stk = ++tk; - return 1; -} - -static int maddr(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - struct stmt *stmt = stmt_cur(p); - struct set *s = &stmt->u.set; - const struct stentry *e; - - while (!lex_eof(l, tk) && !kw((tk)->s)) - { - const struct stentry *e = fn_var(fn_cur(p), tk); - - if (e && e->t->type != PTR) - { - errloc(tk, "destination \"%s\" not a pointer", tk->s); - return -1; - } - else if (dst(l, tk++, s, p)) - return -1; - } - - /* skip "to address of" */ - tk += 3; - - if (!(e = fn_var(fn_cur(p), tk))) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - else if (pop(l, p)) - return -1; - - s->type = SET_ADDR; - s->src = e; - p->stk = ++tk; - fputs("\t\tadding set ", stderr); - - for (size_t i = 0; i < s->ndsts; i++) - fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); - - fprintf(stderr, "to address of %s\n", s->src->tk->s); - return 1; -} - -static int msz(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - const struct stentry *e; - struct stmt *stmt = stmt_cur(p); - struct set *s = &stmt->u.set; - const struct fn *fn = fn_cur(p); - const struct type *t; - - while (!lex_eof(l, tk) && !kw(tk->s)) - { - const struct stentry *e = fn_var(fn_cur(p), tk); - - if (e && e->t->type != BUILTIN) - { - errloc(tk, "destination \"%s\" not an integer", tk->s); - return -1; - } - else if (dst(l, tk++, s, p)) - return -1; - } - - /* skip "to size of" */ - tk += 3; - - if (tk->type == NUM) - { - errloc(tk, "cannot compute size of a number"); - return -1; - } - else if (tk->type == LIT) - s->srcv = strlen(tk->s) + 1; - else if ((t = type_find(fn, tk->s))) - { - if (!t->sz) - { - errloc(tk, "type \"%s\" has no size", tk->s); - return-1; - } - - s->srcv = t->sz; - } - else if ((e = fn_var(fn, tk))) - s->srcv = e->t->sz; - else - return-1; - - if (pop(l, p)) - return -1; - - s->type = SET_VAL; - p->stk = ++tk; - fputs("\t\tadding set ", stderr); - - for (size_t i = 0; i < s->ndsts; i++) - fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); - - fprintf(stderr, "size=%llu\n", s->srcv); - return 1; -} - -static int mimb(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - const struct fn *fn = fn_cur(p); - struct stmt *stmt = stmt_cur(p); - struct set *s = &stmt->u.set; - - while (!lex_eof(l, tk) && !kw((tk)->s)) - if (dst(l, tk++, s, p)) - return -1; - - /* skip "to" */ - tk++; - - fputs("\t\tadding set ", stderr); - - for (size_t i = 0; i < s->ndsts; i++) - fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); - - if (tk->type == LIT) - { - errloc(tk, "unexpected literal \"%s\"", tk->s); - return -1; - } - else if (tk->type == ID && !(s->off = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - else if (tk->type == NUM) - s->srcv = tonum(tk->s); - - fprintf(stderr, "to [%s] ", tk->s); - - /* skip index and "of" */ - tk += 2; - - if (!(s->src = fn_var(fn, tk))) - { - errloc(tk, "undefined reference to \"%s\"", tk->s); - return -1; - } - else if (pop(l, p)) - return -1; - - fprintf(stderr, " of %s\n", tk->s); - s->type = SET_IMB; - p->stk = ++tk; - return 1; -} - -void set_free(struct set *m) -{ - if (m) - free(m->dsts); -} - -static int cg_val(const struct set *s, const struct stentry *dst, - struct cgen *c) -{ - const char *szstr = cgen_sz(dst->t->sz), *ab = cgen_abity(dst->t); - const struct fn *fn = c->fn; - - if (ab) - { - printf("store%s %llu, ", szstr, s->srcv); - cgen_printvar(fn, dst); - } - else - { - fputs("%r =l call $memset(l ", stdout); - cgen_printvar(fn, dst); - printf(", w 0, l %zu)", dst->t->sz); - } - - putchar('\n'); - return 0; -} - -static int cg_addr(const struct set *s, const struct stentry *dst, - struct cgen *c) -{ - printf("store%s ", cgen_sz(dst->t->sz)); - cgen_printvar(c->fn, s->src); - fputs(", ", stdout); - cgen_printvar(c->fn, dst); - putchar('\n'); - return 0; -} - -static int cg_var(const struct set *s, const struct stentry *dst, - struct cgen *c) -{ - const struct stentry *src = s->src; - const char *tmp = cgen_tmp(src->t->sz); - - printf("%%%s =%s load%s ", tmp, cgen_sz(src->t->sz), cgen_load(src->t)); - cgen_printvar(c->fn, src); - putchar('\n'); - printf("store%s %%%s, ", cgen_sz(dst->t->sz), tmp); - cgen_printvar(c->fn, dst); - putchar('\n'); - return 0; -} - -static int cg_imb(const struct set *s, const struct stentry *e, struct cgen *c) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} - -int set_cgen(const struct set *s, struct cgen *c) -{ - for (size_t i = 0; i < s->ndsts; i++) - { - const struct stentry *dst = s->dsts[i].entry; - - static int (*const f[])(const struct set *, const struct stentry *, - struct cgen *) = - { - [SET_VAL] = cg_val, - [SET_ADDR] = cg_addr, - [SET_VAR] = cg_var, - [SET_IMB] = cg_imb - }; - - if (f[s->type](s, dst, c)) - return -1; - } - - return 0; -} - -int set(const struct lex *l, struct prv *p) -{ - const struct tk *next = p->tk; - const char *ns; - struct fn *fn = fn_cur(p); - size_t n = fn->nstmts + 1; - struct stmt *stmts; - - if (lex_eof(l, next)) - { - errloc(next - 1, "incomplete set statement"); - return -1; - } - else if (kw((ns = next->s))) - { - errloc(next, "incomplete set statement"); - return -1; - } - else if (!(stmts = realloc(fn->stmts, n * sizeof *stmts))) - { - perror("realloc(3)"); - return -1; - } - - fn->stmts = stmts; - fn->stmts[fn->nstmts++] = (struct stmt){.type = SET}; - - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - if (push(&init, p)) - return -1; - - p->stk = p->tk; - return 1; -} diff --git a/set.h b/set.h deleted file mode 100644 index fdd067a..0000000 --- a/set.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SET_H -#define SET_H - -#include "cgen.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include "storage.h" -#include - -struct setdst -{ - const struct stentry *entry; -}; - -struct set -{ - enum {SET_VAL, SET_VAR, SET_ADDR, SET_IMB} type; - const struct stentry *off, *src; - unsigned long long srcv; - struct setdst *dsts; - size_t ndsts; -}; - -int set(const struct lex *l, struct prv *p); -int set_cgen(const struct set *s, struct cgen *c); -void set_free(struct set *s); - -#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..e8df6c6 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(prc) +add_subdirectory(prc1) diff --git a/src/prc1/CMakeLists.txt b/src/prc1/CMakeLists.txt new file mode 100644 index 0000000..3579ca6 --- /dev/null +++ b/src/prc1/CMakeLists.txt @@ -0,0 +1,39 @@ +add_executable(prc1 + call.c + cgen.c + display.c + div.c + end.c + errloc.c + exit.c + fn.c + from.c + gl.c + im.c + kw.c + lex.c + lit.c + lk.c + prc1.c + set.c + parse.c + pop.c + pr.c + print.c + push.c + sdup.c + stmt.c + storage.c + td.c + tmp.c + type.c + warn.c + ws.c +) + +target_compile_options(prc1 PRIVATE -g -Wall -pedantic) +set_target_properties(prc1 PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(prc1 PRIVATE -Og) +endif() +# install(TARGETS prc1) diff --git a/src/prc1/call.c b/src/prc1/call.c new file mode 100644 index 0000000..8140eba --- /dev/null +++ b/src/prc1/call.c @@ -0,0 +1,488 @@ +#include "call.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "lit.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "type.h" +#include +#include +#include +#include + +static int callpr(const struct lex *l, struct prv *p); +static int callp(const struct lex *l, struct prv *p); +static int callr(const struct lex *l, struct prv *p); +static int callv(const struct lex *l, struct prv *p); + +static const struct seq seqs[] = +{ + {(struct step[]){ + {ID}, + {ID, "using"}, + {ANY, NULL, 1}, + {ID, "returning"}, + {ID}, + {0}}, .fn = callpr}, + {(struct step[]){ + {ID}, + {ID, "using"}, + {ANY, NULL, 1}, + {0}}, .fn = callp}, + {(struct step[]){ + {ID}, + {ID, "returning"}, + {ID}, + {0}}, .fn = callr}, + {(struct step[]){ + {ID}, + {0}}, .fn = callv}, + {0} +}; + +static int param(const struct lex *l, struct prv *p, const struct tk *tk, + struct call *c) +{ + const struct fn *fn = fn_cur(p); + size_t n = c->nparams + 1; + struct callparam *params; + const struct lit *lit = NULL; + const struct stentry *e = NULL; + const struct type *t = NULL; + int sign = 0; + union callv u = {0}; + + if (tk->type == LIT) + { + if (!(lit = lit_push(tk, p))) + return -1; + } + else if (tk->type == NUM) + { + if ((sign = *tk->s == '-')) + u.v = strtoll(tk->s, NULL, 0); + else + u.uv = strtoull(tk->s, NULL, 0); + } + else if ((t = type_find(fn, tk->s))) + { + if (t->type != C) + { + errloc(tk, "type \"%s\" not a constant", tk->s); + return -1; + } + } + else if (!(e = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to parameter \"%s\"", tk->s); + return -1; + } + + if (!(params = realloc(c->params, n * sizeof *params))) + { + perror("realloc(3)"); + return -1; + } + + c->params = params; + c->params[c->nparams++] = (struct callparam) + { + .entry = e, + .lit = lit, + .t = t, + .u = u + }; + + return 0; +} + +static int callpr(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk + 2; + struct call *c = &stmt_cur(p)->u.call; + const struct pr *pr = c->pr; + const struct stentry *e; + size_t n = 0; + + while (!lex_eof(l, tk) && !kw((tk++)->s)) + n++; + + if (pr->variadic) + { + if (n < pr->nparams) + { + errloc(tk, "function \"%s\" expects at least %zu parameters, " + "but %zu were given", c->tk->s, pr->nparams, n); + return -1; + } + } + else if (n != pr->nparams) + { + tk -= 2; + errloc(tk, "function \"%s\" expects %zu parameters, " + "but %zu were given", c->tk->s, pr->nparams, n); + return -1; + } + + if (!pr->ret) + { + errloc(tk, "function \"%s\" does not expect any return variable", + c->tk->s); + return -1; + } + + tk = p->stk + 2; + + for (size_t i = 0; i < n; i++) + if (param(l, p, tk++, c)) + return -1; + + if (!(e = fn_var(fn_cur(p), ++tk))) + { + errloc(tk, "undefined reference to return variable \"%s\"", + tk->s); + return -1; + } + else if (pop(l, p)) + return -1; + + fprintf(stderr, "\t\tadding call to %s using %zu params " + "and %s as return variable\n", c->tk->s, n, tk->s); + c->ret = e; + c->nparams = n; + p->stk = ++tk; + return 1; +} + +static int callr(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk + 2; + const struct fn *fn = fn_cur(p); + const struct stentry *e; + struct call *c = &stmt_cur(p)->u.call; + const struct pr *pr = c->pr; + + if (!pr->ret) + { + errloc(tk, "function \"%s\" does not expect any return variable", + c->tk->s); + return -1; + } + else if (pr->nparams) + { + errloc(tk, "function \"%s\" expects %zu parameters, " + "but none were given", c->tk->s, pr->nparams); + return -1; + } + else if (!(e = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to return variable \"%s\"", tk->s); + return -1; + } + else if (pop(l, p)) + return -1; + + fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", + c->tk->s, tk->s); + c->ret = e; + p->stk = ++tk; + return 1; +} + +static int callp(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk + 2; + struct call *c = &stmt_cur(p)->u.call; + const struct pr *pr = c->pr; + size_t n = 0; + + while (!lex_eof(l, tk) && !kw((tk++)->s)) + n++; + + if (lex_eof(l, tk)) + tk--; + + if (pr->variadic) + { + if (n < pr->nparams) + { + errloc(tk, "function \"%s\" expects at least %zu parameters, " + "but %zu were given", c->tk->s, pr->nparams, n); + return -1; + } + } + else if (pr->nparams != n) + { + errloc(tk, "function \"%s\" expects %zu parameters, " + "but %zu were given", c->tk->s, pr->nparams, n); + return -1; + } + + tk = p->stk + 2; + + for (size_t i = 0; i < n; i++) + if (param(l, p, tk++, c)) + return -1; + + if (pop(l, p)) + return -1; + + fprintf(stderr, "\t\tadding call to %s with 1 param\n", c->tk->s); + p->stk = tk; + return 1; +} + +static int callv(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + struct call *c = &stmt_cur(p)->u.call; + const struct pr *pr = c->pr; + + if (pr->nparams) + { + errloc(tk, "function \"%s\" expects %zu parameters, " + "but none were given", c->tk->s, pr->nparams); + return -1; + } + else if (pop(l, p)) + return -1; + + fprintf(stderr, "\t\tadding call to %s with %s as return variable\n", + c->tk->s, tk->s); + p->stk = ++tk; + return 1; +} + +static const struct pr *find_proto(const struct fn *fn, const char *s) +{ + const struct type *t = type_find(fn, s); + + if (t && t->type == P) + return t->u.p.fn->pr; + + return NULL; +} + +static const struct pr *find(const struct ast *ast, const char *s) +{ + for (size_t i = 0; i < ast->nfns; i++) + { + const struct fn *fn = &ast->fns[i]; + const struct pr *pr; + + if ((pr = find_proto(fn, s))) + return pr; + else if (!strcmp(fn->tk->s, s)) + return fn->pr; + } + + return NULL; +} + +static int gettmp(char *tmp, size_t n) +{ + size_t j; + + for (j = 0; j < n; j++) + { + char c = tmp[j]; + + if (!c) + return tmp[j] = 'a'; + else if (c != 'z') + return ++(tmp[j]); + } + + return EOF; +} + +static int param_lit(const struct lit *lit, struct cgen *c) +{ + printf("l $%s", lit->name); + return 0; +} + +static int param_id(const struct stentry *e, struct cgen *c, char *tmp, + size_t n) +{ + const char *name = e->tk->s; + const struct type *t = e->t; + + printf("%s ", cgen_sz(t->sz)); + + if (cgen_global(c->fn, e)) + printf("$%s", name); + else if (cgen_abity(t)) + { + if (gettmp(tmp, n) == EOF) + return -1; + + printf("%%%s", tmp); + } + else + printf("%%%s_", name); + + return 0; +} + +static int param_c(const struct type *t, struct cgen *cg) +{ + const union c *c = &t->u.c; + + /* TODO: adapt type to expected param size */ + fputs("l ", stdout); + + if (t->sign) + printf("%lld", c->v); + else + printf("%llu", c->uv); + + return 0; +} + +static int param_num(const struct callparam *cp, struct cgen *c) +{ + const union callv *u = &cp->u; + + /* TODO: adapt type to expected param size */ + fputs("w ", stdout); + + if (cp->sign) + printf("%lld", u->v); + else + printf("%llu", u->uv); + + return 0; +} + +static int param_load(const struct call *m, struct cgen *c) +{ + char tmp[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; + + for (size_t i = 0; i < m->nparams; i++) + { + const struct callparam *cp = &m->params[i]; + const struct stentry *e = cp->entry; + + if (!e || cgen_global(c->fn, e) || !cgen_abity(e->t)) + continue; + else if (gettmp(tmp, sizeof tmp - 1) == EOF) + { + fprintf(stderr, "%s: exhausted temporaries\n", __func__); + return -1; + } + + printf("%%%s =%s load%s %%%s_\n", tmp, cgen_sz(e->t->sz), + cgen_load(e->t), e->tk->s); + } + + return 0; +} + +int call_cgen(const struct call *m, struct cgen *c) +{ + char tmps[sizeof "abcdefghijklmnopqrstuvwxyz"] = {0}; + const struct stentry *ret = m->ret; + const char *tmp; + size_t sz; + + if (param_load(m, c)) + return -1; + else if (ret) + { + tmp = cgen_tmp((sz = ret->t->sz)); + printf("%%%s =%s ", tmp, cgen_sz(sz)); + } + + printf("call $%s(", m->tk->s); + + for (size_t i = 0; i < m->nparams; i++) + { + const struct callparam *cp = &m->params[i]; + int var = m->pr->variadic; + + if (cp->lit) + param_lit(cp->lit, c); + else if (cp->entry) + param_id(cp->entry, c, tmps, sizeof tmps - 1); + else if (cp->t) + param_c(cp->t, c); + else + param_num(cp, c); + + if (var && i + 1 == var - 1) + fputs(", ...", stdout); + + if (i + 1 < m->nparams) + fputs(", ", stdout); + } + + puts(")"); + + if (ret) + { + printf("store%s %%%s, ", cgen_sz(sz), tmp); + cgen_printvar(c->fn, ret); + putchar('\n'); + } + + return 0; +} + +void call_free(struct call *c) +{ + if (c) + free(c->params); +} + +int call(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->tk; + const struct pr *pr; + struct fn *fn = fn_cur(p); + size_t n = fn->nstmts +1; + struct stmt *stmts; + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + /* TODO: function pointers */ + + if (lex_eof(l, tk)) + { + errloc(tk - 1, "incomplete call statement"); + return -1; + } + else if (!(pr = find(p->ast, tk->s))) + { + errloc(tk, "undefined reference to function \"%s\"", tk->s); + return -1; + } + else if (!(stmts = realloc(fn->stmts, n * sizeof *stmts))) + { + perror("realloc(3)"); + return -1; + } + + fn->stmts = stmts; + fn->stmts[fn->nstmts++] = (struct stmt) + { + .type = CALL, + .u.call = + { + .tk = tk, + .pr = pr + } + }; + + if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/call.h b/src/prc1/call.h new file mode 100644 index 0000000..0126e7f --- /dev/null +++ b/src/prc1/call.h @@ -0,0 +1,37 @@ +#ifndef CALL_H +#define CALL_H + +#include "cgen.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include + +struct callparam +{ + const struct lit *lit; + const struct type *t; + const struct stentry *entry; + int sign; + + union callv + { + long long v; + unsigned long long uv; + } u; +}; + +struct call +{ + const struct tk *tk; + const struct pr *pr; + const struct stentry *ret; + struct callparam *params; + size_t nparams; +}; + +int call(const struct lex *l, struct prv *p); +int call_cgen(const struct call *m, struct cgen *c); +void call_free(struct call *c); + +#endif diff --git a/src/prc1/cgen.c b/src/prc1/cgen.c new file mode 100644 index 0000000..44e9d24 --- /dev/null +++ b/src/prc1/cgen.c @@ -0,0 +1,195 @@ +#include "cgen.h" +#include "fn.h" +#include "lex.h" +#include "lit.h" +#include "parse.h" +#include "storage.h" +#include +#include +#include + +void cgen_free(struct cgen *c) +{ +} + +const char *cgen_sz(const size_t sz) +{ + switch (sz) + { + case 1: + return "b"; + case 2: + return "h"; + case 4: + return "w"; + case 8: + return "l"; + default: + break; + } + + return NULL; +} + +const char *cgen_tmp(const size_t sz) +{ + switch (sz) + { + case 1: + return "vb"; + case 2: + return "vh"; + case 4: + return "vw"; + case 8: + return "vl"; + default: + break; + } + + return "v"; +} + +const char *cgen_type(const struct type *t) +{ + switch (t->sz) + { + case 1: + return t->sign ? "b" : "ub"; + case 2: + return t->sign ? "h" : "uh"; + case 4: + return t->sign ? "w" : "uw"; + case 8: + return t->sign ? "l" : "ul"; + + default: + break; + } + + return NULL; +} + +const char *cgen_abity(const struct type *t) +{ + switch (t->sz) + { + case 1: + return t->sign ? "b" : "ub"; + case 2: + return t->sign ? "h" : "uh"; + case 4: + return "w"; + case 8: + return "l"; + + default: + break; + } + + return NULL; +} + +const char *cgen_load(const struct type *t) +{ + switch (t->sz) + { + case 1: + return t->sign ? "sb" : "ub"; + case 2: + return t->sign ? "sh" : "uh"; + case 4: + return t->sign ? "sw" : "uw"; + case 8: + return "l"; + + default: + break; + } + + return NULL; +} + +int cgen_param(const struct fn *fn, const struct stentry *e) +{ + const struct pr *pr = fn->pr; + const char *name = e->tk->s; + + for (size_t i = 0; i < pr->nparams; i++) + if (!strcmp(pr->params[i].tk->s, name)) + return 1; + + return 0; +} + +void cgen_printvar(const struct fn *fn, const struct stentry *e) +{ + const char *name = e->tk->s; + + if (cgen_global(fn, e)) + printf("$%s", name); + else + printf("%%%s_", name); +} + +int cgen_global(const struct fn *fn, const struct stentry *e) +{ + const struct storage *ws = fn->ws, *gl = fn->gl; + const struct pr *pr = fn->pr; + const struct param *ret = pr->ret; + const char *name = e->tk->s; + + /* A variable is only global if it is defined inside the global + * variables section ("gl"), or if it is not listed on the working + * storage section ("ws"), as a function parameter or a return value. */ + + if (gl) + for (size_t i = 0; i < gl->nentries; i++) + if (!strcmp(gl->entries[i].tk->s, name)) + return 1; + + if (cgen_param(fn, e) || (ret && !strcmp(ret->tk->s, name))) + return 0; + else if (ws) + for (size_t i = 0; i < ws->nentries; i++) + if (!strcmp(ws->entries[i].tk->s, name)) + return 0; + + for (const struct tmp *t = fn->tmps; t; t = t->next) + if (!strcmp(t->tk.s, name)) + return 0; + + return 1; +} + +static void pushfmt(const char *type, const char *fmt) +{ + printf("data $____fmt%s = { b \"%s\" , b 0 }\n", type, fmt); +} + +int cgen(const struct ast *ast, struct cgen *c) +{ + /* generate literals to use with printf(3) */ + pushfmt("b", "%hhd"); + pushfmt("h", "%hd"); + pushfmt("w", "%d"); + pushfmt("l", "%ld"); + pushfmt("ub", "%hhu"); + pushfmt("uh", "%hu"); + pushfmt("uw", "%u"); + pushfmt("ul", "%lu"); + pushfmt("bx", "%#hhx"); + pushfmt("hx", "%#hx"); + pushfmt("wx", "%#x"); + pushfmt("lx", "%#lx"); + + for (const struct lit *l = ast->lits; l; l = l->next) + if (lit_cgen(l)) + return-1; + + for (size_t i = 0; i < ast->nfns; i++) + if (fn_cgen((c->fn = &ast->fns[i]), c)) + return -1; + + return 0; +} diff --git a/src/prc1/cgen.h b/src/prc1/cgen.h new file mode 100644 index 0000000..0a30138 --- /dev/null +++ b/src/prc1/cgen.h @@ -0,0 +1,23 @@ +#ifndef CGEN_H +#define CGEN_H + +#include "parse.h" +#include "storage.h" + +struct cgen +{ + const struct fn *fn; +}; + +int cgen(const struct ast *ast, struct cgen *c); +int cgen_param(const struct fn *fn, const struct stentry *e); +int cgen_global(const struct fn *fn, const struct stentry *e); +void cgen_printvar(const struct fn *fn, const struct stentry *e); +const char *cgen_sz(const size_t sz); +const char *cgen_tmp(const size_t sz); +const char *cgen_type(const struct type *t); +const char *cgen_abity(const struct type *t); +const char *cgen_load(const struct type *t); +void cgen_free(struct cgen *c); + +#endif diff --git a/src/prc1/display.c b/src/prc1/display.c new file mode 100644 index 0000000..885fbe7 --- /dev/null +++ b/src/prc1/display.c @@ -0,0 +1,142 @@ +#include "display.h" +#include "cgen.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include +#include +#include + +static int finalize(const struct lex *l, const struct prv *p, + const struct print *pr) +{ + const struct ast *ast = p->ast; + struct fn *fn = &ast->fns[ast->nfns - 1]; + size_t n = fn->nstmts + 1; + struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); + + if (!stmts) + { + perror("realloc(3)"); + return -1; + } + + fn->stmts = stmts; + fn->stmts[fn->nstmts++] = (struct stmt) + { + .type = DISPLAY, + .u.display.p = *pr + }; + + fprintf(stderr, "\t\tadding display statement with %zu entries%s\n", + pr->nentries, pr->println ? "" : ", no lf"); + return 0; +} + +static int cg_val(const struct tk *tk) +{ + const char *num = tk->s; + int neg = *num == '-'; + unsigned long long uv; + char *end; + + fputs("call $printf(l $____fmt", stdout); + errno = 0; + uv = strtoull(num, &end, 16); + + if (!neg && !errno && !*end) + printf("lx, ..., l %llu )\n", uv); + else + { + errno = 0; + uv = strtoull(num, &end, 0); + + if (neg || errno || *end) + { + long long v = strtoll(num, NULL, 0); + printf("l, ..., l %lld )\n", v); + } + else + printf("l, ..., l %llu )\n", uv); + } + + return 0; +} + +static int cg_lit(const struct prientry *e) +{ + const struct lit *l = e->lit; + const char *tmp; + + if (!l) + { + fprintf(stderr, "%s: unexpected null literal\n", __func__); + return -1; + } + + printf("%%%s =l loadl $stdout\n", (tmp = cgen_tmp(sizeof (void *)))); + printf("call $fputs(l $%s, w %%%s)\n", l->name, tmp); + return 0; +} + +static int cg_id(const struct prientry *de, const struct fn *fn) +{ + const struct stentry *e = de->entry; + const struct type *t = e->t; + const char *id = e->tk->s; + int global = cgen_global(fn, e); + size_t sz = t->sz; + const char *asz = cgen_sz(sz < 4 ? 4 : sz), *tmp = cgen_tmp(sz); + + if (global) + printf("%%%s =%s load%s $%s\n", tmp, asz, cgen_load(t), id); + else + printf("%%%s =%s load%s %%%s_\n", tmp, asz, cgen_load(t), id); + + fputs("call $printf(l $____fmt", stdout); + + if (t->type == PTR) + fputs("lx, ..., l ", stdout); + else + printf("%s, ..., %s ", cgen_type(t), asz); + + printf("%%%s)\n", tmp); + + return 0; +} + +int display_cgen(const struct display *d, struct cgen *c) +{ + const struct print *p = &d->p; + + for (size_t i = 0; i < p->nentries; i++) + { + const struct prientry *e = &p->entries[i]; + const struct tk *tk = e->tk; + + if (tk->type == LIT && cg_lit(e)) + return -1; + else if (tk->type == NUM && cg_val(tk)) + return -1; + else if (tk->type == ID && e->entry && cg_id(e, c->fn)) + return -1; + else if (tk->type == ID && e->lit && cg_lit(e)) + return -1; + } + + if (p->println) + puts("call $putchar(l 10)"); + + return 0; +} + +void display_free(struct display *d) +{ + print_free(&d->p); +} + +int display(const struct lex *l, struct prv *p) +{ + return print(l, p, finalize); +} diff --git a/src/prc1/display.h b/src/prc1/display.h new file mode 100644 index 0000000..9b073b1 --- /dev/null +++ b/src/prc1/display.h @@ -0,0 +1,17 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include "lex.h" +#include "print.h" +#include "prv.h" + +struct display +{ + struct print p; +}; + +int display(const struct lex *l, struct prv *p); +int display_cgen(const struct display *d, struct cgen *c); +void display_free(struct display *d); + +#endif diff --git a/src/prc1/div.c b/src/prc1/div.c new file mode 100644 index 0000000..9061ac6 --- /dev/null +++ b/src/prc1/div.c @@ -0,0 +1,89 @@ +#include "div.h" +#include "gl.h" +#include "im.h" +#include "lk.h" +#include "pr.h" +#include "td.h" +#include "ws.h" + +static const struct seq linkage = + {(struct step[]){{ID, "linkage"}, {0}}, .fn = lk}, + types = {(struct step[]){{ID, "types"}, {0}}, .fn = td}, + imports = {(struct step[]){{ID, "imports"}, {0}}, .fn = im}, + procedure = {(struct step[]){{ID, "procedure"}, {0}}, .fn = pr}; + +static const struct seq fnseq[] = +{ + linkage, + types, + imports, + procedure, + {(struct step[]){{ID, "storage"}, {0}}, .fn = ws}, + {(struct step[]){{ID, "globals"}, {0}}, .fn = gl}, + {0} +}; + +static const struct seq imseq[] = +{ + linkage, + types, + imports, + {0} +}; + +static const struct seq pseq[] = +{ + linkage, + procedure, + {0} +}; + +int div_fn(const struct lex *l, struct prv *p) +{ + struct pos init = + { + .seq = fnseq, + .stseq = fnseq, + .step = fnseq->steps + }; + + if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 0; +} + +int div_im(const struct lex *l, struct prv *p) +{ + struct pos init = + { + .seq = imseq, + .stseq = imseq, + .step = imseq->steps + }; + + if (lex_eof(l, p->stk)) + return 0; + else if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} + +int div_p(const struct lex *l, struct prv *p) +{ + struct pos init = + { + .seq = pseq, + .stseq = pseq, + .step = pseq->steps + }; + + if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/div.h b/src/prc1/div.h new file mode 100644 index 0000000..8a0df6d --- /dev/null +++ b/src/prc1/div.h @@ -0,0 +1,11 @@ +#ifndef DIV_H +#define DIV_H + +#include "lex.h" +#include "prv.h" + +int div_fn(const struct lex *l, struct prv *p); +int div_im(const struct lex *l, struct prv *p); +int div_p(const struct lex *l, struct prv *p); + +#endif diff --git a/src/prc1/end.c b/src/prc1/end.c new file mode 100644 index 0000000..b9ad790 --- /dev/null +++ b/src/prc1/end.c @@ -0,0 +1,80 @@ +#include "end.h" +#include "errloc.h" +#include "fn.h" +#include "stmt.h" +#include +#include +#include + +void end_free(struct end *e) +{ +} + +int end_cgen(const struct end *e, struct cgen *c) +{ + const struct stmt *s = &c->fn->stmts[e->block_i]; + + if (!s->end) + { + fprintf(stderr, "%s: unreachable\n", __func__); + return -1; + } + else if (s->end(s, c)) + return -1; + + printf("@__end%zu\n", e->block_i); + return 0; +} + +int end(const struct lex *l, struct prv *p) +{ + struct pos *pos = &p->pos[p->i]; + struct fn *fn = fn_cur(p); + size_t nst = fn->nstmts + 1, *bl, bl_i; + struct stmt *s; + + if (!fn->nblocks) + { + errloc(p->stk, "unexpected \"end\" statement"); + return -1; + } + + bl_i = fn->blocks[fn->nblocks - 1]; + + if (fn->nblocks > 1) + { + if (!(bl = realloc(fn->blocks, (fn->nblocks - 1) * sizeof *bl))) + { + perror("realloc(3)"); + return -1; + } + + fn->blocks = bl; + } + else + { + free(fn->blocks); + fn->blocks = NULL; + } + + fn->nblocks--; + + if (!(s = realloc(fn->stmts, nst * sizeof *s))) + { + perror("realloc(3)"); + return -1; + } + + s[fn->nstmts++] = (struct stmt) + { + .type = END, + .u.end.block_i = bl_i + }; + + fn->stmts = s; + pos->seq = pos->stseq = stmts; + pos->step = stmts->steps; + p->stk = p->tk; + fprintf(stderr, "\t\tadding end statement, block index %zu\n", bl_i); + return 1; +} diff --git a/src/prc1/end.h b/src/prc1/end.h new file mode 100644 index 0000000..5286f4f --- /dev/null +++ b/src/prc1/end.h @@ -0,0 +1,18 @@ +#ifndef END_H +#define END_H + +#include "cgen.h" +#include "lex.h" +#include "prv.h" +#include + +struct end +{ + size_t block_i; +}; + +int end(const struct lex *l, struct prv *p); +int end_cgen(const struct end *e, struct cgen *c); +void end_free(struct end *e); + +#endif diff --git a/src/prc1/errloc.c b/src/prc1/errloc.c new file mode 100644 index 0000000..1f3e224 --- /dev/null +++ b/src/prc1/errloc.c @@ -0,0 +1,28 @@ +#include "errloc.h" +#include "lex.h" +#include +#include + +void errcloc(const struct lex *l, const char *fmt, ...) +{ + const struct loc *loc = &l->loc; + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s:%d:%d: error: ", loc->f, loc->line, loc->col); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} + +void errloc(const struct tk *tk, const char *fmt, ...) +{ + const struct loc *loc = &tk->loc; + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s:%d:%d: error: ", loc->f, loc->line, loc->col); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} diff --git a/src/prc1/errloc.h b/src/prc1/errloc.h new file mode 100644 index 0000000..127caa7 --- /dev/null +++ b/src/prc1/errloc.h @@ -0,0 +1,9 @@ +#ifndef ERRLOC_H +#define ERRLOC_H + +#include "lex.h" + +void errloc(const struct tk *tk, const char *fmt, ...); +void errcloc(const struct lex *l, const char *fmt, ...); + +#endif diff --git a/src/prc1/exit.c b/src/prc1/exit.c new file mode 100644 index 0000000..0438b66 --- /dev/null +++ b/src/prc1/exit.c @@ -0,0 +1,8 @@ +#include "exit.h" +#include "prv.h" + +int s_exit(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} diff --git a/src/prc1/exit.h b/src/prc1/exit.h new file mode 100644 index 0000000..24b1292 --- /dev/null +++ b/src/prc1/exit.h @@ -0,0 +1,16 @@ +#ifndef EXIT_H +#define EXIT_H + +#include "lex.h" +#include "prv.h" +#include + +struct exit +{ + int dummy; +}; + +int s_exit(const struct lex *l, struct prv *p); +void exit_free(struct exit *d); + +#endif diff --git a/src/prc1/fn.c b/src/prc1/fn.c new file mode 100644 index 0000000..c2d3b4f --- /dev/null +++ b/src/prc1/fn.c @@ -0,0 +1,273 @@ +#include "fn.h" +#include "div.h" +#include "errloc.h" +#include "gl.h" +#include "im.h" +#include "parse.h" +#include "prv.h" +#include "pr.h" +#include "stmt.h" +#include "storage.h" +#include "td.h" +#include "ws.h" +#include +#include +#include + +static int pubfn(const struct lex *l, struct prv *p); +static int prvfn(const struct lex *l, struct prv *p); + +static const struct seq fnseq[] = +{ + {(struct step[]) + {{ID, "public"}, {ID, "function"}, {ID}, {0}}, .fn = pubfn, + .end = fn_end}, + {(struct step[]) + {{ID, "function"}, {ID}, {0}}, .fn = prvfn, .end = fn_end}, + {0} +}; + +int fn_end(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + + if (!fn->pr) + { + const struct tk *tk = fn->tk; + const char *s = p->proto ? "prototype" : "function"; + + errloc(p->stk - 1, "%s \"%s\" has no procedure", s, tk->s); + return -1; + } + else if (fn->nblocks) + { + const struct tk *tk = lex_eof(l, p->stk) ? p->tk - 1 : p->stk; + + errloc(tk, "missing \"end\" in function \"%s\"", fn->tk->s); + return -1; + } + + return 0; +} + +static const struct tk *findfn(const char *s, const struct ast *ast) +{ + for (size_t i = 0; i < ast->nfns; i++) + { + const struct tk *tk = ast->fns[i].tk; + + if (!strcmp(tk->s, s)) + return tk; + } + + return NULL; +} + +static int pushfn(const struct tk *tk, const struct lex *lex, struct prv *p, + enum linkage l) +{ + const struct tk *def; + struct ast *ast = p->ast; + size_t n = ast->nfns + 1; + struct fn *fns; + + if ((def = findfn(tk->s, ast))) + { + const struct loc *loc = &def->loc; + + errloc(tk, "function \"%s\" already defined at %s:%d:%d", tk->s, + loc->f, loc->line, loc->col); + return -1; + } + else if (!(fns = realloc(ast->fns, n * sizeof *fns))) + { + perror("realloc(3)"); + return -1; + } + + fns[ast->nfns++] = (struct fn){.linkage = l, .tk = tk}; + ast->fns = fns; + + if (div_fn(lex, p)) + return -1; + + fprintf(stderr, "adding %s function %s\n", + l == STATIC ? "private" : "public", tk->s); + return 1; +} + +static int pubfn(const struct lex *l, struct prv *p) +{ + return pushfn(p->stk + 2, l, p, EXTERNAL); +} + +static int prvfn(const struct lex *l, struct prv *p) +{ + return pushfn(p->stk + 1, l, p, STATIC); +} + +const struct stentry *fn_var(const struct fn *fn, const struct tk *tk) +{ + const struct storage *lk = fn->lk, *ws = fn->ws, *gl = fn->gl; + const struct stentry *e; + + if ((lk && (e = storage_find(tk->s, lk))) + || (ws && (e = storage_find(tk->s, ws))) + || (gl && (e = storage_find(tk->s, gl)))) + return e; + + for (size_t i = 0; i < fn->nimps; i++) + if ((e = fn_var(fn->imps[i].ast.fns, tk))) + return e; + + return NULL; +} + +int fn_cgen(const struct fn *fn, struct cgen *c) +{ + const struct pr *pr = fn->pr; + const struct param *ret = pr->ret; + const struct type *rt = NULL; + const char *s = NULL; + + if (fn->gl && gl_cgen(fn->gl, c)) + return -1; + + switch (fn->linkage) + { + case STATIC: + printf("function "); + break; + case EXTERNAL: + printf("export function "); + break; + } + + if (ret) + { + rt = ret->entry->t; + s = ret->entry->tk->s; + printf("%s ", cgen_abity(ret->entry->t)); + } + + printf("$%s(", fn->tk->s); + + for (size_t i = 0; i < pr->nparams; i++) + { + const struct param *p = &pr->params[i]; + + printf(" %s", cgen_abity(p->entry->t)); + printf(" %%__param_%s ", p->tk->s); + + if (i + 1 < pr->nparams) + fputs(", ", stdout); + } + + puts(") {\n@start"); + + for (size_t i = 0; i < pr->nparams; i++) + { + const struct param *p = &pr->params[i]; + const struct type *t = p->entry->t; + const char *s = p->tk->s; + + printf("%%%s_ =l alloc%zu %zu\n", s, t->align, t->sz); + printf("store%s %%__param_%s, %%%s_\n", cgen_sz(t->sz), s, s); + } + + if (ret) + printf("%%%s_ =l alloc%zu %zu\n", s, rt->align, rt->sz); + + if (fn->ws && ws_cgen(fn->ws, c)) + return -1; + + for (const struct tmp *tmp = fn->tmps; tmp; tmp = tmp->next) + { + const struct stentry *e = &tmp->e; + const struct type *t = tmp->e.t; + + printf("%%%s_ =l alloc%zu %zu\n", e->tk->s, t->align, t->sz); + } + + for (size_t i = 0; i < fn->nstmts; i++) + if (stmt_cgen(&fn->stmts[i], c)) + return -1; + + if (ret) + { + const char *t = cgen_tmp(rt->sz); + + printf("%%%s =%s load%s %%%s_\n", t, cgen_sz(rt->sz), cgen_load(rt), s); + printf("ret %%%s", t); + } + else + fputs("ret", stdout); + + puts("\n}"); + return 0; +} + +void fn_cgen_free(struct fn_cgen *c) +{ + free(c); +} + +void fn_free(struct fn *fn) +{ + for (size_t i = 0; i < fn->nimps; i++) + im_free(&fn->imps[i]); + + for (size_t i = 0; i < fn->nstmts; i++) + stmt_free(&fn->stmts[i]); + + for (struct tmp *t = fn->tmps; t;) + { + struct tmp *next = t->next; + + free(t->tk.s); + free(t); + t = next; + } + + storage_free(fn->lk); + storage_free(fn->ws); + storage_free(fn->gl); + pr_free(fn->pr); + td_free(fn->td); + free(fn->imps); + free(fn->stmts); + free(fn->blocks); +} + +struct fn *fn_cur(const struct prv *p) +{ + struct ast *ast = p->ast; + + if (p->proto) + return p->proto; + + return &ast->fns[p->ast->nfns - 1]; +} + +int fn(const struct lex *l, struct prv *p) +{ + struct pos init = + { + .seq = fnseq, + .stseq = fnseq, + .step = fnseq->steps + }; + + if (lex_eof(l, p->stk)) + return 0; + else if (lex_eof(l, p->stk + 1)) + { + errloc(p->stk, "incomplete function statement"); + return -1; + } + else if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/fn.h b/src/prc1/fn.h new file mode 100644 index 0000000..6c65ae5 --- /dev/null +++ b/src/prc1/fn.h @@ -0,0 +1,22 @@ +#ifndef FN_H +#define FN_H + +#include "cgen.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" + +struct fn_cgen +{ + int dummy; +}; + +int fn(const struct lex *l, struct prv *p); +struct fn *fn_cur(const struct prv *p); +int fn_cgen(const struct fn *fn, struct cgen *c); +const struct stentry *fn_var(const struct fn *fn, const struct tk *tk); +int fn_end(const struct lex *l, struct prv *p); +void fn_free(struct fn *fn); +void fn_cgen_free(struct fn_cgen *c); + +#endif diff --git a/src/prc1/from.c b/src/prc1/from.c new file mode 100644 index 0000000..b9cb99e --- /dev/null +++ b/src/prc1/from.c @@ -0,0 +1,364 @@ +#include "from.h" +#include "cgen.h" +#include "fn.h" +#include "errloc.h" +#include "stmt.h" +#include "storage.h" +#include "tmp.h" +#include "type.h" +#include +#include +#include +#include +#include + +void from_free(struct from *fr) +{ +} + +static int loadvar(const struct from_it *st, struct cgen *c) +{ + const struct stentry *e = st->u.e; + size_t sz = e->t->sz; + const char *tmp = cgen_tmp(sz); + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(e->t)); + cgen_printvar(c->fn, e); + putchar('\n'); + return 0; +} + +/* TODO: de-duplicate function */ +static unsigned long long tonum(const char *s) +{ + unsigned long long v; + char *end; + + errno = 0; + v = strtoull(s, &end, 0); + + if (*s == '-' || errno || *end) + return strtoll(s, NULL, 0); + + return v; +} + +static int loadval(const struct from *fr, struct cgen *c) +{ + const struct stentry *dst = fr->var; + const struct from_it *st = &fr->start; + unsigned long long v = tonum(st->u.tk->s); + + printf("store%s %llu, ", cgen_sz(dst->t->sz), v); + cgen_printvar(c->fn, dst); + putchar('\n'); + return 0; +} + +static int endvar(const struct from *fr, struct cgen *c) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int endval(const struct from *fr, struct cgen *c) +{ + const struct stentry *src = fr->var; + size_t sz = src->t->sz; + const char *tmp = cgen_tmp(sz); + const struct from_it *end = &fr->end; + const struct tk *tk = end->u.tk; + int neg = *tk->s == '-'; + size_t bl = fr->block_i; + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(src->t)); + cgen_printvar(c->fn, src); + putchar('\n'); + printf("%%%s =%s c", tmp, cgen_sz(sz)); + fputs(neg ? "sge" : "uge", stdout); + printf("%s ", cgen_sz(sz)); + printf("%%%s, %s\n", tmp, tk->s); + printf("jnz %%%s, @__end%zu, @__blockbody%zu\n", tmp, bl, bl); + printf("@__blockbody%zu\n", bl); + return 0; +} + +static int from_var(const struct from *fr, struct cgen *c) +{ + const struct from_it *st = &fr->start; + + switch (st->type) + { + case FR_VAR: + if (loadvar(st, c)) + return -1; + break; + + case FR_VAL: + if (loadval(fr, c)) + return -1; + break; + } + + printf("@__block%zu\n", fr->block_i); + + switch (fr->end.type) + { + case FR_VAR: + if (endvar(fr, c)) + return -1; + break; + + case FR_VAL: + if (endval(fr, c)) + return -1; + break; + } + + return 0; +} + +int from_cgen(const struct from *fr, struct cgen *c) +{ + return from_var(fr, c); +} + +static int from_end(const struct stmt *s, struct cgen *c) +{ + const struct from *fr = &s->u.from; + const struct stentry *src = fr->var; + const struct type *t = src->t; + size_t sz = t->sz; + const char *tmp = cgen_tmp(sz); + const struct fn *fn = c->fn; + + printf("%%%s =%s load%s ", tmp, cgen_sz(sz), cgen_load(t)); + cgen_printvar(fn, src); + putchar('\n'); + printf("%%%s =%s add %%%s, 1\n", tmp, cgen_sz(sz), tmp); + printf("store%s %%%s, ", cgen_sz(sz), tmp); + cgen_printvar(fn, src); + putchar('\n'); + printf("jmp @__block%zu\n", fr->block_i); + return 0; +} + +static int checksym(const struct fn *fn, const struct tk *tk, + struct from_it *fr) +{ + const struct stentry *e = fn_var(fn, tk); + + if (!e) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + + switch (e->t->type) + { + case C: + case BUILTIN: + break; + case U: + case S: + case P: + case T: + case PTR: + case ARY: + { + char *s = type_name(e->t); + + if (s) + errloc(tk, "\"%s\" (\"%s\") cannot be used in \"from\" loop", + tk->s, s); + + free(s); + return -1; + } + } + + fr->type = FR_VAR; + fr->u.e = e; + return 0; +} + +static int check(const struct fn *fn, const struct tk *tk, struct from_it *fr) +{ + switch (tk->type) + { + case NUM: + fr->type = FR_VAL; + fr->u.tk = tk; + break; + case ID: + return checksym(fn, tk, fr); + case LIT: + errloc(tk, "unexpected literal"); + return -1; + case UNDEF: + case ANY: + fprintf(stderr, "%s: unreachable\n", __func__); + return -1; + } + + return 0; +} + +static int finalize(struct prv *p, struct fn *fn, struct from *fr) +{ + struct stmt *s; + struct pos *pos = &p->pos[p->i]; + size_t nst = fn->nstmts + 1, nbl = fn->nblocks + 1, + *bl = realloc(fn->blocks, nbl * sizeof *bl); + + if (!bl) + { + perror("realloc(3)"); + return -1; + } + + fr->block_i = bl[fn->nblocks++] = fn->nstmts; + fn->blocks = bl; + + if (!(s = realloc(fn->stmts, nst * sizeof *s))) + { + perror("realloc(3)"); + return -1; + } + + s[fn->nstmts++] = (struct stmt) + { + .type = FROM, + .u.from = *fr, + .end = from_end + }; + + fn->stmts = s; + pos->seq = pos->stseq = stmts; + pos->step = stmts->steps; + fprintf(stderr, ", iterator %s, block index %zu\n", fr->var->tk->s, + bl[fn->nblocks - 1]); + return 0; +} + +static const struct type *valtype(const struct fn *fn, const struct tk *tk) +{ + char *end; + + errno = 0; + strtol(tk->s, &end, 0); + + if (errno || *end) + { + errno = 0; + strtoll(tk->s, &end, 0); + + if (errno || *end) + return type_find(fn, "ulong"); + + return type_find(fn, "long"); + } + + return type_find(fn, "word"); +} + +static const struct type *ittype(const struct fn *fn, const struct from_it *it) +{ + switch (it->type) + { + case FR_VAL: + return valtype(fn, it->u.tk); + case FR_VAR: + return it->u.e->t; + } + + fprintf(stderr, "%s: unreachable\n", __func__); + return NULL; +} + +static const struct type *gettype(const struct fn *fn, + const struct from_it *a, const struct from_it *b) +{ + const struct type *ta = ittype(fn, a), *tb = ittype(fn, b); + + return ta->sz > tb->sz ? ta : tb; +} + +int from(const struct lex *l, struct prv *p) +{ + const struct tk *start = p->stk + 1, *end = p->stk + 3; + struct fn *fn = fn_cur(p); + struct from fr = {0}; + const struct type *t; + + if (check(fn, start, &fr.start) + || check(fn, end, &fr.end) + || !(t = gettype(fn, &fr.start, &fr.end)) + || !(fr.var = tmp_create(fn, t))) + return -1; + + fprintf(stderr, "\t\tadding from statement [%s, %s]", start->s, end->s); + + if (finalize(p, fn, &fr)) + return -1; + + p->stk = ++end; + return 1; +} + +static int checkvar(const struct fn *fn, const struct tk *tk, struct from *fr) +{ + const struct stentry *e; + + if (tk->type != ID) + { + errloc(tk, "\"%s\" not a variable", tk->s); + return -1; + } + else if (!(e = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (e->t->type != BUILTIN) + { + errloc(tk, "variable \"%s\" not an integer", tk->s); + return -1; + } + + fr->var = e; + return 0; +} + +int from_id(const struct lex *l, struct prv *p) +{ + const struct tk *start = p->stk + 1, *end = p->stk + 3, *var = p->stk + 5; + struct fn *fn = fn_cur(p); + struct from fr = {0}; + + if (check(fn, start, &fr.start) + || check(fn, end, &fr.end) + || checkvar(fn, var, &fr)) + return -1; + + fprintf(stderr, "\t\tadding from statement [%s, %s] using %s", + start->s, end->s, var->s); + + if (finalize(p, fn, &fr)) + return -1; + + p->stk = ++var; + return 1; +} + +int from_by(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +int from_idby(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} diff --git a/src/prc1/from.h b/src/prc1/from.h new file mode 100644 index 0000000..8a77629 --- /dev/null +++ b/src/prc1/from.h @@ -0,0 +1,34 @@ +#ifndef FROM_H +#define FROM_H + +#include "cgen.h" +#include "lex.h" +#include "storage.h" +#include "prv.h" +#include + +struct from +{ + struct from_it + { + enum {FR_VAL, FR_VAR} type; + + union + { + const struct tk *tk; + const struct stentry *e; + } u; + } start, end; + + size_t block_i; + const struct stentry *var; +}; + +int from(const struct lex *l, struct prv *p); +int from_id(const struct lex *l, struct prv *p); +int from_by(const struct lex *l, struct prv *p); +int from_idby(const struct lex *l, struct prv *p); +int from_cgen(const struct from *m, struct cgen *c); +void from_free(struct from *fr); + +#endif diff --git a/src/prc1/gl.c b/src/prc1/gl.c new file mode 100644 index 0000000..de0293f --- /dev/null +++ b/src/prc1/gl.c @@ -0,0 +1,24 @@ +#include "gl.h" +#include "fn.h" +#include "prv.h" +#include "parse.h" +#include "storage.h" + +int gl_cgen(const struct storage *gl, struct cgen *c) +{ + for (size_t i = 0; i < gl->nentries; i++) + { + const struct stentry *e = &gl->entries[i]; + + printf("export data $%s = { z %zu }\n", e->tk->s, e->t->sz); + } + + return 0; +} + +int gl(const struct lex *l, struct prv *p) +{ + struct fn *fn = fn_cur(p); + + return storage(l, p, "globals section", 1, &fn->gl); +} diff --git a/src/prc1/gl.h b/src/prc1/gl.h new file mode 100644 index 0000000..d8aaaaf --- /dev/null +++ b/src/prc1/gl.h @@ -0,0 +1,12 @@ +#ifndef GL_H +#define GL_H + +#include "cgen.h" +#include "lex.h" +#include "prv.h" +#include "storage.h" + +int gl(const struct lex *l, struct prv *p); +int gl_cgen(const struct storage *gl, struct cgen *c); + +#endif diff --git a/src/prc1/im.c b/src/prc1/im.c new file mode 100644 index 0000000..e9a208c --- /dev/null +++ b/src/prc1/im.c @@ -0,0 +1,125 @@ +#include "im.h" +#include "errloc.h" +#include "fn.h" +#include "prv.h" +#include "parse.h" +#include +#include +#include +#include +#include + +static int imlit(const struct lex *, struct prv *); + +static const struct seq seqs[] = +{ + {(struct step[]){{LIT, NULL, 1}, {0}}, .fn = imlit}, + {0} +}; + +void im_free(struct im *im) +{ + ast_free(&im->ast); + lex_free(&im->l); +} + +static int doim(const struct lex *l, const struct tk *tk, struct prv *p) +{ + int ret = -1; + FILE *f = NULL; + struct im *im; + struct fn *fn = fn_cur(p); + struct ast *ast; + size_t n = fn->nimps + 1; + const char *path = tk->s; + + if (!strcmp(l->loc.f, path)) + { + errloc(tk, "detected recursive import \"%s\"", path); + goto end; + } + /* TODO: honor -I flags */ + if (!(f = fopen(path, "rb"))) + { + errloc(tk, "failed to open import \"%s\": %s", path, strerror(errno)); + goto end; + } + else if (!(im = realloc(fn->imps, n * sizeof *im))) + { + perror("realloc(3)"); + goto end; + } + + fn->imps = im; + im = &fn->imps[fn->nimps++]; + *im = (struct im){.l.loc.f = path}; + ast = &im->ast; + + if (!(ast->fns = malloc(sizeof *ast->fns))) + { + perror("malloc(3)"); + goto end; + } + + *ast->fns = (struct fn){.tk = tk}; + /* hack: treat imports as a function */ + ast->nfns = 1; + + if (lex(&im->l, f) || parse_im(&im->l, ast)) + goto end; + + ret = 0; + +end: + + if (f && fclose(f)) + { + fprintf(stderr, "fclose(3) %s: %s\n", path, strerror(errno)); + ret = -1; + } + + return ret; +} + +static int imlit(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + + while (!lex_eof(l, tk) && !kw(tk->s)) + if (doim(l, tk++, p)) + return -1; + + if (pop(l, p)) + return -1; + + p->stk = p->tk; + return 1; +} + +int im(const struct lex *l, struct prv *p) +{ + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + struct fn *fn = fn_cur(p); + + if (fn->im) + { + const struct loc *loc = &fn->im->loc; + + errloc(p->stk, "imports section already defined at %s:%d:%d", + loc->f, loc->line, loc->col); + return -1; + } + + if (push(&init, p)) + return -1; + + fn->im = p->stk; + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/im.h b/src/prc1/im.h new file mode 100644 index 0000000..30382ed --- /dev/null +++ b/src/prc1/im.h @@ -0,0 +1,11 @@ +#ifndef IM_H +#define IM_H + +#include "lex.h" +#include "parse.h" +#include "prv.h" + +int im(const struct lex *l, struct prv *p); +void im_free(struct im *im); + +#endif diff --git a/src/prc1/kw.c b/src/prc1/kw.c new file mode 100644 index 0000000..d5e22ca --- /dev/null +++ b/src/prc1/kw.c @@ -0,0 +1,41 @@ +#include "prv.h" +#include +#include + +static const char *kws[] = +{ + /* headers */ + "public", "function", + /* sections */ + "types", "storage", "linkage", "procedure", "locals", "globals", "imports", + /* types */ + "union", "struct", "constant", "alias", "prototype", + /* operators */ + "add", "subtract", "multiply", "divide", "xor", "bitor", "bitand", + "leftshift", "rightshift", "address", "size", "call", "set", + /* procedures */ + "using", "returning", + /* built-in functions */ + "display", "warn", + /* flow control */ + "while", "if", "else", "end", "return", "go", "label", "default", + /* prepositions */ + "by", "from", "to", "than", "of", "etc", + /* comparators */ + "is", "not", "equal", "greater", "smaller", "and", "or", + /* built-in types */ + "void", "array", "pointer", + /* built-in signed types */ + "byte", "halfword", "word", "long", + /* built-in unsigned types */ + "ubyte", "uhalfword", "uword", "ulong" +}; + +int kw(const char *s) +{ + for (size_t i = 0; i < sizeof kws / sizeof *kws; i++) + if (!strcmp(s, kws[i])) + return 1; + + return 0; +} diff --git a/src/prc1/lex.c b/src/prc1/lex.c new file mode 100644 index 0000000..736ebdd --- /dev/null +++ b/src/prc1/lex.c @@ -0,0 +1,249 @@ +#include "lex.h" +#include "errloc.h" +#include +#include +#include +#include +#include + +static void free_tk(struct tk *tk) +{ + free(tk->s); +} + +static int invnum(const struct tk *tk, char *end) +{ + if (errno) + errloc(tk, "invalid number: %s (%s)", tk->s, strerror(errno)); + else if (*end) + errloc(tk, "invalid number: %s", tk->s); + + return -1; +} + +static int fintok(struct lex *lex) +{ + struct tk *tk = &lex->tk, *tokens; + const struct tk empty = {.loc = tk->loc}; + size_t ntk = lex->ntok + 1; + char *s; + + if (tk->type == UNDEF) + return 0; + else if (!(s = realloc(tk->s, lex->len + 1))) + { + perror("realloc(3)"); + return -1; + } + + tk->s = s; + tk->s[lex->len] = '\0'; + + switch (tk->type) + { + case UNDEF: + break; + + case ANY: + errloc(tk, "%s: unreachable", __func__); + return -1; + + case LIT: + case ID: + break; + + case NUM: + { + int neg = *tk->s == '-'; + char *end; + + errno = 0; + strtoll(tk->s, &end, 0); + + if (errno || *end) + { + if (neg) + return invnum(tk, end); + + errno = 0; + strtoull(tk->s, &end, 0); + + if (errno || *end) + return invnum(tk, end); + } + } + } + + if (!(tokens = realloc(lex->tokens, ntk * sizeof *tokens))) + { + perror("realloc(3)"); + return -1; + } + + tokens[lex->ntok++] = lex->tk; + lex->tokens = tokens; + lex->tk = empty; + lex->len = 0; + return 0; +} + +static int printable(char c) +{ + return c >= '!' && c <= '~'; +} + +static void invch(const struct lex *l, char c) +{ + if (printable(c)) + errcloc(l, "invalid character: %c", c); + else + errcloc(l, "invalid character: (%#hhx)", c); +} + +static int ch(char c, struct lex *lex) +{ + struct tk *tk = &lex->tk; + char *s; + + switch (tk->type) + { + case UNDEF: + tk->loc = lex->loc; + + if (c == '\"') + { + tk->type = LIT; + return 0; + } + else if (c == '-' || c == '+' + || (c >= '0' && c <= '9')) + tk->type = NUM; + else if (c == '_' + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) + tk->type = ID; + else + { + invch(lex, c); + return -1; + } + + break; + + case LIT: + if (c == '\"') + return fintok(lex); + + break; + + case NUM: + if (c == '\"') + { + invch(lex, c); + return -1; + } + + break; + + case ID: + if (c == '\"' || c == '-' || c == '+') + { + invch(lex, c); + return -1; + } + else if (!(c == '_' + || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z'))) + { + invch(lex, c); + return -1; + } + + break; + case ANY: + errcloc(lex, "%s: unreachable", __func__); + return -1; + } + + if (!(s = realloc(tk->s, lex->len + 1))) + { + perror("realloc(3)"); + return -1; + } + + s[lex->len++] = c; + tk->s = s; + return 0; +} + +static int clex(char c, struct lex *lex) +{ + struct tk *tk = &lex->tk; + struct loc *loc = &lex->loc; + + ++loc->col; + + switch (c) + { + case '*': + lex->comment = 1; + return fintok(lex); + + case '\n': + if (tk->type == LIT) + { + errcloc(lex, "unterminated literal"); + return -1; + } + else if (fintok(lex)) + return -1; + + loc->line++; + loc->col = lex->comment = 0; + return 0; + + case '\t': + /* assume columns as 8-space width */ + loc->col += 7; + case ' ': + if (tk->type != LIT) + return lex->comment ? 0 : fintok(lex); + default: + return lex->comment ? 0 : ch(c, lex); + } + + invch(lex, c); + return -1; +} + +void lex_free(struct lex *lex) +{ + for (size_t i = 0; i < lex->ntok; i++) + free_tk(&lex->tokens[i]); + + free(lex->tokens); + free_tk(&lex->tk); +} + +int lex_eof(const struct lex *lex, const struct tk *tk) +{ + return tk - lex->tokens >= lex->ntok; +} + +int lex(struct lex *l, FILE *f) +{ + l->loc.line = 1; + + for (;;) + { + int c = fgetc(f); + + if (c == EOF) + break; + else if (clex(c, l)) + return -1; + } + + return 0; +} diff --git a/src/prc1/lex.h b/src/prc1/lex.h new file mode 100644 index 0000000..6e836ac --- /dev/null +++ b/src/prc1/lex.h @@ -0,0 +1,34 @@ +#ifndef LEX_H +#define LEX_H + +#include +#include + +enum tktype {UNDEF, ID, LIT, NUM, ANY}; + +struct loc +{ + const char *f; + int line, col; +}; + +struct tk +{ + enum tktype type; + struct loc loc; + char *s; +}; + +struct lex +{ + struct loc loc; + struct tk *tokens, tk; + size_t ntok, len; + int comment; +}; + +int lex(struct lex *lex, FILE *f); +int lex_eof(const struct lex *lex, const struct tk *tk); +void lex_free(struct lex *lex); + +#endif diff --git a/src/prc1/lit.c b/src/prc1/lit.c new file mode 100644 index 0000000..09528a2 --- /dev/null +++ b/src/prc1/lit.c @@ -0,0 +1,102 @@ +#include "lit.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include +#include +#include +#include + +void lit_free(struct lit *l) +{ + free(l->name); +} + +static char *gen(struct ast *ast, struct fn *fn) +{ + static const char fmt[] = "__str_%zu"; + int n = snprintf(NULL, 0, fmt, ast->litcnt); + char *ret = NULL; + size_t sz; + + if (n < 0) + { + fprintf(stderr, "%s: snprintf(3) failed\n", __func__); + goto failure; + } + else if (!(ret = malloc((sz = n + 1)))) + { + perror("malloc(3)"); + goto failure; + } + + n = snprintf(ret, sz, fmt, ast->litcnt); + + if (n < 0 || n >= sz) + { + fprintf(stderr, "%s: snprintf(3) failed with %d\n", __func__, n); + goto failure; + } + + ast->litcnt++; + return ret; + +failure: + free(ret); + return NULL; +} + +static const struct lit *find(const struct tk *tk, const struct ast *ast) +{ + for (const struct lit *l = ast->lits; l; l = l->next) + if (!strcmp(l->tk->s, tk->s)) + return l; + + return NULL; +} + +int lit_cgen(const struct lit *l) +{ + printf("data $%s = { b \"%s\", b 0 }\n", l->name, l->tk->s); + return 0; +} + +const struct lit *lit_push(const struct tk *tk, struct prv *p) +{ + char *name = NULL; + struct fn *fn = fn_cur(p); + struct ast *ast = p->ast; + const struct lit *prev = find(tk, ast); + struct lit *l; + + if (prev) + return prev; + else if (!(name = gen(ast, fn))) + goto failure; + else if (!(l = malloc(sizeof *l))) + { + perror("malloc(3)"); + goto failure; + } + + *l = (struct lit) + { + .name = name, + .fn = fn, + .tk = tk + }; + + if (!ast->lits) + ast->lits = l; + else if (ast->lastlit) + ast->lastlit->next = l; + + ast->lastlit = l; + fprintf(stderr, "adding literal \"%s\"\n", name); + return l; + +failure: + free(name); + return NULL; +} diff --git a/src/prc1/lit.h b/src/prc1/lit.h new file mode 100644 index 0000000..e94263c --- /dev/null +++ b/src/prc1/lit.h @@ -0,0 +1,12 @@ +#ifndef LIT_H +#define LIT_H + +#include "lex.h" +#include "parse.h" +#include "prv.h" + +const struct lit *lit_push(const struct tk *tk, struct prv *p); +int lit_cgen(const struct lit *l); +void lit_free(struct lit *l); + +#endif diff --git a/src/prc1/lk.c b/src/prc1/lk.c new file mode 100644 index 0000000..8bfb738 --- /dev/null +++ b/src/prc1/lk.c @@ -0,0 +1,12 @@ +#include "lk.h" +#include "fn.h" +#include "prv.h" +#include "parse.h" +#include "storage.h" + +int lk(const struct lex *l, struct prv *p) +{ + struct fn *fn = fn_cur(p); + + return storage(l, p, "linkage section", 1, &fn->lk); +} diff --git a/src/prc1/lk.h b/src/prc1/lk.h new file mode 100644 index 0000000..35df205 --- /dev/null +++ b/src/prc1/lk.h @@ -0,0 +1,9 @@ +#ifndef LK_H +#define LK_H + +#include "lex.h" +#include "prv.h" + +int lk(const struct lex *l, struct prv *p); + +#endif diff --git a/src/prc1/parse.c b/src/prc1/parse.c new file mode 100644 index 0000000..1c3aba2 --- /dev/null +++ b/src/prc1/parse.c @@ -0,0 +1,183 @@ +#include "parse.h" +#include "div.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "lit.h" +#include "prv.h" +#include "type.h" +#include +#include +#include + +void ast_free(struct ast *ast) +{ + struct type *t = ast->types; + + while (t) + { + struct type *next = t->next; + + type_lfree(t); + t = next; + } + + for (struct lit *l = ast->lits, *next; l; l = next) + { + next = l->next; + lit_free(l); + free(l); + } + + for (size_t i = 0; i < ast->nfns; i++) + fn_free(&ast->fns[i]); + + free(ast->fns); +} + +static const char *expected(const struct step *s) +{ + static const char *tmap[] = + { + [ID] = "identifier", [LIT] = "literal", [NUM] = "number" + }; + + return s->id ? s->id : tmap[s->type]; +} + +static int iter(const struct lex *l, struct prv *p) +{ + struct pos *pos = p->pos; + const struct step *s; + const struct tk *tk = p->tk; + + if (!pos) + return p->entry(l, p); + + pos = &p->pos[p->i]; + + if (!(s = pos->step)) + { + if (lex_eof(l, tk)) + return 0; + else if (p->n > 1) + return pop(l, p) ? -1 : 1; + else + { + switch (tk->type) + { + case LIT: + errloc(tk, "unexpected literal \"%s\"", tk->s); + break; + case NUM: + errloc(tk, "unexpected number %s", tk->s); + break; + case ID: + errloc(tk, "unexpected %s %s", kw(tk->s) ? + "keyword" : "identifier", tk->s); + break; + case ANY: + case UNDEF: + errloc(tk, "%s: unreachable", __func__); + break; + } + + return -1; + } + } + else if (lex_eof(l, tk)) + { + if (p->stk == p->tk) + return pop(l, p) ? -1 : 1; + else if (s->type) + { + tk--; + + if (lex_eof(l, p->stk)) + { + errloc(tk, "expected %s", expected(pos->step)); + return -1; + } + } + } + + if (!s->type) + return pos->seq->fn(l, p); + else if ((s->type == ID || s->type == ANY) && !s->id && kw(tk->s) + && !s->chain) + { + if (tk != p->stk || !p->n) + { + errloc(tk, "unexpected keyword %s", tk->s); + return -1; + } + else if (pop(l, p)) + return -1; + + pos = &p->pos[p->i]; + } + else if ((s->type != tk->type && s->type != ANY) + || (s->type == ID && s->id && strcmp(s->id, tk->s)) + || (s->type == ID && kw(tk->s) && s->chain)) + { + pos->step = (++pos->seq)->steps; + p->tk = p->stk; + } + else + { + const struct tk *next = tk + 1; + + if (!s->chain) + pos->step++; + else if (!lex_eof(l, next)) + { + if (s->chain && kw(next->s)) + pos->step++; + } + else + pos->step++; + + if (!lex_eof(l, p->tk)) + p->tk++; + } + + return 1; +} + +static void free_prv(struct prv *p) +{ + free(p->tdc); + free(p->pos); +} + +static int comm(const struct lex *l, struct ast *ast, + int (*entry)(const struct lex *, struct prv *)) +{ + int ret; + struct prv prv = + { + .ast = ast, + .tk = l->tokens, + .stk = l->tokens, + .entry = entry + }; + + if (!prv.stk) + return 0; + + while ((ret = iter(l, &prv)) > 0) + ; + + free_prv(&prv); + return ret; +} + +int parse(const struct lex *l, struct ast *ast) +{ + return comm(l, ast, fn); +} + +int parse_im(const struct lex *l, struct ast *ast) +{ + return comm(l, ast, div_im); +} diff --git a/src/prc1/parse.h b/src/prc1/parse.h new file mode 100644 index 0000000..b85d618 --- /dev/null +++ b/src/prc1/parse.h @@ -0,0 +1,138 @@ +#ifndef PARSE_H +#define PARSE_H + +#include "lex.h" +#include "storage.h" + +struct u +{ + struct storage *storage; +}; + +struct s +{ + struct storage *storage; +}; + +union c +{ + unsigned long long uv; + long long v; +}; + +struct p +{ + struct fn *fn; +}; + +struct t +{ + const struct type *alias; +}; + +struct ptr +{ + const struct type *t; +}; + +struct ary +{ + unsigned long long n; + int etc; +}; + +struct builtin +{ + const char *name; +}; + +struct type +{ + enum {U, S, C, P, T, PTR, ARY, BUILTIN} type; + const struct tk *tk; + size_t sz, align; + int sign; + struct type *child, *next; + + union + { + struct u u; + struct s s; + union c c; + struct p p; + struct t t; + struct ptr ptr; + struct ary ary; + struct builtin b; + } u; +}; + +struct param +{ + const struct tk *tk; + const struct stentry *entry; +}; + +struct pr +{ + const struct tk *tk; + struct param *params, *ret; + size_t nparams; + int variadic; +}; + +struct td +{ + const struct tk *tk; + struct type *types; + size_t ntypes; +}; + +struct tmp +{ + struct tk tk; + struct stentry e; + struct tmp *next; +}; + +struct fn +{ + const struct tk *tk, *im; + const struct fn *parent; + enum linkage {EXTERNAL, STATIC} linkage; + struct storage *lk, *ws, *gl; + struct stmt *stmts; + struct tmp *tmps; + struct im *imps; + struct pr *pr; + struct td *td; + size_t nstmts, nimps, nblocks, ntmps, *blocks; +}; + +struct lit +{ + char *name; + const struct tk *tk; + const struct fn *fn; + struct lit *next; +}; + +struct ast +{ + struct fn *fns; + struct lit *lits, *lastlit; + struct type *types; + size_t nfns, litcnt; +}; + +struct im +{ + struct lex l; + struct ast ast; +}; + +int parse(const struct lex *l, struct ast *ast); +int parse_im(const struct lex *l, struct ast *ast); +void ast_free(struct ast *ast); + +#endif diff --git a/src/prc1/pop.c b/src/prc1/pop.c new file mode 100644 index 0000000..ba2f3a1 --- /dev/null +++ b/src/prc1/pop.c @@ -0,0 +1,37 @@ +#include "prv.h" +#include + +int pop(const struct lex *l, struct prv *p) +{ + size_t n; + struct pos *pos = NULL; + + if (!p->n) + { + fprintf(stderr, "%s: underflow\n", __func__); + return -1; + } + else if (!(n = p->n - 1)) + { + free(p->pos); + p->pos = NULL; + } + else if (!(pos = realloc(p->pos, n * sizeof *pos))) + { + perror("realloc(3)"); + return -1; + } + + p->pos = pos; + p->n = n; + + if (p->n) + { + const struct pos *old = &p->pos[--p->i]; + + if (old->end && old->end(l, p)) + return -1; + } + + return 0; +} diff --git a/src/prc1/pr.c b/src/prc1/pr.c new file mode 100644 index 0000000..a171554 --- /dev/null +++ b/src/prc1/pr.c @@ -0,0 +1,375 @@ +#include "pr.h" +#include "errloc.h" +#include "fn.h" +#include "prv.h" +#include "parse.h" +#include "stmt.h" +#include "storage.h" +#include +#include +#include + +static int prey(const struct lex *l, struct prv *p); +static int pren(const struct lex *l, struct prv *p); +static int pryy(const struct lex *l, struct prv *p); +static int pryn(const struct lex *l, struct prv *p); +static int prny(const struct lex *l, struct prv *p); +static int prnn(const struct lex *l, struct prv *p); + +static const struct seq seqs[] = +{ + /* function definition with variadic parameters and return variable */ + { + (struct step[]) + { + {ID, "using"}, + {ID, NULL, 1}, + {ID, "etc",}, + {ID, "returning"}, + {ID}, + {0} + }, + .fn = prey + }, + + /* function definition with variadic parameters and no return variable */ + { + (struct step[]) + { + {ID, "using"}, + {ID, NULL, 1}, + {ID, "etc",}, + {0} + }, + .fn = pren + }, + + /* function definition with parameters and return variable */ + { + (struct step[]) + { + {ID, "using"}, + {ID, NULL, 1}, + {ID, "returning"}, + {ID}, + {0} + }, + .fn = pryy + }, + + /* function definition with parameters, no return variable */ + { + (struct step[]) + { + {ID, "using"}, + {ID, NULL, 1}, + {0} + }, + + .fn = pryn + }, + + /* function definition with no parameters, with return variable */ + { + (struct step[]) + { + {ID, "returning"}, + {ID}, + {0} + }, + + .fn = prny + }, + + {0} +}; + +static const struct tk *findparam(const char *s, const struct pr *pr) +{ + for (size_t i = 0; i < pr->nparams; i++) + { + const struct param *p = &pr->params[i]; + const struct tk *tk = p->tk; + + if (!strcmp(tk->s, s)) + return tk; + } + + return NULL; +} + +static int param(const struct tk *tk, const struct stentry *e, struct pr *pr) +{ + size_t n = pr->nparams + 1; + struct param *params = realloc(pr->params, n * sizeof *params); + + if (!params) + { + perror("realloc(3)"); + return -1; + } + + pr->params = params; + pr->params[pr->nparams++] = (struct param){.tk = tk, .entry = e}; + return 0; +} + +static int setret(const struct tk *tk, const struct stentry *e, struct pr *pr) +{ + if (!(pr->ret = malloc(sizeof *pr->ret))) + { + perror("malloc(3)"); + return -1; + } + + *pr->ret = (struct param){.tk = tk, .entry = e}; + return 0; +} + +static int finalize(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct pr *pr = fn->pr; + struct pos init = + { + .seq = stmts, + .stseq = stmts, + .step = stmts->steps + }; + + if (p->proto) + { + if (pop(l, p)) + return -1; + + fputc('\t', stderr); + } + else if (push(&init, p)) + return -1; + + fprintf(stderr, "\tadding procedure using %zu%s parameters " + "and%s return value\n", pr->nparams, pr->variadic ? " variadic" : "", + pr->ret ? "" : " no"); + p->stk = p->tk; + return 1; +} + +static int prret(const struct lex *l, const struct tk *tk, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + struct pr *pr = fn->pr; + const char *s = tk->s; + const struct storage *lk = fn->lk, *gl = fn->gl; + const struct stentry *e, *gle; + const struct tk *prm; + + if (!lk || !(e = storage_find(s, lk))) + { + errloc(tk, "return value \"%s\" not in %s", s, tk->s); + return -1; + } + else if (gl && (gle = storage_find(s, gl))) + { + const struct loc *loc = &gle->tk->loc; + + errloc(tk, "return value \"%s\" also in %s at %s:%d:%d", s, gl->name, + loc->f, loc->line, loc->col); + return -1; + } + else if ((prm = findparam(s, pr))) + { + const struct loc *loc = &prm->loc; + + errloc(tk, "return value \"%s\" already listed as " + "parameter at %s:%d:%d", tk->s, loc->f, loc->line, loc->col); + return -1; + } + else if (setret(tk, e, pr)) + return -1; + + return finalize(l, p); +} + +static const struct tk *prparams(const struct lex *l, struct prv *p, int *ret) +{ + const struct tk *tk = p->stk + 1; + const struct fn *fn = fn_cur(p); + struct pr *pr = fn->pr; + + if (ret) + *ret = 0; + + for (;;) + { + const struct storage *lk = fn->lk, *gl = fn->gl; + const struct stentry *e, *gle; + const struct tk *prm; + const char *s; + + if (lex_eof(l, tk)) + return tk; + else if (!strcmp((s = tk->s), "returning") && ret) + { + *ret = 1; + return ++tk; + } + else if (!strcmp(s, "etc")) + { + if (pr->variadic) + { + errloc(tk, "keyword \"etc\" may only appear once as a " + "parameter"); + return NULL; + } + + pr->variadic = tk++ - p->stk; + } + else if (kw(s)) + return tk; + else if (pr->variadic) + { + errloc(tk, "keyword \"etc\" must appear as the last parameter"); + return NULL; + } + else if ((prm = findparam(s, pr))) + { + const struct loc *loc = &prm->loc; + + errloc(tk, "parameter \"%s\" already listed at %d:%d", s, + loc->line, loc->col); + return NULL; + } + else if (!lk || !(e = storage_find(s, lk))) + { + if (p->proto) + { + /* ambiguous syntax: param might be confused + * with next custom type. */ + p->tk = p->stk + pr->nparams + 1; + return tk; + } + else + { + errloc(tk, "parameter \"%s\" not in %s", s, tk->s); + return NULL; + } + } + else if (gl && (gle = storage_find(s, gl))) + { + const struct loc *loc = &gle->tk->loc; + + errloc(tk, "parameter \"%s\" also in %s at %d:%d", s, gl->name, + loc->line, loc->col); + return NULL; + } + else if (param(tk, e, pr)) + return NULL; + else + tk++; + } + + return tk; +} + +static int prey(const struct lex *l, struct prv *p) +{ + int ret; + const struct tk *tk = prparams(l, p, &ret); + + if (!tk) + return -1; + else if (ret) + return prret(l, tk, p); + + return finalize(l, p); +} + +static int pren(const struct lex *l, struct prv *p) +{ + const struct tk *tk = prparams(l, p, NULL); + + if (!tk) + return -1; + + return finalize(l, p); +} + +static int pryy(const struct lex *l, struct prv *p) +{ + int ret; + const struct tk *tk = prparams(l, p, &ret); + + if (!tk) + return -1; + else if (ret) + return prret(l, tk, p); + + return finalize(l, p); +} + +static int pryn(const struct lex *l, struct prv *p) +{ + if (!prparams(l, p, NULL)) + return -1; + + return finalize(l, p); +} + +static int prny(const struct lex *l, struct prv *p) +{ + return prret(l, p->stk + 1, p); +} + +static int prnn(const struct lex *l, struct prv *p) +{ + return finalize(l, p); +} + +void pr_free(struct pr *pr) +{ + if (pr) + { + free(pr->params); + free(pr->ret); + } + + free(pr); +} + +int pr(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->tk - 1, *next = p->tk; + struct fn *fn = fn_cur(p); + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + if (fn->pr) + { + const struct loc *loc = &fn->pr->tk->loc; + + errloc(tk, "procedure already defined at %s:%d:%d", loc->f, loc->line, + loc->col); + return -1; + } + else if (!(fn->pr = malloc(sizeof *fn->pr))) + { + perror("malloc(3)"); + return -1; + } + + *fn->pr = (struct pr){.tk = tk}; + + /* on no parameters or return values, go directly to next sequences list. */ + if (lex_eof(l, next) + || (strcmp(next->s, "using") && strcmp(next->s, "returning"))) + return prnn(l, p); + else if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/pr.h b/src/prc1/pr.h new file mode 100644 index 0000000..e3d8bf8 --- /dev/null +++ b/src/prc1/pr.h @@ -0,0 +1,11 @@ +#ifndef PR_H +#define PR_H + +#include "lex.h" +#include "parse.h" +#include "prv.h" + +int pr(const struct lex *l, struct prv *p); +void pr_free(struct pr *pr); + +#endif diff --git a/src/prc1/prc1.c b/src/prc1/prc1.c new file mode 100644 index 0000000..69165ba --- /dev/null +++ b/src/prc1/prc1.c @@ -0,0 +1,53 @@ +#include "cgen.h" +#include "lex.h" +#include "parse.h" +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + struct lex l = {0}; + struct ast a = {0}; + struct cgen c = {0}; + FILE *f = stdin; + int opened = 0, ret = EXIT_FAILURE; + + if (argc != 2) + { + fprintf(stderr, "%s: error: missing input file\n", *argv); + goto end; + } + else if (strcmp(argv[1], "-")) + { + if (!(f = fopen(argv[1], "rb"))) + { + fprintf(stderr, "failed to open %s: %s\n", argv[1], + strerror(errno)); + goto end; + } + + opened = 1; + l.loc.f = argv[1]; + } + else + l.loc.f = "stdin"; + + if (lex(&l, f) || parse(&l, &a) || cgen(&a, &c)) + goto end; + + ret = EXIT_SUCCESS; + +end: + if (opened && fclose(f)) + { + perror("fclose(3)"); + ret = EXIT_FAILURE; + } + + cgen_free(&c); + ast_free(&a); + lex_free(&l); + return ret; +} diff --git a/src/prc1/print.c b/src/prc1/print.c new file mode 100644 index 0000000..abdb149 --- /dev/null +++ b/src/prc1/print.c @@ -0,0 +1,103 @@ +#include "print.h" +#include "errloc.h" +#include "fn.h" +#include "lit.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include "type.h" +#include +#include + +static int entry(const struct lex *l, const struct tk *tk, struct print *pr, + struct prv *p) +{ + size_t n = pr->nentries + 1; + struct prientry *entries; + const struct stentry *stentry = NULL; + const struct fn *fn = fn_cur(p); + const struct lit *lit = NULL; + + if (tk->type == ID) + { + const struct type *t = NULL; + + if ((t = type_find(fn, tk->s))) + { + if (t->type != C) + { + errloc(tk, "type \"%s\" not a constant", tk->s); + return -1; + } + else if (!(lit = lit_push(t->tk, p))) + return -1; + } + else if (!(stentry = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + } + else if (tk->type == LIT && !(lit = lit_push(tk, p))) + return -1; + + if (!(entries = realloc(pr->entries, n * sizeof *entries))) + { + perror("realloc(3)"); + return -1; + } + + pr->entries = entries; + pr->entries[pr->nentries++] = (struct prientry) + { + .tk = tk, + .lit = lit, + .entry = stentry + }; + + return 0; +} + +void print_free(struct print *pr) +{ + free(pr->entries); +} + +int print(const struct lex *l, struct prv *p, + int (*fn)(const struct lex *, const struct prv *, const struct print *)) +{ + const struct tk *tk = p->stk + 1; + struct print pr = {0}; + struct pos *pos = &p->pos[p->i]; + int eof; + + if (lex_eof(l, tk)) + { + errloc(tk - 1, "incomplete %s statement", p->stk->s); + return -1; + } + + for (;;) + if (entry(l, tk, &pr, p)) + goto failure; + else if ((eof = lex_eof(l, ++tk)) || kw(tk->s)) + break; + + if (eof || strcmp(tk->s, "etc")) + pr.println = 1; + else if (!eof) + tk++; + + if (fn(l, p, &pr)) + goto failure; + + pos->seq = pos->stseq = stmts; + pos->step = stmts->steps; + p->stk = tk; + return 1; + +failure: + print_free(&pr); + return -1; +} diff --git a/src/prc1/print.h b/src/prc1/print.h new file mode 100644 index 0000000..950e0bc --- /dev/null +++ b/src/prc1/print.h @@ -0,0 +1,26 @@ +#ifndef PRINT_H +#define PRINT_H + +#include "cgen.h" +#include "lex.h" +#include + +struct prientry +{ + const struct tk *tk; + const struct lit *lit; + const struct stentry *entry; +}; + +struct print +{ + struct prientry *entries; + size_t nentries; + int println; +}; + +int print(const struct lex *l, struct prv *p, + int (*fn)(const struct lex *, const struct prv *, const struct print *)); +void print_free(struct print *p); + +#endif diff --git a/src/prc1/prv.h b/src/prc1/prv.h new file mode 100644 index 0000000..c0c8930 --- /dev/null +++ b/src/prc1/prv.h @@ -0,0 +1,51 @@ +#ifndef PRV_H +#define PRV_H + +#include "lex.h" +#include + +struct prv; + +struct step +{ + enum tktype type; + const char *id; + int chain; +}; + +struct pos +{ + const struct seq *seq, *stseq; + const struct step *step; + int (*end)(const struct lex *, struct prv *); +}; + +struct prv +{ + const struct tk *tk, *stk, *id; + struct tdconstant *tdc; + struct storage *st; + struct pos *pos; + struct ast *ast; + struct type *ag, *t; + struct fn *proto; + size_t n, i, block; + int (*entry)(const struct lex *, struct prv *); + int (*type)(const struct lex *, struct prv *p, const struct type *t); +}; + +struct seq +{ + const struct step *steps; + int (*fn)(const struct lex *l, struct prv *p); + int (*end)(const struct lex *l, struct prv *p); + const char *chain; +}; + +int kw(const char *s); +int prev(const struct prv *p); +int push(const struct pos *pos, struct prv *p); +int pop(const struct lex *l, struct prv *p); +char *sdup(const char *s); + +#endif diff --git a/src/prc1/push.c b/src/prc1/push.c new file mode 100644 index 0000000..1a9056d --- /dev/null +++ b/src/prc1/push.c @@ -0,0 +1,27 @@ +#include "prv.h" +#include + +int push(const struct pos *pos, struct prv *p) +{ + size_t n = p->n + 1; + struct pos *npos = realloc(p->pos, n * sizeof *npos); + + if (!npos) + { + perror("realloc(3)"); + return -1; + } + else if (p->n) + { + struct pos *prev = &npos[p->n - 1]; + + prev->end = prev->seq->end; + prev->seq = prev->stseq; + prev->step = prev->seq->steps; + p->i++; + } + + npos[p->n++] = *pos; + p->pos = npos; + return 0; +} diff --git a/src/prc1/sdup.c b/src/prc1/sdup.c new file mode 100644 index 0000000..e990744 --- /dev/null +++ b/src/prc1/sdup.c @@ -0,0 +1,16 @@ +#include "prv.h" +#include +#include +#include + +char *sdup(const char *s) +{ + char *n = malloc(strlen(s) + 1); + + if (n) + strcpy(n, s); + else + perror("malloc(3)"); + + return n; +} diff --git a/src/prc1/set.c b/src/prc1/set.c new file mode 100644 index 0000000..3058040 --- /dev/null +++ b/src/prc1/set.c @@ -0,0 +1,552 @@ +#include "set.h" +#include "cgen.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include "type.h" +#include +#include +#include +#include + +static int mv(const struct lex *l, struct prv *p); +static int maddr(const struct lex *l, struct prv *p); +static int msz(const struct lex *l, struct prv *p); +static int mimb(const struct lex *l, struct prv *p); + +static const struct seq seqs[] = +{ + /* size of elementary data types */ + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "void"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "byte"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "halfword"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "word"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "long"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "ubyte"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "uhalfword"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "uword"}, + {0}}, .fn = msz}, + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ID, "ulong"}, + {0}}, .fn = msz}, + + /* address of variable */ + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "address"}, + {ID, "of"}, + {ID}, + {0}}, .fn = maddr}, + + /* size of variable or type alias */ + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ID, "size"}, + {ID, "of"}, + {ANY}, + {0}}, .fn = msz}, + + /* array index or aggregate member */ + {(struct step[]){ + {ID, NULL, 1}, + {ID, "to"}, + {ANY}, + {ID, "of"}, + {ID}, + {0}}, .fn = mimb}, + + /* simple set */ + {(struct step[]){{ID, NULL, 1}, {ID, "to"}, {ANY}, {0}}, .fn = mv}, + {0} +}; + +static unsigned long long tonum(const char *s) +{ + unsigned long long v; + char *end; + + errno = 0; + v = strtoull(s, &end, 0); + + if (*s == '-' || errno || *end) + return strtoll(s, NULL, 0); + + return v; +} + +static int dst(const struct lex *l, const struct tk *tk, struct set *s, + struct prv *p) +{ + const struct stentry *e = fn_var(fn_cur(p), tk); + size_t n = s->ndsts + 1; + struct setdst *dsts; + + if (!e) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (!(dsts = realloc(s->dsts, n * sizeof *dsts))) + { + perror("realloc(3)"); + return -1; + } + + s->dsts = dsts; + s->dsts[s->ndsts++] = (struct setdst){.entry = e}; + return 0; +} + +static int checkzero(const struct tk *tk, const struct set *s, + unsigned long long v) +{ + if (!s->srcv) + return 0; + + for (size_t i = 0; i < s->ndsts; i++) + { + const struct stentry *dst = s->dsts[i].entry; + + if (dst->t->type != BUILTIN) + { + errloc(tk, "destination \"%s\" cannot be set to \"%s\"", + dst->tk->s, tk->s); + return -1; + } + } + + return 0; +} + + +static int checkcompat(const struct tk *tk, const struct set *s) +{ + for (size_t i = 0; i < s->ndsts; i++) + { + const struct stentry *dst = s->dsts[i].entry; + const struct type *st = s->src->t, *dt = dst->t; + + /* TODO: integer promotions */ + if (st->type != dt->type + || st->sz != dt->sz + || st->sign != dt->sign) + { + errloc(tk, "destination \"%s\" cannot be set to \"%s\"", + dst->tk->s, tk->s); + return -1; + } + } + + return 0; +} + +static int mv(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + const struct stentry *e; + struct stmt *stmt = stmt_cur(p); + struct set *s = &stmt->u.set; + + while (!lex_eof(l, tk) && !kw((tk)->s)) + if (dst(l, tk++, s, p)) + return -1; + + /* skip "to" */ + tk++; + + if (tk->type == LIT) + { + /* this can only be applied to arrays of/pointers to chars */ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; + } + else if (tk->type == NUM) + { + s->type = SET_VAL; + s->srcv = tonum(tk->s); + + if (checkzero(tk, s, s->srcv)) + return -1; + } + else if (tk->type == ID) + { + const struct fn *fn = fn_cur(p); + const struct type *t = type_find(fn, tk->s); + + if (t) + { + if (t->type != C) + { + errloc(tk, "type \"%s\" not a constant", tk->s); + return -1; + } + + s->type = SET_VAL; + s->srcv = t->u.c.v; + + if (checkzero(tk, s, s->srcv)) + return -1; + } + else if ((e = fn_var(fn_cur(p), tk))) + { + s->type = SET_VAR; + s->src = e; + + if (checkcompat(tk, s)) + return -1; + } + else + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + } + + fputs("\t\tadding set ", stderr); + + for (size_t i = 0; i < s->ndsts; i++) + fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); + + fprintf(stderr, "to %s\n", tk->s); + + if (pop(l, p)) + return -1; + + p->stk = ++tk; + return 1; +} + +static int maddr(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + struct stmt *stmt = stmt_cur(p); + struct set *s = &stmt->u.set; + const struct stentry *e; + + while (!lex_eof(l, tk) && !kw((tk)->s)) + { + const struct stentry *e = fn_var(fn_cur(p), tk); + + if (e && e->t->type != PTR) + { + errloc(tk, "destination \"%s\" not a pointer", tk->s); + return -1; + } + else if (dst(l, tk++, s, p)) + return -1; + } + + /* skip "to address of" */ + tk += 3; + + if (!(e = fn_var(fn_cur(p), tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (pop(l, p)) + return -1; + + s->type = SET_ADDR; + s->src = e; + p->stk = ++tk; + fputs("\t\tadding set ", stderr); + + for (size_t i = 0; i < s->ndsts; i++) + fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); + + fprintf(stderr, "to address of %s\n", s->src->tk->s); + return 1; +} + +static int msz(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + const struct stentry *e; + struct stmt *stmt = stmt_cur(p); + struct set *s = &stmt->u.set; + const struct fn *fn = fn_cur(p); + const struct type *t; + + while (!lex_eof(l, tk) && !kw(tk->s)) + { + const struct stentry *e = fn_var(fn_cur(p), tk); + + if (e && e->t->type != BUILTIN) + { + errloc(tk, "destination \"%s\" not an integer", tk->s); + return -1; + } + else if (dst(l, tk++, s, p)) + return -1; + } + + /* skip "to size of" */ + tk += 3; + + if (tk->type == NUM) + { + errloc(tk, "cannot compute size of a number"); + return -1; + } + else if (tk->type == LIT) + s->srcv = strlen(tk->s) + 1; + else if ((t = type_find(fn, tk->s))) + { + if (!t->sz) + { + errloc(tk, "type \"%s\" has no size", tk->s); + return-1; + } + + s->srcv = t->sz; + } + else if ((e = fn_var(fn, tk))) + s->srcv = e->t->sz; + else + return-1; + + if (pop(l, p)) + return -1; + + s->type = SET_VAL; + p->stk = ++tk; + fputs("\t\tadding set ", stderr); + + for (size_t i = 0; i < s->ndsts; i++) + fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); + + fprintf(stderr, "size=%llu\n", s->srcv); + return 1; +} + +static int mimb(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + const struct fn *fn = fn_cur(p); + struct stmt *stmt = stmt_cur(p); + struct set *s = &stmt->u.set; + + while (!lex_eof(l, tk) && !kw((tk)->s)) + if (dst(l, tk++, s, p)) + return -1; + + /* skip "to" */ + tk++; + + fputs("\t\tadding set ", stderr); + + for (size_t i = 0; i < s->ndsts; i++) + fprintf(stderr, "%s ", s->dsts[i].entry->tk->s); + + if (tk->type == LIT) + { + errloc(tk, "unexpected literal \"%s\"", tk->s); + return -1; + } + else if (tk->type == ID && !(s->off = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (tk->type == NUM) + s->srcv = tonum(tk->s); + + fprintf(stderr, "to [%s] ", tk->s); + + /* skip index and "of" */ + tk += 2; + + if (!(s->src = fn_var(fn, tk))) + { + errloc(tk, "undefined reference to \"%s\"", tk->s); + return -1; + } + else if (pop(l, p)) + return -1; + + fprintf(stderr, " of %s\n", tk->s); + s->type = SET_IMB; + p->stk = ++tk; + return 1; +} + +void set_free(struct set *m) +{ + if (m) + free(m->dsts); +} + +static int cg_val(const struct set *s, const struct stentry *dst, + struct cgen *c) +{ + const char *szstr = cgen_sz(dst->t->sz), *ab = cgen_abity(dst->t); + const struct fn *fn = c->fn; + + if (ab) + { + printf("store%s %llu, ", szstr, s->srcv); + cgen_printvar(fn, dst); + } + else + { + fputs("%r =l call $memset(l ", stdout); + cgen_printvar(fn, dst); + printf(", w 0, l %zu)", dst->t->sz); + } + + putchar('\n'); + return 0; +} + +static int cg_addr(const struct set *s, const struct stentry *dst, + struct cgen *c) +{ + printf("store%s ", cgen_sz(dst->t->sz)); + cgen_printvar(c->fn, s->src); + fputs(", ", stdout); + cgen_printvar(c->fn, dst); + putchar('\n'); + return 0; +} + +static int cg_var(const struct set *s, const struct stentry *dst, + struct cgen *c) +{ + const struct stentry *src = s->src; + const char *tmp = cgen_tmp(src->t->sz); + + printf("%%%s =%s load%s ", tmp, cgen_sz(src->t->sz), cgen_load(src->t)); + cgen_printvar(c->fn, src); + putchar('\n'); + printf("store%s %%%s, ", cgen_sz(dst->t->sz), tmp); + cgen_printvar(c->fn, dst); + putchar('\n'); + return 0; +} + +static int cg_imb(const struct set *s, const struct stentry *e, struct cgen *c) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +int set_cgen(const struct set *s, struct cgen *c) +{ + for (size_t i = 0; i < s->ndsts; i++) + { + const struct stentry *dst = s->dsts[i].entry; + + static int (*const f[])(const struct set *, const struct stentry *, + struct cgen *) = + { + [SET_VAL] = cg_val, + [SET_ADDR] = cg_addr, + [SET_VAR] = cg_var, + [SET_IMB] = cg_imb + }; + + if (f[s->type](s, dst, c)) + return -1; + } + + return 0; +} + +int set(const struct lex *l, struct prv *p) +{ + const struct tk *next = p->tk; + const char *ns; + struct fn *fn = fn_cur(p); + size_t n = fn->nstmts + 1; + struct stmt *stmts; + + if (lex_eof(l, next)) + { + errloc(next - 1, "incomplete set statement"); + return -1; + } + else if (kw((ns = next->s))) + { + errloc(next, "incomplete set statement"); + return -1; + } + else if (!(stmts = realloc(fn->stmts, n * sizeof *stmts))) + { + perror("realloc(3)"); + return -1; + } + + fn->stmts = stmts; + fn->stmts[fn->nstmts++] = (struct stmt){.type = SET}; + + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + if (push(&init, p)) + return -1; + + p->stk = p->tk; + return 1; +} diff --git a/src/prc1/set.h b/src/prc1/set.h new file mode 100644 index 0000000..fdd067a --- /dev/null +++ b/src/prc1/set.h @@ -0,0 +1,29 @@ +#ifndef SET_H +#define SET_H + +#include "cgen.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include "storage.h" +#include + +struct setdst +{ + const struct stentry *entry; +}; + +struct set +{ + enum {SET_VAL, SET_VAR, SET_ADDR, SET_IMB} type; + const struct stentry *off, *src; + unsigned long long srcv; + struct setdst *dsts; + size_t ndsts; +}; + +int set(const struct lex *l, struct prv *p); +int set_cgen(const struct set *s, struct cgen *c); +void set_free(struct set *s); + +#endif diff --git a/src/prc1/stmt.c b/src/prc1/stmt.c new file mode 100644 index 0000000..8d2fdd4 --- /dev/null +++ b/src/prc1/stmt.c @@ -0,0 +1,92 @@ +#include "stmt.h" +#include "call.h" +#include "fn.h" +#include "from.h" +#include "parse.h" +#include "prv.h" +#include "display.h" +#include "exit.h" +#include "set.h" +#include "warn.h" + +void stmt_free(struct stmt *s) +{ + switch (s->type) + { + case DISPLAY: + display_free(&s->u.display); + break; + case SET: + set_free(&s->u.set); + break; + case CALL: + call_free(&s->u.call); + break; + case WARN: + warn_free(&s->u.warn); + break; + case FROM: + from_free(&s->u.from); + break; + case END: + end_free(&s->u.end); + break; + } +} + +int stmt_cgen(const struct stmt *s, struct cgen *c) +{ + switch (s->type) + { + case DISPLAY: + return display_cgen(&s->u.display, c); + case SET: + return set_cgen(&s->u.set, c); + case CALL: + return call_cgen(&s->u.call, c); + case WARN: + return warn_cgen(&s->u.warn, c); + case FROM: + return from_cgen(&s->u.from, c); + case END: + return end_cgen(&s->u.end, c); + } + + fprintf(stderr, "%s: unreachable\n", __func__); + return -1; +} + +struct stmt *stmt_cur(const struct prv *p) +{ + const struct fn *fn = fn_cur(p); + + return &fn->stmts[fn->nstmts - 1]; +} + +const struct seq stmts[] = +{ + {(struct step[]){ + {ID, "display"}, {ANY, NULL, 1}, {ID, "etc"}, {0}}, .fn = display}, + {(struct step[]) + {{ID, "display"}, {ANY, NULL, 1}, {0}}, .fn = display}, + {(struct step[]){ + {ID, "warn"}, {ANY, NULL, 1}, {ID, "etc"}, {0}}, .fn = warn}, + {(struct step[]) + {{ID, "warn"}, {ANY, NULL, 1}, {0}}, .fn = warn}, + {(struct step[]) + {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "using"}, {ID}, + {ID, "by"}, {ANY}, {0}}, .fn = from_idby}, + {(struct step[]) + {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "by"}, {ANY}, {0}}, + .fn = from_by}, + {(struct step[]) + {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "using"}, {ID}, {0}}, + .fn = from_id}, + {(struct step[]) + {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {0}}, .fn = from}, + {(struct step[]){{ID, "exit"}, {0}}, .fn = s_exit}, + {(struct step[]){{ID, "set"}, {0}}, .fn = set}, + {(struct step[]){{ID, "call"}, {0}}, .fn = call}, + {(struct step[]){{ID, "end"}, {0}}, .fn = end}, + {0} +}; diff --git a/src/prc1/stmt.h b/src/prc1/stmt.h new file mode 100644 index 0000000..5cc650d --- /dev/null +++ b/src/prc1/stmt.h @@ -0,0 +1,44 @@ +#ifndef STMTS_H +#define STMTS_H + +#include "cgen.h" +#include "prv.h" +#include "call.h" +#include "display.h" +#include "end.h" +#include "from.h" +#include "set.h" +#include "warn.h" + +struct stmt +{ + enum + { + DISPLAY, + SET, + CALL, + WARN, + FROM, + END + } type; + + int (*end)(const struct stmt *, struct cgen *); + + union + { + struct display display; + struct set set; + struct call call; + struct warn warn; + struct from from; + struct end end; + } u; +}; + +struct stmt *stmt_cur(const struct prv *p); +int stmt_cgen(const struct stmt *s, struct cgen *c); +void stmt_free(struct stmt *s); + +extern const struct seq stmts[]; + +#endif diff --git a/src/prc1/storage.c b/src/prc1/storage.c new file mode 100644 index 0000000..62f3c1f --- /dev/null +++ b/src/prc1/storage.c @@ -0,0 +1,219 @@ +#include "storage.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "prv.h" +#include "type.h" +#include +#include +#include + +static int id(const struct lex *l, struct prv *p); + +static const struct seq seqs[] = +{ + {(struct step[]){{ID}, {0}}, .fn = id}, + {0} +}; + +static int compat(const struct fn *fn, const struct prv *p, + const struct tk *name, const struct type *t, const struct type **ot) +{ + const struct stentry *oe; + const struct fn *top = fn_cur(p); + + /* allow global entries if already found on linkage section + * and vice versa, as long as the types are compatible. */ + if (p->st == top->gl) + { + for (size_t i = 0; i < fn->nimps; i++) + { + const struct im *im = &fn->imps[i]; + + if (compat(im->ast.fns, p, name, t, ot)) + return 1; + } + + if (fn->lk && (oe = storage_find(name->s, fn->lk))) + { + if (t == oe->t) + return 1; + + *ot = oe->t; + return -1; + } + } + else if (p->st == top->lk) + { + if (fn->gl && (oe = storage_find(name->s, fn->gl))) + { + if (t == oe->t) + return 1; + + *ot = oe->t; + return -1; + } + } + + return 0; +} + +static int stpush(const struct lex *l, struct prv *p, const struct tk *name, + const struct type *t) +{ + int ret = -1; + struct stentry *entries; + struct storage *st = p->st; + size_t n = st->nentries + 1; + const struct fn *fn = fn_cur(p); + const struct loc *loc = &name->loc; + const struct stentry *e; + char *tname = type_name(t); + + if (!tname) + goto end; + else if (!t->sz && p->st != fn->lk) + { + errloc(name + 1, "type \"%s\" has null size", tname); + goto end; + } + else if (st->check && (e = fn_var(fn, name))) + { + const struct loc *loc = &e->tk->loc; + const struct type *ot; + int ret = compat(fn, p, name, t, &ot); + + if (ret < 0) + { + errloc(name, "variable \"%s\" (\"%s\") already defined at " + "%s:%d:%d with incompatible type (\"%s\")", + name->s, type_name(t), loc->f, loc->line, loc->col, + type_name(ot)); + goto end; + } + else if (!ret) + { + errloc(name, "variable \"%s\" already defined at %s:%d:%d", + name->s, loc->f, loc->line, loc->col); + goto end; + } + } + + /* find var in currently known symbols */ + for (size_t i = 0; i < st->nentries; i++) + { + const struct stentry *e = &st->entries[i]; + const struct tk *tk = e->tk; + + if (!strcmp(name->s, tk->s)) + { + const struct loc *loc = &tk->loc; + + errloc(tk, "variable \"%s\" already defined at %s:%d:%d", + tk->s, loc->f, loc->line, loc->col); + goto end; + } + } + + if (pop(l, p)) + goto end; + else if (!(entries = realloc(st->entries, n * sizeof *entries))) + { + perror("realloc(3)"); + goto end; + } + + if (t->sz) + st->offset += st->offset % t->sz; + + entries[st->nentries++] = (struct stentry) + { + .t = t, + .tk = name, + .offset = st->offset + }; + + st->entries = entries; + st->offset += t->sz; + p->stk = p->tk; + + if (p->proto) + fputc('\t', stderr); + + fprintf(stderr, "\tadding %s (%d:%d) to %s, type %s, offset %zu, " + "size %zu\n", name->s, loc->line, loc->col, st->name, tname, + entries[st->nentries - 1].offset, t->sz); + ret = 1; +end: + free(tname); + return ret; +} + +static int v(const struct lex *l, struct prv *p, const struct type *t) +{ + return stpush(l, p, p->id, t); +} + +static int id(const struct lex *l, struct prv *p) +{ + p->id = p->stk; + return type(l, p, v); +} + +void storage_free(struct storage *s) +{ + if (s) + free(s->entries); + + free(s); +} + +const struct stentry *storage_find(const char *name, const struct storage *s) +{ + for (size_t i = 0; i < s->nentries; i++) + { + const struct stentry *e = &s->entries[i]; + + if (!strcmp(name, e->tk->s)) + return e; + } + + return NULL; +} + +int storage(const struct lex *l, struct prv *p, const char *name, int check, + struct storage **out) +{ + struct storage *st = NULL; + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + if (*out) + { + const struct loc *loc = &(*out)->tk->loc; + + errloc(p->stk, "%s already defined at %s:%d:%d", name, loc->f, + loc->line, loc->col); + goto failure; + } + else if (!(st = malloc(sizeof *st))) + { + perror("malloc(3)"); + goto failure; + } + else if (push(&init, p)) + goto failure; + + *st = (struct storage){.name = name, .tk = p->stk, .check = check}; + *out = p->st = st; + p->stk = p->tk; + return 1; + +failure: + free(st); + return -1; +} diff --git a/src/prc1/storage.h b/src/prc1/storage.h new file mode 100644 index 0000000..a3509c5 --- /dev/null +++ b/src/prc1/storage.h @@ -0,0 +1,29 @@ +#ifndef STORAGE_H +#define STORAGE_H + +#include "lex.h" +#include "prv.h" +#include + +struct stentry +{ + const struct tk *tk; + const struct type *t; + size_t offset; +}; + +struct storage +{ + const char *name; + const struct tk *tk; + struct stentry *entries; + size_t nentries, offset; + int check; +}; + +int storage(const struct lex *l, struct prv *p, const char *name, int check, + struct storage **out); +const struct stentry *storage_find(const char *name, const struct storage *s); +void storage_free(struct storage *s); + +#endif diff --git a/src/prc1/td.c b/src/prc1/td.c new file mode 100644 index 0000000..72c379f --- /dev/null +++ b/src/prc1/td.c @@ -0,0 +1,587 @@ +#include "td.h" +#include "div.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include "storage.h" +#include "type.h" +#include +#include +#include +#include +#include +#include + +static int cid(const struct lex *, struct prv *); +static int cnum(const struct lex *, struct prv *); +static int end(const struct lex *, struct prv *); +static int endp(const struct lex *, struct prv *); +static int u(const struct lex *, struct prv *); +static int s(const struct lex *, struct prv *); +static int c(const struct lex *, struct prv *); +static int a(const struct lex *, struct prv *); +static int p(const struct lex *, struct prv *); + +static const struct seq seqs[] = +{ + {(struct step[]){{ID, "end"}, {0}}, .fn = end}, + {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {ID}, {0}}, .fn = cid}, + {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {NUM}, {0}}, .fn = cnum}, + {(struct step[]){{ID}, {ID, "alias"}, {0}}, .fn = a}, + {(struct step[]){{ID}, {ID, "union"}, {0}}, .fn = u}, + {(struct step[]){{ID}, {ID, "struct"}, {0}}, .fn = s}, + {(struct step[]){{ID}, {ID, "constant"}, {0}}, .fn = c}, + {(struct step[]){{ID}, {ID, "prototype"}, {0}}, .fn = p, .end = endp}, + {0} +}; + +static void reset(struct prv *p) +{ + struct pos *pos = &p->pos[p->i]; + + pos->seq = seqs; + pos->step = seqs->steps; + p->stk = p->tk; +} + +static int bump(const struct tk *tk, const struct type *t, struct prv *p) +{ + struct tdconstant *tdc = p->tdc; + int neg = 0; + + if (!t->sign) + { + unsigned long long uv = t->u.c.uv; + + if (uv + 1 < uv) + { + errloc(tk, "constant value exceeds maximum (%llu)", ULLONG_MAX); + return -1; + } + + tdc->u.uv = ++uv; + } + else + { + long long v = t->u.c.v; + + if (++v < 0) + neg = 1; + + tdc->u.v = v; + } + + tdc->neg = neg; + + for (size_t i = 0; i < p->block; i++) + fputc('\t', stderr); + + fprintf(stderr, "\t\tnext %s constant value set to ", + neg ? "negative" : "positive"); + + if (neg) + fprintf(stderr, "%lld", tdc->u.v); + else + fprintf(stderr, "%llu", tdc->u.uv); + + fputc('\n', stderr); + return 0; +} + +static int cid(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct tk *id = p->stk, *v = p->stk + 3; + const struct stentry *e; + const struct type *t = type_find(fn, id->s); + struct tdconstant *tdc = p->tdc; + struct td *td = fn->td; + size_t n = td->ntypes + 1; + struct type *types, *nt; + + if (t) + { + const struct loc *loc = &t->tk->loc; + + errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, + loc->line, loc->col); + return -1; + } + else if ((e = fn_var(fn, id))) + { + const struct loc *loc = &e->tk->loc; + + errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, + loc->f, loc->line, loc->col); + return -1; + } + else if ((e = fn_var(fn, v))) + { + const struct loc *loc = &e->tk->loc; + + errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", + v->s, loc->f, loc->line, loc->col); + return -1; + } + else if (!(t = type_find(fn, v->s))) + { + errloc(id, "undefined reference to value \"%s\"", v->s); + return -1; + } + else if (t->type != C) + { + const struct loc *loc = &t->tk->loc; + + errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", + v->s, loc->f, loc->line, loc->col); + return -1; + } + else if (!(types = realloc(td->types, n * sizeof *types))) + { + perror("realloc(3)"); + return -1; + } + + td->types = types; + nt = &td->types[td->ntypes++]; + *nt = (struct type) + { + .type = C, + .tk = id, + .sign = t->sign, + .u.c = t->u.c + }; + + tdc->neg = t->sign; + + if (bump(id, t, p)) + return -1; + + for (size_t i = 0; i < p->block; i++) + fputc('\t', stderr); + + fprintf(stderr, "\tadding constant %s to %s (%lld)\n", id->s, v->s, + t->u.c.v); + reset(p); + return 1; +} + +static int cnum(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct tk *id = p->stk, *num = p->stk + 3; + const char *name = id->s; + const struct stentry *e; + struct td *td = fn->td; + size_t n = td->ntypes + 1; + struct type *types, *nt; + struct tdconstant *tdc = p->tdc; + const struct type *t = type_find(fn, name); + int sign = *num->s == '-'; + unsigned long long uv = 0; + long long v; + char *end; + + errno = 0; + v = strtoll(num->s, &end, 0); + + if (!sign || errno || *end) + { + errno = 0; + uv = strtoull(num->s, NULL, 0); + } + + if (t) + { + const struct loc *loc = &t->tk->loc; + + errloc(id, "type \"%s\" already defined at %s:%d:%d", name, loc->f, + loc->line, loc->col); + return -1; + } + else if ((e = fn_var(fn, id))) + { + const struct loc *loc = &e->tk->loc; + + errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, + loc->f, loc->line, loc->col); + return -1; + } + else if (!(types = realloc(td->types, n * sizeof *types))) + { + perror("realloc(3)"); + return -1; + } + + td->types = types; + nt = &td->types[td->ntypes++]; + *nt = (struct type) + { + .type = C, + .tk = id, + .sign = sign + }; + + if (sign) + tdc->u.v = nt->u.c.v = v; + else + tdc->u.uv = nt->u.c.uv = uv; + + tdc->neg = sign; + + for (size_t i = 0; i < p->block; i++) + fputc('\t', stderr); + + fprintf(stderr, "\tadding constant %s to %s\n", id->s, num->s); + + if (bump(id, nt, p)) + return -1; + + reset(p); + return 1; +} + +static int c(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct tk *id = p->stk; + const struct stentry *e; + const struct type *t = type_find(fn, id->s); + struct td *td = fn->td; + size_t n = td->ntypes + 1; + struct type *types, *nt; + const struct tdconstant *tdc = p->tdc; + + if (t) + { + const struct loc *loc = &t->tk->loc; + + errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, + loc->line, loc->col); + return -1; + } + else if ((e = fn_var(fn, id))) + { + const struct loc *loc = &e->tk->loc; + + errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, + loc->f, loc->line, loc->col); + return -1; + } + else if (!(types = realloc(td->types, n * sizeof *types))) + { + perror("realloc(3)"); + return -1; + } + + td->types = types; + nt = &td->types[td->ntypes]; + *nt = (struct type) + { + .type = C, + .tk = id, + .sign = tdc->neg, + }; + + if (nt->sign) + nt->u.c.v = tdc->u.v; + else + nt->u.c.uv = tdc->u.uv; + + for (size_t i = 0; i < p->block; i++) + fputc('\t', stderr); + + fprintf(stderr, "\tadding constant %s to ", id->s); + + if (tdc->neg) + fprintf(stderr, "%lld", tdc->u.v); + else + fprintf(stderr, "%llu", tdc->u.uv); + + fputc('\n', stderr); + + if (bump(id, &td->types[td->ntypes++], p)) + return -1; + + reset(p); + return 1; +} + +static int p(const struct lex *l, struct prv *p) +{ + struct fn *fn = fn_cur(p), *pt = NULL; + struct td *td = fn->td; + size_t n = td->ntypes + 1; + struct type *types; + + if (!(pt = malloc(sizeof *pt))) + { + perror("malloc(3)"); + goto failure; + } + + *pt = (struct fn){.tk = p->stk, .parent = fn}; + + if (!(types = realloc(td->types, n * sizeof *types))) + { + perror("realloc(3)"); + goto failure; + } + + types[td->ntypes++] = (struct type) + { + .type = P, + .tk = p->stk, + .sz = sizeof (void *), + .align = sizeof (void *), + .u.p.fn = pt + }; + + td->types = types; + p->proto = pt; + fprintf(stderr, "\tadding prototype %s\n", p->stk->s); + return div_p(l, p); + +failure: + free(pt); + return -1; +} + +static int ends(struct type *t) +{ + const struct s *s = &t->u.s; + const struct storage *st = s->storage; + const struct stentry *e; + + if (!st->nentries) + { + errloc(t->tk, "struct \"%s\" has no members", t->tk->s); + return -1; + } + + e = &st->entries[st->nentries - 1]; + t->align = st->entries->t->align; + t->sz = e->offset + e->t->sz; + t->sz += t->align - (t->sz % t->align); + fprintf(stderr, "\tadding struct %s, size %zu, align %zu\n", t->tk->s, + t->sz, t->align); + return 0; +} + +static int endu(struct type *t) +{ + const struct u *u = &t->u.u; + + if (!u->storage->nentries) + { + errloc(t->tk, "union \"%s\" has no members", t->tk->s); + return -1; + } + + return 0; +} + +static int end(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->tk - 1; + struct type *t; + + if (!p->block) + { + errloc(tk, "unexpected \"end\" statement"); + return -1; + } + else if (!(t = p->ag)) + { + errloc(tk, "unreachable"); + return -1; + } + + switch (t->type) + { + case U: + if (endu(t)) + return -1; + + break; + + case S: + if (ends(t)) + return -1; + + break; + + default: + errloc(tk, "unreachable"); + return -1; + } + + p->ag = NULL; + p->block--; + reset(p); + return 1; +} + +static int endp(const struct lex *l, struct prv *p) +{ + if (fn_end(l, p)) + return -1; + + p->proto = NULL; + return 0; +} + +static int s(const struct lex *l, struct prv *p) +{ + const struct tk *id = p->stk; + struct fn *fn = fn_cur(p); + struct td *td = fn->td; + size_t nt = td->ntypes + 1; + struct type *types, *newt; + const struct type *t = type_find(fn, id->s); + + if (t) + { + const struct loc *loc = &t->tk->loc; + + errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, + loc->line, loc->col); + return -1; + } + else if (!(types = realloc(td->types, nt * sizeof *types))) + { + perror("realloc(3)"); + return -1; + } + + td->types = types; + newt = &td->types[td->ntypes++]; + *newt = (struct type) + { + .type = S, + .tk = id + }; + + p->ag = newt; + p->block++; + return storage(l, p, id->s, 0, &newt->u.s.storage); +} + +static int u(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int tt(const struct lex *l, struct prv *p, const struct type *t) +{ + int ret = -1; + const struct fn *fn = fn_cur(p); + const struct tk *id = p->id; + const struct type *tp = type_ufind(fn, id->s); + const struct loc *loc = &id->loc; + struct td *td = fn->td; + size_t n = td->ntypes + 1; + struct type *types, *nt; + char *s = type_name(t); + + if (!s) + goto end; + else if (tp) + { + const struct loc *loc = &tp->tk->loc; + + errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, + loc->line, loc->col); + goto end; + } + else if (pop(l, p)) + return -1; + else if (!(types = realloc(td->types, n * sizeof *types))) + { + perror("realloc(3)"); + goto end; + } + + td->types = types; + nt = &td->types[td->ntypes++]; + *nt = (struct type) + { + .type = T, + .tk = id, + .u.t.alias = t + }; + + fprintf(stderr, "\tadding %s (%d:%d) alias %s\n", id->s, loc->line, + loc->col, s); + reset(p); + p->id = NULL; + ret = 1; +end: + free(s); + return ret; +} + +static int a(const struct lex *l, struct prv *p) +{ + p->id = p->stk; + return type(l, p, tt); +} + +void td_free(struct td *td) +{ + if (td) + { + for (size_t i = 0; i < td->ntypes; i++) + type_free(&td->types[i]); + + free(td->types); + } + + free(td); +} + +int td(const struct lex *l, struct prv *p) +{ + const struct tk *tk = p->stk; + struct fn *fn = fn_cur(p); + struct td *td = NULL, *prev = fn->td; + struct tdconstant *tdc = NULL; + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + if (prev) + { + const struct loc *loc = &prev->tk->loc; + + errloc(tk, "types section already defined at %s:%d:%d", loc->f, + loc->line, loc->col); + goto failure; + } + else if (!(td = malloc(sizeof *td)) + || !(tdc = malloc(sizeof *tdc))) + { + perror("malloc(3)"); + goto failure; + } + else if (push(&init, p)) + goto failure; + + *tdc = (struct tdconstant){0}; + *td = (struct td){.tk = tk}; + fn->td = td; + p->tdc = tdc; + p->stk = p->tk; + return 1; + +failure: + free(tdc); + free(td); + return -1; +} diff --git a/src/prc1/td.h b/src/prc1/td.h new file mode 100644 index 0000000..2e23348 --- /dev/null +++ b/src/prc1/td.h @@ -0,0 +1,22 @@ +#ifndef TD_H +#define TD_H + +#include "lex.h" +#include "parse.h" +#include "prv.h" + +struct tdconstant +{ + int neg; + + union + { + unsigned long long uv; + long long v; + } u; +}; + +int td(const struct lex *l, struct prv *prv); +void td_free(struct td *td); + +#endif diff --git a/src/prc1/tmp.c b/src/prc1/tmp.c new file mode 100644 index 0000000..c93443f --- /dev/null +++ b/src/prc1/tmp.c @@ -0,0 +1,69 @@ +#include "tmp.h" +#include "type.h" +#include +#include +#include + +const struct stentry *tmp_create(struct fn *fn, const struct type *t) +{ + static const char fmt[] = "__tmp%zu"; + int r = snprintf(NULL, 0, fmt, fn->ntmps); + char *s = NULL, *tname = NULL; + struct tmp *tmp; + + if (!(tname = type_name(t))) + goto failure; + else if (r < 0) + { + fprintf(stderr, "%s: snprintf(3) failed\n", __func__); + goto failure; + } + else if (!(s = malloc(r + 1))) + { + perror("malloc(3)"); + goto failure; + } + + snprintf(s, r + 1, fmt, fn->ntmps++); + + if (!(tmp = malloc(sizeof *tmp))) + { + perror("realloc(3)"); + goto failure; + } + + *tmp = (struct tmp) + { + .tk = + { + .type = ID, + .s = s, + .loc.f = "(temporary)" + }, + + .e = + { + .tk = &tmp->tk, + .t = t + } + }; + + if (!fn->tmps) + fn->tmps = tmp; + else + for (struct tmp *t = fn->tmps; t ; t = t->next) + if (!t->next) + { + t->next = tmp; + break; + } + + fprintf(stderr, "\tcreating temporary variable %s, type %s\n", s, tname); + free(tname); + return &tmp->e; + +failure: + free(s); + free(tname); + return NULL; +} diff --git a/src/prc1/tmp.h b/src/prc1/tmp.h new file mode 100644 index 0000000..b62487a --- /dev/null +++ b/src/prc1/tmp.h @@ -0,0 +1,9 @@ +#ifndef TMP_H +#define TMP_H + +#include "parse.h" +#include "storage.h" + +const struct stentry *tmp_create(struct fn *fn, const struct type *t); + +#endif diff --git a/src/prc1/type.c b/src/prc1/type.c new file mode 100644 index 0000000..c7e43d0 --- /dev/null +++ b/src/prc1/type.c @@ -0,0 +1,459 @@ +#include "type.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include +#include +#include +#include + +static int aetc(const struct lex *l, struct prv *p); +static int aid(const struct lex *l, struct prv *p); +static int anum(const struct lex *l, struct prv *p); +static int p(const struct lex *l, struct prv *p); +static int t(const struct lex *l, struct prv *p); + +static const struct seq seqs[] = +{ + {(struct step[]) + {{ID, "array"}, {ID, "of"}, {ID, "etc"}, {0}}, .fn = aetc}, + {(struct step[]){{ID, "array"}, {ID, "of"}, {NUM}, {0}}, .fn = anum}, + {(struct step[]){{ID, "array"}, {ID, "of"}, {ID}, {0}}, .fn = aid}, + {(struct step[]){{ID, "pointer"}, {ID, "to"}, {0}}, .fn = p}, + {(struct step[]){{ID, "void"}, {0}}, .fn = t}, + {(struct step[]){{ID, "byte"}, {0}}, .fn = t}, + {(struct step[]){{ID, "halfword"}, {0}}, .fn = t}, + {(struct step[]){{ID, "word"}, {0}}, .fn = t}, + {(struct step[]){{ID, "long"}, {0}}, .fn = t}, + {(struct step[]){{ID, "ubyte"}, {0}}, .fn = t}, + {(struct step[]){{ID, "uhalfword"}, {0}}, .fn = t}, + {(struct step[]){{ID, "uword"}, {0}}, .fn = t}, + {(struct step[]){{ID, "ulong"}, {0}}, .fn = t}, + {(struct step[]){{ID}, {0}}, .fn = t}, + {0} +}; + +void type_free(struct type *t) +{ + switch (t->type) + { + case U: + { + struct u *u = &t->u.u; + + storage_free(u->storage); + } + break; + + case S: + { + struct s *s = &t->u.s; + + storage_free(s->storage); + } + break; + + case C: + break; + + case P: + { + struct p *p = &t->u.p; + + fn_free(p->fn); + free(p->fn); + } + break; + + case T: + case ARY: + case PTR: + case BUILTIN: + break; + } +} + +void type_lfree(struct type *t) +{ + if (t->child) + type_lfree(t->child); + + free(t); +} + +static int append(const char *s, char **out) +{ + size_t n = *out ? strlen(*out) : 0; + char *ns = realloc(*out, strlen(s) + n + 1); + + if (!ns) + { + perror("realloc(3)"); + return -1; + } + + strcpy(ns + n, s); + *out = ns; + return 0; +} + +char *type_name(const struct type *t) +{ + char *ret = NULL; + + while (t) + { + int n = -1; + + switch (t->type) + { + case BUILTIN: + n = append(t->u.b.name, &ret); + break; + + case ARY: + { + const struct ary *ary = &t->u.ary; + char s[sizeof "18446744073709551615 "]; + + if (ary->etc) + snprintf(s, sizeof s, "etc "); + else + snprintf(s, sizeof s, "%llu ", t->u.ary.n); + + n = append("array of ", &ret) || append(s, &ret); + break; + } + + case PTR: + n = append("pointer to ", &ret); + break; + + case U: + case S: + case C: + case P: + case T: + n = append(t->tk->s, &ret); + break; + } + + if (n) + { + free(ret); + return NULL; + } + + t = t->child; + } + + return ret; +} + +const struct type *type_ufind(const struct fn *fn, const char *s) +{ + static const struct type builtins[] = + { + {.type = BUILTIN, .u.b.name = "void"}, + {.type = BUILTIN, .u.b.name = "byte", .sz = 1, .sign = 1, .align = 1}, + {.type = BUILTIN, .u.b.name = "halfword", .sz = 2, .sign = 1, .align = 2}, + {.type = BUILTIN, .u.b.name = "word", .sz = 4, .sign = 1, .align = 4}, + {.type = BUILTIN, .u.b.name = "long", .sz = 8, .sign = 1, .align = 8}, + {.type = BUILTIN, .u.b.name = "ubyte", .sz = 1, .align = 1}, + {.type = BUILTIN, .u.b.name = "uhalfword", .sz = 2, .align = 2}, + {.type = BUILTIN, .u.b.name = "uword", .sz = 4, .align = 4}, + {.type = BUILTIN, .u.b.name = "ulong", .sz = 8, .align = 8} + }; + + const struct td *td = fn->td; + + if (fn->parent) + { + const struct type *t = type_find(fn->parent, s); + + if (t) + return t; + } + + for (size_t i = 0; i < sizeof builtins / sizeof *builtins; i++) + { + const struct type *t = &builtins[i]; + + if (!strcmp(t->u.b.name, s)) + return t; + } + + if (td) + for (size_t i = 0; i < td->ntypes; i++) + { + const struct type *t = &td->types[i]; + + if (!strcmp(t->tk->s, s)) + return t; + } + + for (size_t i = 0; i < fn->nimps; i++) + { + const struct type *t = type_ufind(fn->imps[i].ast.fns, s); + + if (t) + return t; + } + + return NULL; +} + +const struct type *type_find(const struct fn *fn, const char *s) +{ + const struct type *t = type_ufind(fn, s); + + if (t && t->type == T) + return t->u.t.alias; + + return t; +} + +static int queue(struct prv *p, struct type *t) +{ + struct type *tt; + struct pos *pos = &p->pos[p->i]; + + if (!(tt = p->t)) + p->t = t; + else + { + while (tt->child) + tt = tt->child; + + tt->child = t; + } + + pos->seq = pos->stseq; + pos->step = pos->seq->steps; + p->stk = p->tk; + return 1; +} + +static int aetc(const struct lex *l, struct prv *p) +{ + struct type *t; + const struct type *tt = p->t; + + while (tt) + { + if (tt->type == ARY && tt->u.ary.etc) + { + errloc(p->stk, "multi-dimensional arrays " + "with unknown size are not allowed"); + return -1; + } + + tt = tt->next; + } + + if (!(t = malloc(sizeof *t))) + { + perror("malloc"); + return -1; + } + + *t = (struct type){.type = ARY, .u.ary.etc = 1}; + return queue(p, t); +} + +static int aid(const struct lex *l, struct prv *p) +{ + const struct tk *qty = p->stk + 2; + const struct type *ct = type_find(fn_cur(p), qty->s); + struct type *t; + unsigned long long v; + + if (!ct) + { + errloc(qty, "undefined reference to type \"%s\"", qty->s); + return -1; + } + else if (ct->type != C) + { + errloc(qty, "type \"%s\" not a constant", qty->s); + return -1; + } + else if (ct->sign) + { + errloc(qty, "type \"%s\" defines a negative constant (%lld)", + qty->s, ct->u.c.v); + return -1; + } + else if (!(v = ct->u.c.uv)) + { + errloc(qty, "constant \"%s\" equals zero and cannot be used " + "for array sizes", qty->s); + return -1; + } + else if (!(t = malloc(sizeof *t))) + { + perror("malloc"); + return -1; + } + + *t = (struct type){.type = ARY, .u.ary.n = v}; + return queue(p, t); +} + +static int anum(const struct lex *l, struct prv *p) +{ + const struct tk *qty = p->stk + 2; + unsigned long long n = strtoull(qty->s, NULL, 0); + struct type *t; + + if (*qty->s == '-' || errno) + { + errloc(qty, "invalid negative size for array"); + return -1; + } + else if (!n) + { + errloc(qty, "array size cannot be zero"); + return -1; + } + else if (!(t = malloc(sizeof *t))) + { + perror("malloc"); + return -1; + } + + *t = (struct type){.type = ARY, .u.ary.n = n}; + return queue(p, t); +} + +static int p(const struct lex *l, struct prv *p) +{ + struct type *t = malloc(sizeof *t), *tt; + + if (!t) + { + perror("malloc"); + return -1; + } + + *t = (struct type) + { + .type = PTR, + .sz = sizeof (void *), + .align = sizeof (void *) + }; + + if ((tt = p->t) && tt->type == ARY) + { + tt->sz = tt->u.ary.n * sizeof (void *); + tt->align = sizeof (void *); + } + + return queue(p, t); +} + +static int aryeq(const struct type *a, const struct type *b) +{ + const struct ary *aa = &a->u.ary, *ab = &b->u.ary; + + return !memcmp(aa, ab, sizeof *aa); +} + +static int eq(const struct type *a, const struct type *b) +{ + for (; a && b; a = a->child, b = b->child) + if (a->type != b->type) + return 0; + else if (a->type == ARY && !aryeq(a, b)) + return 0; + + return !a && !b; +} + +static const struct type *insert(struct prv *p) +{ + struct ast *ast = p->ast; + struct type *a = p->t, *tt = ast->types; + + for (const struct type *b = ast->types; b; b = b->next) + if (eq(a, b)) + { + type_lfree(a); + return b; + } + + if (!ast->types) + ast->types = a; + else + { + while (tt->next) + tt = tt->next; + + tt->next = a; + } + + return a; +} + +static int t(const struct lex *l, struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct tk *tk = p->stk; + const struct type *t = type_find(fn, tk->s); + struct type *tt = p->t; + + if (!t) + { + errloc(tk, "undefined reference to type \"%s\"", tk->s); + return -1; + } + else if (tt) + { + struct type *nt = malloc(sizeof *nt); + + if (!nt) + { + perror("malloc(3)"); + return -1; + } + + *nt = *t; + + while (tt->child) + tt = tt->child; + + tt->child = nt; + tt = p->t; + + /* array size still undecided */ + if (tt->type == ARY && !tt->sz) + { + tt->sz = tt->u.ary.n * nt->sz; + tt->align = t->align; + } + + if (!(t = insert(p))) + return -1; + + p->t = NULL; + } + + return p->type(l, p, t); +} + +int type(const struct lex *l, struct prv *p, + int (*fn)(const struct lex *, struct prv *, const struct type *)) +{ + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + p->stk = p->tk; + p->type = fn; + return push(&init, p) ? -1 : 1; +} diff --git a/src/prc1/type.h b/src/prc1/type.h new file mode 100644 index 0000000..7de6c28 --- /dev/null +++ b/src/prc1/type.h @@ -0,0 +1,16 @@ +#ifndef TYPE_H +#define TYPE_H + +#include "lex.h" +#include "prv.h" +#include "parse.h" + +const struct type *type_ufind(const struct fn *fn, const char *s); +const struct type *type_find(const struct fn *fn, const char *s); +char *type_name(const struct type *t); +int type(const struct lex *l, struct prv *p, + int (*fn)(const struct lex *, struct prv *p, const struct type *t)); +void type_free(struct type *t); +void type_lfree(struct type *t); + +#endif diff --git a/src/prc1/warn.c b/src/prc1/warn.c new file mode 100644 index 0000000..456ce79 --- /dev/null +++ b/src/prc1/warn.c @@ -0,0 +1,146 @@ +#include "warn.h" +#include "cgen.h" +#include "parse.h" +#include "prv.h" +#include "stmt.h" +#include "storage.h" +#include +#include +#include + +static int finalize(const struct lex *l, const struct prv *p, + const struct print *pr) +{ + const struct ast *ast = p->ast; + struct fn *fn = &ast->fns[ast->nfns - 1]; + size_t n = fn->nstmts + 1; + struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); + + if (!stmts) + { + perror("realloc(3)"); + return -1; + } + + fn->stmts = stmts; + fn->stmts[fn->nstmts++] = (struct stmt) + { + .type = WARN, + .u.warn.p = *pr + }; + + fprintf(stderr, "\t\tadding warn statement with %zu entries%s\n", + pr->nentries, pr->println ? "" : ", no lf"); + return 0; +} + +static int cg_val(const struct tk *tk) +{ + const char *num = tk->s; + int neg = *num == '-'; + unsigned long long uv; + char *end; + + fputs("call $printf(l $____fmt", stdout); + errno = 0; + uv = strtoull(num, &end, 16); + + if (!neg && !errno && !*end) + printf("lx, ..., l %llu )\n", uv); + else + { + errno = 0; + uv = strtoull(num, &end, 0); + + if (neg || errno || *end) + { + long long v = strtoll(num, NULL, 0); + printf("l, ..., l %lld )\n", v); + } + else + printf("l, ..., l %llu )\n", uv); + } + + return 0; +} + +static int cg_lit(const struct prientry *e) +{ + const struct lit *l = e->lit; + const char *tmp; + + if (!l) + { + fprintf(stderr, "%s: unexpected null literal\n", __func__); + return -1; + } + + printf("%%%s =l loadl $stderr\n", (tmp = cgen_tmp(sizeof (void *)))); + printf("call $fputs(l $%s, w %%%s)\n", l->name, tmp); + return 0; +} + +static int cg_id(const struct prientry *de, const struct fn *fn) +{ + const struct stentry *e = de->entry; + const struct type *t = e->t; + const char *id = e->tk->s; + int global = cgen_global(fn, e); + size_t sz = t->sz; + const char *asz = cgen_sz(sz < 4 ? 4 : sz), *tmp = cgen_tmp(sz); + + if (global) + printf("%%%s =%s load%s $%s\n", tmp, asz, cgen_load(t), id); + else + printf("%%%s =%s load%s %%%s_\n", tmp, asz, cgen_load(t), id); + + puts("%z =l loadl $stderr"); + fputs("call $fprintf(w %z, l $____fmt", stdout); + + if (t->type == PTR) + fputs("lx, ..., l ", stdout); + else + printf("%s, ..., %s ", cgen_type(t), asz); + + printf("%%%s)\n", tmp); + + return 0; +} + +int warn_cgen(const struct warn *w, struct cgen *c) +{ + const struct print *p = &w->p; + + for (size_t i = 0; i < p->nentries; i++) + { + const struct prientry *e = &p->entries[i]; + const struct tk *tk = e->tk; + + if (tk->type == LIT && cg_lit(e)) + return -1; + else if (tk->type == NUM && cg_val(tk)) + return -1; + else if (tk->type == ID && e->entry && cg_id(e, c->fn)) + return -1; + else if (tk->type == ID && e->lit && cg_lit(e)) + return -1; + } + + if (p->println) + { + puts("%v =l loadl $stderr"); + puts("call $fputc(l 10 , w %v)"); + } + + return 0; +} + +void warn_free(struct warn *w) +{ + print_free(&w->p); +} + +int warn(const struct lex *l, struct prv *p) +{ + return print(l, p, finalize); +} diff --git a/src/prc1/warn.h b/src/prc1/warn.h new file mode 100644 index 0000000..5327592 --- /dev/null +++ b/src/prc1/warn.h @@ -0,0 +1,17 @@ +#ifndef WARN_H +#define WARN_H + +#include "lex.h" +#include "print.h" +#include "prv.h" + +struct warn +{ + struct print p; +}; + +int warn(const struct lex *l, struct prv *p); +int warn_cgen(const struct warn *w, struct cgen *c); +void warn_free(struct warn *w); + +#endif diff --git a/src/prc1/ws.c b/src/prc1/ws.c new file mode 100644 index 0000000..59e1aec --- /dev/null +++ b/src/prc1/ws.c @@ -0,0 +1,29 @@ +#include "ws.h" +#include "fn.h" +#include "prv.h" +#include "parse.h" +#include "storage.h" + +static int wspush(const struct stentry *e, struct cgen *c) +{ + const struct type *t = e->t; + + printf("%%%s_ =l alloc%zu %zu\n", e->tk->s, t->align, t->sz); + return 0; +} + +int ws_cgen(const struct storage *s, struct cgen *c) +{ + for (size_t i = 0; i < s->nentries; i++) + if (wspush(&s->entries[i], c)) + return -1; + + return 0; +} + +int ws(const struct lex *l, struct prv *p) +{ + struct fn *fn = fn_cur(p); + + return storage(l, p, "storage section", 1, &fn->ws); +} diff --git a/src/prc1/ws.h b/src/prc1/ws.h new file mode 100644 index 0000000..fa44a37 --- /dev/null +++ b/src/prc1/ws.h @@ -0,0 +1,12 @@ +#ifndef WS_H +#define WS_H + +#include "lex.h" +#include "cgen.h" +#include "prv.h" + +int ws(const struct lex *l, struct prv *p); +int ws_cgen(const struct storage *s, struct cgen *c); +extern const struct seq wsseq[]; + +#endif diff --git a/stmt.c b/stmt.c deleted file mode 100644 index 8d2fdd4..0000000 --- a/stmt.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "stmt.h" -#include "call.h" -#include "fn.h" -#include "from.h" -#include "parse.h" -#include "prv.h" -#include "display.h" -#include "exit.h" -#include "set.h" -#include "warn.h" - -void stmt_free(struct stmt *s) -{ - switch (s->type) - { - case DISPLAY: - display_free(&s->u.display); - break; - case SET: - set_free(&s->u.set); - break; - case CALL: - call_free(&s->u.call); - break; - case WARN: - warn_free(&s->u.warn); - break; - case FROM: - from_free(&s->u.from); - break; - case END: - end_free(&s->u.end); - break; - } -} - -int stmt_cgen(const struct stmt *s, struct cgen *c) -{ - switch (s->type) - { - case DISPLAY: - return display_cgen(&s->u.display, c); - case SET: - return set_cgen(&s->u.set, c); - case CALL: - return call_cgen(&s->u.call, c); - case WARN: - return warn_cgen(&s->u.warn, c); - case FROM: - return from_cgen(&s->u.from, c); - case END: - return end_cgen(&s->u.end, c); - } - - fprintf(stderr, "%s: unreachable\n", __func__); - return -1; -} - -struct stmt *stmt_cur(const struct prv *p) -{ - const struct fn *fn = fn_cur(p); - - return &fn->stmts[fn->nstmts - 1]; -} - -const struct seq stmts[] = -{ - {(struct step[]){ - {ID, "display"}, {ANY, NULL, 1}, {ID, "etc"}, {0}}, .fn = display}, - {(struct step[]) - {{ID, "display"}, {ANY, NULL, 1}, {0}}, .fn = display}, - {(struct step[]){ - {ID, "warn"}, {ANY, NULL, 1}, {ID, "etc"}, {0}}, .fn = warn}, - {(struct step[]) - {{ID, "warn"}, {ANY, NULL, 1}, {0}}, .fn = warn}, - {(struct step[]) - {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "using"}, {ID}, - {ID, "by"}, {ANY}, {0}}, .fn = from_idby}, - {(struct step[]) - {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "by"}, {ANY}, {0}}, - .fn = from_by}, - {(struct step[]) - {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {ID, "using"}, {ID}, {0}}, - .fn = from_id}, - {(struct step[]) - {{ID, "from"}, {ANY}, {ID, "to"}, {ANY}, {0}}, .fn = from}, - {(struct step[]){{ID, "exit"}, {0}}, .fn = s_exit}, - {(struct step[]){{ID, "set"}, {0}}, .fn = set}, - {(struct step[]){{ID, "call"}, {0}}, .fn = call}, - {(struct step[]){{ID, "end"}, {0}}, .fn = end}, - {0} -}; diff --git a/stmt.h b/stmt.h deleted file mode 100644 index 5cc650d..0000000 --- a/stmt.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef STMTS_H -#define STMTS_H - -#include "cgen.h" -#include "prv.h" -#include "call.h" -#include "display.h" -#include "end.h" -#include "from.h" -#include "set.h" -#include "warn.h" - -struct stmt -{ - enum - { - DISPLAY, - SET, - CALL, - WARN, - FROM, - END - } type; - - int (*end)(const struct stmt *, struct cgen *); - - union - { - struct display display; - struct set set; - struct call call; - struct warn warn; - struct from from; - struct end end; - } u; -}; - -struct stmt *stmt_cur(const struct prv *p); -int stmt_cgen(const struct stmt *s, struct cgen *c); -void stmt_free(struct stmt *s); - -extern const struct seq stmts[]; - -#endif diff --git a/storage.c b/storage.c deleted file mode 100644 index 62f3c1f..0000000 --- a/storage.c +++ /dev/null @@ -1,219 +0,0 @@ -#include "storage.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "prv.h" -#include "type.h" -#include -#include -#include - -static int id(const struct lex *l, struct prv *p); - -static const struct seq seqs[] = -{ - {(struct step[]){{ID}, {0}}, .fn = id}, - {0} -}; - -static int compat(const struct fn *fn, const struct prv *p, - const struct tk *name, const struct type *t, const struct type **ot) -{ - const struct stentry *oe; - const struct fn *top = fn_cur(p); - - /* allow global entries if already found on linkage section - * and vice versa, as long as the types are compatible. */ - if (p->st == top->gl) - { - for (size_t i = 0; i < fn->nimps; i++) - { - const struct im *im = &fn->imps[i]; - - if (compat(im->ast.fns, p, name, t, ot)) - return 1; - } - - if (fn->lk && (oe = storage_find(name->s, fn->lk))) - { - if (t == oe->t) - return 1; - - *ot = oe->t; - return -1; - } - } - else if (p->st == top->lk) - { - if (fn->gl && (oe = storage_find(name->s, fn->gl))) - { - if (t == oe->t) - return 1; - - *ot = oe->t; - return -1; - } - } - - return 0; -} - -static int stpush(const struct lex *l, struct prv *p, const struct tk *name, - const struct type *t) -{ - int ret = -1; - struct stentry *entries; - struct storage *st = p->st; - size_t n = st->nentries + 1; - const struct fn *fn = fn_cur(p); - const struct loc *loc = &name->loc; - const struct stentry *e; - char *tname = type_name(t); - - if (!tname) - goto end; - else if (!t->sz && p->st != fn->lk) - { - errloc(name + 1, "type \"%s\" has null size", tname); - goto end; - } - else if (st->check && (e = fn_var(fn, name))) - { - const struct loc *loc = &e->tk->loc; - const struct type *ot; - int ret = compat(fn, p, name, t, &ot); - - if (ret < 0) - { - errloc(name, "variable \"%s\" (\"%s\") already defined at " - "%s:%d:%d with incompatible type (\"%s\")", - name->s, type_name(t), loc->f, loc->line, loc->col, - type_name(ot)); - goto end; - } - else if (!ret) - { - errloc(name, "variable \"%s\" already defined at %s:%d:%d", - name->s, loc->f, loc->line, loc->col); - goto end; - } - } - - /* find var in currently known symbols */ - for (size_t i = 0; i < st->nentries; i++) - { - const struct stentry *e = &st->entries[i]; - const struct tk *tk = e->tk; - - if (!strcmp(name->s, tk->s)) - { - const struct loc *loc = &tk->loc; - - errloc(tk, "variable \"%s\" already defined at %s:%d:%d", - tk->s, loc->f, loc->line, loc->col); - goto end; - } - } - - if (pop(l, p)) - goto end; - else if (!(entries = realloc(st->entries, n * sizeof *entries))) - { - perror("realloc(3)"); - goto end; - } - - if (t->sz) - st->offset += st->offset % t->sz; - - entries[st->nentries++] = (struct stentry) - { - .t = t, - .tk = name, - .offset = st->offset - }; - - st->entries = entries; - st->offset += t->sz; - p->stk = p->tk; - - if (p->proto) - fputc('\t', stderr); - - fprintf(stderr, "\tadding %s (%d:%d) to %s, type %s, offset %zu, " - "size %zu\n", name->s, loc->line, loc->col, st->name, tname, - entries[st->nentries - 1].offset, t->sz); - ret = 1; -end: - free(tname); - return ret; -} - -static int v(const struct lex *l, struct prv *p, const struct type *t) -{ - return stpush(l, p, p->id, t); -} - -static int id(const struct lex *l, struct prv *p) -{ - p->id = p->stk; - return type(l, p, v); -} - -void storage_free(struct storage *s) -{ - if (s) - free(s->entries); - - free(s); -} - -const struct stentry *storage_find(const char *name, const struct storage *s) -{ - for (size_t i = 0; i < s->nentries; i++) - { - const struct stentry *e = &s->entries[i]; - - if (!strcmp(name, e->tk->s)) - return e; - } - - return NULL; -} - -int storage(const struct lex *l, struct prv *p, const char *name, int check, - struct storage **out) -{ - struct storage *st = NULL; - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - if (*out) - { - const struct loc *loc = &(*out)->tk->loc; - - errloc(p->stk, "%s already defined at %s:%d:%d", name, loc->f, - loc->line, loc->col); - goto failure; - } - else if (!(st = malloc(sizeof *st))) - { - perror("malloc(3)"); - goto failure; - } - else if (push(&init, p)) - goto failure; - - *st = (struct storage){.name = name, .tk = p->stk, .check = check}; - *out = p->st = st; - p->stk = p->tk; - return 1; - -failure: - free(st); - return -1; -} diff --git a/storage.h b/storage.h deleted file mode 100644 index a3509c5..0000000 --- a/storage.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef STORAGE_H -#define STORAGE_H - -#include "lex.h" -#include "prv.h" -#include - -struct stentry -{ - const struct tk *tk; - const struct type *t; - size_t offset; -}; - -struct storage -{ - const char *name; - const struct tk *tk; - struct stentry *entries; - size_t nentries, offset; - int check; -}; - -int storage(const struct lex *l, struct prv *p, const char *name, int check, - struct storage **out); -const struct stentry *storage_find(const char *name, const struct storage *s); -void storage_free(struct storage *s); - -#endif diff --git a/td.c b/td.c deleted file mode 100644 index 72c379f..0000000 --- a/td.c +++ /dev/null @@ -1,587 +0,0 @@ -#include "td.h" -#include "div.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include "storage.h" -#include "type.h" -#include -#include -#include -#include -#include -#include - -static int cid(const struct lex *, struct prv *); -static int cnum(const struct lex *, struct prv *); -static int end(const struct lex *, struct prv *); -static int endp(const struct lex *, struct prv *); -static int u(const struct lex *, struct prv *); -static int s(const struct lex *, struct prv *); -static int c(const struct lex *, struct prv *); -static int a(const struct lex *, struct prv *); -static int p(const struct lex *, struct prv *); - -static const struct seq seqs[] = -{ - {(struct step[]){{ID, "end"}, {0}}, .fn = end}, - {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {ID}, {0}}, .fn = cid}, - {(struct step[]){{ID}, {ID, "constant"}, {ID, "to"}, {NUM}, {0}}, .fn = cnum}, - {(struct step[]){{ID}, {ID, "alias"}, {0}}, .fn = a}, - {(struct step[]){{ID}, {ID, "union"}, {0}}, .fn = u}, - {(struct step[]){{ID}, {ID, "struct"}, {0}}, .fn = s}, - {(struct step[]){{ID}, {ID, "constant"}, {0}}, .fn = c}, - {(struct step[]){{ID}, {ID, "prototype"}, {0}}, .fn = p, .end = endp}, - {0} -}; - -static void reset(struct prv *p) -{ - struct pos *pos = &p->pos[p->i]; - - pos->seq = seqs; - pos->step = seqs->steps; - p->stk = p->tk; -} - -static int bump(const struct tk *tk, const struct type *t, struct prv *p) -{ - struct tdconstant *tdc = p->tdc; - int neg = 0; - - if (!t->sign) - { - unsigned long long uv = t->u.c.uv; - - if (uv + 1 < uv) - { - errloc(tk, "constant value exceeds maximum (%llu)", ULLONG_MAX); - return -1; - } - - tdc->u.uv = ++uv; - } - else - { - long long v = t->u.c.v; - - if (++v < 0) - neg = 1; - - tdc->u.v = v; - } - - tdc->neg = neg; - - for (size_t i = 0; i < p->block; i++) - fputc('\t', stderr); - - fprintf(stderr, "\t\tnext %s constant value set to ", - neg ? "negative" : "positive"); - - if (neg) - fprintf(stderr, "%lld", tdc->u.v); - else - fprintf(stderr, "%llu", tdc->u.uv); - - fputc('\n', stderr); - return 0; -} - -static int cid(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - const struct tk *id = p->stk, *v = p->stk + 3; - const struct stentry *e; - const struct type *t = type_find(fn, id->s); - struct tdconstant *tdc = p->tdc; - struct td *td = fn->td; - size_t n = td->ntypes + 1; - struct type *types, *nt; - - if (t) - { - const struct loc *loc = &t->tk->loc; - - errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, - loc->line, loc->col); - return -1; - } - else if ((e = fn_var(fn, id))) - { - const struct loc *loc = &e->tk->loc; - - errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, - loc->f, loc->line, loc->col); - return -1; - } - else if ((e = fn_var(fn, v))) - { - const struct loc *loc = &e->tk->loc; - - errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", - v->s, loc->f, loc->line, loc->col); - return -1; - } - else if (!(t = type_find(fn, v->s))) - { - errloc(id, "undefined reference to value \"%s\"", v->s); - return -1; - } - else if (t->type != C) - { - const struct loc *loc = &t->tk->loc; - - errloc(id, "value \"%s\" (defined at %s:%d:%d) is not a constant", - v->s, loc->f, loc->line, loc->col); - return -1; - } - else if (!(types = realloc(td->types, n * sizeof *types))) - { - perror("realloc(3)"); - return -1; - } - - td->types = types; - nt = &td->types[td->ntypes++]; - *nt = (struct type) - { - .type = C, - .tk = id, - .sign = t->sign, - .u.c = t->u.c - }; - - tdc->neg = t->sign; - - if (bump(id, t, p)) - return -1; - - for (size_t i = 0; i < p->block; i++) - fputc('\t', stderr); - - fprintf(stderr, "\tadding constant %s to %s (%lld)\n", id->s, v->s, - t->u.c.v); - reset(p); - return 1; -} - -static int cnum(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - const struct tk *id = p->stk, *num = p->stk + 3; - const char *name = id->s; - const struct stentry *e; - struct td *td = fn->td; - size_t n = td->ntypes + 1; - struct type *types, *nt; - struct tdconstant *tdc = p->tdc; - const struct type *t = type_find(fn, name); - int sign = *num->s == '-'; - unsigned long long uv = 0; - long long v; - char *end; - - errno = 0; - v = strtoll(num->s, &end, 0); - - if (!sign || errno || *end) - { - errno = 0; - uv = strtoull(num->s, NULL, 0); - } - - if (t) - { - const struct loc *loc = &t->tk->loc; - - errloc(id, "type \"%s\" already defined at %s:%d:%d", name, loc->f, - loc->line, loc->col); - return -1; - } - else if ((e = fn_var(fn, id))) - { - const struct loc *loc = &e->tk->loc; - - errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, - loc->f, loc->line, loc->col); - return -1; - } - else if (!(types = realloc(td->types, n * sizeof *types))) - { - perror("realloc(3)"); - return -1; - } - - td->types = types; - nt = &td->types[td->ntypes++]; - *nt = (struct type) - { - .type = C, - .tk = id, - .sign = sign - }; - - if (sign) - tdc->u.v = nt->u.c.v = v; - else - tdc->u.uv = nt->u.c.uv = uv; - - tdc->neg = sign; - - for (size_t i = 0; i < p->block; i++) - fputc('\t', stderr); - - fprintf(stderr, "\tadding constant %s to %s\n", id->s, num->s); - - if (bump(id, nt, p)) - return -1; - - reset(p); - return 1; -} - -static int c(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - const struct tk *id = p->stk; - const struct stentry *e; - const struct type *t = type_find(fn, id->s); - struct td *td = fn->td; - size_t n = td->ntypes + 1; - struct type *types, *nt; - const struct tdconstant *tdc = p->tdc; - - if (t) - { - const struct loc *loc = &t->tk->loc; - - errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, - loc->line, loc->col); - return -1; - } - else if ((e = fn_var(fn, id))) - { - const struct loc *loc = &e->tk->loc; - - errloc(id, "\"%s\" already defined as a variable at %s:%d:%d", id->s, - loc->f, loc->line, loc->col); - return -1; - } - else if (!(types = realloc(td->types, n * sizeof *types))) - { - perror("realloc(3)"); - return -1; - } - - td->types = types; - nt = &td->types[td->ntypes]; - *nt = (struct type) - { - .type = C, - .tk = id, - .sign = tdc->neg, - }; - - if (nt->sign) - nt->u.c.v = tdc->u.v; - else - nt->u.c.uv = tdc->u.uv; - - for (size_t i = 0; i < p->block; i++) - fputc('\t', stderr); - - fprintf(stderr, "\tadding constant %s to ", id->s); - - if (tdc->neg) - fprintf(stderr, "%lld", tdc->u.v); - else - fprintf(stderr, "%llu", tdc->u.uv); - - fputc('\n', stderr); - - if (bump(id, &td->types[td->ntypes++], p)) - return -1; - - reset(p); - return 1; -} - -static int p(const struct lex *l, struct prv *p) -{ - struct fn *fn = fn_cur(p), *pt = NULL; - struct td *td = fn->td; - size_t n = td->ntypes + 1; - struct type *types; - - if (!(pt = malloc(sizeof *pt))) - { - perror("malloc(3)"); - goto failure; - } - - *pt = (struct fn){.tk = p->stk, .parent = fn}; - - if (!(types = realloc(td->types, n * sizeof *types))) - { - perror("realloc(3)"); - goto failure; - } - - types[td->ntypes++] = (struct type) - { - .type = P, - .tk = p->stk, - .sz = sizeof (void *), - .align = sizeof (void *), - .u.p.fn = pt - }; - - td->types = types; - p->proto = pt; - fprintf(stderr, "\tadding prototype %s\n", p->stk->s); - return div_p(l, p); - -failure: - free(pt); - return -1; -} - -static int ends(struct type *t) -{ - const struct s *s = &t->u.s; - const struct storage *st = s->storage; - const struct stentry *e; - - if (!st->nentries) - { - errloc(t->tk, "struct \"%s\" has no members", t->tk->s); - return -1; - } - - e = &st->entries[st->nentries - 1]; - t->align = st->entries->t->align; - t->sz = e->offset + e->t->sz; - t->sz += t->align - (t->sz % t->align); - fprintf(stderr, "\tadding struct %s, size %zu, align %zu\n", t->tk->s, - t->sz, t->align); - return 0; -} - -static int endu(struct type *t) -{ - const struct u *u = &t->u.u; - - if (!u->storage->nentries) - { - errloc(t->tk, "union \"%s\" has no members", t->tk->s); - return -1; - } - - return 0; -} - -static int end(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->tk - 1; - struct type *t; - - if (!p->block) - { - errloc(tk, "unexpected \"end\" statement"); - return -1; - } - else if (!(t = p->ag)) - { - errloc(tk, "unreachable"); - return -1; - } - - switch (t->type) - { - case U: - if (endu(t)) - return -1; - - break; - - case S: - if (ends(t)) - return -1; - - break; - - default: - errloc(tk, "unreachable"); - return -1; - } - - p->ag = NULL; - p->block--; - reset(p); - return 1; -} - -static int endp(const struct lex *l, struct prv *p) -{ - if (fn_end(l, p)) - return -1; - - p->proto = NULL; - return 0; -} - -static int s(const struct lex *l, struct prv *p) -{ - const struct tk *id = p->stk; - struct fn *fn = fn_cur(p); - struct td *td = fn->td; - size_t nt = td->ntypes + 1; - struct type *types, *newt; - const struct type *t = type_find(fn, id->s); - - if (t) - { - const struct loc *loc = &t->tk->loc; - - errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, - loc->line, loc->col); - return -1; - } - else if (!(types = realloc(td->types, nt * sizeof *types))) - { - perror("realloc(3)"); - return -1; - } - - td->types = types; - newt = &td->types[td->ntypes++]; - *newt = (struct type) - { - .type = S, - .tk = id - }; - - p->ag = newt; - p->block++; - return storage(l, p, id->s, 0, &newt->u.s.storage); -} - -static int u(const struct lex *l, struct prv *p) -{ - fprintf(stderr, "%s: TODO\n", __func__); - return -1; -} - -static int tt(const struct lex *l, struct prv *p, const struct type *t) -{ - int ret = -1; - const struct fn *fn = fn_cur(p); - const struct tk *id = p->id; - const struct type *tp = type_ufind(fn, id->s); - const struct loc *loc = &id->loc; - struct td *td = fn->td; - size_t n = td->ntypes + 1; - struct type *types, *nt; - char *s = type_name(t); - - if (!s) - goto end; - else if (tp) - { - const struct loc *loc = &tp->tk->loc; - - errloc(id, "type \"%s\" already defined at %s:%d:%d", id->s, loc->f, - loc->line, loc->col); - goto end; - } - else if (pop(l, p)) - return -1; - else if (!(types = realloc(td->types, n * sizeof *types))) - { - perror("realloc(3)"); - goto end; - } - - td->types = types; - nt = &td->types[td->ntypes++]; - *nt = (struct type) - { - .type = T, - .tk = id, - .u.t.alias = t - }; - - fprintf(stderr, "\tadding %s (%d:%d) alias %s\n", id->s, loc->line, - loc->col, s); - reset(p); - p->id = NULL; - ret = 1; -end: - free(s); - return ret; -} - -static int a(const struct lex *l, struct prv *p) -{ - p->id = p->stk; - return type(l, p, tt); -} - -void td_free(struct td *td) -{ - if (td) - { - for (size_t i = 0; i < td->ntypes; i++) - type_free(&td->types[i]); - - free(td->types); - } - - free(td); -} - -int td(const struct lex *l, struct prv *p) -{ - const struct tk *tk = p->stk; - struct fn *fn = fn_cur(p); - struct td *td = NULL, *prev = fn->td; - struct tdconstant *tdc = NULL; - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - if (prev) - { - const struct loc *loc = &prev->tk->loc; - - errloc(tk, "types section already defined at %s:%d:%d", loc->f, - loc->line, loc->col); - goto failure; - } - else if (!(td = malloc(sizeof *td)) - || !(tdc = malloc(sizeof *tdc))) - { - perror("malloc(3)"); - goto failure; - } - else if (push(&init, p)) - goto failure; - - *tdc = (struct tdconstant){0}; - *td = (struct td){.tk = tk}; - fn->td = td; - p->tdc = tdc; - p->stk = p->tk; - return 1; - -failure: - free(tdc); - free(td); - return -1; -} diff --git a/td.h b/td.h deleted file mode 100644 index 2e23348..0000000 --- a/td.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TD_H -#define TD_H - -#include "lex.h" -#include "parse.h" -#include "prv.h" - -struct tdconstant -{ - int neg; - - union - { - unsigned long long uv; - long long v; - } u; -}; - -int td(const struct lex *l, struct prv *prv); -void td_free(struct td *td); - -#endif diff --git a/tmp.c b/tmp.c deleted file mode 100644 index c93443f..0000000 --- a/tmp.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "tmp.h" -#include "type.h" -#include -#include -#include - -const struct stentry *tmp_create(struct fn *fn, const struct type *t) -{ - static const char fmt[] = "__tmp%zu"; - int r = snprintf(NULL, 0, fmt, fn->ntmps); - char *s = NULL, *tname = NULL; - struct tmp *tmp; - - if (!(tname = type_name(t))) - goto failure; - else if (r < 0) - { - fprintf(stderr, "%s: snprintf(3) failed\n", __func__); - goto failure; - } - else if (!(s = malloc(r + 1))) - { - perror("malloc(3)"); - goto failure; - } - - snprintf(s, r + 1, fmt, fn->ntmps++); - - if (!(tmp = malloc(sizeof *tmp))) - { - perror("realloc(3)"); - goto failure; - } - - *tmp = (struct tmp) - { - .tk = - { - .type = ID, - .s = s, - .loc.f = "(temporary)" - }, - - .e = - { - .tk = &tmp->tk, - .t = t - } - }; - - if (!fn->tmps) - fn->tmps = tmp; - else - for (struct tmp *t = fn->tmps; t ; t = t->next) - if (!t->next) - { - t->next = tmp; - break; - } - - fprintf(stderr, "\tcreating temporary variable %s, type %s\n", s, tname); - free(tname); - return &tmp->e; - -failure: - free(s); - free(tname); - return NULL; -} diff --git a/tmp.h b/tmp.h deleted file mode 100644 index b62487a..0000000 --- a/tmp.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef TMP_H -#define TMP_H - -#include "parse.h" -#include "storage.h" - -const struct stentry *tmp_create(struct fn *fn, const struct type *t); - -#endif diff --git a/type.c b/type.c deleted file mode 100644 index c7e43d0..0000000 --- a/type.c +++ /dev/null @@ -1,459 +0,0 @@ -#include "type.h" -#include "errloc.h" -#include "fn.h" -#include "lex.h" -#include "parse.h" -#include "prv.h" -#include -#include -#include -#include - -static int aetc(const struct lex *l, struct prv *p); -static int aid(const struct lex *l, struct prv *p); -static int anum(const struct lex *l, struct prv *p); -static int p(const struct lex *l, struct prv *p); -static int t(const struct lex *l, struct prv *p); - -static const struct seq seqs[] = -{ - {(struct step[]) - {{ID, "array"}, {ID, "of"}, {ID, "etc"}, {0}}, .fn = aetc}, - {(struct step[]){{ID, "array"}, {ID, "of"}, {NUM}, {0}}, .fn = anum}, - {(struct step[]){{ID, "array"}, {ID, "of"}, {ID}, {0}}, .fn = aid}, - {(struct step[]){{ID, "pointer"}, {ID, "to"}, {0}}, .fn = p}, - {(struct step[]){{ID, "void"}, {0}}, .fn = t}, - {(struct step[]){{ID, "byte"}, {0}}, .fn = t}, - {(struct step[]){{ID, "halfword"}, {0}}, .fn = t}, - {(struct step[]){{ID, "word"}, {0}}, .fn = t}, - {(struct step[]){{ID, "long"}, {0}}, .fn = t}, - {(struct step[]){{ID, "ubyte"}, {0}}, .fn = t}, - {(struct step[]){{ID, "uhalfword"}, {0}}, .fn = t}, - {(struct step[]){{ID, "uword"}, {0}}, .fn = t}, - {(struct step[]){{ID, "ulong"}, {0}}, .fn = t}, - {(struct step[]){{ID}, {0}}, .fn = t}, - {0} -}; - -void type_free(struct type *t) -{ - switch (t->type) - { - case U: - { - struct u *u = &t->u.u; - - storage_free(u->storage); - } - break; - - case S: - { - struct s *s = &t->u.s; - - storage_free(s->storage); - } - break; - - case C: - break; - - case P: - { - struct p *p = &t->u.p; - - fn_free(p->fn); - free(p->fn); - } - break; - - case T: - case ARY: - case PTR: - case BUILTIN: - break; - } -} - -void type_lfree(struct type *t) -{ - if (t->child) - type_lfree(t->child); - - free(t); -} - -static int append(const char *s, char **out) -{ - size_t n = *out ? strlen(*out) : 0; - char *ns = realloc(*out, strlen(s) + n + 1); - - if (!ns) - { - perror("realloc(3)"); - return -1; - } - - strcpy(ns + n, s); - *out = ns; - return 0; -} - -char *type_name(const struct type *t) -{ - char *ret = NULL; - - while (t) - { - int n = -1; - - switch (t->type) - { - case BUILTIN: - n = append(t->u.b.name, &ret); - break; - - case ARY: - { - const struct ary *ary = &t->u.ary; - char s[sizeof "18446744073709551615 "]; - - if (ary->etc) - snprintf(s, sizeof s, "etc "); - else - snprintf(s, sizeof s, "%llu ", t->u.ary.n); - - n = append("array of ", &ret) || append(s, &ret); - break; - } - - case PTR: - n = append("pointer to ", &ret); - break; - - case U: - case S: - case C: - case P: - case T: - n = append(t->tk->s, &ret); - break; - } - - if (n) - { - free(ret); - return NULL; - } - - t = t->child; - } - - return ret; -} - -const struct type *type_ufind(const struct fn *fn, const char *s) -{ - static const struct type builtins[] = - { - {.type = BUILTIN, .u.b.name = "void"}, - {.type = BUILTIN, .u.b.name = "byte", .sz = 1, .sign = 1, .align = 1}, - {.type = BUILTIN, .u.b.name = "halfword", .sz = 2, .sign = 1, .align = 2}, - {.type = BUILTIN, .u.b.name = "word", .sz = 4, .sign = 1, .align = 4}, - {.type = BUILTIN, .u.b.name = "long", .sz = 8, .sign = 1, .align = 8}, - {.type = BUILTIN, .u.b.name = "ubyte", .sz = 1, .align = 1}, - {.type = BUILTIN, .u.b.name = "uhalfword", .sz = 2, .align = 2}, - {.type = BUILTIN, .u.b.name = "uword", .sz = 4, .align = 4}, - {.type = BUILTIN, .u.b.name = "ulong", .sz = 8, .align = 8} - }; - - const struct td *td = fn->td; - - if (fn->parent) - { - const struct type *t = type_find(fn->parent, s); - - if (t) - return t; - } - - for (size_t i = 0; i < sizeof builtins / sizeof *builtins; i++) - { - const struct type *t = &builtins[i]; - - if (!strcmp(t->u.b.name, s)) - return t; - } - - if (td) - for (size_t i = 0; i < td->ntypes; i++) - { - const struct type *t = &td->types[i]; - - if (!strcmp(t->tk->s, s)) - return t; - } - - for (size_t i = 0; i < fn->nimps; i++) - { - const struct type *t = type_ufind(fn->imps[i].ast.fns, s); - - if (t) - return t; - } - - return NULL; -} - -const struct type *type_find(const struct fn *fn, const char *s) -{ - const struct type *t = type_ufind(fn, s); - - if (t && t->type == T) - return t->u.t.alias; - - return t; -} - -static int queue(struct prv *p, struct type *t) -{ - struct type *tt; - struct pos *pos = &p->pos[p->i]; - - if (!(tt = p->t)) - p->t = t; - else - { - while (tt->child) - tt = tt->child; - - tt->child = t; - } - - pos->seq = pos->stseq; - pos->step = pos->seq->steps; - p->stk = p->tk; - return 1; -} - -static int aetc(const struct lex *l, struct prv *p) -{ - struct type *t; - const struct type *tt = p->t; - - while (tt) - { - if (tt->type == ARY && tt->u.ary.etc) - { - errloc(p->stk, "multi-dimensional arrays " - "with unknown size are not allowed"); - return -1; - } - - tt = tt->next; - } - - if (!(t = malloc(sizeof *t))) - { - perror("malloc"); - return -1; - } - - *t = (struct type){.type = ARY, .u.ary.etc = 1}; - return queue(p, t); -} - -static int aid(const struct lex *l, struct prv *p) -{ - const struct tk *qty = p->stk + 2; - const struct type *ct = type_find(fn_cur(p), qty->s); - struct type *t; - unsigned long long v; - - if (!ct) - { - errloc(qty, "undefined reference to type \"%s\"", qty->s); - return -1; - } - else if (ct->type != C) - { - errloc(qty, "type \"%s\" not a constant", qty->s); - return -1; - } - else if (ct->sign) - { - errloc(qty, "type \"%s\" defines a negative constant (%lld)", - qty->s, ct->u.c.v); - return -1; - } - else if (!(v = ct->u.c.uv)) - { - errloc(qty, "constant \"%s\" equals zero and cannot be used " - "for array sizes", qty->s); - return -1; - } - else if (!(t = malloc(sizeof *t))) - { - perror("malloc"); - return -1; - } - - *t = (struct type){.type = ARY, .u.ary.n = v}; - return queue(p, t); -} - -static int anum(const struct lex *l, struct prv *p) -{ - const struct tk *qty = p->stk + 2; - unsigned long long n = strtoull(qty->s, NULL, 0); - struct type *t; - - if (*qty->s == '-' || errno) - { - errloc(qty, "invalid negative size for array"); - return -1; - } - else if (!n) - { - errloc(qty, "array size cannot be zero"); - return -1; - } - else if (!(t = malloc(sizeof *t))) - { - perror("malloc"); - return -1; - } - - *t = (struct type){.type = ARY, .u.ary.n = n}; - return queue(p, t); -} - -static int p(const struct lex *l, struct prv *p) -{ - struct type *t = malloc(sizeof *t), *tt; - - if (!t) - { - perror("malloc"); - return -1; - } - - *t = (struct type) - { - .type = PTR, - .sz = sizeof (void *), - .align = sizeof (void *) - }; - - if ((tt = p->t) && tt->type == ARY) - { - tt->sz = tt->u.ary.n * sizeof (void *); - tt->align = sizeof (void *); - } - - return queue(p, t); -} - -static int aryeq(const struct type *a, const struct type *b) -{ - const struct ary *aa = &a->u.ary, *ab = &b->u.ary; - - return !memcmp(aa, ab, sizeof *aa); -} - -static int eq(const struct type *a, const struct type *b) -{ - for (; a && b; a = a->child, b = b->child) - if (a->type != b->type) - return 0; - else if (a->type == ARY && !aryeq(a, b)) - return 0; - - return !a && !b; -} - -static const struct type *insert(struct prv *p) -{ - struct ast *ast = p->ast; - struct type *a = p->t, *tt = ast->types; - - for (const struct type *b = ast->types; b; b = b->next) - if (eq(a, b)) - { - type_lfree(a); - return b; - } - - if (!ast->types) - ast->types = a; - else - { - while (tt->next) - tt = tt->next; - - tt->next = a; - } - - return a; -} - -static int t(const struct lex *l, struct prv *p) -{ - const struct fn *fn = fn_cur(p); - const struct tk *tk = p->stk; - const struct type *t = type_find(fn, tk->s); - struct type *tt = p->t; - - if (!t) - { - errloc(tk, "undefined reference to type \"%s\"", tk->s); - return -1; - } - else if (tt) - { - struct type *nt = malloc(sizeof *nt); - - if (!nt) - { - perror("malloc(3)"); - return -1; - } - - *nt = *t; - - while (tt->child) - tt = tt->child; - - tt->child = nt; - tt = p->t; - - /* array size still undecided */ - if (tt->type == ARY && !tt->sz) - { - tt->sz = tt->u.ary.n * nt->sz; - tt->align = t->align; - } - - if (!(t = insert(p))) - return -1; - - p->t = NULL; - } - - return p->type(l, p, t); -} - -int type(const struct lex *l, struct prv *p, - int (*fn)(const struct lex *, struct prv *, const struct type *)) -{ - struct pos init = - { - .seq = seqs, - .stseq = seqs, - .step = seqs->steps - }; - - p->stk = p->tk; - p->type = fn; - return push(&init, p) ? -1 : 1; -} diff --git a/type.h b/type.h deleted file mode 100644 index 7de6c28..0000000 --- a/type.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TYPE_H -#define TYPE_H - -#include "lex.h" -#include "prv.h" -#include "parse.h" - -const struct type *type_ufind(const struct fn *fn, const char *s); -const struct type *type_find(const struct fn *fn, const char *s); -char *type_name(const struct type *t); -int type(const struct lex *l, struct prv *p, - int (*fn)(const struct lex *, struct prv *p, const struct type *t)); -void type_free(struct type *t); -void type_lfree(struct type *t); - -#endif diff --git a/warn.c b/warn.c deleted file mode 100644 index 456ce79..0000000 --- a/warn.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "warn.h" -#include "cgen.h" -#include "parse.h" -#include "prv.h" -#include "stmt.h" -#include "storage.h" -#include -#include -#include - -static int finalize(const struct lex *l, const struct prv *p, - const struct print *pr) -{ - const struct ast *ast = p->ast; - struct fn *fn = &ast->fns[ast->nfns - 1]; - size_t n = fn->nstmts + 1; - struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); - - if (!stmts) - { - perror("realloc(3)"); - return -1; - } - - fn->stmts = stmts; - fn->stmts[fn->nstmts++] = (struct stmt) - { - .type = WARN, - .u.warn.p = *pr - }; - - fprintf(stderr, "\t\tadding warn statement with %zu entries%s\n", - pr->nentries, pr->println ? "" : ", no lf"); - return 0; -} - -static int cg_val(const struct tk *tk) -{ - const char *num = tk->s; - int neg = *num == '-'; - unsigned long long uv; - char *end; - - fputs("call $printf(l $____fmt", stdout); - errno = 0; - uv = strtoull(num, &end, 16); - - if (!neg && !errno && !*end) - printf("lx, ..., l %llu )\n", uv); - else - { - errno = 0; - uv = strtoull(num, &end, 0); - - if (neg || errno || *end) - { - long long v = strtoll(num, NULL, 0); - printf("l, ..., l %lld )\n", v); - } - else - printf("l, ..., l %llu )\n", uv); - } - - return 0; -} - -static int cg_lit(const struct prientry *e) -{ - const struct lit *l = e->lit; - const char *tmp; - - if (!l) - { - fprintf(stderr, "%s: unexpected null literal\n", __func__); - return -1; - } - - printf("%%%s =l loadl $stderr\n", (tmp = cgen_tmp(sizeof (void *)))); - printf("call $fputs(l $%s, w %%%s)\n", l->name, tmp); - return 0; -} - -static int cg_id(const struct prientry *de, const struct fn *fn) -{ - const struct stentry *e = de->entry; - const struct type *t = e->t; - const char *id = e->tk->s; - int global = cgen_global(fn, e); - size_t sz = t->sz; - const char *asz = cgen_sz(sz < 4 ? 4 : sz), *tmp = cgen_tmp(sz); - - if (global) - printf("%%%s =%s load%s $%s\n", tmp, asz, cgen_load(t), id); - else - printf("%%%s =%s load%s %%%s_\n", tmp, asz, cgen_load(t), id); - - puts("%z =l loadl $stderr"); - fputs("call $fprintf(w %z, l $____fmt", stdout); - - if (t->type == PTR) - fputs("lx, ..., l ", stdout); - else - printf("%s, ..., %s ", cgen_type(t), asz); - - printf("%%%s)\n", tmp); - - return 0; -} - -int warn_cgen(const struct warn *w, struct cgen *c) -{ - const struct print *p = &w->p; - - for (size_t i = 0; i < p->nentries; i++) - { - const struct prientry *e = &p->entries[i]; - const struct tk *tk = e->tk; - - if (tk->type == LIT && cg_lit(e)) - return -1; - else if (tk->type == NUM && cg_val(tk)) - return -1; - else if (tk->type == ID && e->entry && cg_id(e, c->fn)) - return -1; - else if (tk->type == ID && e->lit && cg_lit(e)) - return -1; - } - - if (p->println) - { - puts("%v =l loadl $stderr"); - puts("call $fputc(l 10 , w %v)"); - } - - return 0; -} - -void warn_free(struct warn *w) -{ - print_free(&w->p); -} - -int warn(const struct lex *l, struct prv *p) -{ - return print(l, p, finalize); -} diff --git a/warn.h b/warn.h deleted file mode 100644 index 5327592..0000000 --- a/warn.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WARN_H -#define WARN_H - -#include "lex.h" -#include "print.h" -#include "prv.h" - -struct warn -{ - struct print p; -}; - -int warn(const struct lex *l, struct prv *p); -int warn_cgen(const struct warn *w, struct cgen *c); -void warn_free(struct warn *w); - -#endif diff --git a/ws.c b/ws.c deleted file mode 100644 index 59e1aec..0000000 --- a/ws.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "ws.h" -#include "fn.h" -#include "prv.h" -#include "parse.h" -#include "storage.h" - -static int wspush(const struct stentry *e, struct cgen *c) -{ - const struct type *t = e->t; - - printf("%%%s_ =l alloc%zu %zu\n", e->tk->s, t->align, t->sz); - return 0; -} - -int ws_cgen(const struct storage *s, struct cgen *c) -{ - for (size_t i = 0; i < s->nentries; i++) - if (wspush(&s->entries[i], c)) - return -1; - - return 0; -} - -int ws(const struct lex *l, struct prv *p) -{ - struct fn *fn = fn_cur(p); - - return storage(l, p, "storage section", 1, &fn->ws); -} diff --git a/ws.h b/ws.h deleted file mode 100644 index fa44a37..0000000 --- a/ws.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef WS_H -#define WS_H - -#include "lex.h" -#include "cgen.h" -#include "prv.h" - -int ws(const struct lex *l, struct prv *p); -int ws_cgen(const struct storage *s, struct cgen *c); -extern const struct seq wsseq[]; - -#endif -- cgit v1.2.3