add lefty, dotty, lneato to graphviz2 tree
authorellson <devnull@localhost>
Thu, 6 Jan 2005 15:01:43 +0000 (15:01 +0000)
committerellson <devnull@localhost>
Thu, 6 Jan 2005 15:01:43 +0000 (15:01 +0000)
cmd/lefty/dot2l/.cvsignore [new file with mode: 0644]
cmd/lefty/dot2l/Makefile.am [new file with mode: 0644]
cmd/lefty/dot2l/dot2l.c [new file with mode: 0644]
cmd/lefty/dot2l/dot2l.h [new file with mode: 0644]
cmd/lefty/dot2l/dotlex.c [new file with mode: 0644]
cmd/lefty/dot2l/dotparse.y [new file with mode: 0644]
cmd/lefty/dot2l/dottrie.c [new file with mode: 0644]
cmd/lefty/dot2l/triefa.c [new file with mode: 0644]
cmd/lefty/dot2l/triefa.h [new file with mode: 0644]
cmd/lefty/examples/.cvsignore [new file with mode: 0644]
cmd/lefty/examples/Makefile.am [new file with mode: 0644]

diff --git a/cmd/lefty/dot2l/.cvsignore b/cmd/lefty/dot2l/.cvsignore
new file mode 100644 (file)
index 0000000..5b66182
--- /dev/null
@@ -0,0 +1,9 @@
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+dotparse.c
+dotparse.h
+dotparse.output
diff --git a/cmd/lefty/dot2l/Makefile.am b/cmd/lefty/dot2l/Makefile.am
new file mode 100644 (file)
index 0000000..0c5b222
--- /dev/null
@@ -0,0 +1,26 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = -I$(top_srcdir)/lefty
+
+AM_YFLAGS = -dv
+
+noinst_HEADERS = dot2l.h triefa.h dotparse.h
+if WITH_X
+noinst_LTLIBRARIES = libdot2l.la
+endif
+
+libdot2l_la_SOURCES = dot2l.c dotlex.c dotparse.y dottrie.c 
+
+dotlex.o dotlex.lo : dotparse.h
+
+dotparse.c : dotparse.y
+
+dotparse.h : dotparse.c
+
+# this is a home-made tool
+# trie.c : trie_input
+#       triegen  < trie_input > trie.c
+
+DISTCLEANFILES = y.output dotparse.[ch]
+
+EXTRA_DIST = $(libdot2l_la_SOURCES) triefa.c
diff --git a/cmd/lefty/dot2l/dot2l.c b/cmd/lefty/dot2l/dot2l.c
new file mode 100644 (file)
index 0000000..b0730e4
--- /dev/null
@@ -0,0 +1,784 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+#include "common.h"
+#include "mem.h"
+#include "io.h"
+#include "code.h"
+#include "tbl.h"
+#include "dot2l.h"
+
+extern void lex_begin(int);
+
+char *gtype, *etype;
+int yaccdone;
+int attrclass;
+int inattrstmt;
+
+static graphframe_t *gstack, *topgframe;
+static Tobj allgraphs, alledges, allnodes;
+static Tobj gdict, /* edict, */ ndict, N;
+static long newgid, neweid, newnid, gmark, errflag;
+
+static jmp_buf ljbuf;
+
+static void filllabeltable(Tobj, int);
+static void filllabelrect(Tobj);
+
+static char *lsp, *rsp;
+
+static void writesgraph(int, Tobj, int, int, char *);
+static void writeattr(int, Tobj, char *);
+static void quotestring(char *, Tobj);
+
+Tobj D2Lparsegraphlabel(Tobj lo, Tobj ro)
+{
+    volatile long lm;
+    volatile Tobj to;
+
+    lm = Mpushmark(lo);
+    Mpushmark(ro);
+    to = Ttable(4);
+    Mpushmark(to);
+    lsp = Tgetstring(lo);
+    if (ro && T_ISSTRING(ro))
+       rsp = Tgetstring(ro);
+    else
+       rsp = NULL;
+
+    if (setjmp(ljbuf)) {
+       to = NULL;
+       fprintf(stderr, "error in label >>%s<<\n", lsp);
+    } else
+       filllabeltable(to, TRUE);
+    Mpopmark(lm);
+    return to;
+}
+
+#define HASTEXT 1
+#define HASPORT 2
+#define HASTABLE 4
+#define INTEXT 8
+#define INPORT 16
+
+#define ISCTRL(c) \
+    ((c) == '{' || (c) == '}' || (c) == '|' || (c) == '<' || (c) == '>')
+
+static void filllabeltable(Tobj to, int flag)
+{
+    Tobj cto, fo;
+    char *tsp, *psp, *hstsp, *hspsp;
+    char text[10240], port[256];
+    long cti;
+    int mode, wflag, ishardspace;
+
+    mode = 0;
+    cti = 0;
+    Tinsi(to, cti++, (cto = Ttable(2)));
+    hstsp = tsp = &text[0], hspsp = psp = &port[0];
+    wflag = TRUE;
+    ishardspace = FALSE;
+    while (wflag) {
+       switch (*lsp) {
+       case '<':
+           if (mode & (HASTABLE | HASPORT))
+               longjmp(ljbuf, 1);      /* DOESN'T RETURN */
+           mode &= ~INTEXT;
+           mode |= (HASPORT | INPORT);
+           lsp++;
+           break;
+       case '>':
+           if (!(mode & INPORT))
+               longjmp(ljbuf, 1);      /* DOESN'T RETURN */
+           mode &= ~INPORT;
+           lsp++;
+           break;
+       case '{':
+           lsp++;
+           if (mode != 0 || !*lsp)
+               longjmp(ljbuf, 1);      /* DOESN'T RETURN */
+           Tinss(cto, "fields", (fo = Ttable(2)));
+           mode = HASTABLE;
+           filllabeltable(fo, FALSE);
+           break;
+       case '}':
+       case '|':
+       case '\000':
+           if ((!*lsp && !flag) || (mode & INPORT))
+               longjmp(ljbuf, 1);      /* DOESN'T RETURN */
+           if (mode & HASPORT) {
+               if (psp > &port[0] + 1 && psp - 1 != hspsp
+                   && *(psp - 1) == ' ')
+                   psp--;
+               *psp = '\000';
+               Tinss(cto, "port", Tstring(&port[0]));
+               hspsp = psp = &port[0];
+           }
+           if (!(mode & (HASTEXT | HASTABLE)))
+               mode |= HASTEXT, *tsp++ = ' ';
+           if (mode & HASTEXT) {
+               if (tsp > &text[0] + 1 && tsp - 1 != hstsp
+                   && *(tsp - 1) == ' ')
+                   tsp--;
+               *tsp = '\000';
+               Tinss(cto, "text", Tstring(&text[0]));
+               hstsp = tsp = &text[0];
+           }
+           if (mode & (HASTEXT | HASPORT))
+               filllabelrect(cto);
+           if (*lsp) {
+               if (*lsp == '}') {
+                   lsp++;
+                   return;
+               }
+               Tinsi(to, cti++, (cto = Ttable(2)));
+               mode = 0;
+               lsp++;
+           } else
+               wflag = FALSE;
+           break;
+       case '\\':
+           if (*(lsp + 1)) {
+               if (ISCTRL(*(lsp + 1)))
+                   lsp++;
+               else if (*(lsp + 1) == ' ')
+                   ishardspace = TRUE, lsp++;
+           }
+           /* falling through ... */
+       default:
+           if ((mode & HASTABLE) && *lsp != ' ')
+               longjmp(ljbuf, 1);      /* DOESN'T RETURN */
+           if (!(mode & (INTEXT | INPORT))
+               && (ishardspace || *lsp != ' '))
+               mode |= (INTEXT | HASTEXT);
+           if (mode & INTEXT) {
+               if (!(*lsp == ' ' && !ishardspace && *(tsp - 1) == ' '))
+                   *tsp++ = *lsp;
+               if (ishardspace)
+                   hstsp = tsp - 1;
+           } else if (mode & INPORT) {
+               if (!(*lsp == ' ' && !ishardspace && (psp == &port[0] ||
+                                                     *(psp - 1) == ' ')))
+                   *psp++ = *lsp;
+               if (ishardspace)
+                   hspsp = psp - 1;
+           }
+           ishardspace = FALSE;
+           lsp++;
+           break;
+       }
+    }
+    return;
+}
+
+static void filllabelrect(Tobj to)
+{
+    Tobj ro, p0o, p1o;
+    char *s2, *s3;
+    char c, c2;
+    int i;
+
+    if (!rsp)
+       return;
+    for (s2 = rsp; *s2 && *s2 != ' '; s2++);
+    c = *s2, *s2 = 0;
+    Tinss(to, "rect", (ro = Ttable(2)));
+    Tinsi(ro, 0, (p0o = Ttable(2)));
+    Tinsi(ro, 1, (p1o = Ttable(2)));
+    for (i = 0; i < 4; i++) {
+       for (s3 = rsp; *s3 && *s3 != ','; s3++);
+       c2 = *s3, *s3 = 0;
+       if (s3 == rsp)
+           longjmp(ljbuf, 1);  /* DOESN'T RETURN */
+       switch (i) {
+       case 0:
+           Tinss(p0o, "x", Tinteger((long) atoi(rsp)));
+           break;
+       case 1:
+           Tinss(p0o, "y", Tinteger((long) atoi(rsp)));
+           break;
+       case 2:
+           Tinss(p1o, "x", Tinteger((long) atoi(rsp)));
+           break;
+       case 3:
+           Tinss(p1o, "y", Tinteger((long) atoi(rsp)));
+           break;
+       }
+       *s3 = c2;
+       rsp = s3;
+       if (*rsp == ',')
+           rsp++;
+    }
+    *s2 = c;
+    rsp = s2 + 1;
+}
+
+static Tobj nameo, attro, edgeso, hporto, tporto, heado, tailo, protogo;
+
+Tobj D2Lreadgraph(int ioi, Tobj protograph)
+{
+    graphframe_t *gframe, *tgframe;
+    edgeframe_t *eframe, *teframe;
+    Tobj graph;
+    long m;
+
+    protogo = protograph;
+    nameo = Tstring("name");
+    m = Mpushmark(nameo);
+    attro = Tstring("attr");
+    Mpushmark(attro);
+    edgeso = Tstring("edges");
+    Mpushmark(edgeso);
+    hporto = Tstring("hport");
+    Mpushmark(hporto);
+    tporto = Tstring("tport");
+    Mpushmark(tporto);
+    heado = Tstring("head");
+    Mpushmark(heado);
+    tailo = Tstring("tail");
+    Mpushmark(tailo);
+    yaccdone = FALSE;
+    gstack = topgframe = NULL;
+    errflag = FALSE;
+    lex_begin(ioi);
+    yyparse();
+    graph = NULL;
+    if (topgframe) {
+       graph = (errflag) ? NULL : topgframe->g;
+       for (gframe = gstack; gframe; gframe = tgframe) {
+           for (eframe = gframe->estack; eframe; eframe = teframe) {
+               teframe = eframe->next;
+               Mfree(eframe, M_BYTE2SIZE(sizeof(edgeframe_t)));
+           }
+           tgframe = gframe->next;
+           Mfree(gframe, M_BYTE2SIZE(sizeof(graphframe_t)));
+       }
+       goto done;
+    }
+  done:
+    Mpopmark(m);
+    return graph;
+}
+
+void D2Lwritegraph(int ioi, Tobj graph, int flag)
+{
+    Tobj nodes, node, sgraphs, sgraph, edges, edge, tail, head, tport,
+       hport;
+    Tobj so, no, eo, to;
+    char buf[10240];
+    char *s;
+    int isdag, n = 0, nn, i;
+
+    if (!(so = Tfinds(graph, "type")) || !T_ISSTRING(so))
+       s = "digraph";
+    else {
+       s = Tgetstring(so);
+       if (!*s)
+           s = "digraph";
+    }
+    strcpy(buf, s);
+    if (strcmp(s, "digraph") == 0 || strcmp(s, "strict digraph") == 0)
+       isdag = 1;
+    else
+       isdag = 0;
+    if (!(so = Tfinds(graph, "name")) || !T_ISSTRING(so))
+       s = "g";
+    else {
+       s = Tgetstring(so);
+       if (!*s)
+           s = "g";
+    }
+    strcat(buf, " ");
+    quotestring(buf, Tstring(s));
+    strcat(buf, " {");
+    IOwriteline(ioi, buf);
+    buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
+    if ((to = Tfinds(graph, "graphattr")) && T_ISTABLE(to)) {
+       IOwriteline(ioi, "\tgraph [");
+       writeattr(ioi, to, buf);
+       IOwriteline(ioi, "\t]");
+    }
+    if ((to = Tfinds(graph, "nodeattr")) && T_ISTABLE(to)) {
+       IOwriteline(ioi, "\tnode [");
+       writeattr(ioi, to, buf);
+       IOwriteline(ioi, "\t]");
+    }
+    if ((to = Tfinds(graph, "edgeattr")) && T_ISTABLE(to)) {
+       IOwriteline(ioi, "\tedge [");
+       writeattr(ioi, to, buf);
+       IOwriteline(ioi, "\t]");
+    }
+    if ((nodes = Tfinds(graph, "nodes"))) {
+       if (!(no = Tfinds(graph, "maxnid")) || !T_ISNUMBER(no))
+           n = 100 * Tgettablen(nodes);
+       else
+           n = Tgetnumber(no);
+       for (i = 0; i < n; i++) {
+           if (!(node = Tfindi(nodes, i)))
+               continue;
+           buf[0] = '\t', buf[1] = 0;
+           quotestring(buf, Tfinds(node, "name"));
+           strcat(buf, " [");
+           IOwriteline(ioi, buf);
+           buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
+           if ((to = Tfinds(node, "attr")))
+               writeattr(ioi, to, buf);
+           IOwriteline(ioi, "\t]");
+       }
+    }
+    nn = n;
+    if ((sgraphs = Tfinds(graph, "graphs"))) {
+       if (!(no = Tfinds(graph, "maxgid")) || !T_ISNUMBER(no))
+           n = 100 * Tgettablen(sgraphs);
+       else
+           n = Tgetnumber(no);
+       for (i = 0; i < n; i++) {
+           if (!(sgraph = Tfindi(sgraphs, i)) || Tfinds(sgraph, "wmark"))
+               continue;
+           buf[0] = '\t', buf[1] = 0;
+           writesgraph(ioi, sgraph, n, nn, buf);
+       }
+       for (i = 0; i < n; i++) {
+           if (!(sgraph = Tfindi(sgraphs, i)))
+               continue;
+           Tdels(sgraph, "wmark");
+       }
+    }
+    if ((edges = Tfinds(graph, "edges"))) {
+       if (!(eo = Tfinds(graph, "maxeid")) || !T_ISNUMBER(eo))
+           n = 100 * Tgettablen(edges);
+       else
+           n = Tgetnumber(eo);
+       for (i = 0; i < n; i++) {
+           if (!(edge = Tfindi(edges, i)))
+               continue;
+           if (!(tail = Tfinds(edge, "tail")))
+               continue;
+           if (!(head = Tfinds(edge, "head")))
+               continue;
+           tport = Tfinds(edge, "tport");
+           hport = Tfinds(edge, "hport");
+           buf[0] = '\t', buf[1] = 0;
+           quotestring(buf, Tfinds(tail, "name"));
+           if (tport && T_ISSTRING(tport)) {
+               strcat(buf, ":");
+               quotestring(buf, tport);
+           }
+           strcat(buf, isdag ? " -> " : " -- ");
+           quotestring(buf, Tfinds(head, "name"));
+           if (hport && T_ISSTRING(hport)) {
+               strcat(buf, ":");
+               quotestring(buf, hport);
+           }
+           strcat(buf, " [");
+           IOwriteline(ioi, buf);
+           buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
+           if ((to = Tfinds(edge, "attr")))
+               writeattr(ioi, to, buf);
+           if (flag) {
+               sprintf(buf, "\t\tid = %d", i);
+               IOwriteline(ioi, buf);
+           }
+           IOwriteline(ioi, "\t]");
+       }
+    }
+    IOwriteline(ioi, "}");
+}
+
+static void writesgraph(int ioi, Tobj graph, int gn, int nn, char *buf)
+{
+    Tobj nodes, node, sgraphs, sgraph, so, to;
+    char *s1, *s2, *s3;
+    int i;
+
+    Tinss(graph, "wmark", Tinteger(1));
+    s1 = buf + strlen(buf);
+    if (!(so = Tfinds(graph, "name")) || !T_ISSTRING(so))
+       sprintf(s1, "{");
+    else {
+       strcat(s1, "subgraph ");
+       quotestring(s1, so);
+       strcat(s1, " {");
+    }
+    IOwriteline(ioi, buf);
+    s2 = s1 + 1;
+    s3 = s2 + 1;
+    *s1 = '\t', *s2 = 0;
+    if ((to = Tfinds(graph, "graphattr")) && T_ISTABLE(to)) {
+       strcat(s1, "graph [");
+       IOwriteline(ioi, buf);
+       *s2 = '\t', *s3 = 0;
+       writeattr(ioi, to, buf);
+       *s2 = 0;
+       strcat(s1, "]");
+       IOwriteline(ioi, buf);
+       *s2 = 0;
+    }
+    if ((to = Tfinds(graph, "nodeattr")) && T_ISTABLE(to)) {
+       strcat(s1, "node [");
+       IOwriteline(ioi, buf);
+       *s2 = '\t', *s3 = 0;
+       writeattr(ioi, to, buf);
+       *s2 = 0;
+       strcat(s1, "]");
+       IOwriteline(ioi, buf);
+       *s2 = 0;
+    }
+    if ((to = Tfinds(graph, "edgeattr")) && T_ISTABLE(to)) {
+       strcat(s1, "edge [");
+       IOwriteline(ioi, buf);
+       *s2 = '\t', *s3 = 0;
+       writeattr(ioi, to, buf);
+       *s2 = 0;
+       strcat(s1, "]");
+       IOwriteline(ioi, buf);
+       *s2 = 0;
+    }
+    if ((nodes = Tfinds(graph, "nodes"))) {
+       for (i = 0; i < nn; i++) {
+           *s2 = 0;
+           if (!(node = Tfindi(nodes, i)))
+               continue;
+           quotestring(buf, Tfinds(node, "name"));
+           IOwriteline(ioi, buf);
+       }
+    }
+    if ((sgraphs = Tfinds(graph, "graphs"))) {
+       for (i = 0; i < gn; i++) {
+           if (!(sgraph = Tfindi(sgraphs, i)) || Tfinds(sgraph, "wmark"))
+               continue;
+           *s2 = 0;
+           writesgraph(ioi, sgraph, gn, nn, buf);
+       }
+    }
+    *s1 = '}', *s2 = 0;
+    IOwriteline(ioi, buf);
+    *s1 = 0;
+}
+
+static void writeattr(int ioi, Tobj to, char *buf)
+{
+    Tkvindex_t tkvi;
+    char *s1, *s2, *s3;
+
+    s1 = buf + strlen(buf);
+    for (Tgetfirst(to, &tkvi); tkvi.kvp; Tgetnext(&tkvi)) {
+       switch (Tgettype(tkvi.kvp->ko)) {
+       case T_INTEGER:
+           sprintf(s1, "%ld = ", Tgetinteger(tkvi.kvp->ko));
+           break;
+       case T_REAL:
+           sprintf(s1, "%f = ", Tgetreal(tkvi.kvp->ko));
+           break;
+       case T_STRING:
+           sprintf(s1, "%s = ", Tgetstring(tkvi.kvp->ko));
+           break;
+       case T_CODE:
+       case T_TABLE:
+       case T_SIZE:
+           break;
+       }
+       s2 = buf + strlen(buf);
+       switch (Tgettype(tkvi.kvp->vo)) {
+       case T_INTEGER:
+           sprintf(s2, "\"%ld\"", Tgetinteger(tkvi.kvp->vo));
+           break;
+       case T_REAL:
+           sprintf(s2, "\"%f\"", Tgetreal(tkvi.kvp->vo));
+           break;
+       case T_STRING:
+           *s2++ = '"';
+           for (s3 = Tgetstring(tkvi.kvp->vo); *s3; s3++)
+               if (*s3 == '"')
+                   *s2++ = '\\', *s2++ = *s3;
+               else
+                   *s2++ = *s3;
+           *s2++ = '"', *s2 = 0;
+           break;
+       default:
+           sprintf(s2, "\"\"");
+           break;
+       }
+       IOwriteline(ioi, buf);
+    }
+    *s1 = 0;
+}
+
+static void quotestring(char *buf, Tobj so)
+{
+    char *s1, *s2;
+
+    s1 = buf + strlen(buf);
+    *s1++ = '"';
+    if (so && T_ISSTRING(so)) {
+       for (s2 = Tgetstring(so); *s2; s2++) {
+           if (*s2 == '"')
+               *s1++ = '\\', *s1++ = *s2;
+           else
+               *s1++ = *s2;
+       }
+    }
+    *s1++ = '"', *s1 = 0;
+}
+
+void D2Lbegin(char *name)
+{
+
+    newgid = neweid = newnid = 0;
+    attrclass = GRAPH;
+
+    if (!(gstack = Mallocate(sizeof(graphframe_t))))
+       panic(POS, "D2Lbegingraph", "cannot allocate graph stack");
+    gstack->next = NULL;
+    gstack->estack = NULL;
+    topgframe = gstack;
+
+    gmark = Mpushmark((gstack->g = Ttable(12)));
+    Tinss(gstack->g, "type", Tstring(gtype));
+    Tinss(gstack->g, "name", Tstring(name));
+
+    /* the dictionaries */
+    Tinss(gstack->g, "graphdict", (gdict = Ttable(10)));
+    Tinss(gstack->g, "nodedict", (ndict = Ttable(10)));
+    Tinss(gstack->g, "edgedict", ( /* edict = */ Ttable(10)));
+
+    /* this graph's nodes, edges, subgraphs */
+    Tinss(gstack->g, "nodes", (allnodes = gstack->nodes = Ttable(10)));
+    Tinss(gstack->g, "graphs", (allgraphs = gstack->graphs = Ttable(10)));
+    Tinss(gstack->g, "edges", (alledges = gstack->edges = Ttable(10)));
+
+    /* attributes */
+    gstack->gattr = gstack->nattr = gstack->eattr = NULL;
+    if (protogo) {
+       gstack->gattr = Tfinds(protogo, "graphattr");
+       gstack->nattr = Tfinds(protogo, "nodeattr");
+       gstack->eattr = Tfinds(protogo, "edgeattr");
+    }
+    gstack->gattr = (gstack->gattr ? Tcopy(gstack->gattr) : Ttable(10));
+    Tinss(gstack->g, "graphattr", gstack->gattr);
+    gstack->nattr = (gstack->nattr ? Tcopy(gstack->nattr) : Ttable(10));
+    Tinss(gstack->g, "nodeattr", gstack->nattr);
+    gstack->eattr = (gstack->eattr ? Tcopy(gstack->eattr) : Ttable(10));
+    Tinss(gstack->g, "edgeattr", gstack->eattr);
+    gstack->ecopy = gstack->eattr;
+}
+
+void D2Lend(void)
+{
+    Mpopmark(gmark);
+    yaccdone = TRUE;
+}
+
+void D2Labort(void)
+{
+    Mpopmark(gmark);
+    errflag = TRUE;
+    yaccdone = TRUE;
+}
+
+void D2Lpushgraph(char *name)
+{
+    graphframe_t *gframe;
+    Tobj g, idobj, nameobj;
+    long gid;
+
+    if (!(gframe = Mallocate(sizeof(graphframe_t))))
+       panic(POS, "D2Lpushgraph", "cannot allocate graph stack");
+    gframe->next = gstack, gstack = gframe;
+    gstack->estack = NULL;
+
+    if (name && (idobj = Tfinds(gdict, name))) {
+       gid = Tgetnumber(idobj), gstack->g = g = Tfindi(allgraphs, gid);
+       gstack->nodes = Tfinds(g, "nodes");
+       gstack->graphs = Tfinds(g, "graphs");
+       gstack->edges = Tfinds(g, "edges");
+       gstack->gattr = Tfinds(g, "graphattr");
+       gstack->nattr = Tfinds(g, "nodeattr");
+       gstack->ecopy = gstack->eattr = Tfinds(g, "edgeattr");
+       return;
+    }
+    if (!name)
+       gid = newgid++, nameobj = Tinteger(gid),
+           Tinso(gdict, nameobj, nameobj);
+    else
+       Tinso(gdict, (nameobj = Tstring(name)),
+             Tinteger((gid = newgid++)));
+    Tinsi(allgraphs, gid, (gstack->g = g = Ttable(10)));
+    Tinss(g, "name", nameobj);
+    Tinss(g, "nodes", (gstack->nodes = Ttable(10)));
+    Tinss(g, "graphs", (gstack->graphs = Ttable(10)));
+    Tinss(g, "edges", (gstack->edges = Ttable(10)));
+    Tinss(g, "graphattr", (gstack->gattr = Tcopy(gstack->next->gattr)));
+    Tinss(g, "nodeattr", (gstack->nattr = Tcopy(gstack->next->nattr)));
+    Tinss(g, "edgeattr",
+         (gstack->ecopy = gstack->eattr = Tcopy(gstack->next->eattr)));
+    for (gframe = gstack->next; gframe->graphs != allgraphs;
+        gframe = gframe->next) {
+       if (Tfindi(gframe->graphs, gid))
+           break;
+       Tinsi(gframe->graphs, gid, g);
+    }
+    return;
+}
+
+Tobj D2Lpopgraph(void)
+{
+    graphframe_t *gframe;
+    Tobj g;
+
+    gframe = gstack, gstack = gstack->next;
+    g = gframe->g;
+    Mfree(gframe, M_BYTE2SIZE(sizeof(graphframe_t)));
+    return g;
+}
+
+Tobj D2Linsertnode(char *name)
+{
+    graphframe_t *gframe;
+    Tobj n, idobj, nameobj;
+    long nid, m;
+
+    if ((idobj = Tfinds(ndict, name))) {
+       nid = Tgetnumber(idobj), n = Tfindi(allnodes, nid);
+    } else {
+       m = Mpushmark((nameobj = Tstring(name)));
+       Tinso(ndict, nameobj, Tinteger((nid = newnid++)));
+       Mpopmark(m);
+       Tinsi(allnodes, nid, (n = Ttable(3)));
+       Tinso(n, nameo, nameobj);
+       Tinso(n, attro, Tcopy(gstack->nattr));
+       Tinso(n, edgeso, Ttable(2));
+    }
+    for (gframe = gstack; gframe->nodes != allnodes; gframe = gframe->next) {
+       if (Tfindi(gframe->nodes, nid))
+           break;
+       Tinsi(gframe->nodes, nid, n);
+    }
+    N = n;
+    return n;
+}
+
+void D2Linsertedge(Tobj tail, char *tport, Tobj head, char *hport)
+{
+    graphframe_t *gframe;
+    Tobj e;
+    long eid;
+
+    Tinsi(alledges, (eid = neweid++),
+         (e = Ttable((long) (3 + (tport ? 1 : 0) + (hport ? 1 : 0)))));
+    Tinso(e, tailo, tail);
+    if (tport && tport[0])
+       Tinso(e, tporto, Tstring(tport));
+    Tinso(e, heado, head);
+    if (hport && hport[0])
+       Tinso(e, hporto, Tstring(hport));
+    Tinso(e, attro, Tcopy(gstack->ecopy));
+    Tinsi(Tfinds(head, "edges"), eid, e);
+    Tinsi(Tfinds(tail, "edges"), eid, e);
+    for (gframe = gstack; gframe->edges != alledges; gframe = gframe->next)
+       Tinsi(gframe->edges, eid, e);
+}
+
+void D2Lbeginedge(int type, Tobj obj, char *port)
+{
+    if (!(gstack->estack = Mallocate(sizeof(edgeframe_t))))
+       panic(POS, "D2Lbeginedge", "cannot allocate edge stack");
+    gstack->estack->next = NULL;
+    gstack->estack->type = type;
+    gstack->estack->obj = obj;
+    gstack->estack->port = strdup(port);
+    gstack->emark = Mpushmark((gstack->ecopy = Tcopy(gstack->eattr)));
+}
+
+void D2Lmidedge(int type, Tobj obj, char *port)
+{
+    edgeframe_t *eframe;
+
+    if (!(eframe = Mallocate(sizeof(edgeframe_t))))
+       panic(POS, "D2Lmidedge", "cannot allocate edge stack");
+    eframe->next = gstack->estack, gstack->estack = eframe;
+    gstack->estack->type = type;
+    gstack->estack->obj = obj;
+    gstack->estack->port = strdup(port);
+}
+
+void D2Lendedge(void)
+{
+    edgeframe_t *eframe, *hframe, *tframe;
+    Tobj tnodes, hnodes;
+    Tkvindex_t tkvi, hkvi;
+
+    for (eframe = gstack->estack; eframe->next; eframe = tframe) {
+       hframe = eframe, tframe = eframe->next;
+       if (hframe->type == NODE && tframe->type == NODE) {
+           D2Linsertedge(tframe->obj, tframe->port,
+                         hframe->obj, hframe->port);
+       } else if (hframe->type == NODE && tframe->type == GRAPH) {
+           tnodes = Tfinds(tframe->obj, "nodes");
+           for (Tgetfirst(tnodes, &tkvi); tkvi.kvp; Tgetnext(&tkvi))
+               D2Linsertedge(tkvi.kvp->vo, NULL, hframe->obj,
+                             hframe->port);
+       } else if (eframe->type == GRAPH && eframe->next->type == NODE) {
+           hnodes = Tfinds(hframe->obj, "nodes");
+           for (Tgetfirst(hnodes, &hkvi); hkvi.kvp; Tgetnext(&hkvi))
+               D2Linsertedge(tframe->obj, tframe->port, hkvi.kvp->vo,
+                             NULL);
+       } else {
+           tnodes = Tfinds(tframe->obj, "nodes");
+           hnodes = Tfinds(hframe->obj, "nodes");
+           for (Tgetfirst(tnodes, &tkvi); tkvi.kvp; Tgetnext(&tkvi))
+               for (Tgetfirst(hnodes, &hkvi); hkvi.kvp; Tgetnext(&hkvi))
+                   D2Linsertedge(tkvi.kvp->vo, NULL, hkvi.kvp->vo, NULL);
+       }
+       free(eframe->port);
+       Mfree(eframe, M_BYTE2SIZE(sizeof(edgeframe_t)));
+    }
+    free(eframe->port);
+    Mfree(eframe, M_BYTE2SIZE(sizeof(edgeframe_t)));
+    Mpopmark(gstack->emark);
+    gstack->estack = NULL;
+}
+
+void D2Lsetattr(char *name, char *value)
+{
+    if (inattrstmt) {
+       switch (attrclass) {
+       case NODE:
+           Tinss(gstack->nattr, name, Tstring(value));
+           break;
+       case EDGE:
+           Tinss(gstack->eattr, name, Tstring(value));
+           break;
+       case GRAPH:
+           Tinss(gstack->gattr, name, Tstring(value));
+           break;
+       }
+       return;
+    }
+    switch (attrclass) {
+    case NODE:
+       Tinss(Tfinds(N, "attr"), name, Tstring(value));
+       break;
+    case EDGE:
+       Tinss(gstack->ecopy, name, Tstring(value));
+       break;
+       /* a subgraph cannot have optional attrs? */
+    case GRAPH:
+       Tinss(gstack->gattr, name, Tstring(value));
+       break;
+    }
+}
diff --git a/cmd/lefty/dot2l/dot2l.h b/cmd/lefty/dot2l/dot2l.h
new file mode 100644 (file)
index 0000000..ff2010f
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef _DOT2L_H
+#define _DOT2L_H
+#define SMALLBUF 128
+
+    int yyparse(void);
+    int yylex(void);
+
+    typedef struct edgeframe_t {
+       struct edgeframe_t *next;
+       int type;
+       void *obj;
+       char *port;
+    } edgeframe_t;
+
+    typedef struct graphframe_t {
+       struct graphframe_t *next;
+       Tobj g, graphs, nodes, edges;
+       Tobj gattr, nattr, eattr, ecopy;
+       long emark;
+       struct edgeframe_t *estack;
+    } graphframe_t;
+
+    typedef enum {
+       NODE, EDGE, GRAPH
+    } objtype_t;
+
+    extern char *gtype, *etype;
+    extern int yaccdone;
+    extern int attrclass;
+    extern int inattrstmt;
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+    Tobj D2Lparsegraphlabel(Tobj, Tobj);
+    Tobj D2Lreadgraph(int, Tobj);
+    void D2Lwritegraph(int, Tobj, int);
+    void D2Lbegin(char *);
+    void D2Lend(void);
+    void D2Labort(void);
+    void D2Lpushgraph(char *);
+    Tobj D2Lpopgraph(void);
+    Tobj D2Linsertnode(char *);
+    void D2Linsertedge(Tobj, char *, Tobj, char *);
+    void D2Lbeginedge(int, Tobj, char *);
+    void D2Lmidedge(int, Tobj, char *);
+    void D2Lendedge(void);
+    void D2Lsetattr(char *, char *);
+#endif                         /* _DOT2L_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cmd/lefty/dot2l/dotlex.c b/cmd/lefty/dot2l/dotlex.c
new file mode 100644 (file)
index 0000000..209f678
--- /dev/null
@@ -0,0 +1,305 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* the graph lexer */
+
+typedef void *Tobj;
+#include "common.h"
+#include "dotparse.h"
+#include "dot2l.h"
+#include "io.h"
+#include "triefa.c"
+
+static int Syntax_errors;
+static int Lexer_fd;
+#define LEXBUFSIZE 10240
+static char LexBuf[LEXBUFSIZE], *LexPtr;
+static int In_comment;
+static int Comment_start;
+int Line_number;
+
+static char *lex_gets(void);
+static int lex_token(char *);
+static void error_context(void);
+static char *skip_wscomments(char *);
+static char *scan_token(char *);
+static char *scan_num(char *);
+static char *quoted_string(char *);
+
+void lex_begin(int ioi)
+{
+    Lexer_fd = ioi;
+    LexPtr = NULL;
+}
+
+int myyylex(void)
+{                              /* for debugging */
+    int rv = myyylex();
+
+    fprintf(stderr, "returning %d\n", rv);
+    if (rv == T_id)
+       fprintf(stderr, "string val is %s\n", yylval.s);
+    return rv;
+}
+
+int yylex(void)
+{
+    int token;
+    char *p;
+
+    /* if the parser has accepted a graph, reset and return EOF */
+    if (yaccdone) {
+       yaccdone = FALSE;
+       return EOF;
+    }
+
+    /* get a nonempty lex buffer */
+    do {
+       if ((LexPtr == NULL) || (LexPtr[0] == '\0'))
+           if ((LexPtr = lex_gets()) == NULL) {
+               if (In_comment)
+                   fprintf(stderr,
+                           "warning, nonterminated comment in line %d\n",
+                           Comment_start);
+               return EOF;
+           }
+       LexPtr = skip_wscomments(LexPtr);
+    } while (LexPtr[0] == '\0');
+
+    /* scan quoted strings */
+    if (LexPtr[0] == '\"') {
+       LexPtr = quoted_string(LexPtr);
+       yylval.s = (char *) strdup(LexBuf);
+       return T_id;
+    }
+
+    /* scan edge operator */
+    if (etype && (strncmp(LexPtr, etype, strlen(etype)) == 0)) {
+       LexPtr += strlen(etype);
+       return T_edgeop;
+    }
+
+    /* scan numbers */
+    if ((p = scan_num(LexPtr))) {
+       LexPtr = p;
+       yylval.s = strdup(LexBuf);
+       return T_id;
+    } else {
+       if (ispunct(LexPtr[0]) && (LexPtr[0] != '_'))
+           return *LexPtr++;
+       else
+           LexPtr = scan_token(LexPtr);
+    }
+
+    /* scan other tokens */
+    token = lex_token(LexBuf);
+    if (token == -1) {
+       yylval.s = strdup(LexBuf);
+       token = T_id;
+    }
+    return token;
+}
+
+void yyerror(char *fmt, char *s)
+{
+    if (Syntax_errors++)
+       return;
+    fprintf(stderr, "graph parser: ");
+    fprintf(stderr, fmt, s);
+    fprintf(stderr, " near line %d\n", Line_number);
+    error_context();
+}
+
+static char *lex_gets(void)
+{
+    char *clp;
+    int len, curlen;
+
+    curlen = 0;
+    do {
+       /* off by one so we can back up in LineBuf */
+       if (IOreadline(Lexer_fd,
+                      LexBuf + curlen + 1, LEXBUFSIZE - curlen - 1) == -1)
+           break;
+       clp = LexBuf + curlen + 1;
+       len = strlen(clp);
+       clp[len++] = '\n';
+       clp[len] = 0;
+
+       if (clp == LexBuf + 1 && clp[0] == '#') {
+           /* comment line or cpp line sync */
+           if (sscanf(clp + 1, "%d", &Line_number) == 0)
+               Line_number++;
+           len = 0;
+           clp[len] = 0;
+           continue;
+       }
+
+       Line_number++;
+       if ((len = strlen(clp)) > 1) {
+           if (clp[len - 2] == '\\') {
+               len = len - 2;
+               clp[len] = '\0';
+           }
+       }
+       curlen += len;
+    } while (clp[len - 1] != '\n');
+
+    if (curlen > 0)
+       return LexBuf + 1;
+    else
+       return NULL;
+}
+
+static int lex_token(char *p)
+{
+    TFA_Init();
+    while (*p)
+       TFA_Advance(*p++);
+    return TFA_Definition();
+}
+
+static void error_context(void)
+{
+    char *p, *q;
+
+    if (LexPtr == NULL)
+       return;
+    fprintf(stderr, "context: ");
+    for (p = LexPtr - 1; (p > LexBuf) && (isspace(*p) == FALSE); p--);
+    for (q = LexBuf; q < p; q++)
+       fputc(*q, stderr);
+    fputs(" >>> ", stderr);
+    for (; q < LexPtr; q++)
+       fputc(*q, stderr);
+    fputs(" <<< ", stderr);
+    fputs(LexPtr, stderr);
+}
+
+/* i wrote this and it still frightens me */
+/* skip white space and comments in p */
+static char *skip_wscomments(char *p)
+{
+    do {
+       while (isspace(*p))
+           p++;
+       while (In_comment && p[0]) {
+           while (p[0] && (p[0] != '*'))
+               p++;
+           if (p[0]) {
+               if (p[1] == '/') {
+                   In_comment = FALSE;
+                   p += 2;
+                   break;
+               } else
+                   p++;
+           }
+       }
+       if (p[0] == '/') {
+           if (p[1] == '/')
+               while (*p)
+                   p++;        /* skip to end of line */
+           else {
+               if (p[1] == '*') {
+                   In_comment = TRUE;
+                   Comment_start = Line_number;
+                   p += 2;
+                   continue;
+               } else
+                   break;      /* return a slash */
+           }
+       } else {
+           if (!isspace(*p))
+               break;
+       }
+    } while (p[0]);
+    return p;
+}
+
+/* scan an unquoted token and return the position after its terminator */
+static char *scan_token(char *p)
+{
+    char *q;
+
+    q = LexBuf;
+    if (p == '\0')
+       return NULL;
+    while (isalnum(*p) || (*p == '_'))
+       *q++ = *p++;
+    *q = '\0';
+    return p;
+}
+
+static char *scan_num(char *p)
+{
+    char *q, *z;
+    int saw_rp = FALSE;
+    int saw_digit = FALSE;
+
+    z = p;
+    q = LexBuf;
+    if (*z == '-')
+       *q++ = *z++;
+    if (*z == '.') {
+       saw_rp = TRUE;
+       *q++ = *z++;
+    }
+    while (isdigit(*z)) {
+       saw_digit = TRUE;
+       *q++ = *z++;
+    }
+    if ((*z == '.') && (saw_rp == FALSE)) {
+       saw_rp = TRUE;
+       *q++ = *z++;
+       while (isdigit(*z)) {
+           saw_digit = TRUE;
+           *q++ = *z++;
+       }
+    }
+    *q = '\0';
+    if (saw_digit && *z && (isalpha(*z)))
+       yyerror("badly formed number %s", LexBuf);
+
+    if (saw_digit == FALSE)
+       z = NULL;
+    return z;
+}
+
+/* scan a quoted string and return the position after its terminator */
+static char *quoted_string(char *p)
+{
+    char quote, *q;
+
+    quote = *p++;
+    q = LexBuf;
+    while ((*p) && (*p != quote)) {
+       if (*p == '\\') {
+           if (*(p + 1) == quote)
+               p++;
+           else {
+               if (*(p + 1) == '\\')
+                   *q++ = *p++;
+           }
+       }
+       *q++ = *p++;
+    }
+    if (*p == '\0')
+       yyerror("string ran past end of line", "");
+    else
+       p++;
+    *q = 0;
+    return p;
+}
diff --git a/cmd/lefty/dot2l/dotparse.y b/cmd/lefty/dot2l/dotparse.y
new file mode 100644 (file)
index 0000000..a1912af
--- /dev/null
@@ -0,0 +1,199 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+%{
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+typedef void *Tobj;
+
+#include "dot2l.h"
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#include <string.h>
+
+static char portstr[SMALLBUF];
+
+extern void yyerror(char *);
+%}
+
+%union {
+    long i;
+    char *s;
+    void *o;
+}
+
+%token <i> T_graph T_digraph T_strict
+%token <i> T_node T_edge T_edgeop
+%token <s> T_id
+%type <o> node_name node_id subg_stmt
+%left <i> T_subgraph /* to eliminate subgraph hdr shift/reduce conflict */
+%left '{'
+%%
+
+file: graph_type T_id
+    { D2Lbegin ($2); free ($2); }
+  '{' stmt_list '}'
+    { D2Lend (); }
+| error
+    { D2Labort (); }
+| /* empty*/
+    { D2Labort (); }
+;
+
+graph_type: T_graph /* safe to change graph type/name before contents appear */
+    { gtype = "graph"; etype = "--"; }
+| T_strict T_graph
+    { gtype = "strict graph"; etype = "--"; }
+| T_digraph
+    { gtype = "digraph"; etype = "->"; }
+| T_strict T_digraph
+    { gtype = "strict digraph"; etype = "->"; }
+;
+
+stmt_list: stmt_list1
+| /* empty */
+;
+
+stmt_list1: stmt
+| stmt_list1 stmt
+;
+
+stmt: stmt1
+| stmt1 ';'
+;
+
+stmt1: node_stmt /* create nodes and set attributes */
+| edge_stmt /* create edges and set attributes */
+| attr_stmt /* reset value of attributes */
+| subg_stmt {}
+;
+
+node_stmt: node_id { attrclass = NODE; portstr[0] = '\000'; }
+    opt_attr_list { attrclass = GRAPH; }
+;
+
+node_id: node_name node_port
+    { $$ = $1; }
+;
+
+node_name: T_id
+    { $$ = D2Linsertnode ($1); free ($1); }
+;
+
+edge_stmt: node_id
+    { D2Lbeginedge (NODE, $1, portstr); portstr[0] = '\000'; }
+  edgeRHS
+    { attrclass = EDGE; }
+  opt_attr_list
+    { D2Lendedge (); attrclass = GRAPH; }
+| subg_stmt
+    { D2Lbeginedge (GRAPH, $1, ""); }
+  edgeRHS
+    { attrclass = EDGE; }
+  opt_attr_list
+    { D2Lendedge (); attrclass = GRAPH; }
+;
+
+edgeRHS: T_edgeop node_id
+    { D2Lmidedge (NODE, $2, portstr); portstr[0] = '\000'; }
+| T_edgeop node_id
+    { D2Lmidedge (NODE, $2, portstr); portstr[0] = '\000'; } edgeRHS
+| T_edgeop subg_stmt
+    { D2Lmidedge (GRAPH, $2, ""); portstr[0] = '\000'; }
+| T_edgeop subg_stmt
+    { D2Lmidedge (GRAPH, $2, ""); portstr[0] = '\000'; } edgeRHS
+;
+
+node_port: /* empty */
+| port_location
+| port_angle
+| port_angle port_location
+| port_location port_angle
+;
+
+port_location: ':' T_id
+    {
+        strcat (portstr, $2); free ($2);
+    }
+| ':' '(' T_id ',' T_id ')'
+    {
+        strcat (portstr, "("); strcat (portstr, $3);
+        strcat (portstr, ","); strcat (portstr, $5);
+        strcat (portstr, ")");
+        free ($3), free ($5);
+    }
+;
+
+port_angle: '@' T_id
+    {
+        strcat (portstr, "@"); strcat (portstr, $2); free ($2);
+    }
+;
+
+attr_stmt: attr_class
+    { inattrstmt = TRUE; }
+  attr_list
+    { attrclass = GRAPH; inattrstmt = FALSE; }
+| attr_set
+    { attrclass = GRAPH; }
+;
+
+attr_class: T_graph
+    { attrclass = GRAPH; }
+| T_node
+    { attrclass = NODE; }
+| T_edge
+    { attrclass = EDGE; }
+;
+
+opt_attr_list: rec_attr_list
+;
+
+rec_attr_list: rec_attr_list attr_list
+| /* empty */
+;
+
+attr_list: '[' inside_attr_list ']'
+;
+
+inside_attr_list: attr_set optcomma inside_attr_list
+| /* empty */
+;
+
+attr_set: T_id '=' T_id
+    { D2Lsetattr ($1, $3); free ($1); free ($3); }
+;
+
+optcomma: /* empty */
+| ','
+;
+
+subg_stmt: subg_hdr '{' stmt_list '}' %prec '{'
+    { $$ = D2Lpopgraph (); }
+| '{' { D2Lpushgraph (NULL); } stmt_list '}'
+    { $$ = D2Lpopgraph (); }
+| subg_hdr %prec T_subgraph
+    { $$ = D2Lpopgraph (); }
+;
+
+subg_hdr: T_subgraph T_id
+    { D2Lpushgraph ($2); free ($2); }
+;
diff --git a/cmd/lefty/dot2l/dottrie.c b/cmd/lefty/dot2l/dottrie.c
new file mode 100644 (file)
index 0000000..b6e68e9
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "common.h"
+#include "dotparse.h"
+#include "triefa.h"
+
+TrieState TrieStateTbl[34] = {
+    {-1, 0, 0x42058}
+    ,
+    {-1, 5, 0x100}
+    ,
+    {-1, 6, 0x40}
+    ,
+    {-1, 7, 0x20000}
+    ,
+    {-1, 8, 0x1}
+    ,
+    {-1, 9, 0x8000}
+    ,
+    {-1, 10, 0x80}
+    ,
+    {T_digraph, 11, 0x0}
+    ,
+    {-1, 11, 0x8}
+    ,
+    {-1, 12, 0x40}
+    ,
+    {-1, 13, 0x10}
+    ,
+    {T_edge, 14, 0x0}
+    ,
+    {-1, 14, 0x20000}
+    ,
+    {-1, 15, 0x1}
+    ,
+    {-1, 16, 0x8000}
+    ,
+    {-1, 17, 0x80}
+    ,
+    {T_graph, 18, 0x0}
+    ,
+    {-1, 18, 0x4000}
+    ,
+    {-1, 19, 0x8}
+    ,
+    {-1, 20, 0x10}
+    ,
+    {T_node, 21, 0x0}
+    ,
+    {-1, 21, 0x180000}
+    ,
+    {-1, 23, 0x20000}
+    ,
+    {-1, 24, 0x100}
+    ,
+    {-1, 25, 0x4}
+    ,
+    {-1, 26, 0x80000}
+    ,
+    {T_strict, 27, 0x0}
+    ,
+    {-1, 27, 0x2}
+    ,
+    {-1, 28, 0x40}
+    ,
+    {-1, 29, 0x20000}
+    ,
+    {-1, 30, 0x1}
+    ,
+    {-1, 31, 0x8000}
+    ,
+    {-1, 32, 0x80}
+    ,
+    {T_subgraph, 33, 0x0}
+    ,
+};
+TrieTrans TrieTransTbl[33] = {
+    /* State   0 */ {'s', 21}
+    , {'e', 8}
+    , {'g', 12}
+    ,
+    {'n', 17}
+    , {'d', 1}
+    ,
+    /* State   1 */ {'i', 2}
+    ,
+    /* State   2 */ {'g', 3}
+    ,
+    /* State   3 */ {'r', 4}
+    ,
+    /* State   4 */ {'a', 5}
+    ,
+    /* State   5 */ {'p', 6}
+    ,
+    /* State   6 */ {'h', 7}
+    ,
+    /* State   8 */ {'d', 9}
+    ,
+    /* State   9 */ {'g', 10}
+    ,
+    /* State  10 */ {'e', 11}
+    ,
+    /* State  12 */ {'r', 13}
+    ,
+    /* State  13 */ {'a', 14}
+    ,
+    /* State  14 */ {'p', 15}
+    ,
+    /* State  15 */ {'h', 16}
+    ,
+    /* State  17 */ {'o', 18}
+    ,
+    /* State  18 */ {'d', 19}
+    ,
+    /* State  19 */ {'e', 20}
+    ,
+    /* State  21 */ {'t', 22}
+    , {'u', 27}
+    ,
+    /* State  22 */ {'r', 23}
+    ,
+    /* State  23 */ {'i', 24}
+    ,
+    /* State  24 */ {'c', 25}
+    ,
+    /* State  25 */ {'t', 26}
+    ,
+    /* State  27 */ {'b', 28}
+    ,
+    /* State  28 */ {'g', 29}
+    ,
+    /* State  29 */ {'r', 30}
+    ,
+    /* State  30 */ {'a', 31}
+    ,
+    /* State  31 */ {'p', 32}
+    ,
+    /* State  32 */ {'h', 33}
+    ,
+};
diff --git a/cmd/lefty/dot2l/triefa.c b/cmd/lefty/dot2l/triefa.c
new file mode 100644 (file)
index 0000000..a86e12b
--- /dev/null
@@ -0,0 +1,95 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+/* File - TrieFA.ins.c
+ *
+ *    This file contains code to be included in the scanner file using a
+ *    generated trie-based FA.
+ */
+
+#include "triefa.h"
+
+#ifdef UNDERLINE
+static long CharMask[28] = {
+    0x0000001, 0x0000000, 0x0000004, 0x0000008,
+    0x0000010, 0x0000020, 0x0000040, 0x0000080,
+    0x0000100, 0x0000200, 0x0000400, 0x0000800,
+    0x0001000, 0x0002000, 0x0004000, 0x0008000,
+    0x0010000, 0x0020000, 0x0040000, 0x0080000,
+    0x0100000, 0x0200000, 0x0400000, 0x0800000,
+    0x1000000, 0x2000000, 0x4000000, 0x8000000,
+};
+
+#define IN_MASK_RANGE(C) (islower (C) || ((C) == '_'))
+#define MASK_INDEX(C)    ((C) - '_')
+
+#else
+static long CharMask[26] = {
+    0x0000001, 0x0000002, 0x0000004, 0x0000008,
+    0x0000010, 0x0000020, 0x0000040, 0x0000080,
+    0x0000100, 0x0000200, 0x0000400, 0x0000800,
+    0x0001000, 0x0002000, 0x0004000, 0x0008000,
+    0x0010000, 0x0020000, 0x0040000, 0x0080000,
+    0x0100000, 0x0200000, 0x0400000, 0x0800000,
+    0x1000000, 0x2000000
+};
+
+#define IN_MASK_RANGE(C) islower (C)
+#define MASK_INDEX(C)    ((C) - 'a')
+
+#endif
+
+static short TFA_State;
+
+/* TFA_Init:
+ *
+ *    Initialize the trie FA.
+ */
+#define TFA_Init() TFA_State = 0
+
+/* TFA_Advance:
+ *
+ * Advance to the next state (or -1) on the lowercase letter c.
+ * This should be an inline routine, but the C++ implementation
+ * isn't advanced enough so we use a macro.
+ */
+#define TFA_Advance(C) { \
+    char c = C; \
+    if (TFA_State >= 0) { \
+        if (isupper (c)) \
+            c = tolower (c); \
+        else if (! IN_MASK_RANGE (c)) { \
+            TFA_State = -1; \
+            goto TFA_done; \
+        } \
+        if (TrieStateTbl[TFA_State].mask & CharMask[MASK_INDEX (c)]) { \
+            short i = TrieStateTbl[TFA_State].trans_base; \
+            while (TrieTransTbl[i].c != c) \
+                i++; \
+            TFA_State = TrieTransTbl[i].next_state; \
+        } \
+        else \
+            TFA_State = -1; \
+    } \
+  TFA_done:; \
+}                              /* end of TFA_Advance. */
+
+/* TFA_Definition:
+ *
+ *    Return the definition (if any) associated with the current state.
+ */
+#define TFA_Definition() \
+    ((TFA_State < 0) ? -1 : TrieStateTbl[TFA_State].def)
diff --git a/cmd/lefty/dot2l/triefa.h b/cmd/lefty/dot2l/triefa.h
new file mode 100644 (file)
index 0000000..b5f3266
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* File - TrieFA.h
+ *
+ *    The data types for the generated trie-baseed finite automata.
+ */
+
+    struct TrieState {         /* An entry in the FA state table */
+       short def;              /* If this state is an accepting state then */
+       /* this is the definition, otherwise -1.    */
+       short trans_base;       /* The base index into the transition table. */
+       long mask;              /* The transition mask.                     */
+    };
+
+    struct TrieTrans {         /* An entry in the FA transition table. */
+       short c;                /* The transition character (lowercase). */
+       short next_state;       /* The next state.                       */
+    };
+
+    typedef struct TrieState TrieState;
+    typedef struct TrieTrans TrieTrans;
+
+    extern TrieState TrieStateTbl[];
+    extern TrieTrans TrieTransTbl[];
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cmd/lefty/examples/.cvsignore b/cmd/lefty/examples/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/cmd/lefty/examples/Makefile.am b/cmd/lefty/examples/Makefile.am
new file mode 100644 (file)
index 0000000..dfa751d
--- /dev/null
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+
+leftydir = $(pkgdatadir)/lefty
+
+lefty_SCRIPTS = box.lefty def.lefty fractal.lefty fractal2.lefty \
+       slides.lefty tree.lefty
+
+EXTRA_DIST = $(lefty_SCRIPTS)