From: Mart Lubbers Date: Thu, 11 Feb 2021 13:15:08 +0000 (+0100) Subject: add scc and update other code X-Git-Url: https://git.martlubbers.net/?a=commitdiff_plain;h=b4f2044dd15f91bfa6089b7de6ba42fd29942c0a;p=ccc.git add scc and update other code --- diff --git a/Makefile b/Makefile index 749b3fd..949b3e8 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CFLAGS+=-Wall -Wextra -std=c99 -pedantic -D_XOPEN_SOURCE=700 -ggdb YFLAGS+=-d --locations -v --defines=parse.h LFLAGS+=--header-file=scan.h -OBJECTS:=scan.o parse.o ast.o util.o type.o genc.o +OBJECTS:=scan.o parse.o ast.o util.o list.o type.o genc.o scc.o all: splc splc: $(OBJECTS) diff --git a/ast.c b/ast.c index 2bfcf43..e9ebb56 100644 --- a/ast.c +++ b/ast.c @@ -289,7 +289,7 @@ void ast_print(struct ast *ast, FILE *out) if (ast == NULL) return; for (int i = 0; indecls; i++) - decl_print(ast->decls[i], 0, out); + decl_print(ast->decls[i], out); } void vardecl_print(struct vardecl *decl, int indent, FILE *out) @@ -304,13 +304,12 @@ void vardecl_print(struct vardecl *decl, int indent, FILE *out) safe_fprintf(out, ";\n"); } -void decl_print(struct decl *decl, int indent, FILE *out) +void decl_print(struct decl *decl, FILE *out) { if (decl == NULL) return; switch(decl->type) { case dfundecl: - pindent(indent, out); safe_fprintf(out, "%s (", decl->data.dfun.ident); for (int i = 0; idata.dfun.nargs; i++) { safe_fprintf(out, "%s", decl->data.dfun.args[i]); @@ -329,12 +328,15 @@ void decl_print(struct decl *decl, int indent, FILE *out) } safe_fprintf(out, " {\n"); for (int i = 0; idata.dfun.nbody; i++) - stmt_print(decl->data.dfun.body[i], indent+1, out); - pindent(indent, out); + stmt_print(decl->data.dfun.body[i], 1, out); safe_fprintf(out, "}\n"); break; case dvardecl: - vardecl_print(decl->data.dvar, indent, out); + vardecl_print(decl->data.dvar, 0, out); + break; + case dcomponent: + for (int i = 0; idata.dcomponent.ndecls; i++) + decl_print(decl, out); break; default: die("Unsupported decl node\n"); @@ -517,6 +519,11 @@ void decl_free(struct decl *decl) if (decl == NULL) return; switch(decl->type) { + case dcomponent: + for (int i = 0; idata.dcomponent.ndecls; i++) + decl_free(decl->data.dcomponent.decls[i]); + free(decl->data.dcomponent.decls); + break; case dfundecl: free(decl->data.dfun.ident); for (int i = 0; idata.dfun.nargs; i++) diff --git a/ast.h b/ast.h index b797c57..bea8b7c 100644 --- a/ast.h +++ b/ast.h @@ -37,8 +37,12 @@ struct type { }; struct decl { - enum {dfundecl, dvardecl} type; + enum {dcomponent, dfundecl, dvardecl} type; union { + struct { + int ndecls; + struct decl **decls; + } dcomponent; struct { char *ident; int nargs; @@ -158,7 +162,7 @@ struct type *type_var(char *ident); void ast_print(struct ast *, FILE *out); void vardecl_print(struct vardecl *decl, int indent, FILE *out); -void decl_print(struct decl *ast, int indent, FILE *out); +void decl_print(struct decl *ast, FILE *out); void stmt_print(struct stmt *ast, int indent, FILE *out); void expr_print(struct expr *ast, FILE *out); void type_print(struct type *type, FILE *out); diff --git a/genc.c b/genc.c index 10f3d4f..617bcf6 100644 --- a/genc.c +++ b/genc.c @@ -2,9 +2,7 @@ #include "ast.h" -#define gdie(msg) { fprintf(stderr, "%s", msg); return 1; } - -int expr_genc(struct expr *expr, FILE *cout); +void expr_genc(struct expr *expr, FILE *cout); void binop_genc(char *fun, struct expr *l, struct expr *r, FILE *cout) { @@ -15,12 +13,11 @@ void binop_genc(char *fun, struct expr *l, struct expr *r, FILE *cout) safe_fprintf(cout, ")"); } -int expr_genc(struct expr *expr, FILE *cout) +void expr_genc(struct expr *expr, FILE *cout) { - int r = 0; char buf[] = "\\x55"; if (expr == NULL) - return 0; + return; switch(expr->type) { case ebinop: if (expr->type == ebinop && expr->data.ebinop.op == cons) { @@ -87,45 +84,39 @@ int expr_genc(struct expr *expr, FILE *cout) default: die("Unknown expression node\n"); } - return r; } -int type_genc(struct type *type, FILE *cout) +void type_genc(struct type *type, FILE *cout) { - if (type == NULL) { + if (type == NULL) + die("unresolved var type\n"); + switch(type->type) { + case tbasic: fprintf(cout, "WORD "); - } else { - switch(type->type) { - case tbasic: - fprintf(cout, "WORD "); - break; - case tlist: - fprintf(cout, "struct splc_list *"); - break; - case ttuple: - fprintf(cout, "struct splc_tuple *"); - break; - case tvar: - fprintf(cout, "WORD "); - break; - default: - die("Unsupported type node\n"); - } + break; + case tlist: + fprintf(cout, "struct splc_list *"); + break; + case ttuple: + fprintf(cout, "struct splc_tuple *"); + break; + case tvar: + fprintf(cout, "WORD "); + break; + default: + die("Unsupported type node\n"); } - return 0; } -int vardecl_genc(struct vardecl *vardecl, int indent, FILE *cout) +void vardecl_genc(struct vardecl *vardecl, int indent, FILE *cout) { - int r = 0; if (vardecl == NULL) - return 0; + return; pindent(indent, cout); type_genc(vardecl->type, cout); fprintf(cout, "%s = ", vardecl->ident); - r = expr_genc(vardecl->expr, cout); + expr_genc(vardecl->expr, cout); fprintf(cout, ";\n"); - return r; } void stmt_genc(struct stmt *stmt, int indent, FILE *cout) @@ -185,15 +176,20 @@ void stmt_genc(struct stmt *stmt, int indent, FILE *cout) } } -int decl_genc(struct decl *decl, FILE *cout) +void decl_genc(struct decl *decl, FILE *cout) { switch (decl->type) { + case dcomponent: + //TODO generate prototypes? + for (int i = 0; idata.dcomponent.ndecls; i++) + decl_genc(decl->data.dcomponent.decls[i], cout); + break; case dfundecl: type_genc(decl->data.dfun.rtype, cout); safe_fprintf(cout, "%s (", decl->data.dfun.ident); for (int i = 0; idata.dfun.nargs; i++) { if (i < decl->data.dfun.natypes) - type_genc(decl->data.dfun.atypes[i], cout); + die("function with unmatched type\n"); safe_fprintf(cout, "%s", decl->data.dfun.args[i]); if (i < decl->data.dfun.nargs - 1) safe_fprintf(cout, ", "); @@ -214,12 +210,12 @@ int decl_genc(struct decl *decl, FILE *cout) safe_fprintf(cout, "}\n"); break; case dvardecl: - return vardecl_genc(decl->data.dvar, 0, cout); + vardecl_genc(decl->data.dvar, 0, cout); + break; } - return 0; } -int genc(struct ast *ast, FILE *cout) +void genc(struct ast *ast, FILE *cout) { fprintf(cout, "#include \n" @@ -246,10 +242,8 @@ int genc(struct ast *ast, FILE *cout) "\treturn res;\n" "}\n" ); - int r = 0; - for (int i = 0; indecls && r == 0; i++) { + for (int i = 0; indecls; i++) { fprintf(cout, "\n"); - r = decl_genc(ast->decls[i], cout); + decl_genc(ast->decls[i], cout); } - return r; } diff --git a/genc.h b/genc.h index 37e772d..439b78d 100644 --- a/genc.h +++ b/genc.h @@ -1,11 +1,10 @@ #ifndef GENC_H #define GENC_H -#include #include #include "ast.h" -int genc(struct ast *res, FILE *cout); +void genc(struct ast *res, FILE *cout); #endif diff --git a/list.c b/list.c new file mode 100644 index 0000000..62af95e --- /dev/null +++ b/list.c @@ -0,0 +1,62 @@ +#include +#include + +#include "list.h" +#include "util.h" + +struct list *list_append(void *el, struct list *head) +{ + if (head == NULL) + return list_cons(el, NULL); + struct list *tail = head; + while (tail->tail != NULL) + tail = tail->tail; + tail->tail = list_cons(el, NULL); + return head; +} + +struct list *list_cons(void *el, struct list *tail) +{ + struct list *res = safe_malloc(sizeof(struct list)); + res->el = el; + res->tail = tail; + return res; +} + +void list_free(struct list *head, void (*freefun)(void *)) +{ + while (head != NULL) { + struct list *t = head; + if (freefun != NULL) + freefun(head->el); + head = head->tail; + free(t); + } +} + +void **list_to_array(struct list *list, int *num, bool reverse) +{ + int i = list_length(list); + *num = i; + void **ptr = safe_malloc(i*sizeof(void *)); + + struct list *r = list; + while(i > 0) { + if (reverse) + ptr[--i] = r->el; + else + ptr[*num-(--i)-1] = r->el; + struct list *t = r; + r = r->tail; + free(t); + } + return ptr; +} + +int list_length(struct list *r) +{ + int i = 0; + FOREACH(e, r) + i++; + return i; +} diff --git a/list.h b/list.h new file mode 100644 index 0000000..1cc3fb2 --- /dev/null +++ b/list.h @@ -0,0 +1,19 @@ +#ifndef LIST_H +#define LIST_H + +#include + +#define FOREACH(x, l) for(struct list *x = l; x != NULL; x = x->tail) + +struct list { + void *el; + struct list *tail; +}; + +struct list *list_append(void *el, struct list *head); +struct list *list_cons(void *el, struct list *tail); +void list_free(struct list *head, void (*freefun)(void *)); +void **list_to_array(struct list *list, int *num, bool reverse); +int list_length(struct list *head); + +#endif diff --git a/scc.c b/scc.c new file mode 100644 index 0000000..3c690a2 --- /dev/null +++ b/scc.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include + +#include "list.h" +#include "util.h" +#include "scc.h" + +struct node { + int lowlink; + int index; + bool onStack; + void *data; +}; + +struct edge2 { + struct node *from; + struct node *to; +}; + +int ptrcmp(const void *l, const void *r) +{ + return ((ptrdiff_t)((struct node *)l)->data) + -((ptrdiff_t)((struct node *)r)->data); +} + +int nodecmp(const void *l, const void *r) +{ + return ((ptrdiff_t)l) -((ptrdiff_t)((struct node *)r)->data); +} + +struct components *strongconnect(struct node *v, struct node **stack, int *sp, + int *index, int nedges, struct edge2 *edges, struct components *components) +{ + struct node *w; + v->index = *index; + v->lowlink = *index; + (*index)++; + stack[(*sp)++] = v; + v->onStack = true; + + for (int i = 0; iindex == -1) { + components = strongconnect(w, stack, sp, index, + nedges, edges, components); + } else if (w->onStack) { + v->lowlink = min(v->lowlink, w->index); + } + } + + if (v->lowlink == v->index) { + struct list *res = NULL; + do { + w = stack[--*sp]; + w->onStack = false; + res = list_cons(w->data, res); + } while (w != v); + struct components *ng = safe_malloc(sizeof(struct components)); + ng->next = components; + ng->nodes = list_to_array(res, &ng->nnodes, false); + components = ng; + } + return components; +} + +struct components *scc(int nnodes, void **nodedata, int nedges, struct edge *edgedata) +{ + struct components *res = NULL; + struct node *nodes = safe_malloc(nnodes*sizeof(struct node)); + for (int i = 0; innodes; i++) + freefun(cs->nodes[i]); + free(cs->nodes); + struct components *t = cs->next; + free(cs); + cs = t; + } +} +// +//int main () +//{ +// void *nodes[] = {(void *)1, (void *)2, (void *)3}; +// struct edge edges[] = {{(void *)1, (void *)2}, {(void *)2, (void *)1}}; +// struct components *cs = scc(3, &nodes[0], 2, &edges[0]); +// FOREACHCOMP(c, cs) { +// fprintf(stderr, "comp: "); +// for (int i = 0; innodes; i++) +// fprintf(stderr, "%d, ", c->nodes[i]); +// fprintf(stderr, "\n"); +// } +// components_free(cs, NULL); +//} diff --git a/scc.h b/scc.h new file mode 100644 index 0000000..d7c378e --- /dev/null +++ b/scc.h @@ -0,0 +1,38 @@ +#ifndef SCC_H +#define SCC_H + +#include +struct edge { + void *from; + void *to; +}; + +struct components { + int nnodes; + void **nodes; + struct components *next; +}; +#define FOREACHCOMP(x, l) for(struct components *x = l; x != NULL; x = x->next) + +/** + * Calculate the strongly connected components using Tarjan's algorithm: + * en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + * + * Returns NULL when there are invalid edges + * + * @param number of nodes + * @param data of the nodes + * @param number of edges + * @param data of edges + */ +struct components *scc(int nnodes, void **nodedata, int nedges, struct edge *edgedata); + +/** + * Free a list of components + * + * @param cs components + * @param freefun function to free the data with, if NULL, data isn't freed + */ +void components_free(struct components *cs, void (*free)(void *)); + +#endif diff --git a/splc.c b/splc.c index f4f6682..bee929a 100644 --- a/splc.c +++ b/splc.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) free(cfile); switch(lang) { case langc: - r = genc(result, cout); + genc(result, cout); break; default: die("unsupported language\n"); diff --git a/type.c b/type.c index 3ced0eb..f1828bc 100644 --- a/type.c +++ b/type.c @@ -8,6 +8,9 @@ struct vardecl *type_vardecl(struct vardecl *vardecl) struct decl *type_decl(struct decl *decl) { switch (decl->type) { + case dcomponent: + fprintf(stderr, "type_decl:component unsupported\n"); + break; case dfundecl: fprintf(stderr, "type_decl:fundecl unsupported\n"); break; diff --git a/util.c b/util.c index a3d8bcf..efe22c7 100644 --- a/util.c +++ b/util.c @@ -6,51 +6,6 @@ #include "util.h" -struct list *list_cons(void *el, struct list *tail) -{ - struct list *res = safe_malloc(sizeof(struct list)); - res->el = el; - res->tail = tail; - return res; -} - -void list_free(struct list *head, void (*freefun)(void *)) -{ - while (head != NULL) { - freefun(head->el); - head = head->tail; - } -} - -void **list_to_array(struct list *list, int *num, bool reverse) -{ - int i = list_length(list); - *num = i; - void **ptr = safe_malloc(i*sizeof(void *)); - - struct list *r = list; - while(i > 0) { - if (reverse) - ptr[--i] = r->el; - else - ptr[*num-(--i)] = r->el; - struct list *t = r; - r = r->tail; - free(t); - } - return ptr; -} - -int list_length(struct list *r) -{ - int i = 0; - while(r != NULL) { - i++; - r = r->tail; - } - return i; -} - int fromHex(char c) { if (c >= '0' && c <= '9') diff --git a/util.h b/util.h index 47677a8..ac47fa6 100644 --- a/util.h +++ b/util.h @@ -5,11 +5,7 @@ #include #include -struct list { void *el; struct list *tail; }; -struct list *list_cons(void *el, struct list *tail); -void list_free(struct list *head, void (*freefun)(void *)); -void **list_to_array(struct list *list, int *num, bool reverse); -int list_length(struct list *head); +#define min(x, y) ((x)<(y)?(x):(y)) void die(const char *msg, ...); void pdie(const char *msg);