diff options
Diffstat (limited to 'src/prc1')
57 files changed, 5875 insertions, 0 deletions
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 <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> + +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 <stddef.h> +#include <stdlib.h> +#include <string.h> + +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 <errno.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +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 <stddef.h> + +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 <stdarg.h> +#include <stdio.h> + +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 <stddef.h> + +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 <stdlib.h> +#include <stdio.h> +#include <string.h> + +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 <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> + +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 <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> +#include <string.h> + +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 <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +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 <stddef.h> +#include <stdio.h> + +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 <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +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 <stddef.h> +#include <stdlib.h> +#include <string.h> + +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 <stdlib.h> + +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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +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 <stdlib.h> +#include <string.h> + +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 <stddef.h> + +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 <stddef.h> + +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 <stdlib.h> + +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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +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 <stddef.h> + +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 <stddef.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> + +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 <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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 <errno.h> +#include <stdlib.h> +#include <string.h> + +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 |
