add scc and update other code
authorMart Lubbers <mart@martlubbers.net>
Thu, 11 Feb 2021 13:15:08 +0000 (14:15 +0100)
committerMart Lubbers <mart@martlubbers.net>
Thu, 11 Feb 2021 13:15:08 +0000 (14:15 +0100)
13 files changed:
Makefile
ast.c
ast.h
genc.c
genc.h
list.c [new file with mode: 0644]
list.h [new file with mode: 0644]
scc.c [new file with mode: 0644]
scc.h [new file with mode: 0644]
splc.c
type.c
util.c
util.h

index 749b3fd..949b3e8 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 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 (file)
--- 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; i<ast->ndecls; 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; i<decl->data.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; i<decl->data.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; i<decl->data.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; i<decl->data.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; i<decl->data.dfun.nargs; i++)
diff --git a/ast.h b/ast.h
index b797c57..bea8b7c 100644 (file)
--- 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 (file)
--- 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; i<decl->data.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; i<decl->data.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 <stdint.h>\n"
@@ -246,10 +242,8 @@ int genc(struct ast *ast, FILE *cout)
                "\treturn res;\n"
                "}\n"
                );
-       int r = 0;
-       for (int i = 0; i<ast->ndecls && r == 0; i++) {
+       for (int i = 0; i<ast->ndecls; 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 (file)
--- a/genc.h
+++ b/genc.h
@@ -1,11 +1,10 @@
 #ifndef GENC_H
 #define GENC_H
 
-#include <stdbool.h>
 #include <stdio.h>
 
 #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 (file)
index 0000000..62af95e
--- /dev/null
+++ b/list.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+#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 (file)
index 0000000..1cc3fb2
--- /dev/null
+++ b/list.h
@@ -0,0 +1,19 @@
+#ifndef LIST_H
+#define LIST_H
+
+#include <stdbool.h>
+
+#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 (file)
index 0000000..3c690a2
--- /dev/null
+++ b/scc.c
@@ -0,0 +1,135 @@
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#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; 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);
+               }
+       }
+
+       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; i<nnodes; i++)
+               nodes[i] = (struct node){.lowlink=-1, .index=-1,
+                       .onStack=false, .data=nodedata[i]};
+       qsort(nodes, nnodes, sizeof(struct node), ptrcmp);
+
+       struct edge2 *edges = safe_malloc(nedges*sizeof(struct edge2));
+       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;
+               }
+               edges[i] = (struct edge2){.from=from, .to=to};
+       }
+
+       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;
+       }
+}
+//
+//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
new file mode 100644 (file)
index 0000000..d7c378e
--- /dev/null
+++ b/scc.h
@@ -0,0 +1,38 @@
+#ifndef SCC_H
+#define SCC_H
+
+#include <stdbool.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 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 (file)
--- 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 (file)
--- 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 (file)
--- 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 (file)
--- a/util.h
+++ b/util.h
@@ -5,11 +5,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 
-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);