strongly connected components
authorMart Lubbers <mart@martlubbers.net>
Fri, 12 Feb 2021 14:15:54 +0000 (15:15 +0100)
committerMart Lubbers <mart@martlubbers.net>
Fri, 12 Feb 2021 14:15:54 +0000 (15:15 +0100)
Makefile
ast.c
ast.h
genc.c
parse.y
scc.c
scc.h
splc.c
tarjan.c [new file with mode: 0644]
tarjan.h [new file with mode: 0644]
type.c

index 949b3e8..fe1880a 100644 (file)
--- 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 list.o type.o genc.o scc.o
+OBJECTS:=scan.o parse.o ast.o util.o list.o type.o genc.o scc.o tarjan.o
 
 all: splc
 splc: $(OBJECTS)
diff --git a/ast.c b/ast.c
index 72af738..bb8a541 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -36,20 +36,23 @@ struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr)
        res->expr = expr;
        return res;
 }
-
-struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
+struct fundecl *fundecl(char *ident, struct list *args, struct list *atypes,
        struct type *rtype, struct list *body)
+{
+       struct fundecl *res = safe_malloc(sizeof(struct fundecl));
+       res->ident = ident;
+       res->args = (char **)list_to_array(args, &res->nargs, true);
+       res->atypes = (struct type **)list_to_array(atypes, &res->natypes, true);
+       res->rtype = rtype;
+       res->body = (struct stmt **)list_to_array(body, &res->nbody, true);
+       return res;
+}
+
+struct decl *decl_fun(struct fundecl *fundecl)
 {
        struct decl *res = safe_malloc(sizeof(struct decl));
        res->type = dfundecl;
-       res->data.dfun.ident = ident;
-       res->data.dfun.args = (char **)
-               list_to_array(args, &res->data.dfun.nargs, true);
-       res->data.dfun.atypes = (struct type **)
-               list_to_array(atypes, &res->data.dfun.natypes, true);
-       res->data.dfun.rtype = rtype;
-       res->data.dfun.body = (struct stmt **)
-               list_to_array(body, &res->data.dfun.nbody, true);
+       res->data.dfun = fundecl;
        return res;
 }
 
@@ -305,39 +308,46 @@ void vardecl_print(struct vardecl *decl, int indent, FILE *out)
        safe_fprintf(out, ";\n");
 }
 
+void fundecl_print(struct fundecl *decl, FILE *out)
+{
+       safe_fprintf(out, "%s (", decl->ident);
+       for (int i = 0; i<decl->nargs; i++) {
+               safe_fprintf(out, "%s", decl->args[i]);
+               if (i < decl->nargs - 1)
+                       safe_fprintf(out, ", ");
+       }
+       safe_fprintf(out, ")");
+       if (decl->rtype != NULL) {
+               safe_fprintf(out, " :: ");
+               for (int i = 0; i<decl->natypes; i++) {
+                       type_print(decl->atypes[i], out);
+                       safe_fprintf(out, " ");
+               }
+               safe_fprintf(out, "-> ");
+               type_print(decl->rtype, out);
+       }
+       safe_fprintf(out, " {\n");
+       for (int i = 0; i<decl->nbody; i++)
+               stmt_print(decl->body[i], 1, out);
+       safe_fprintf(out, "}\n");
+}
+
 void decl_print(struct decl *decl, FILE *out)
 {
        if (decl == NULL)
                return;
        switch(decl->type) {
        case dfundecl:
-               safe_fprintf(out, "%s (", decl->data.dfun.ident);
-               for (int i = 0; i<decl->data.dfun.nargs; i++) {
-                       safe_fprintf(out, "%s", decl->data.dfun.args[i]);
-                       if (i < decl->data.dfun.nargs - 1)
-                               safe_fprintf(out, ", ");
-               }
-               safe_fprintf(out, ")");
-               if (decl->data.dfun.rtype != NULL) {
-                       safe_fprintf(out, " :: ");
-                       for (int i = 0; i<decl->data.dfun.natypes; i++) {
-                               type_print(decl->data.dfun.atypes[i], out);
-                               safe_fprintf(out, " ");
-                       }
-                       safe_fprintf(out, "-> ");
-                       type_print(decl->data.dfun.rtype, out);
-               }
-               safe_fprintf(out, " {\n");
-               for (int i = 0; i<decl->data.dfun.nbody; i++)
-                       stmt_print(decl->data.dfun.body[i], 1, out);
-               safe_fprintf(out, "}\n");
+               fundecl_print(decl->data.dfun, out);
                break;
        case dvardecl:
                vardecl_print(decl->data.dvar, 0, out);
                break;
-       case dcomponent:
-               for (int i = 0; i<decl->data.dcomponent.ndecls; i++)
-                       decl_print(decl, out);
+       case dcomp:
+               fprintf(out, "//<<<comp\n");
+               for (int i = 0; i<decl->data.dcomp.ndecls; i++)
+                       fundecl_print(decl->data.dcomp.decls[i], out);
+               fprintf(out, "//>>>comp\n");
                break;
        default:
                die("Unsupported decl node\n");
@@ -515,28 +525,34 @@ void vardecl_free(struct vardecl *decl)
        free(decl);
 }
 
+void fundecl_free(struct fundecl *decl)
+{
+       free(decl->ident);
+       for (int i = 0; i<decl->nargs; i++)
+               free(decl->args[i]);
+       free(decl->args);
+       for (int i = 0; i<decl->natypes; i++)
+               type_free(decl->atypes[i]);
+       free(decl->atypes);
+       type_free(decl->rtype);
+       for (int i = 0; i<decl->nbody; i++)
+               stmt_free(decl->body[i]);
+       free(decl->body);
+       free(decl);
+}
+
 void decl_free(struct decl *decl)
 {
        if (decl == NULL)
                return;
        switch(decl->type) {
-       case dcomponent:
-               for (int i = 0; i<decl->data.dcomponent.ndecls; i++)
-                       decl_free(decl->data.dcomponent.decls[i]);
-               free(decl->data.dcomponent.decls);
+       case dcomp:
+               for (int i = 0; i<decl->data.dcomp.ndecls; i++)
+                       fundecl_free(decl->data.dcomp.decls[i]);
+               free(decl->data.dcomp.decls);
                break;
        case dfundecl:
-               free(decl->data.dfun.ident);
-               for (int i = 0; i<decl->data.dfun.nargs; i++)
-                       free(decl->data.dfun.args[i]);
-               free(decl->data.dfun.args);
-               for (int i = 0; i<decl->data.dfun.natypes; i++)
-                       type_free(decl->data.dfun.atypes[i]);
-               free(decl->data.dfun.atypes);
-               type_free(decl->data.dfun.rtype);
-               for (int i = 0; i<decl->data.dfun.nbody; i++)
-                       stmt_free(decl->data.dfun.body[i]);
-               free(decl->data.dfun.body);
+               fundecl_free(decl->data.dfun);
                break;
        case dvardecl:
                vardecl_free(decl->data.dvar);
diff --git a/ast.h b/ast.h
index bea8b7c..db69333 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -21,6 +21,16 @@ struct vardecl {
        char *ident;
        struct expr *expr;
 };
+struct fundecl {
+       char *ident;
+       int nargs;
+       char **args;
+       int natypes;
+       struct type **atypes;
+       struct type *rtype;
+       int nbody;
+       struct stmt **body;
+};
 
 enum basictype {btbool, btchar, btint, btvoid};
 struct type {
@@ -37,22 +47,14 @@ struct type {
 };
 
 struct decl {
-       enum {dcomponent, dfundecl, dvardecl} type;
+       //NOTE: DON'T CHANGE THIS ORDER
+       enum {dcomp, dvardecl, dfundecl} type;
        union {
                struct {
                        int ndecls;
-                       struct decl **decls;
-               } dcomponent;
-               struct {
-                       char *ident;
-                       int nargs;
-                       char **args;
-                       int natypes;
-                       struct type **atypes;
-                       struct type *rtype;
-                       int nbody;
-                       struct stmt **body;
-               } dfun;
+                       struct fundecl **decls;
+               } dcomp;
+               struct fundecl *dfun;
                struct vardecl *dvar;
        } data;
 };
@@ -132,9 +134,10 @@ struct expr {
 struct ast *ast(struct list *decls);
 
 struct vardecl *vardecl(struct type *type, char *ident, struct expr *expr);
-
-struct decl *decl_fun(char *ident, struct list *args, struct list *atypes,
+struct fundecl *fundecl(char *ident, struct list *args, struct list *atypes,
        struct type *rtype, struct list *body);
+
+struct decl *decl_fun(struct fundecl *fundecl);
 struct decl *decl_var(struct vardecl *vardecl);
 
 struct stmt *stmt_assign(char *ident, struct list *fields, struct expr *expr);
@@ -162,6 +165,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 fundecl_print(struct fundecl *decl, 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);
@@ -169,6 +173,7 @@ void type_print(struct type *type, FILE *out);
 
 void ast_free(struct ast *);
 void vardecl_free(struct vardecl *decl);
+void fundecl_free(struct fundecl *fundecl);
 void decl_free(struct decl *ast);
 void stmt_free(struct stmt *ast);
 void expr_free(struct expr *ast);
diff --git a/genc.c b/genc.c
index 617bcf6..5ebfa29 100644 (file)
--- a/genc.c
+++ b/genc.c
@@ -176,38 +176,43 @@ void stmt_genc(struct stmt *stmt, int indent, FILE *cout)
        }
 }
 
+void fundecl_genc(struct fundecl *decl, FILE *cout)
+{
+       type_genc(decl->rtype, cout);
+       safe_fprintf(cout, "%s (", decl->ident);
+       for (int i = 0; i<decl->nargs; i++) {
+               if (i < decl->natypes)
+                       die("function with unmatched type\n");
+               safe_fprintf(cout, "%s", decl->args[i]);
+               if (i < decl->nargs - 1)
+                       safe_fprintf(cout, ", ");
+       }
+       safe_fprintf(cout, ") /*");
+       if (decl->rtype != NULL) {
+               safe_fprintf(cout, " :: ");
+               for (int i = 0; i<decl->natypes; i++) {
+                       type_print(decl->atypes[i], cout);
+                       safe_fprintf(cout, " ");
+               }
+               safe_fprintf(cout, "-> ");
+               type_print(decl->rtype, cout);
+       }
+       safe_fprintf(cout, "*/ {\n");
+       for (int i = 0; i<decl->nbody; i++)
+               stmt_genc(decl->body[i], 1, cout);
+       safe_fprintf(cout, "}\n");
+}
+
 void decl_genc(struct decl *decl, FILE *cout)
 {
        switch (decl->type) {
-       case dcomponent:
+       case dcomp:
                //TODO generate prototypes?
-               for (int i = 0; i<decl->data.dcomponent.ndecls; i++)
-                       decl_genc(decl->data.dcomponent.decls[i], cout);
+               for (int i = 0; i<decl->data.dcomp.ndecls; i++)
+                       fundecl_genc(decl->data.dcomp.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; i<decl->data.dfun.nargs; i++) {
-                       if (i < decl->data.dfun.natypes)
-                               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, ", ");
-               }
-               safe_fprintf(cout, ") /*");
-               if (decl->data.dfun.rtype != NULL) {
-                       safe_fprintf(cout, " :: ");
-                       for (int i = 0; i<decl->data.dfun.natypes; i++) {
-                               type_print(decl->data.dfun.atypes[i], cout);
-                               safe_fprintf(cout, " ");
-                       }
-                       safe_fprintf(cout, "-> ");
-                       type_print(decl->data.dfun.rtype, cout);
-               }
-               safe_fprintf(cout, "*/ {\n");
-               for (int i = 0; i<decl->data.dfun.nbody; i++)
-                       stmt_genc(decl->data.dfun.body[i], 1, cout);
-               safe_fprintf(cout, "}\n");
+               fundecl_genc(decl->data.dfun, cout);
                break;
        case dvardecl:
                vardecl_genc(decl->data.dvar, 0, cout);
diff --git a/parse.y b/parse.y
index 8a8dca7..29fa0ca 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -29,7 +29,7 @@ int yywrap()
        struct stmt *stmt;
        struct list *list;
        struct vardecl *vardecl;
-       struct decl *decl;
+       struct fundecl *fundecl;
        struct type *type;
        char *ident;
 }
@@ -52,12 +52,12 @@ int yywrap()
 %right POWER
 
 %type <ast> start
-%type <decl> fundecl
 %type <expr> expr
 %type <list> args body decls fargs field fnargs nargs funtype bbody
 %type <stmt> stmt
 %type <type> type ftype
 %type <vardecl> vardecl
+%type <fundecl> fundecl
 
 %%
 
@@ -65,7 +65,7 @@ start : decls { *result = ast($1); } ;
 decls
        : /* empty */ { $$ = NULL; }
        | decls vardecl { $$ = list_cons(decl_var($2), $1); }
-       | decls fundecl { $$ = list_cons($2, $1); }
+       | decls fundecl { $$ = list_cons(decl_fun($2), $1); }
        ;
 vardecl
        : VAR IDENT ASSIGN expr SEMICOLON { $$ = vardecl(NULL, $2, $4); }
@@ -73,9 +73,9 @@ vardecl
        ;
 fundecl
        : IDENT BOPEN args BCLOSE COPEN body CCLOSE
-               { $$ = decl_fun($1, $3, NULL, NULL, $6); }
+               { $$ = fundecl($1, $3, NULL, NULL, $6); }
        | IDENT BOPEN args BCLOSE CONS CONS funtype ARROW ftype COPEN body CCLOSE
-               { $$ = decl_fun($1, $3, $7, $9, $11); }
+               { $$ = fundecl($1, $3, $7, $9, $11); }
        ;
 funtype
        : /* empty */ { $$ = NULL; }
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);
-//}
diff --git a/scc.h b/scc.h
index 2392556..919e440 100644 (file)
--- a/scc.h
+++ b/scc.h
@@ -1,37 +1,9 @@
 #ifndef SCC_H
 #define SCC_H
 
-struct edge {
-       void *from;
-       void *to;
-};
+#include "ast.h"
 
-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 (*freefun)(void *));
+// Split up the AST in strongly connected components
+struct ast *ast_scc(struct ast *ast);
 
 #endif
diff --git a/splc.c b/splc.c
index bee929a..aeb2e89 100644 (file)
--- a/splc.c
+++ b/splc.c
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
        free(cfile);
        switch(lang) {
        case langc:
-               genc(result, cout);
+//             genc(result, cout);
                break;
        default:
                die("unsupported language\n");
diff --git a/tarjan.c b/tarjan.c
new file mode 100644 (file)
index 0000000..5ac7e2d
--- /dev/null
+++ b/tarjan.c
@@ -0,0 +1,131 @@
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+struct edge {
+       void *from;
+       void *to;
+};
+
+struct components {
+       int nnodes;
+       void **nodes;
+       struct components *next;
+};
+
+struct node {
+       int lowlink;
+       int index;
+       bool onStack;
+       void *data;
+};
+
+static int ptrcmp(const void *l, const void *r)
+{
+       return (ptrdiff_t)((struct node *)l)->data
+               - (ptrdiff_t)((struct node *)r)->data;
+}
+
+static 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 edge *edges,
+       struct components *res, struct components **tail)
+{
+       struct node *w;
+       v->index = *index;
+       v->lowlink = *index;
+       (*index)++;
+       stack[(*sp)++] = v;
+       v->onStack = true;
+
+       for (int i = 0; i<nedges; i++) {
+               //Only consider nodes reachable from v
+               if (edges[i].from != v)
+                       continue;
+               w = edges[i].to;
+               if (w->index == -1)
+                       res = strongconnect(w, stack, sp, index,
+                               nedges, edges, res, tail);
+               else if (w->onStack)
+                       v->lowlink = min(v->lowlink, w->index);
+       }
+
+       if (v->lowlink == v->index) {
+               struct components *ng = safe_malloc(sizeof(struct components));
+               if (*tail == NULL)
+                       res = ng;
+               else
+                       (*tail)->next = ng;
+               *tail = ng;
+               ng->next = NULL;
+               ng->nnodes = *sp;
+               do {
+                       w = stack[--(*sp)];
+                       w->onStack = false;
+               } while (w != v);
+               ng->nnodes -= *sp;
+               ng->nodes = safe_malloc(ng->nnodes*sizeof(void *));
+               for (int i = 0; i<ng->nnodes; i++)
+                       ng->nodes[i] = stack[*sp+i]->data;
+       }
+       return res;
+}
+
+#define nsearch(key)\
+       bsearch(key, nodes, nnodes, sizeof(struct node), nodecmp);\
+       if (key == NULL) {\
+               fprintf(stderr, "edge references unknown node\n");\
+               goto end;\
+       }\
+
+struct components *scc(int nnodes, void **nodedata, int nedges, struct edge **edgedata)
+{
+       //Create nodes
+       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);
+
+       //Create edges
+       struct edge *edges = safe_malloc(nedges*sizeof(struct edge));
+       for (int i = 0; i<nedges; i++) {
+               struct node *from = nsearch(edgedata[i]->from);
+               struct node *to = nsearch(edgedata[i]->to);
+               edges[i] = (struct edge){.from=from, .to=to};
+       }
+
+       //Tarjan's
+       struct components *res = NULL, *tail = NULL;
+       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, &tail);
+       }
+       free(stack);
+end:
+       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;
+       }
+}
diff --git a/tarjan.h b/tarjan.h
new file mode 100644 (file)
index 0000000..b2a8fbb
--- /dev/null
+++ b/tarjan.h
@@ -0,0 +1,38 @@
+#ifndef SCC_H
+#define SCC_H
+
+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 nn, void **nodes, int ne, struct edge **edges);
+
+/**
+ * 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 (*freefun)(void *));
+
+#endif
diff --git a/type.c b/type.c
index 3325de8..0cf22e1 100644 (file)
--- a/type.c
+++ b/type.c
@@ -1,3 +1,8 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "list.h"
+#include "scc.h"
 #include "ast.h"
 
 void type_error(const char *msg, ...)
@@ -37,7 +42,7 @@ struct vardecl *type_vardecl(struct vardecl *vardecl)
 struct decl *type_decl(struct decl *decl)
 {
        switch (decl->type) {
-       case dcomponent:
+       case dcomp:
                fprintf(stderr, "type_decl:component unsupported\n");
                break;
        case dfundecl:
@@ -52,6 +57,8 @@ struct decl *type_decl(struct decl *decl)
 
 struct ast *type(struct ast *ast)
 {
+       ast = ast_scc(ast);
+
        for (int i = 0; i<ast->ndecls; i++) {
                if (ast->decls[i]->type == dvardecl) {
                        //Check globals
@@ -61,4 +68,3 @@ struct ast *type(struct ast *ast)
        }
        return ast;
 }
-