-
Notifications
You must be signed in to change notification settings - Fork 1
/
graphviz_codegen.c
116 lines (91 loc) · 3.13 KB
/
graphviz_codegen.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <stdio.h>
#include <stdlib.h>
#include "graphviz_codegen.h"
#include "sinc.h"
#include "parse.h"
#include "error.h"
/*
* TODO
* The structure of this file is very similar to that of sinter_codegen.c; maybe
* they can be merged?
*/
typedef struct func_str {
/* FIXME: magic size */
char buf[100000];
struct func_str *next;
} func_str;
func_str *ffs;
func_str *lfs;
int nid;
static int make_node(char *buf, sexpr *ast, sexpr *parent) {
if (!ast) {
return sprintf(buf, "\"%p%p\"[label=\"()\",shape=\"circle\"]\n",
(void *) parent, (void *) ast);
} else switch (ast->type) {
case INT:
return sprintf(buf, "\"%p%p\"[label=\"%i\"]\n", (void *) parent,
(void *) ast, ast->contents.i);
case FLOAT:
return sprintf(buf, "\"%p%p\"[label=\"%f\"]\n", (void *) parent,
(void *) ast, ast->contents.f);
case STRING:
return sprintf(buf, "\"%p%p\"[label=\"\\\"%s\\\"\"]\n",
(void *) parent, (void *) ast, ast->contents.s);
case ID:
return sprintf(buf, "\"%p%p\"[label=\"%s\"]\n", (void *) parent,
(void *) ast, ast->contents.s);
case BRANCH:
return sprintf(buf,
"\"%p%p\"[label=\"\",shape=\"circle\",style=\"filled\",width=\"0.2\",fillcolor=\"black\"]\n",
(void *) parent, (void *) ast);
default:
return 0;
}
}
static int make_children(char *buf, sexpr *ast, sexpr *parent) {
if (!ast || ast->type != BRANCH) return 0;
char *old_buf = buf;
buf += sprintf(buf, "{\nrank=\"same\"\nrankdir=\"LR\"\n");
sexpr *last = ast->contents.n.l;
sexpr *rast = ast->contents.n.r;
buf += make_node(buf, last, ast);
buf += make_node(buf, rast, ast);
buf += sprintf(buf, "\"%p%p\"->\"%p%p\"[style=\"invis\"]\n", (void *) ast,
(void *) last, (void *) ast, (void *) rast);
buf += sprintf(buf, "}\n");
buf += sprintf(buf, "\"%p%p\"->\"%p%p\"\n", (void *) parent, (void *) ast,
(void *) ast, (void *) last);
buf += sprintf(buf, "\"%p%p\"->\"%p%p\"\n", (void *) parent, (void *) ast,
(void *) ast, (void *) rast);
buf += make_children(buf, last, ast);
buf += make_children(buf, rast, ast);
return buf - old_buf;
}
void graphviz_codegen_prologue() {
ffs = 0;
lfs = 0;
nid = 0;
}
void graphviz_codegen(sexpr *ast) {
func_str *fs = (func_str *) malloc(sizeof (*fs));
if (!fs) error(GENERAL_ERROR, "cannot malloc");
char *buf = fs->buf;
buf += sprintf(buf, "subgraph \"cluster_%i\" {\n", ++nid);
buf += make_node(buf, ast, 0);
buf += make_children(buf, ast, 0);
buf += sprintf(buf, "}\n");
fs->next = 0;
if (!ffs) ffs = fs;
if (lfs) lfs->next = fs;
lfs = fs;
}
int graphviz_codegen_epilogue(char *output_filename) {
FILE *fp = fopen(output_filename, "w");
fprintf(fp, "digraph {\n");
fprintf(fp, "node[fontname=\"monospace\"]\n");
for (func_str *fs = ffs; fs; fs = fs->next) {
fprintf(fp, "%s\n", fs->buf);
}
fprintf(fp, "}\n");
return 0;
}