A -> B -> C 我以为要分开写成A -> B; B -> C。另外我不想重复,比如A-> B; A-> C我想表示为A然后缩进一个空格写B,C。
于是有了下面的一个小工具。
/*indent text file to graphviz dot description
usage: cat in.txt | ./i2g | xdot
e.g.
indent and chains:
aaa -> bb
AAA
BB -> bb -> cc
CC -> dd
DD -> EE
"aa bb"
alice
"bob Bob"
with label for edges:
A -> D [label=ddd] -> E
with label for nodes:
A D[label=ddd] E
label for nodes and edges:
A D[label=ddd] D -> E[label=eee]
D[shape=circle, label=ddd] A -> D [label=ad, style = bold, shape = circle] -> E[label=eee, color=red, style = dotted]
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define STK 8
#define W 128
char stk[STK][128];
int get_attr(char *w, int s, char **ptr)
{//get "[any stuff here]"
char *p = *ptr;
char *q = w;
int i, found = 0;
while(*p && isspace(*p)){
p++;
}
if(*p != '['){
*w = 0;
return 0;
}
for(i = 0; i < s - 1; ++i)
{
*w++ = *p++;
if(w[-1] == ']'){
found = 1;
break;
}
}
if(!found){
w = q;
}
*w = 0;
*ptr = p;
return w - q;
}
int get_node(char *w, int s, char **ptr)
{//get non-spaced string or quoted spaced string e.g. "aa bb "
char *p = *ptr;
char *q = w;
int i, quote = 0;
while(*p && isspace(*p)){
p++;
}
if(*p == '"'){
*w++ = *p++;
quote = 1;
}
for(i = 0; i < s-1 && *p; ++i){
if(1 == quote && *p == '"'){
*w++ = *p++;
break;
}
if(*p == '[')
break;
*w++ = *p++;
if(!quote && isspace(*p)){
break;
}
}
*w = 0;
*ptr = p;
return w - q;
}
int output(char *from, char *to, char *attr)
{
if(!from[0] || !to[0]){
return -1;
}
fprintf(stdout, "%s -> %s %s;\n", from, to, attr);
return 0;
}
int main(int ac, char **av)
{
char line[1024];
char w[W] = "", a[W] = "", last[W] = "", la[W] = "";
char *ptr;
int idt, flag, first, tail;
fprintf(stdout, "digraph g {\nnode [shape=plaintext];\n");
while(fgets(line, sizeof(line), stdin)){
ptr = line;
while(*ptr == ' '){ptr++;}
idt = ptr - line;
if(idt >= STK)idt = 0;
first = 1;
flag = 0;
tail = 0;
while(get_node(w, sizeof(w), &ptr)){
get_attr(a, sizeof(a), &ptr);
if(first){
strcpy(stk[idt], w);
first = 0;
}
if(w[0] == '-'){//"--" "->"
flag = w[1] == '>' ? 1 : 2;
}else{
if(idt){//has indent
output(stk[idt-1], w, a);
a[0] = 0;
strcpy(stk[idt], w);
idt = 0;
}else if(flag){//A -> B
output(last, w, a);
a[0] = 0;
flag = 0;
tail = 0;
}else if(!flag){//A B
if(last[0])
fprintf(stdout, "%s %s ", last, la);
tail = 1;
}
strcpy(last, w);
strcpy(la, a);
}
}
if(tail && last[0])
fprintf(stdout, "%s %s \n", last, la);
}
fprintf(stdout, "}\n");
return 0;
}
[1] dotguide.pdf