strongly connected components
[ccc.git] / scc.c
diff --git a/scc.c b/scc.c
index a3743e2..bf8a8b4 100644 (file)
--- a/scc.c
+++ b/scc.c
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <string.h>
 #include <stdlib.h>
 
+#include "ast.h"
 #include "list.h"
-#include "util.h"
-#include "scc.h"
+#include "tarjan.h"
 
-struct node {
-       int lowlink;
-       int index;
-       bool onStack;
-       void *data;
-};
-
-int ptrcmp(const void *l, const void *r)
+int iddeclcmp(const void *l, const void *r)
 {
-       return ((ptrdiff_t)((struct node *)l)->data)
-               -((ptrdiff_t)((struct node *)r)->data);
+       return strcmp((char *)l, (*(struct decl **)r)->data.dfun->ident);
 }
 
-int nodecmp(const void *l, const void *r)
+struct list *edges_expr(int ndecls, struct decl **decls, void *parent,
+       struct expr *expr, struct list *l)
 {
-       return ((ptrdiff_t)l) -((ptrdiff_t)((struct node *)r)->data);
+       if (expr == NULL)
+               return l;
+       switch(expr->type) {
+       case ebinop:
+               l = edges_expr(ndecls, decls, parent, expr->data.ebinop.l, l);
+               l = edges_expr(ndecls, decls, parent, expr->data.ebinop.r, l);
+               break;
+       case ebool:
+               break;
+       case echar:
+               break;
+       case efuncall:
+               for(int i = 0; i<expr->data.efuncall.nargs; i++)
+                       l = edges_expr(ndecls, decls, parent,
+                               expr->data.efuncall.args[i], l);
+               struct decl **to = bsearch(expr->data.efuncall.ident, decls,
+                       ndecls, sizeof(struct decl *), iddeclcmp);
+               if (to == NULL) {
+                       fprintf(stderr, "calling an unknown function\n");
+               } else {
+                       struct edge *edge = safe_malloc(sizeof(struct edge));
+                       edge->from = parent;
+                       edge->to = (void *)*to;
+                       l = list_cons(edge, l);
+               }
+               break;
+       case eint:
+               break;
+       case eident:
+               break;
+       case enil:
+               break;
+       case etuple:
+               l = edges_expr(ndecls, decls, parent,
+                       expr->data.etuple.left, l);
+               l = edges_expr(ndecls, decls, parent,
+                       expr->data.etuple.right, l);
+               break;
+       case estring:
+               break;
+       case eunop:
+               l = edges_expr(ndecls, decls, parent, expr->data.eunop.l, l);
+               break;
+       default:
+               die("Unsupported expr node\n");
+       }
+       return l;
 }
 
-struct components *strongconnect(struct node *v, struct node **stack, int *sp,
-       int *index, int nedges, struct edge *edges, struct components *components)
+struct list *edges_stmt(int ndecls, struct decl **decls, void *parent,
+               struct stmt *stmt, struct list *l)
 {
-       struct node *w;
-       v->index = *index;
-       v->lowlink = *index;
-       (*index)++;
-       stack[(*sp)++] = v;
-       v->onStack = true;
-
-       for (int i = 0; i<nedges; i++) {
-               if (edges[i].from != v)
-                       continue;
-               w = edges[i].to;
-               if (w->index == -1) {
-                       components = strongconnect(w, stack, sp, index,
-                               nedges, edges, components);
-               } else if (w->onStack) {
-                       v->lowlink = min(v->lowlink, w->index);
-               }
+       switch(stmt->type) {
+       case sassign:
+               l = edges_expr(ndecls, decls, parent,
+                       stmt->data.sassign.expr, l);
+               break;
+       case sif:
+               l = edges_expr(ndecls, decls, parent, stmt->data.sif.pred, l);
+               for (int i = 0; i<stmt->data.sif.nthen; i++)
+                       l = edges_stmt(ndecls, decls, parent,
+                               stmt->data.sif.then[i], l);
+               for (int i = 0; i<stmt->data.sif.nels; i++)
+                       l = edges_stmt(ndecls, decls, parent,
+                               stmt->data.sif.els[i], l);
+               break;
+       case sreturn:
+               l = edges_expr(ndecls, decls, parent, stmt->data.sreturn, l);
+               break;
+       case sexpr:
+               l = edges_expr(ndecls, decls, parent, stmt->data.sexpr, l);
+               break;
+       case svardecl:
+               l = edges_expr(ndecls, decls, parent,
+                       stmt->data.svardecl->expr, l);
+               break;
+       case swhile:
+               l = edges_expr(ndecls, decls, parent,
+                       stmt->data.swhile.pred, l);
+               for (int i = 0; i<stmt->data.swhile.nbody; i++)
+                       l = edges_stmt(ndecls, decls, parent,
+                               stmt->data.swhile.body[i], l);
+               break;
+       default:
+               die("Unsupported stmt node\n");
        }
+       return l;
+}
 
-       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;
+int declcmp(const void *l, const void *r)
+{
+       return (*(struct decl **)l)->type - (*(struct decl **)r)->type;
 }
 
-struct components *scc(int nnodes, void **nodedata, int nedges, struct edge *edgedata)
+struct ast *ast_scc(struct ast *ast)
 {
-       struct components *res = NULL;
-       struct node *nodes = safe_malloc(nnodes*sizeof(struct node));
-       for (int i = 0; i<nnodes; i++)
-               nodes[i] = (struct node){.lowlink=-1, .index=-1,
-                       .onStack=false, .data=nodedata[i]};
-       qsort(nodes, nnodes, sizeof(struct node), ptrcmp);
+       //Sort so that the functions are at the end
+       qsort(ast->decls, ast->ndecls, sizeof(struct decl *), declcmp);
+       //Index of the first function
+       int ffun;
+       for (ffun = 0; ffun<ast->ndecls; ffun++)
+               if (ast->decls[ffun]->type == dfundecl)
+                       break;
+       //Number of functions
+       int nfun = ast->ndecls-ffun;
 
-       struct edge *edges = safe_malloc(nedges*sizeof(struct edge));
-       for (int i = 0; i<nedges; i++) {
-               struct node *from = bsearch(edgedata[i].from, nodes, nnodes,
-                       sizeof(struct node), nodecmp);
-               if (from == NULL) {
-                       fprintf(stderr, "edge from references unknown node\n");
-                       goto end;
-               }
-               struct node *to = bsearch(edgedata[i].to, nodes, nnodes,
-                       sizeof(struct node), nodecmp);
-               if (to == NULL) {
-                       fprintf(stderr, "edge to references unknown node\n");
-                       goto end;
+       //Calculate the edges
+       struct decl **fundecls = ast->decls+ffun;
+       struct list *edges = NULL;
+       for (int i = 0; i<nfun; i++)
+               for (int j = 0; j<fundecls[i]->data.dfun->nbody; j++)
+                       edges = edges_stmt(nfun, fundecls, fundecls[i],
+                               fundecls[i]->data.dfun->body[j], edges);
+       int nedges;
+       struct edge **edgedata = (struct edge **)
+               list_to_array(edges, &nedges, false);
+
+       // Do tarjan's and convert back into the declaration list
+       struct components *cs = scc(nfun, (void **)fundecls, nedges, edgedata);
+       int i = ffun;
+       FOREACHCOMP(c, cs) {
+               struct decl *d = safe_malloc(sizeof(struct decl));
+               if (c->nnodes > 1) {
+                       d->type = dcomp;
+                       d->data.dcomp.ndecls = c->nnodes;
+                       d->data.dcomp.decls = safe_malloc(
+                               c->nnodes*sizeof(struct fundecl *));
+                       for (int i = 0; i<c->nnodes; i++)
+                               d->data.dcomp.decls[i] =
+                                       ((struct decl *)c->nodes[i])->data.dfun;
+               } else {
+                       d->type = dfundecl;
+                       d->data.dfun = ((struct decl *)c->nodes[0])->data.dfun;
                }
-               edges[i] = (struct edge){.from=from, .to=to};
+               ast->decls[i++] = d;
        }
+       ast->ndecls = i;
 
-       struct node **stack = safe_malloc(nnodes*sizeof(struct node *));
-       int sp = 0;
-       int index = 0;
-       for (int i = 0; i < nnodes; i++)
-               if (nodes[i].index == -1)
-                       res = strongconnect(&nodes[i], stack, &sp, &index,
-                               nedges, edges, res);
-end:
-       free(stack);
-       free(nodes);
-       free(edges);
-       return res;
-}
-
-void components_free(struct components *cs, void (*freefun)(void *))
-{
-       while (cs != NULL) {
-               if (freefun != NULL)
-                       for (int i = 0; i<cs->nnodes; i++)
-                               freefun(cs->nodes[i]);
-               free(cs->nodes);
-               struct components *t = cs->next;
-               free(cs);
-               cs = t;
-       }
+       //Cleanup
+       for (int i = 0; i<nedges; i++)
+               free(edgedata[i]);
+       free(edgedata);
+       components_free(cs, free);
+       return ast;
 }
-//
-//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; i<c->nnodes; i++)
-//                     fprintf(stderr, "%d, ", c->nodes[i]);
-//             fprintf(stderr, "\n");
-//     }
-//     components_free(cs, NULL);
-//}