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)
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;
}
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");
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);
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 {
};
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;
};
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);
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);
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);
}
}
+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);
struct stmt *stmt;
struct list *list;
struct vardecl *vardecl;
- struct decl *decl;
+ struct fundecl *fundecl;
struct type *type;
char *ident;
}
%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
%%
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); }
;
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; }
-#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);
-//}
#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
free(cfile);
switch(lang) {
case langc:
- genc(result, cout);
+// genc(result, cout);
break;
default:
die("unsupported language\n");
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+#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
+#include <stdlib.h>
+#include <string.h>
+
+#include "list.h"
+#include "scc.h"
#include "ast.h"
void type_error(const char *msg, ...)
struct decl *type_decl(struct decl *decl)
{
switch (decl->type) {
- case dcomponent:
+ case dcomp:
fprintf(stderr, "type_decl:component unsupported\n");
break;
case dfundecl:
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
}
return ast;
}
-