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; }