From 034f4676d29b5640f33016c848c6faead6a6ccc3 Mon Sep 17 00:00:00 2001 From: erg Date: Tue, 23 Jun 2009 22:12:55 +0000 Subject: [PATCH] Make gvpr into a library. --- cmd/gvpr/Makefile.am | 52 ++-- cmd/gvpr/Makefile.old | 28 +- cmd/gvpr/gvprmain.c | 109 +++++++ configure.ac | 2 + lib/Makefile.am | 2 +- lib/gvpr/Makefile.am | 50 ++++ lib/gvpr/Makefile.old | 50 ++++ {cmd => lib}/gvpr/actions.c | 48 ++-- {cmd => lib}/gvpr/actions.h | 0 {cmd => lib}/gvpr/compile.c | 276 ++++++++++++------ {cmd => lib}/gvpr/compile.h | 2 + lib/gvpr/gdefs.h | 304 ++++++++++++++++++++ {cmd => lib}/gvpr/gprdata | 0 {cmd => lib}/gvpr/gprstate.c | 39 ++- {cmd => lib}/gvpr/gprstate.h | 13 +- {cmd => lib}/gvpr/gvpr.c | 540 +++++++++++++++++++++++++---------- lib/gvpr/gvpr.h | 48 ++++ lib/gvpr/libgvpr.pc.in | 11 + {cmd => lib}/gvpr/mkdefs.c | 0 {cmd => lib}/gvpr/parse.c | 85 ++++-- {cmd => lib}/gvpr/parse.h | 1 + {cmd => lib}/gvpr/queue.c | 0 {cmd => lib}/gvpr/queue.h | 0 lib/gvpr/trie.c | 136 +++++++++ lib/gvpr/trieFA.h | 87 ++++++ 25 files changed, 1544 insertions(+), 339 deletions(-) create mode 100644 cmd/gvpr/gvprmain.c create mode 100644 lib/gvpr/Makefile.am create mode 100644 lib/gvpr/Makefile.old rename {cmd => lib}/gvpr/actions.c (93%) rename {cmd => lib}/gvpr/actions.h (100%) rename {cmd => lib}/gvpr/compile.c (91%) rename {cmd => lib}/gvpr/compile.h (96%) create mode 100644 lib/gvpr/gdefs.h rename {cmd => lib}/gvpr/gprdata (100%) rename {cmd => lib}/gvpr/gprstate.c (71%) rename {cmd => lib}/gvpr/gprstate.h (86%) rename {cmd => lib}/gvpr/gvpr.c (56%) create mode 100644 lib/gvpr/gvpr.h create mode 100644 lib/gvpr/libgvpr.pc.in rename {cmd => lib}/gvpr/mkdefs.c (100%) rename {cmd => lib}/gvpr/parse.c (87%) rename {cmd => lib}/gvpr/parse.h (96%) rename {cmd => lib}/gvpr/queue.c (100%) rename {cmd => lib}/gvpr/queue.h (100%) create mode 100644 lib/gvpr/trie.c create mode 100644 lib/gvpr/trieFA.h diff --git a/cmd/gvpr/Makefile.am b/cmd/gvpr/Makefile.am index b57dd71ff..dedaed705 100644 --- a/cmd/gvpr/Makefile.am +++ b/cmd/gvpr/Makefile.am @@ -3,10 +3,11 @@ pdfdir = $(pkgdatadir)/doc/pdf + AM_CPPFLAGS = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/lib/expr \ - -I$(top_builddir)/lib/expr \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib/expr \ + -I$(top_builddir)/lib/expr \ -I$(top_srcdir)/lib/vmalloc \ -I$(top_srcdir)/lib/sfio \ -I$(top_srcdir)/lib/ast \ @@ -14,34 +15,35 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/cgraph \ -I$(top_srcdir)/lib/cdt +if ENABLE_STATIC +bin_PROGRAMS = gvpr gvpr_static +else bin_PROGRAMS = gvpr -noinst_PROGRAMS = mkdefs -noinst_HEADERS = actions.h compile.h gprstate.h parse.h queue.h +endif + man_MANS = gvpr.1 pdf_DATA = gvpr.1.pdf -gvpr_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c - -gvpr_LDADD = \ - $(top_builddir)/lib/vmalloc/libvmalloc_C.la \ - $(top_builddir)/lib/sfio/libsfio_C.la \ - $(top_builddir)/lib/ingraphs/libingraphs_C.la \ - $(top_builddir)/lib/expr/libexpr_C.la \ - $(top_builddir)/lib/cgraph/libcgraph.la @MATH_LIBS@ - -gvpr_DEPENDENCIES = \ - $(top_builddir)/lib/ast/libast_C.la - -$(gvpr_OBJECTS): gdefs.h - -mkdefs_SOURCES = mkdefs.c - -gdefs.h: $(top_srcdir)/cmd/gvpr/gprdata mkdefs - ./mkdefs gdefs.h < $(top_srcdir)/cmd/gvpr/gprdata +gvpr_SOURCES = gvprmain.c +gvpr_CPPFLAGS = $(AM_CPPFLAGS) +gvpr_LDADD = $(top_builddir)/lib/gvpr/libgvpr.la gvpr.1.pdf: $(srcdir)/gvpr.1 - @GROFF@ -Tps -man $(srcdir)/gvpr.1 | @PS2PDF@ - - >gvpr.1.pdf -EXTRA_DIST = $(man_MANS) $(pdf_DATA) lib Makefile.old gprdata mkdefs.c gdefs.h gvpr.vcproj +gvpr_static_SOURCES = gvprmain.c +gvpr_static_CPPFLAGS = $(AM_CPPFLAGS) +gvpr_static_LDADD = \ + $(top_builddir)/lib/gvpr/libgvpr_C.la \ + $(top_builddir)/lib/expr/libexpr_C.la \ + $(top_builddir)/lib/sfio/libsfio_C.la \ + $(top_builddir)/lib/vmalloc/libvmalloc_C.la \ + $(top_builddir)/lib/ingraphs/libingraphs_C.la \ + $(top_builddir)/lib/ast/libast_C.la \ + $(top_builddir)/lib/cgraph/libcgraph_C.la \ + $(top_builddir)/lib/cdt/libcdt_C.la \ + $(MATH_LIBS) + +EXTRA_DIST = $(man_MANS) $(pdf_DATA) Makefile.old gvpr.vcproj -DISTCLEANFILES = $(pdf_DATA) gdefs.h mkdefs +DISTCLEANFILES = $(pdf_DATA) diff --git a/cmd/gvpr/Makefile.old b/cmd/gvpr/Makefile.old index 13838999a..e48a0a6d6 100644 --- a/cmd/gvpr/Makefile.old +++ b/cmd/gvpr/Makefile.old @@ -10,24 +10,22 @@ LOC_LIB=$(ROOT)/lib LOC_INCDIR=$(LOC_LIB)/include LOC_LIBDIR=$(LOC_LIB)/lib -INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt +INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/gvpr -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt DEFINES = -DHAVE_CONFIG_H -DUSE_CGRAPH -OBJS = gvpr.o parse.o compile.o gprstate.o actions.o queue.o +OBJS = gvprmain.o -compile.o : gdefs.h +LIBS = -L$(LOC_LIB)/gvpr -lgvpr \ + -L$(LOC_LIB)/expr -lexpr \ + -L$(LOC_LIB)/ast -last \ + -L$(LOC_LIB)/sfio -lsfio \ + -L$(LOC_LIB)/vmalloc -lvmalloc \ + -L$(LOC_LIB)/ingraphs -lingraphs \ + -L$(LOC_LIB)/cgraph -lcgraph \ + -L$(LOC_LIB)/cdt -lcdt -lm -gdefs.h : gprdata mkdefs - mkdefs gdefs.h < gprdata - -mkdefs : mkdefs.o - $(CC) $(LDFLAGS) mkdefs.o -o $@ - -GLIBS = -L$(LOC_LIB)/cgraph -L$(LOC_LIB)/cdt -lcgraph -lcdt -LIBS = -L$(LOC_LIBDIR) -lexpr -last -lvmalloc -lsfio -lingraphs $(GLIBS) -lm - -gvpr : $(OBJS) $(LOC_LIBDIR)/libexpr.a +gvpr : $(OBJS) $(CSLD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ $(OBJS) : gdefs.h @@ -39,7 +37,7 @@ install : all $(INSTALL) gvpr.1 $(MANDIR) clean : - $(RM) core gdefs.h *.o + $(RM) core *.o distclean : clean - $(RM) mkdefs $(ALL) + $(RM) $(ALL) diff --git a/cmd/gvpr/gvprmain.c b/cmd/gvpr/gvprmain.c new file mode 100644 index 000000000..3c09f7aab --- /dev/null +++ b/cmd/gvpr/gvprmain.c @@ -0,0 +1,109 @@ +/* $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 * +**********************************************************/ + + +/* + * gvpr: graph pattern recognizer + * + * Written by Emden Gansner + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#else +#include "compat_unistd.h" +#endif +#include "gvpr.h" + +#ifdef DEBUG +#include "sfio.h" +static ssize_t outfn (void* sp, const char *buf, size_t nbyte, void* dp) +{ + write (1, " ", 8); + return write (1, buf, nbyte); +} + +static ssize_t errfn (void* sp, const char *buf, size_t nbyte, void* dp) +{ + write (2, " ", 8); + return write (2, buf, nbyte); +} + +static int iofread(void *chan, char *buf, int bufsize) +{ + return read(sffileno((Sfio_t *) chan), buf, bufsize); +} + +static int ioputstr(void *chan, char *str) +{ + return sfputr((Sfio_t *) chan, str, -1); +} + +static int ioflush(void *chan) +{ + return sfsync((Sfio_t *) chan); +} + +static Agiodisc_t gprIoDisc = { iofread, ioputstr, ioflush }; + +static Agdisc_t gprDisc = { &AgMemDisc, &AgIdDisc, &gprIoDisc }; + +int +main (int argc, char* argv[]) +{ + Agraph_t* gs[2]; + Agraph_t* g = agread (sfstdin, &gprDisc); + int rv, i; + gvpropts opts; + + gs[0] = g; + gs[1] = 0; + opts.ingraphs = gs; + opts.out = outfn; + opts.err = errfn; + opts.flags = GV_USE_OUTGRAPH; + + rv = gvpr (argc, argv, &opts); + + sfprintf (sfstderr, "rv %d\n", rv); + /* for (i = 0; i < opts.n_outgraphs; i++) */ + /* agwrite (opts.outgraphs[i], sfstdout); */ + + rv = gvpr (argc, argv, &opts); + + return rv; +} + +#else +int +main (int argc, char* argv[]) +{ + gvpropts opts; + opts.ingraphs = 0; + opts.out = 0; + opts.err = 0; + opts.flags = GV_USE_EXIT; + + return gvpr (argc, argv, &opts); +} + +#endif + diff --git a/configure.ac b/configure.ac index 74d122885..1901c66a9 100644 --- a/configure.ac +++ b/configure.ac @@ -3033,6 +3033,8 @@ AC_CONFIG_FILES(Makefile lib/sparse/Makefile lib/sfdpgen/Makefile lib/osage/Makefile + lib/gvpr/Makefile + lib/gvpr/libgvpr.pc lib/circogen/Makefile lib/twopigen/Makefile lib/patchwork/Makefile diff --git a/lib/Makefile.am b/lib/Makefile.am index 92c981e7a..38591d58d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,6 +4,6 @@ SUBDIRS = cdt graph cgraph gd pathplan sfio vmalloc ast \ vpsc rbtree ortho sparse patchwork expr common \ pack gvc xdot ingraphs topfish glcomp \ - circogen dotgen fdpgen neatogen twopigen sfdpgen osage + circogen dotgen fdpgen neatogen twopigen sfdpgen osage gvpr EXTRA_DIST = Makefile.old gvc.vcproj gvc.def diff --git a/lib/gvpr/Makefile.am b/lib/gvpr/Makefile.am new file mode 100644 index 000000000..0dbb7e4fd --- /dev/null +++ b/lib/gvpr/Makefile.am @@ -0,0 +1,50 @@ +# $Id$Revision: +## Process this file with automake to produce Makefile.in + +pkgconfigdir = $(libdir)/pkgconfig + +GVPR_VERSION="1:0:0" + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib/expr \ + -I$(top_builddir)/lib/expr \ + -I$(top_srcdir)/lib/vmalloc \ + -I$(top_srcdir)/lib/sfio \ + -I$(top_srcdir)/lib/ast \ + -I$(top_srcdir)/lib/ingraphs \ + -I$(top_srcdir)/lib/cgraph \ + -I$(top_srcdir)/lib/cdt + +pkginclude_HEADERS = gvpr.h +noinst_PROGRAMS = mkdefs +noinst_HEADERS = actions.h compile.h gprstate.h parse.h queue.h +noinst_LTLIBRARIES = libgvpr_C.la +lib_LTLIBRARIES = libgvpr.la +pkgconfig_DATA = libgvpr.pc + +libgvpr_C_la_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c +$(libgvpr_C_la_OBJECTS): gdefs.h +libgvpr_C_la_DEPENDENCIES = \ + $(top_builddir)/lib/expr/libexpr_C.la \ + $(top_builddir)/lib/ingraphs/libingraphs_C.la + + +libgvpr_la_LDFLAGS = -version-info $(GVPR_VERSION) -no-undefined +libgvpr_la_SOURCES = $(libgvpr_C_la_SOURCES) +libgvpr_la_LIBADD = $(libgvpr_C_la_LIBADD) \ + $(top_builddir)/lib/ingraphs/libingraphs_C.la \ + $(top_builddir)/lib/expr/libexpr_C.la \ + $(top_builddir)/lib/cdt/libcdt.la \ + $(top_builddir)/lib/cgraph/libcgraph.la \ + $(MATH_LIBS) +libgvpr_la_DEPENDENCIES = $(libgvpr_C_la_DEPENDENCIES) + +mkdefs_SOURCES = mkdefs.c + +gdefs.h: $(top_srcdir)/lib/gvpr/gprdata mkdefs + ./mkdefs gdefs.h < $(top_srcdir)/lib/gvpr/gprdata + +EXTRA_DIST = $(man_MANS) $(pdf_DATA) lib Makefile.old gprdata mkdefs.c gdefs.h gvpr.vcproj + +DISTCLEANFILES = $(pdf_DATA) gdefs.h mkdefs diff --git a/lib/gvpr/Makefile.old b/lib/gvpr/Makefile.old new file mode 100644 index 000000000..33c546045 --- /dev/null +++ b/lib/gvpr/Makefile.old @@ -0,0 +1,50 @@ +# gvpr library make file +# Written by Emden R. Gansner (23 June 2009) +ALL = libgvpr.a +all : $(ALL) +ROOT=../.. +include $(ROOT)/Config.mk +include $(ROOT)/makearch/$(ARCH) + +LOC_LIB=$(ROOT)/lib +LOC_INCDIR=$(LOC_LIB)/include +LOC_LIBDIR=$(LOC_LIB)/lib + +INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt \ + -I$(LOC_LIB)/expr -I$(LOC_LIB)/ast -I$(LOC_LIB)/sfio -I$(LOC_LIB)/vmalloc -I$(LOC_LIB)/ingraphs + +DEFINES = -DHAVE_CONFIG_H -DUSE_CGRAPH + +OBJS = gvpr.o parse.o compile.o gprstate.o actions.o queue.o trie.o + + +compile.o : gdefs.h + +gdefs.h : gprdata mkdefs + mkdefs gdefs.h < gprdata + +mkdefs : mkdefs.o + $(CC) $(LDFLAGS) mkdefs.o -o $@ + +GLIBS = -L$(LOC_LIB)/cgraph -L$(LOC_LIB)/cdt -lcgraph -lcdt +LIBS = -L$(LOC_LIBDIR) -lexpr -last -lvmalloc -lsfio -lingraphs $(GLIBS) -lm + +gvpr : $(OBJS) $(LOC_LIBDIR)/libexpr.a + $(CSLD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +libgvpr.a: $(OBJS) + $(RM) libgvpr.a + $(AR) cr libgvpr.a $(OBJS) + $(RANLIB) libgvpr.a + +install: libgvpr.a + $(MKPATH) $(LIBDIR) + $(INSTALL) libpgvpr.a $(LIBDIR) + + +$(OBJS) : gdefs.h + +clean : + $(RM) core gdefs.h *.o + +distclean : clean + $(RM) mkdefs $(ALL) diff --git a/cmd/gvpr/actions.c b/lib/gvpr/actions.c similarity index 93% rename from cmd/gvpr/actions.c rename to lib/gvpr/actions.c index a9b6ad856..2662a1dd3 100644 --- a/cmd/gvpr/actions.c +++ b/lib/gvpr/actions.c @@ -189,7 +189,7 @@ Agobj_t *copy(Agraph_t * g, Agobj_t * obj) char *name = agnameof(obj); if ((kind != AGRAPH) && !g) { - error(ERROR_FATAL, "NULL graph with non-graph object in copy()"); + exerror("NULL graph with non-graph object in copy()"); return 0; } @@ -247,26 +247,32 @@ static Agraph_t *cloneSubg(Agraph_t * tgt, Agraph_t * g, Dt_t* emap) return 0; for (t = agfstnode(g); t; t = agnxtnode(g, t)) { newt = agnode(tgt, agnameof(t), 0); - if (!newt) - error(ERROR_PANIC, "node %s not found in cloned graph %s", + if (!newt) { + exerror("node %s not found in cloned graph %s", agnameof(t), agnameof(tgt)); - agsubnode(ng, newt, 1); + return 0; + } + else + agsubnode(ng, newt, 1); } for (t = agfstnode(g); t; t = agnxtnode(g, t)) { for (e = agfstout(g, t); e; e = agnxtout(g, e)) { newe = mapEdge (emap, e); - if (!newe) - error(ERROR_PANIC, - "edge (%s,%s)[%s] not found in cloned graph %s", + if (!newe) { + exerror("edge (%s,%s)[%s] not found in cloned graph %s", agnameof(agtail(e)), agnameof(aghead(e)), agnameof(e), agnameof(tgt)); - agsubedge(ng, newe, 1); + return 0; + } + else + agsubedge(ng, newe, 1); } } for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) { if (!cloneSubg(ng, sg, emap)) { - error(ERROR_FATAL, "error cloning subgraph %s from graph %s", + exerror("error cloning subgraph %s from graph %s", agnameof(sg), agnameof(g)); + return 0; } } return ng; @@ -306,17 +312,17 @@ static void cloneGraph(Agraph_t * tgt, Agraph_t * src) for (t = agfstnode(src); t; t = agnxtnode(src, t)) { if (!copy(tgt, OBJ(t))) { - error(ERROR_FATAL, "error cloning node %s from graph %s", + exerror("error cloning node %s from graph %s", agnameof(t), agnameof(src)); } } for (t = agfstnode(src); t; t = agnxtnode(src, t)) { for (e = agfstout(src, t); e; e = agnxtout(src, e)) { if (!(ne = (Agedge_t*)copy(tgt, OBJ(e)))) { - error(ERROR_FATAL, - "error cloning edge (%s,%s)[%s] from graph %s", + exerror("error cloning edge (%s,%s)[%s] from graph %s", agnameof(agtail(e)), agnameof(aghead(e)), agnameof(e), agnameof(src)); + return; } ep->key = e; ep->val = ne; @@ -325,7 +331,7 @@ static void cloneGraph(Agraph_t * tgt, Agraph_t * src) } for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) { if (!cloneSubg(tgt, sg, emap)) { - error(ERROR_FATAL, "error cloning subgraph %s from graph %s", + exerror("error cloning subgraph %s from graph %s", agnameof(sg), agnameof(src)); } } @@ -352,7 +358,7 @@ Agobj_t *clone(Agraph_t * g, Agobj_t * obj) char *name = agnameof(obj); if ((kind != AGRAPH) && !g) { - error(ERROR_FATAL, "NULL graph with non-graph object in clone()"); + exerror("NULL graph with non-graph object in clone()"); return 0; } @@ -545,12 +551,12 @@ int writeFile(Agraph_t * g, char *f) Sfio_t *fp; if (!f) { - error(ERROR_FATAL, "NULL string passed to writeG"); + exerror("NULL string passed to writeG"); return 1; } fp = sfopen(0, f, "w"); if (!fp) { - error(ERROR_FATAL, "Could not open %s for writing in writeG", f); + exerror("Could not open %s for writing in writeG", f); return 1; } rv = agwrite(g, fp); @@ -568,12 +574,12 @@ Agraph_t *readFile(char *f) Sfio_t *fp; if (!f) { - error(ERROR_FATAL, "NULL string passed to readG"); + exerror("NULL string passed to readG"); return 0; } fp = sfopen(0, f, "r"); if (!fp) { - error(ERROR_FATAL, "Could not open %s for reading in readG", f); + exerror("Could not open %s for reading in readG", f); return 0; } gp = readG(fp); @@ -615,7 +621,7 @@ int openFile(Expr_t * ex, char *fname, char *mode) if (!ex->file[idx]) break; if (idx == elementsof(ex->file)) { - error(ERROR_FATAL, "openF: no available descriptors"); + exerror("openF: no available descriptors"); return -1; } ex->file[idx] = sfopen(0, fname, mode); @@ -630,11 +636,11 @@ int closeFile(Expr_t * ex, int fd) int rv; if ((0 <= fd) && (fd <= 2)) { - error(ERROR_FATAL, "closeF: cannot close standard stream %d", fd); + exerror("closeF: cannot close standard stream %d", fd); return -1; } if (!ex->file[fd]) { - error(ERROR_FATAL, "closeF: stream %d not open", fd); + exerror("closeF: stream %d not open", fd); return -1; } rv = sfclose(ex->file[fd]); diff --git a/cmd/gvpr/actions.h b/lib/gvpr/actions.h similarity index 100% rename from cmd/gvpr/actions.h rename to lib/gvpr/actions.h diff --git a/cmd/gvpr/compile.c b/lib/gvpr/compile.c similarity index 91% rename from cmd/gvpr/compile.c rename to lib/gvpr/compile.c index ccdc5c21a..306d8b9ec 100644 --- a/cmd/gvpr/compile.c +++ b/lib/gvpr/compile.c @@ -48,6 +48,9 @@ #include +#include "ctype.h" +#include "trie.c" + #define BITS_PER_BYTE 8 #ifdef HAVE_INTPTR_T #define INT2PTR(t,v) ((t)(intptr_t)(v)) @@ -234,10 +237,9 @@ static Agobj_t *deref(Expr_t * pgm, Exnode_t * x, Exref_t * ref, x->data.variable.dyna->data.variable.dyna->data. constant.value.integer); if (!ptr) { - error(ERROR_FATAL, "null reference %s in expression %s.%s", + exerror("null reference %s in expression %s.%s", ref->symbol->name, ref->symbol->name, deparse(pgm, x, - state-> - tmp)); + state->tmp)); return ptr; } else return deref(pgm, x, ref->next, (Agobj_t *) ptr, state); @@ -260,36 +262,71 @@ static Agobj_t *deref(Expr_t * pgm, Exnode_t * x, Exref_t * ref, break; case M_head: if (!objp && !(objp = state->curobj)) { - error(ERROR_WARNING, "Current object $ not defined"); + exerror("Current object $ not defined"); return 0; } if (ISEDGE(objp)) return deref(pgm, x, ref->next, (Agobj_t *) AGHEAD((Agedge_t *) objp), state); else - error(ERROR_FATAL, "head of non-edge"); + exerror("head of non-edge"); break; case M_tail: if (!objp && !(objp = state->curobj)) { - error(ERROR_FATAL, "Current object $ not defined"); + exerror("Current object $ not defined"); return 0; } if (ISEDGE(objp)) return deref(pgm, x, ref->next, (Agobj_t *) AGTAIL((Agedge_t *) objp), state); else - error(ERROR_FATAL, "tail of non-edge %x", objp); + exerror("tail of non-edge %x", objp); break; default: - error(ERROR_WARNING, "%s : illegal reference", + exerror("%s : illegal reference", ref->symbol->name); - return 0; break; } return 0; } +/* assignable: + * Check that attribute is not a read-only, pseudo-attribute. + * Return 1 if okay; fatal otherwise. + */ +static int +assignable (Agobj_t *objp, unsigned char* name) +{ + unsigned int ch; + int rv; + unsigned char* p = name; + + TFA_Init(); + while ((TFA_State >= 0) && (ch = *p)) { + TFA_Advance(ch & ~127 ? 127 : ch); + p++; + } + rv = TFA_Definition(); + if (rv < 0) return 1; + + switch (AGTYPE(objp)) { + case AGRAPH : + if (rv & Y(G)) + exerror("Cannot assign to pseudo-graph attribute %s", name); + break; + case AGNODE : + if (rv & Y(V)) + exerror("Cannot assign to pseudo-node attribute %s", name); + break; + default : /* edge */ + if (rv & Y(E)) + exerror("Cannot assign to pseudo-edge attribute %s", name); + break; + } + return 1; +} + /* setattr: * Set object's attribute name to val. * Initialize attribute if necessary. @@ -366,7 +403,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGNODE) v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 1, 0); else { - error(ERROR_FATAL, "indegree of non-node"); + exerror("indegree of non-node"); return -1; } break; @@ -374,7 +411,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGNODE) v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 0, 1); else { - error(ERROR_FATAL, "outdegree of non-node"); + exerror("outdegree of non-node"); return -1; } break; @@ -382,7 +419,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGNODE) v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 1, 1); else { - error(ERROR_FATAL, "degree of non-node"); + exerror("degree of non-node"); return -1; } break; @@ -390,7 +427,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGRAPH) v->integer = PTR2INT(agparent((Agraph_t *) objp)); else { - error(ERROR_FATAL, "parent of non-graph"); + exerror("parent of non-graph"); return -1; } break; @@ -401,7 +438,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGRAPH) v->integer = agnedges((Agraph_t *) objp); else { - error(ERROR_FATAL, "n_edges of non-graph"); + exerror("n_edges of non-graph"); return -1; } break; @@ -409,7 +446,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGRAPH) v->integer = agnnodes((Agraph_t *) objp); else { - error(ERROR_FATAL, "n_nodes of non-graph"); + exerror("n_nodes of non-graph"); return -1; } break; @@ -417,7 +454,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGRAPH) v->integer = agisdirected((Agraph_t *) objp); else { - error(ERROR_FATAL, "directed of non-graph"); + exerror("directed of non-graph"); return -1; } break; @@ -425,7 +462,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, if (AGTYPE(objp) == AGRAPH) v->integer = agisstrict((Agraph_t *) objp); else { - error(ERROR_FATAL, "strict of non-graph"); + exerror("strict of non-graph"); return -1; } break; @@ -438,7 +475,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, Agsym_t *gsym = agattrsym(objp, sym->name); if (!gsym) { gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), sym->name, ""); - error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\"", sym->name, kindOf (objp), nameOf(pgm, objp)); + error(ERROR_WARNING, "Using value of uninitialized %s attribute \"%s\" of \"%s\"", kindOf (objp), sym->name, nameOf(pgm, objp)); } v->string = agxget(objp, gsym); } @@ -452,7 +489,8 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v, static char *getArg(int n, Gpr_t * state) { if (n >= state->argc) { - error(ERROR_FATAL, "program references ARGV[%d] - undefined", n); + exerror("program references ARGV[%d] - undefined", n); + return 0; } return (state->argv[n]); } @@ -502,7 +540,8 @@ toKind (char* k, char* fn) kind = AGNODE; break; default : - error(ERROR_FATAL, "Unknown kind \"%s\" passed to %s()", k, fn); + exerror("Unknown kind \"%s\" passed to %s()", k, fn); + kind = 0; break; } return kind; @@ -520,7 +559,8 @@ nxtAttr (Agraph_t *gp, char* k, char* name) if (name) { sym = agattr (gp, kind, name, 0); if (!sym) { - error(ERROR_FATAL, "Third argument \"%s\" in nxtAttr() must be the name of an existing attribute", name); + exerror("Third argument \"%s\" in nxtAttr() must be the name of an existing attribute", name); + return ""; } } @@ -549,7 +589,7 @@ getDfltAttr (Agraph_t *gp, char* k, char* name) /* getval: * Return value associated with gpr identifier. */ -Extype_t +static Extype_t getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, void *env, int elt, Exdisc_t * disc) { @@ -749,7 +789,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, case F_kindof: objp = INT2PTR(Agobj_t *, args[0].integer); if (!objp) { - error(ERROR_FATAL, "NULL object passed to kindOf()"); + exerror("NULL object passed to kindOf()"); + v.string = 0; } else switch (AGTYPE(objp)) { case AGRAPH : v.string = "G"; @@ -1173,9 +1214,11 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, objp = INT2PTR(Agobj_t *, args[0].integer); name = args[1].string; if (!objp) { - error(ERROR_FATAL, "NULL object passed to aget()/hasAttr()"); + exerror("NULL object passed to aget()/hasAttr()"); + v.integer = 0; } else if (!name) { - error(ERROR_FATAL, "NULL name passed to aget()/hasAttr()"); + exerror("NULL name passed to aget()/hasAttr()"); + v.integer = 0; } else { Agsym_t *gsym = agattrsym(objp, name); @@ -1184,7 +1227,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, else { if (!gsym) { gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), name, ""); - error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\" in aget()", name, kindOf (objp), nameOf(pgm, objp)); + error(ERROR_WARNING, "Using value of %s uninitialized attribute \"%s\" of \"%s\" in aget()", kindOf (objp), name, nameOf(pgm, objp)); } v.string = agxget(objp, gsym); } @@ -1242,13 +1285,15 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, if (gp) { char* kind = args[1].string; if (!kind) { - error(ERROR_FATAL,"NULL kind passed to fstAttr()"); + error(ERROR_ERROR,"NULL kind passed to fstAttr()"); + v.string = 0; } else { v.string = nxtAttr (gp, kind, NULL); } } else { - error(ERROR_FATAL, "NULL graph passed to fstAttr()"); + exerror("NULL graph passed to fstAttr()"); + v.string = 0; } break; case F_nxtattr: @@ -1259,10 +1304,12 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, char* kind = args[1].string; char* name = args[2].string; if (!name) { - error(ERROR_FATAL,"NULL name passed to %s", sym->name); + exerror("NULL name passed to %s", sym->name); + v.string = 0; } else if (!kind) { - error(ERROR_FATAL,"NULL kind passed to %s", sym->name); + exerror("NULL kind passed to %s", sym->name); + v.string = 0; } else if (sym->index == F_isattr) { v.integer = (agattr(gp, toKind (kind, sym->name), name, 0) != NULL); @@ -1274,7 +1321,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, v.string = getDfltAttr(gp, kind, name); } } else { - error(ERROR_FATAL, "NULL graph passed to %s", sym->name); + exerror("NULL graph passed to %s", sym->name); + v.string = 0; } break; case F_canon: @@ -1305,7 +1353,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, v.integer = match(args[0].string, args[1].string); break; default: - error(ERROR_FATAL, "unknown function call: %s", sym->name); + exerror("unknown function call: %s", sym->name); } return v; } else if (elt == EX_ARRAY) { @@ -1316,7 +1364,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, v.string = getArg(args[0].integer, state); break; default: - error(ERROR_FATAL, "unknown array name: %s", sym->name); + exerror("unknown array name: %s", sym->name); + v.string = 0; } return v; } @@ -1325,7 +1374,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, if (ref) { objp = deref(pgm, node, ref, 0, state); if (!objp) - error(ERROR_FATAL, "null reference in expression %s", + exerror("null reference in expression %s", deparse(pgm, node, state->tmp)); } else if ((sym->lex == ID) && (sym->index <= LAST_V)) { switch (sym->index) { @@ -1360,15 +1409,20 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, return v; } else { objp = state->curobj; - if (!objp) - error(ERROR_FATAL, - "current object $ not defined as reference for %s", + if (!objp) { + exerror("current object $ not defined as reference for %s", deparse(pgm, node, state->tmp)); + } } - if (lookup(pgm, objp, sym, &v, state)) - error(ERROR_FATAL, "in expression %s", - deparse(pgm, node, state->tmp)); + if (objp) { + if (lookup(pgm, objp, sym, &v, state)) { + exerror("in expression %s", deparse(pgm, node, state->tmp)); + v.integer = 0; + } + } + else + v.integer = 0; return v; } @@ -1385,7 +1439,7 @@ static char *typeName(Expr_t * pg, int op) * Return -1 if not allowed. * Assume already type correct. */ -int +static int setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref, void *env, int elt, Extype_t v, Exdisc_t * disc) { @@ -1399,7 +1453,7 @@ setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref, if (ref) { objp = deref(pgm, x, ref, 0, state); if (!objp) { - error(ERROR_FATAL, "in expression %s.%s", + exerror("in expression %s.%s", ref->symbol->name, deparse(pgm, x, state->tmp)); return -1; } @@ -1439,13 +1493,14 @@ setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref, return rv; } else { objp = state->curobj; - if (!objp) - error(ERROR_FATAL, - "current object $ undefined in expression %s", + if (!objp) { + exerror("current object $ undefined in expression %s", deparse(pgm, x, state->tmp)); + return -1; + } } - + assignable (objp, (unsigned char*)(sym->name)); return setattr(objp, sym->name, v.string); } @@ -1570,7 +1625,7 @@ static tctype typeChkExp(Exref_t * ref, Exid_t * sym) * The grammar has been altered to disallow the first 3. * Type check expressions; return value unused. */ -Extype_t +static Extype_t refval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, char *str, int elt, Exdisc_t * disc) { @@ -1624,24 +1679,16 @@ refval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, break; } } else { - if (!typeChkExp(ref, sym)) + if (!typeChkExp(ref, sym)) { + Gpr_t *state = (Gpr_t *) (disc->user); exerror("type error using %s", - deparse(pgm, node, sfstropen())); + deparse(pgm, node, state->tmp)); + } v = exzero(node->type); } return v; } -#ifdef OLD -static void cvtError(Exid_t * xref, char *msg) -{ - if (xref) - error(ERROR_FATAL, "%s: %s", xref->name, msg); - else - error(ERROR_FATAL, "%s", msg); -} -#endif - /* binary: * Evaluate (l ex->op r) producing a value of type ex->type, * stored in l. @@ -1802,9 +1849,9 @@ strToTvtype (char* s) } else if (!strcmp(sfx, "prepostrev")) { rt = TV_prepostrev; } else - error(ERROR_FATAL, "illegal string \"%s\" for type tvtype_t", s); + exerror("illegal string \"%s\" for type tvtype_t", s); } else - error(ERROR_FATAL, "illegal string \"%s\" for type tvtype_t", s); + exerror("illegal string \"%s\" for type tvtype_t", s); return rt; } @@ -1869,22 +1916,27 @@ tvtypeToStr (int v) * Return -1 if conversion cannot be done, 0 otherwise. * If arg is > 0, conversion unnecessary; just report possibility. */ -int stringOf(Expr_t * prog, register Exnode_t * x, int arg) +static int stringOf(Expr_t * prog, register Exnode_t * x, int arg) { Agobj_t *objp; + int rv = 0; if (arg) return 0; if (x->type == T_tvtyp) { - x->data.constant.value.string = - tvtypeToStr (x->data.constant.value.integer); + if (!(x->data.constant.value.string = + tvtypeToStr (x->data.constant.value.integer))) + rv = -1; } else { objp = INT2PTR(Agobj_t *, x->data.constant.value.integer); - if (!objp) + if (!objp) { exerror("cannot generate name for NULL %s", typeName(prog, x->type)); - x->data.constant.value.string = nameOf(prog, objp); + rv = -1; + } + else + x->data.constant.value.string = nameOf(prog, objp); } x->type = STRING; return 0; @@ -1898,7 +1950,7 @@ int stringOf(Expr_t * prog, register Exnode_t * x, int arg) * Use #ifdef OLD to remove graph object conversion to strings, * as this seemed to dangerous. */ -int +static int convert(Expr_t * prog, register Exnode_t * x, int type, register Exid_t * xref, int arg, Exdisc_t * disc) { @@ -1967,7 +2019,7 @@ convert(Expr_t * prog, register Exnode_t * x, int type, else if (validTVT(x->data.constant.value.integer)) ret = 0; else - error(ERROR_FATAL, "Integer value %d not legal for type tvtype_t", + exerror("Integer value %d not legal for type tvtype_t", x->data.constant.value.integer); } /* in case libexpr hands us the trivial case */ @@ -2029,26 +2081,34 @@ static Exdisc_t *initDisc(Gpr_t * state) Exdisc_t *dp; dp = newof(0, Exdisc_t, 1, 0); - if (!dp) - error(ERROR_FATAL, + if (!dp) { + error(ERROR_ERROR, "could not create libexp discipline: out of memory"); + return 0; + } dp->version = EX_VERSION; - dp->flags = EX_CHARSTRING | EX_FATAL | EX_UNDECLARED; + dp->flags = EX_CHARSTRING | EX_UNDECLARED; dp->symbols = symbols; dp->convertf = convert; dp->stringof = stringOf; dp->binaryf = binary; dp->typename = typeName; - dp->errorf = (Exerror_f) errorf; + if (state->errf) + dp->errorf = state->errf; + else + dp->errorf = (Exerror_f) errorf; dp->keyf = keyval; dp->getf = getval; dp->reff = refval; dp->setf = setval; dp->matchf = matchval; + dp->exitf = state->exitf; dp->types = a2t; dp->user = state; + state->dp = dp; /* dp is freed when state is freed */ + return dp; } @@ -2059,9 +2119,10 @@ static Exdisc_t *initDisc(Gpr_t * state) static Exnode_t *compile(Expr_t * prog, char *src, char *input, int line, char *lbl, char *sfx, int kind) { - Exnode_t *e; + Exnode_t *e = 0; Sfio_t *sf; Sfio_t *prefix; + int rv; /* create input stream */ if (sfx) { @@ -2082,13 +2143,13 @@ static Exnode_t *compile(Expr_t * prog, char *src, char *input, int line, line--; } - /* prog is set to exit on errors */ if (!src) src = ""; - excomp(prog, src, line, 0, sf); + rv = excomp(prog, src, line, 0, sf); sfclose(sf); - e = exexpr(prog, lbl, NiL, kind); + if (rv >= 0 && (getErrorErrors() == 0)) + e = exexpr(prog, lbl, NiL, kind); return e; } @@ -2101,12 +2162,7 @@ static void checkGuard(Exnode_t * gp, char *src, int line) gp = exnoncast(gp); if (gp && exisAssign(gp)) { if (src) { -#ifdef GVDLL setErrorFileLine (src, line); -#else - error_info.file = src; - error_info.line = line; -#endif } error(ERROR_WARNING, "assignment used as bool in guard"); } @@ -2128,12 +2184,14 @@ static case_stmt *mkStmts(Expr_t * prog, char *src, case_info * sp, sfprintf(tmps, "%s_g%d", lbl, i); cs[i].guard = compile(prog, src, sp->guard, sp->gstart, sfstruse(tmps), 0, INTEGER); + if (getErrorErrors()) break; checkGuard(cs[i].guard, src, sp->gstart); } if (sp->action) { sfprintf(tmps, "%s_a%d", lbl, i); cs[i].action = compile(prog, src, sp->action, sp->astart, sfstruse(tmps), 0, INTEGER); + if (getErrorErrors()) break; } sp = sp->next; } @@ -2161,7 +2219,6 @@ static char *doFlags(int flags, Sfio_t * s) comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) { comp_prog *p; - Exdisc_t *dp; Sfio_t *tmps = sfstropen(); char *endg_sfx = 0; @@ -2169,9 +2226,11 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) assert(BITS_PER_BYTE * sizeof(tctype) >= (1 << TBITS)); p = newof(0, comp_prog, 1, 0); - if (!p) - error(ERROR_FATAL, + if (!p) { + error(ERROR_ERROR, "could not create compiled program: out of memory"); + goto finish; + } if (flags) { endg_sfx = doFlags(flags, tmps); @@ -2179,13 +2238,19 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) endg_sfx = 0; } - dp = initDisc(state); - p->prog = exopen(dp); + if (!(initDisc(state))) + goto finish; + + exinit(); + if (!(p->prog = exopen(state->dp))) + goto finish; codePhase = 0; if (inp->begin_stmt) { p->begin_stmt = compile(p->prog, inp->source, inp->begin_stmt, inp->l_begin, 0, 0, VOID); + if (getErrorErrors()) + goto finish; } codePhase = 1; @@ -2194,6 +2259,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) tchk[V_this][1] = Y(G); p->begg_stmt = compile(p->prog, inp->source, inp->begg_stmt, inp->l_beging, "_begin_g", 0, VOID); + if (getErrorErrors()) + goto finish; } codePhase = 2; @@ -2203,6 +2270,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) p->n_nstmts = inp->n_nstmts; p->node_stmts = mkStmts(p->prog, inp->source, inp->node_stmts, inp->n_nstmts, "_nd"); + if (getErrorErrors()) + goto finish; } codePhase = 3; @@ -2212,6 +2281,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) p->n_estmts = inp->n_estmts; p->edge_stmts = mkStmts(p->prog, inp->source, inp->edge_stmts, inp->n_estmts, "_eg"); + if (getErrorErrors()) + goto finish; } codePhase = 4; @@ -2220,6 +2291,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) tchk[V_this][1] = Y(G); p->endg_stmt = compile(p->prog, inp->source, inp->endg_stmt, inp->l_endg, "_end_g", endg_sfx, VOID); + if (getErrorErrors()) + goto finish; } codePhase = 5; @@ -2227,16 +2300,32 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags) symbols[0].type = T_obj; p->end_stmt = compile(p->prog, inp->source, inp->end_stmt, inp->l_end, "_end_", 0, VOID); + if (getErrorErrors()) + goto finish; + } + setErrorLine (0); /* execution errors have no line numbers */ + + finish: + if (getErrorErrors()) { + freeCompileProg (p); + p = 0; } + sfclose(tmps); -#ifdef GVDLL - setErrorLine (0); -#else - error_info.line = 0; /* execution errors have no line numbers */ -#endif return p; } +void +freeCompileProg (comp_prog *p) +{ + if (!p) return; + + exclose (p->prog, 1); + free (p->node_stmts); + free (p->edge_stmts); + free (p); +} + /* walksGraph; * Returns true if program actually has node or edge statements. */ @@ -2312,6 +2401,10 @@ Agraph_t *openG(char *name, Agdesc_t desc) { Agraph_t *g; +#ifdef GVDLL + gprDisc.mem = &AgMemDisc; + gprDisc.id = &AgIdDisc; +#endif g = agopen(name, desc, &gprDisc); if (g) agbindrec(g, UDATA, sizeof(gdata), 0); @@ -2366,3 +2459,4 @@ Agedge_t *openEdge(Agraph_t* g, Agnode_t * t, Agnode_t * h, char *key) agbindrec(ep, UDATA, sizeof(edata), 0); return ep; } + diff --git a/cmd/gvpr/compile.h b/lib/gvpr/compile.h similarity index 96% rename from cmd/gvpr/compile.h rename to lib/gvpr/compile.h index 7fa45f6bc..588d73ae0 100644 --- a/cmd/gvpr/compile.h +++ b/lib/gvpr/compile.h @@ -62,6 +62,7 @@ extern "C" { #define SRCOUT 0x1 #define INDUCE 0x2 +#define CLONE 0x4 typedef struct { Expr_t *prog; @@ -76,6 +77,7 @@ extern "C" { } comp_prog; extern comp_prog *compileProg(parse_prog *, Gpr_t *, int); + extern void freeCompileProg (comp_prog *p); extern int usesGraph(comp_prog *); extern int walksGraph(comp_prog *); extern Agraph_t *readG(Sfio_t * fp); diff --git a/lib/gvpr/gdefs.h b/lib/gvpr/gdefs.h new file mode 100644 index 000000000..03bc871f5 --- /dev/null +++ b/lib/gvpr/gdefs.h @@ -0,0 +1,304 @@ +#ifndef GDEFS_H +#define GDEFS_H + +/* generated by mkdefs; do not edit */ + +#define Y(i) (1<<(i)) + +#define V 0x4 /* NODE */ +#define E 0x5 /* EDGE */ +#define G 0x6 /* GRAPH */ +#define O 0x7 /* OBJECT */ +#define TV 0x8 /* TV_ */ +#define YALL (Y(V)|Y(E)|Y(G)) + +#define V_this 1 +#define V_thisg 2 +#define V_targt 3 +#define V_outgraph 4 +#define V_tgtname 5 +#define V_infname 6 +#define V_travroot 7 +#define V_travtype 8 +#define V_ARGC 9 +#define M_degree 10 +#define M_head 11 +#define M_tail 12 +#define M_name 13 +#define M_indegree 14 +#define M_outdegree 15 +#define M_root 16 +#define M_parent 17 +#define M_n_edges 18 +#define M_n_nodes 19 +#define M_directed 20 +#define M_strict 21 +#define T_node 22 +#define T_edge 23 +#define T_graph 24 +#define T_obj 25 +#define T_tvtyp 26 +#define A_ARGV 27 +#define F_graph 28 +#define F_subg 29 +#define F_issubg 30 +#define F_fstsubg 31 +#define F_nxtsubg 32 +#define F_node 33 +#define F_addnode 34 +#define F_fstnode 35 +#define F_nxtnode 36 +#define F_nxtnodesg 37 +#define F_isnode 38 +#define F_issubnode 39 +#define F_indegree 40 +#define F_outdegree 41 +#define F_degree 42 +#define F_isin 43 +#define F_edge 44 +#define F_edgesg 45 +#define F_addedge 46 +#define F_fstout 47 +#define F_nxtout 48 +#define F_fstin 49 +#define F_nxtin 50 +#define F_fstedge 51 +#define F_nxtedge 52 +#define F_fstoutsg 53 +#define F_nxtoutsg 54 +#define F_fstinsg 55 +#define F_nxtinsg 56 +#define F_fstedgesg 57 +#define F_nxtedgesg 58 +#define F_compof 59 +#define F_kindof 60 +#define F_index 61 +#define F_rindex 62 +#define F_isedge 63 +#define F_isedgesg 64 +#define F_issubedge 65 +#define F_length 66 +#define F_match 67 +#define F_write 68 +#define F_writeg 69 +#define F_readg 70 +#define F_fwriteg 71 +#define F_freadg 72 +#define F_openf 73 +#define F_closef 74 +#define F_readl 75 +#define F_induce 76 +#define F_isdirect 77 +#define F_isstrict 78 +#define F_delete 79 +#define F_clone 80 +#define F_copy 81 +#define F_copya 82 +#define F_lock 83 +#define F_nnodes 84 +#define F_nedges 85 +#define F_sqrt 86 +#define F_cos 87 +#define F_sin 88 +#define F_atan2 89 +#define F_exp 90 +#define F_pow 91 +#define F_log 92 +#define F_min 93 +#define F_max 94 +#define F_sys 95 +#define F_xof 96 +#define F_yof 97 +#define F_llof 98 +#define F_urof 99 +#define F_canon 100 +#define F_get 101 +#define F_set 102 +#define F_dget 103 +#define F_dset 104 +#define F_hasattr 105 +#define F_isattr 106 +#define F_fstattr 107 +#define F_nxtattr 108 +#define C_flat 109 +#define C_ne 110 +#define C_en 111 +#define C_bfs 112 +#define C_dfs 113 +#define C_fwd 114 +#define C_rev 115 +#define C_postdfs 116 +#define C_postfwd 117 +#define C_postrev 118 +#define C_prepostdfs 119 +#define C_prepostfwd 120 +#define C_prepostrev 121 +#define C_null 122 + +#define LAST_V 9 +#define LAST_M 21 +#define MINNAME 1 +#define MAXNAME 122 + +static Exid_t symbols[] = { + EX_ID ( "$", ID, V_this, T_obj, 0), + EX_ID ( "$G", ID, V_thisg, T_graph, 0), + EX_ID ( "$T", ID, V_targt, T_graph, 0), + EX_ID ( "$O", ID, V_outgraph, T_graph, 0), + EX_ID ( "$tgtname", ID, V_tgtname, STRING, 0), + EX_ID ( "$F", ID, V_infname, STRING, 0), + EX_ID ( "$tvroot", ID, V_travroot, T_node, 0), + EX_ID ( "$tvtype", ID, V_travtype, T_tvtyp, 0), + EX_ID ( "ARGC", ID, V_ARGC, INTEGER, 0), + EX_ID ( "degree", ID, M_degree, INTEGER, 0), + EX_ID ( "head", ID, M_head, T_node, 0), + EX_ID ( "tail", ID, M_tail, T_node, 0), + EX_ID ( "name", ID, M_name, STRING, 0), + EX_ID ( "indegree", ID, M_indegree, INTEGER, 0), + EX_ID ( "outdegree", ID, M_outdegree, INTEGER, 0), + EX_ID ( "root", ID, M_root, T_graph, 0), + EX_ID ( "parent", ID, M_parent, T_graph, 0), + EX_ID ( "n_edges", ID, M_n_edges, INTEGER, 0), + EX_ID ( "n_nodes", ID, M_n_nodes, INTEGER, 0), + EX_ID ( "directed", ID, M_directed, INTEGER, 0), + EX_ID ( "strict", ID, M_strict, INTEGER, 0), + EX_ID ( "node_t", DECLARE, T_node, T_node, 0), + EX_ID ( "edge_t", DECLARE, T_edge, T_edge, 0), + EX_ID ( "graph_t", DECLARE, T_graph, T_graph, 0), + EX_ID ( "obj_t", DECLARE, T_obj, T_obj, 0), + EX_ID ( "tvtype_t", DECLARE, T_tvtyp, T_tvtyp, 0), + EX_ID ( "ARGV", ARRAY, A_ARGV, S|A(1,I), 0), + EX_ID ( "graph", FUNCTION, F_graph, G|A(1,S)|A(2,S), 0), + EX_ID ( "subg", FUNCTION, F_subg, G|A(1,G)|A(2,S), 0), + EX_ID ( "isSubg", FUNCTION, F_issubg, G|A(1,G)|A(2,S), 0), + EX_ID ( "fstsubg", FUNCTION, F_fstsubg, G|A(1,G), 0), + EX_ID ( "nxtsubg", FUNCTION, F_nxtsubg, G|A(1,G), 0), + EX_ID ( "node", FUNCTION, F_node, V|A(1,G)|A(2,S), 0), + EX_ID ( "subnode", FUNCTION, F_addnode, V|A(1,G)|A(2,V), 0), + EX_ID ( "fstnode", FUNCTION, F_fstnode, V|A(1,G), 0), + EX_ID ( "nxtnode", FUNCTION, F_nxtnode, V|A(1,V), 0), + EX_ID ( "nxtnode_sg", FUNCTION, F_nxtnodesg, V|A(1,G)|A(2,V), 0), + EX_ID ( "isNode", FUNCTION, F_isnode, V|A(1,G)|A(2,S), 0), + EX_ID ( "isSubnode", FUNCTION, F_issubnode, I|A(1,G)|A(2,V), 0), + EX_ID ( "indegreeOf", FUNCTION, F_indegree, I|A(1,G)|A(2,V), 0), + EX_ID ( "outdegreeOf", FUNCTION, F_outdegree, I|A(1,G)|A(2,V), 0), + EX_ID ( "degreeOf", FUNCTION, F_degree, I|A(1,G)|A(2,V), 0), + EX_ID ( "isIn", FUNCTION, F_isin, I|A(1,G)|A(2,O), 0), + EX_ID ( "edge", FUNCTION, F_edge, E|A(1,V)|A(2,V)|A(3,S), 0), + EX_ID ( "edge_sg", FUNCTION, F_edgesg, E|A(1,G)|A(2,V)|A(3,V)|A(4,S), 0), + EX_ID ( "subedge", FUNCTION, F_addedge, E|A(1,G)|A(2,E), 0), + EX_ID ( "fstout", FUNCTION, F_fstout, E|A(1,V), 0), + EX_ID ( "nxtout", FUNCTION, F_nxtout, E|A(1,E), 0), + EX_ID ( "fstin", FUNCTION, F_fstin, E|A(1,V), 0), + EX_ID ( "nxtin", FUNCTION, F_nxtin, E|A(1,E), 0), + EX_ID ( "fstedge", FUNCTION, F_fstedge, E|A(1,V), 0), + EX_ID ( "nxtedge", FUNCTION, F_nxtedge, E|A(1,E)|A(2,V), 0), + EX_ID ( "fstout_sg", FUNCTION, F_fstoutsg, E|A(1,G)|A(2,V), 0), + EX_ID ( "nxtout_sg", FUNCTION, F_nxtoutsg, E|A(1,G)|A(2,E), 0), + EX_ID ( "fstin_sg", FUNCTION, F_fstinsg, E|A(1,G)|A(2,V), 0), + EX_ID ( "nxtin_sg", FUNCTION, F_nxtinsg, E|A(1,G)|A(2,E), 0), + EX_ID ( "fstedge_sg", FUNCTION, F_fstedgesg, E|A(1,G)|A(2,V), 0), + EX_ID ( "nxtedge_sg", FUNCTION, F_nxtedgesg, E|A(1,G)|A(2,E)|A(3,V), 0), + EX_ID ( "compOf", FUNCTION, F_compof, G|A(1,G)|A(2,V), 0), + EX_ID ( "kindOf", FUNCTION, F_kindof, S|A(1,O), 0), + EX_ID ( "index", FUNCTION, F_index, I|A(1,S)|A(2,S), 0), + EX_ID ( "rindex", FUNCTION, F_rindex, I|A(1,S)|A(2,S), 0), + EX_ID ( "isEdge", FUNCTION, F_isedge, E|A(1,V)|A(2,V)|A(3,S), 0), + EX_ID ( "isEdge_sg", FUNCTION, F_isedgesg, E|A(1,G)|A(2,V)|A(3,V)|A(4,S), 0), + EX_ID ( "isSubedge", FUNCTION, F_issubedge, I|A(1,G)|A(2,E), 0), + EX_ID ( "length", FUNCTION, F_length, I|A(1,S), 0), + EX_ID ( "match", FUNCTION, F_match, I|A(1,S)|A(2,S), 0), + EX_ID ( "write", FUNCTION, F_write, I|A(1,G), 0), + EX_ID ( "writeG", FUNCTION, F_writeg, I|A(1,G)|A(2,S), 0), + EX_ID ( "readG", FUNCTION, F_readg, G|A(1,S), 0), + EX_ID ( "fwriteG", FUNCTION, F_fwriteg, I|A(1,G)|A(2,I), 0), + EX_ID ( "freadG", FUNCTION, F_freadg, G|A(1,I), 0), + EX_ID ( "openF", FUNCTION, F_openf, I|A(1,S)|A(2,S), 0), + EX_ID ( "closeF", FUNCTION, F_closef, I|A(1,I), 0), + EX_ID ( "readL", FUNCTION, F_readl, S|A(1,I), 0), + EX_ID ( "induce", FUNCTION, F_induce, I|A(1,G), 0), + EX_ID ( "isDirect", FUNCTION, F_isdirect, I|A(1,G), 0), + EX_ID ( "isStrict", FUNCTION, F_isstrict, I|A(1,G), 0), + EX_ID ( "delete", FUNCTION, F_delete, I|A(1,G)|A(2,O), 0), + EX_ID ( "clone", FUNCTION, F_clone, O|A(1,G)|A(2,O), 0), + EX_ID ( "copy", FUNCTION, F_copy, O|A(1,G)|A(2,O), 0), + EX_ID ( "copyA", FUNCTION, F_copya, I|A(1,O)|A(2,O), 0), + EX_ID ( "lock", FUNCTION, F_lock, I|A(1,G)|A(2,I), 0), + EX_ID ( "nNodes", FUNCTION, F_nnodes, I|A(1,G), 0), + EX_ID ( "nEdges", FUNCTION, F_nedges, I|A(1,G), 0), + EX_ID ( "sqrt", FUNCTION, F_sqrt, F|A(1,F), 0), + EX_ID ( "cos", FUNCTION, F_cos, F|A(1,F), 0), + EX_ID ( "sin", FUNCTION, F_sin, F|A(1,F), 0), + EX_ID ( "atan2", FUNCTION, F_atan2, F|A(1,F)|A(2,F), 0), + EX_ID ( "exp", FUNCTION, F_exp, F|A(1,F), 0), + EX_ID ( "pow", FUNCTION, F_pow, F|A(1,F)|A(2,F), 0), + EX_ID ( "log", FUNCTION, F_log, F|A(1,F), 0), + EX_ID ( "MIN", FUNCTION, F_min, F|A(1,F)|A(2,F), 0), + EX_ID ( "MAX", FUNCTION, F_max, F|A(1,F)|A(2,F), 0), + EX_ID ( "system", FUNCTION, F_sys, I|A(1,S), 0), + EX_ID ( "xOf", FUNCTION, F_xof, S|A(1,S), 0), + EX_ID ( "yOf", FUNCTION, F_yof, S|A(1,S), 0), + EX_ID ( "llOf", FUNCTION, F_llof, S|A(1,S), 0), + EX_ID ( "urOf", FUNCTION, F_urof, S|A(1,S), 0), + EX_ID ( "canon", FUNCTION, F_canon, S|A(1,S), 0), + EX_ID ( "aget", FUNCTION, F_get, S|A(1,O)|A(2,S), 0), + EX_ID ( "aset", FUNCTION, F_set, I|A(1,O)|A(2,S)|A(3,S), 0), + EX_ID ( "getDflt", FUNCTION, F_dget, S|A(1,G)|A(2,S)|A(3,S), 0), + EX_ID ( "setDflt", FUNCTION, F_dset, I|A(1,G)|A(2,S)|A(3,S)|A(4,S), 0), + EX_ID ( "hasAttr", FUNCTION, F_hasattr, I|A(1,O)|A(2,S), 0), + EX_ID ( "isAttr", FUNCTION, F_isattr, I|A(1,G)|A(2,S)|A(3,S), 0), + EX_ID ( "fstAttr", FUNCTION, F_fstattr, S|A(1,G)|A(2,S), 0), + EX_ID ( "nxtAttr", FUNCTION, F_nxtattr, S|A(1,G)|A(2,S)|A(3,S), 0), + EX_ID ( "TV_flat", CONSTANT, C_flat, T_tvtyp, 0), + EX_ID ( "TV_ne", CONSTANT, C_ne, T_tvtyp, 0), + EX_ID ( "TV_en", CONSTANT, C_en, T_tvtyp, 0), + EX_ID ( "TV_bfs", CONSTANT, C_bfs, T_tvtyp, 0), + EX_ID ( "TV_dfs", CONSTANT, C_dfs, T_tvtyp, 0), + EX_ID ( "TV_fwd", CONSTANT, C_fwd, T_tvtyp, 0), + EX_ID ( "TV_rev", CONSTANT, C_rev, T_tvtyp, 0), + EX_ID ( "TV_postdfs", CONSTANT, C_postdfs, T_tvtyp, 0), + EX_ID ( "TV_postfwd", CONSTANT, C_postfwd, T_tvtyp, 0), + EX_ID ( "TV_postrev", CONSTANT, C_postrev, T_tvtyp, 0), + EX_ID ( "TV_prepostdfs", CONSTANT, C_prepostdfs, T_tvtyp, 0), + EX_ID ( "TV_prepostfwd", CONSTANT, C_prepostfwd, T_tvtyp, 0), + EX_ID ( "TV_prepostrev", CONSTANT, C_prepostrev, T_tvtyp, 0), + EX_ID ( "NULL", CONSTANT, C_null, T_obj, 0), + EX_ID ( {0}, 0, 0, 0, 0) +}; + +static char* typenames[] = { + "node_t", + "edge_t", + "graph_t", + "obj_t", + "tvtype_t", +}; + +typedef unsigned short tctype; + +static tctype tchk[][2] = { + { 0, 0 }, + { 0, YALL }, + { 0, Y(G) }, + { 0, Y(G) }, + { 0, Y(G) }, + { 0, Y(S) }, + { 0, Y(S) }, + { 0, Y(V) }, + { 0, Y(TV) }, + { 0, Y(I) }, + { Y(V), Y(I) }, + { Y(E), Y(V) }, + { Y(E), Y(V) }, + { YALL, Y(S) }, + { Y(V), Y(I) }, + { Y(V), Y(I) }, + { YALL, Y(G) }, + { Y(G), Y(G) }, + { Y(G), Y(I) }, + { Y(G), Y(I) }, + { Y(G), Y(I) }, + { Y(G), Y(I) }, +}; + +#endif diff --git a/cmd/gvpr/gprdata b/lib/gvpr/gprdata similarity index 100% rename from cmd/gvpr/gprdata rename to lib/gvpr/gprdata diff --git a/cmd/gvpr/gprstate.c b/lib/gvpr/gprstate.c similarity index 71% rename from cmd/gvpr/gprstate.c rename to lib/gvpr/gprstate.c index b5878e4c1..ad237bff9 100644 --- a/cmd/gvpr/gprstate.c +++ b/lib/gvpr/gprstate.c @@ -34,29 +34,46 @@ int validTVT(int c) return ((TV_flat <= c) && (c <= TV_prepostrev)); } -void initGPRState(Gpr_t * state, Vmalloc_t * vm, gpr_info * info) +void initGPRState(Gpr_t * state, Vmalloc_t * vm) { state->tgtname = vmstrdup(vm, "gvpr_result"); - state->tvt = TV_flat; - state->tvroot = 0; - state->outFile = info->outFile; - state->argc = info->argc; - state->argv = info->argv; } -Gpr_t *openGPRState() +Gpr_t *openGPRState(gpr_info* info) { Gpr_t *state; - if (!(state = newof(0, Gpr_t, 1, 0))) - error(ERROR_FATAL, "Could not create gvpr state: out of memory"); + if (!(state = newof(0, Gpr_t, 1, 0))) { + error(ERROR_ERROR, "Could not create gvpr state: out of memory"); + return state; + } + + if (!(state->tmp = sfstropen())) { + error(ERROR_ERROR, "Could not create state tmpfile"); + free (state); + return 0; + } - if (!(state->tmp = sfstropen())) - error(ERROR_FATAL, "Could not create state"); + state->tvt = TV_flat; + state->tvroot = 0; + state->outFile = info->outFile; + state->argc = info->argc; + state->argv = info->argv; + state->errf = info->errf; + state->flags = info->flags; return state; } +void closeGPRState(Gpr_t* state) +{ + if (!state) return; + if (state->tmp) + sfclose (state->tmp); + free (state->dp); + free (state); +} + #ifdef WIN32_DLL int pathisrelative (char* path) { diff --git a/cmd/gvpr/gprstate.h b/lib/gvpr/gprstate.h similarity index 86% rename from cmd/gvpr/gprstate.h rename to lib/gvpr/gprstate.h index 01f88fb3e..e14333511 100644 --- a/cmd/gvpr/gprstate.h +++ b/lib/gvpr/gprstate.h @@ -25,6 +25,7 @@ extern "C" { #include "cgraph.h" #include "ast.h" #include "vmalloc.h" +#include "expr.h" typedef enum { TV_flat, TV_ne, TV_en, TV_bfs, @@ -39,6 +40,9 @@ extern "C" { Agraph_t *outgraph; Agobj_t *curobj; Sfio_t *tmp; + Exdisc_t *dp; + Exerror_f errf; + Exexit_f exitf; char *tgtname; char *infname; Sfio_t *outFile; @@ -47,16 +51,21 @@ extern "C" { int name_used; int argc; char **argv; + int flags; } Gpr_t; typedef struct { Sfio_t *outFile; int argc; char **argv; + Exerror_f errf; + Exexit_f exitf; + int flags; } gpr_info; - extern Gpr_t *openGPRState(void); - extern void initGPRState(Gpr_t *, Vmalloc_t *, gpr_info *); + extern Gpr_t *openGPRState(gpr_info*); + extern void closeGPRState(Gpr_t* state); + extern void initGPRState(Gpr_t *, Vmalloc_t *); extern int validTVT(int); #ifdef WIN32_DLL diff --git a/cmd/gvpr/gvpr.c b/lib/gvpr/gvpr.c similarity index 56% rename from cmd/gvpr/gvpr.c rename to lib/gvpr/gvpr.c index c026b862b..280a93931 100644 --- a/cmd/gvpr/gvpr.c +++ b/lib/gvpr/gvpr.c @@ -36,26 +36,26 @@ #include "ingraphs.h" #include "compile.h" #include "queue.h" +#include "gvpr.h" +#include "actions.h" #include "sfstr.h" #include #include #include -#ifdef HAVE_GETOPT_H -#include -#else -#include "compat_getopt.h" -#endif - -char *Info[] = { - "gvpr", /* Program */ - VERSION, /* Version */ - BUILDDATE /* Build Date */ -}; +#include #define DFLT_GPRPATH "." +#define GV_USE_JUMP 4 + +static char *Info[] = { + "gvpr", /* Program */ + VERSION, /* Version */ + BUILDDATE /* Build Date */ +}; + static const char *usage = - ": gvpr [-o ] [-a ] ([-f ] | 'prog') [files]\n\ + " [-o ] [-a ] ([-f ] | 'prog') [files]\n\ -c - use source graph for output\n\ -f - find program in file \n\ -i - create node induced subgraph\n\ @@ -66,15 +66,16 @@ static const char *usage = -? - print usage info\n\ If no files are specified, stdin is used\n"; -struct { - char *cmdName; +typedef struct { + char *cmdName; /* command name */ Sfio_t *outFile; /* output stream; stdout default */ - char *program; + char *program; /* program source */ int useFile; /* true if program comes from a file */ int compflags; char **inFiles; int argc; char **argv; + int state; /* > 0 : continue; <= 0 finish */ } options; static Sfio_t *openOut(char *name) @@ -83,7 +84,7 @@ static Sfio_t *openOut(char *name) outs = sfopen(0, name, "w"); if (outs == 0) { - error(ERROR_FATAL, "could not open %s for writing", name); + error(ERROR_ERROR, "could not open %s for writing", name); } return outs; } @@ -99,40 +100,41 @@ static Sfio_t *openOut(char *name) * NB. There must be white space between tokens. Otherwise, they * are concatenated. */ -static char* -gettok (char** sp) +static char *gettok(char **sp) { - char* s = *sp; - char* ws = s; - char* rs = s; - char c; - char q = '\0'; /* if non-0, in quote mode with quote char q */ - - while (isspace(*rs)) rs++; - if ((c = *rs) == '\0') return NULL; + char *s = *sp; + char *ws = s; + char *rs = s; + char c; + char q = '\0'; /* if non-0, in quote mode with quote char q */ + + while (isspace(*rs)) + rs++; + if ((c = *rs) == '\0') + return NULL; while ((c = *rs)) { - if (q && (q == c)) { /* end quote */ + if (q && (q == c)) { /* end quote */ q = '\0'; - } - else if (!q && ((c == '"') || (c == '\''))) { + } else if (!q && ((c == '"') || (c == '\''))) { q = c; - } - else if (c == '\\') { + } else if (c == '\\') { rs++; c = *rs; - if (c) *ws++ = c; + if (c) + *ws++ = c; else { - error(ERROR_WARNING, - "backslash in argument followed by no character - ignored"); + error(ERROR_WARNING, + "backslash in argument followed by no character - ignored"); rs--; } - } - else if (q || !isspace(c)) + } else if (q || !isspace(c)) *ws++ = c; - else break; - rs++; + else + break; + rs++; } - if (*rs) rs++; + if (*rs) + rs++; else if (q) error(ERROR_WARNING, "no closing quote for argument %s", s); *sp = rs; @@ -170,7 +172,7 @@ static int parseArgs(char *s, int argc, char ***argv) argc = oldcnt + cnt; av = oldof(*argv, char *, argc, 0); for (i = 0; i < cnt; i++) - av[oldcnt+i] = strdup(args[i]); + av[oldcnt + i] = strdup(args[i]); *argv = av; } return argc; @@ -189,6 +191,7 @@ static int parseArgs(char *s, int argc, char ***argv) * Translate -f arg parameter into a pathname. * If arg contains '/', return arg. * Else search directories in GPRPATH for arg. + * Return NULL on error. */ static char *resolve(char *arg) { @@ -200,18 +203,20 @@ static char *resolve(char *arg) size_t sz; #ifdef WIN32_DLL - if (!pathisrelative (arg)) + if (!pathisrelative(arg)) #else if (strchr(arg, '/')) #endif - return arg; + return strdup(arg); path = getenv("GPRPATH"); if (!path) path = DFLT_GPRPATH; - if (!(fp = sfstropen())) - error(ERROR_FATAL, "Could not open buffer"); + if (!(fp = sfstropen())) { + error(ERROR_ERROR, "Could not open buffer"); + return 0; + } while (*path && !fname) { if (*path == LISTSEP) { /* skip colons */ @@ -237,102 +242,181 @@ static char *resolve(char *arg) } if (!fname) - error(ERROR_FATAL, "Could not find file \"%s\" in GPRPATH", arg); + error(ERROR_ERROR, "Could not find file \"%s\" in GPRPATH", arg); sfclose(fp); return fname; } -/* scanArgs: - * Parse command line options. +static char* +getOptarg (int c, char** argp, int* argip, int argc, char** argv) +{ + char* rv; + char* arg = *argp; + int argi = *argip; + + if (*arg) { + rv = arg; + while (*arg) arg++; + *argp = arg; + } + else if (argi < argc) { + rv = argv[argi++]; + *argip = argi; + } + else { + rv = NULL; + error(ERROR_WARNING, "missing argument for option -%c", c); + } + return rv; +} + +/* doFlags: + * Process a command-line argument starting with a '-'. + * argi is the index of the next available item in argv[]. + * argc has its usual meaning. + * + * return > 0 given next argi value + * = 0 for exit with 0 + * < 0 for error */ -static void scanArgs(int argc, char **argv) +static int +doFlags(char* arg, int argi, int argc, char** argv, options* opts) { int c; - char *outname = 0; - - options.cmdName = argv[0]; - options.outFile = 0; - options.useFile = 0; - options.argv = 0; - options.argc = 0; -#ifdef GVDLL - setErrorId (options.cmdName); -#else - error_info.id = options.cmdName; -#endif - while ((c = getopt(argc, argv, ":q?Vcia:f:o:")) != -1) { + while ((c = *arg++)) { switch (c) { case 'c': - options.compflags |= SRCOUT; + opts->compflags |= SRCOUT; + break; + case 'C': + opts->compflags |= (SRCOUT|CLONE); break; case 'f': - options.useFile = 1; - options.program = resolve(optarg); + if ((optarg = getOptarg(c, &arg, &argi, argc, argv)) && (opts->program = resolve(optarg))) { + opts->useFile = 1; + } + else return -1; break; case 'i': - options.compflags |= INDUCE; + opts->compflags |= INDUCE; break; case 'a': - options.argc = parseArgs(optarg, options.argc, &options.argv); + if ((optarg = getOptarg(c, &arg, &argi, argc, argv))) { + opts->argc = parseArgs(optarg, opts->argc, &(opts->argv)); + } + else return -1; break; case 'o': - outname = optarg; + if (!(optarg = getOptarg(c, &arg, &argi, argc, argv)) && !(opts->outFile = openOut(optarg))) + return -1; break; case 'q': - setTraceLevel (ERROR_ERROR); + setTraceLevel (ERROR_ERROR); /* Don't emit warning messages */ break; case 'V': - fprintf(stderr, "%s version %s (%s)\n", + sfprintf(sfstderr, "%s version %s (%s)\n", Info[0], Info[1], Info[2]); - exit(0); + return 0; break; case '?': - if (optopt == '?') { - error(ERROR_USAGE, "%s", usage); - exit(0); - } else { - error(ERROR_ERROR, "option -%c unrecognized", optopt); - } + error(ERROR_USAGE|ERROR_WARNING, "%s", usage); + return 0; break; - case ':': - error(ERROR_ERROR, "missing argument for option -%c", optopt); + default : + error(ERROR_WARNING, "option -%c unrecognized", c); break; } } - argv += optind; - argc -= optind; + return argi; +} + +static void +freeOpts (options* opts) +{ + int i; + if (!opts) return; + if (opts->outFile != sfstdout) + sfclose (opts->outFile); + free (opts->inFiles); + if (opts->useFile) + free (opts->program); + if (opts->argc) { + for (i = 0; i < opts->argc; i++) + free (opts->argv[i]); + free (opts->argv); + } + free (opts); +} + +/* scanArgs: + * Parse command line options. + */ +static options* scanArgs(int argc, char **argv, gvpropts* uopts) +{ + int i, nfiles; + char** input_filenames; + char* arg; + options* opts = newof(0,options,1,0); + + opts->cmdName = argv[0]; + opts->state = 1; + setErrorId (opts->cmdName); + + /* estimate number of file names */ + nfiles = 0; + for (i = 1; i < argc; i++) + if (argv[i] && argv[i][0] != '-') + nfiles++; + input_filenames = newof(0,char*,nfiles + 1,0); + + /* loop over arguments */ + nfiles = 0; + for (i = 1; i < argc; ) { + arg = argv[i++]; + if (*arg == '-') { + i = doFlags (arg+1, i, argc, argv, opts); + if (i <= 0) { + opts->state = i; + goto opts_done; + } + } else if (arg) + input_filenames[nfiles++] = arg; + } /* Handle additional semantics */ - if (options.useFile == 0) { - if (argc == 0) { - error(ERROR_ERROR, "No program supplied via argument or -f option"); -#ifdef GVDLL - setErrorErrors (1); -#else - error_info.errors = 1; -#endif + if (opts->useFile == 0) { + if (nfiles == 0) { + error(ERROR_ERROR, + "No program supplied via argument or -f option"); + opts->state = -1; } else { - options.program = *argv++; - argc--; + opts->program = input_filenames[0]; + for (i = 1; i <= nfiles; i++) + input_filenames[i-1] = input_filenames[i]; + nfiles--; } } - if (argc == 0) - options.inFiles = 0; - else - options.inFiles = argv; - if (outname) - options.outFile = openOut(outname); + if (nfiles == 0) { + opts->inFiles = 0; + free (input_filenames); + input_filenames = 0; + } else - options.outFile = sfstdout; + opts->inFiles = input_filenames; -#ifdef GVDLL - if (getErrorErrors ()) -#else - if (error_info.errors) -#endif - error(ERROR_USAGE | 4, "%s", usage); + if (!(opts->outFile)) + opts->outFile = sfstdout; + + opts_done: + if (opts->state <= 0) { + if (opts->state < 0) + error(ERROR_USAGE|ERROR_ERROR, "%s", usage); + free (input_filenames); + } + + return opts; } static void evalEdge(Gpr_t * state, comp_prog * xprog, Agedge_t * e) @@ -404,8 +488,8 @@ static Agnode_t *nextNode(Gpr_t * state, nodestream * nodes) #define PUSH(x) (((x)->iu.integer)|=2) #define POP(x) (((x)->iu.integer)&=(~2)) -typedef Agedge_t *(*fstedgefn_t) (Agraph_t*, Agnode_t *); -typedef Agedge_t *(*nxttedgefn_t) (Agraph_t*, Agedge_t *, Agnode_t *); +typedef Agedge_t *(*fstedgefn_t) (Agraph_t *, Agnode_t *); +typedef Agedge_t *(*nxttedgefn_t) (Agraph_t *, Agedge_t *, Agnode_t *); #define PRE_VISIT 1 #define POST_VISIT 2 @@ -417,9 +501,9 @@ typedef struct { unsigned char visit; } trav_fns; -static trav_fns DFSfns = { agfstedge, agnxtedge, 1, 0}; -static trav_fns FWDfns = { agfstout, (nxttedgefn_t) agnxtout, 0, 0}; -static trav_fns REVfns = { agfstin, (nxttedgefn_t) agnxtin, 0, 0}; +static trav_fns DFSfns = { agfstedge, agnxtedge, 1, 0 }; +static trav_fns FWDfns = { agfstout, (nxttedgefn_t) agnxtout, 0, 0 }; +static trav_fns REVfns = { agfstin, (nxttedgefn_t) agnxtin, 0, 0 }; static void travBFS(Gpr_t * state, comp_prog * xprog) { @@ -428,7 +512,7 @@ static void travBFS(Gpr_t * state, comp_prog * xprog) ndata *nd; Agnode_t *n; Agedge_t *cure; - Agraph_t* g = state->curgraph; + Agraph_t *g = state->curgraph; q = mkQueue(); nodes.oldroot = 0; @@ -438,15 +522,17 @@ static void travBFS(Gpr_t * state, comp_prog * xprog) if (MARKED(nd)) continue; PUSH(nd); - push (q,n); + push(q, n); while ((n = pull(q))) { nd = nData(n); MARK(nd); - POP(nd); + POP(nd); evalNode(state, xprog, n); - for (cure = agfstedge(g, n); cure; cure = agnxtedge(g, cure, n)) { + for (cure = agfstedge(g, n); cure; + cure = agnxtedge(g, cure, n)) { nd = nData(cure->node); - if (MARKED(nd)) continue; + if (MARKED(nd)) + continue; evalEdge(state, xprog, cure); if (!ONSTACK(nd)) { push(q, cure->node); @@ -455,7 +541,7 @@ static void travBFS(Gpr_t * state, comp_prog * xprog) } } } - freeQ (q); + freeQ(q); } static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns) @@ -493,18 +579,18 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns) else cure = fns->fstedge(state->curgraph, curn); if (cure) { - if (entry == agopp(cure)) /* skip edge used to get here */ + if (entry == agopp(cure)) /* skip edge used to get here */ continue; nd = nData(cure->node); if (MARKED(nd)) { - /* For undirected DFS, visit an edge only if its head - * is on the stack, to avoid visiting it twice. - * This is no problem in directed DFS. - */ + /* For undirected DFS, visit an edge only if its head + * is on the stack, to avoid visiting it twice. + * This is no problem in directed DFS. + */ if (fns->undirected) { - if (ONSTACK(nd)) evalEdge(state, xprog, cure); - } - else + if (ONSTACK(nd)) + evalEdge(state, xprog, cure); + } else evalEdge(state, xprog, cure); } else { evalEdge(state, xprog, cure); @@ -531,13 +617,13 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns) } } } - freeQ (stk); + freeQ(stk); } static void travNodes(Gpr_t * state, comp_prog * xprog) { Agnode_t *n; - Agraph_t* g = state->curgraph; + Agraph_t *g = state->curgraph; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { evalNode(state, xprog, n); } @@ -547,7 +633,7 @@ static void travEdges(Gpr_t * state, comp_prog * xprog) { Agnode_t *n; Agedge_t *e; - Agraph_t* g = state->curgraph; + Agraph_t *g = state->curgraph; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { evalEdge(state, xprog, e); @@ -559,7 +645,7 @@ static void travFlat(Gpr_t * state, comp_prog * xprog) { Agnode_t *n; Agedge_t *e; - Agraph_t* g = state->curgraph; + Agraph_t *g = state->curgraph; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { evalNode(state, xprog, n); if (xprog->n_estmts > 0) { @@ -640,6 +726,23 @@ static void traverse(Gpr_t * state, comp_prog * xprog) } } +/* addOutputGraph: + * Append output graph to option struct. + * We know uopts and state->outgraph are non-NULL. + */ +static void +addOutputGraph (Gpr_t* state, gvpropts* uopts) +{ + Agraph_t* g = state->outgraph; + + if ((agroot(g) == state->curgraph) && !uopts->ingraphs) + g = (Agraph_t*)clone (0, (Agobj_t *)g); + + uopts->n_outgraphs++; + uopts->outgraphs = oldof(uopts->outgraphs,Agraph_t*,uopts->n_outgraphs,0); + uopts->outgraphs[uopts->n_outgraphs-1] = g; +} + static void chkClose(Agraph_t * g) { gdata *data; @@ -666,32 +769,131 @@ static int ing_close(void *fp) return sfclose((Sfio_t *) fp); } -#ifdef GVDLL static ingdisc ingDisc = { ing_open, ing_read, ing_close, 0 }; -#else -static ingdisc ingDisc = { ing_open, ing_read, ing_close, &_Sfstdin }; -#endif -int main(int argc, char *argv[]) +static void +setDisc (Sfio_t* sp, Sfdisc_t* dp, gvprwr fn) { - parse_prog *prog; + dp->readf = 0; + dp->writef = (Sfwrite_f)fn; + dp->seekf = 0; + dp->exceptf = 0; + dp->disc = 0; + dp = sfdisc (sp, dp); +} + +static jmp_buf jbuf; + +/* gvexitf: + * Only used if GV_USE_EXIT not set during exeval. + * This implies setjmp/longjmp set up. + */ +static void +gvexitf (Expr_t *handle, Exdisc_t *discipline, int v) +{ + longjmp (jbuf, v); +} + +static int +gverrorf (Expr_t *handle, Exdisc_t *discipline, int level, ...) +{ + va_list ap; + + va_start(ap, level); + errorv((discipline + && handle) ? *((char **) handle) : (char *) handle, level, ap); + va_end(ap); + + if (level >= ERROR_ERROR) { + Gpr_t *state = (Gpr_t*)(discipline->user); + if (state->flags & GV_USE_EXIT) + exit(1); + else if (state->flags & GV_USE_JUMP) + longjmp (jbuf, 1); + } + + return 0; +} + +/* gvpr: + * main loop for gvpr. + * Return 0 on success; non-zero on error. + * + * FIX: + * - close non-source/non-output graphs + */ +int gvpr (int argc, char *argv[], gvpropts * uopts) +{ + Sfdisc_t errdisc; + Sfdisc_t outdisc; + parse_prog *prog = 0; ingraph_state *ing; - comp_prog *xprog; - Gpr_t *state; + comp_prog *xprog = 0; + Gpr_t *state = 0; gpr_info info; + int rv = 0; + options* opts = 0; + int incoreGraphs; + + setErrorErrors (0); + ingDisc.dflt = sfstdin; + if (uopts) { + if (uopts->out) setDisc (sfstdout, &outdisc, uopts->out); + if (uopts->err) setDisc (sfstderr, &errdisc, uopts->err); + } -#ifdef GVDLL - ingDisc.dflt = &_Sfstdin; -#endif - scanArgs(argc, argv); + opts = scanArgs(argc, argv, uopts); + if (opts->state <= 0) { + rv = opts->state; + goto finish; + } + + prog = parseProg(opts->program, opts->useFile); + if (!prog) { + rv = 1; + goto finish; + } + info.outFile = opts->outFile; + info.argc = opts->argc; + info.argv = opts->argv; + info.errf = (Exerror_f)gverrorf; + if (uopts) + info.flags = uopts->flags; + else + info.flags = 0; + if ((uopts->flags & GV_USE_EXIT)) + info.exitf = 0; + else + info.exitf = gvexitf; + state = openGPRState(&info); + if (!state) { + rv = 1; + goto finish; + } + xprog = compileProg(prog, state, opts->compflags); + if (!xprog) { + rv = 1; + goto finish; + } + + initGPRState(state, xprog->prog->vm); + + if ((uopts->flags & GV_USE_OUTGRAPH)) { + uopts->outgraphs = 0; + uopts->n_outgraphs = 0; + } - prog = parseProg(options.program, options.useFile); - state = openGPRState(); - xprog = compileProg(prog, state, options.compflags); - info.outFile = options.outFile; - info.argc = options.argc; - info.argv = options.argv; - initGPRState(state, xprog->prog->vm, &info); + if (!(uopts->flags & GV_USE_EXIT)) { + state->flags |= GV_USE_JUMP; + if ((rv = setjmp (jbuf))) { + goto finish; + } + } + + if (uopts && uopts->ingraphs) + incoreGraphs = 1; + else + incoreGraphs = 0; /* do begin */ if (xprog->begin_stmt) @@ -699,10 +901,17 @@ int main(int argc, char *argv[]) /* if program is not null */ if (usesGraph(xprog)) { - ing = newIng(0, options.inFiles, &ingDisc); + if (uopts && uopts->ingraphs) + ing = newIngGraphs(0, uopts->ingraphs, &ingDisc); + else + ing = newIng(0, opts->inFiles, &ingDisc); + while ((state->curgraph = nextGraph(ing))) { state->infname = fileName(ing); + /* begin graph */ + if (incoreGraphs && (opts->compflags & CLONE)) + state->curgraph = clone (0, (Agobj_t*)(state->curgraph)); state->curobj = (Agobj_t *) state->curgraph; state->tvroot = 0; if (xprog->begg_stmt) @@ -723,24 +932,43 @@ int main(int argc, char *argv[]) agdelete(state->curgraph, state->target); /* output graph, if necessary - * For this, the outgraph must be defined, and either - * be non-empty or the -c option was used. - */ - if (state->outgraph && - (agnnodes(state->outgraph) || (options.compflags & SRCOUT))) - agwrite(state->outgraph, options.outFile); - - chkClose(state->curgraph); + * For this, the outgraph must be defined, and either + * be non-empty or the -c option was used. + */ + if (state->outgraph && (agnnodes(state->outgraph) + || (opts->compflags & SRCOUT))) { + if (uopts && (uopts->flags & GV_USE_OUTGRAPH)) + addOutputGraph (state, uopts); + else + agwrite(state->outgraph, opts->outFile); + } + + if (!incoreGraphs) + chkClose(state->curgraph); state->target = 0; state->outgraph = 0; } } - /* do end */ + /* do end */ state->curgraph = 0; state->curobj = 0; if (xprog->end_stmt) exeval(xprog->prog, xprog->end_stmt, state); - exit(0); + finish: + /* free all allocated resources */ + freeParseProg (prog); + freeCompileProg (xprog); + closeGPRState(state); + closeIngraph (ing); + freeOpts (opts); + + if (uopts) { + if (uopts->out) sfdisc (sfstdout, 0); + if (uopts->err) sfdisc (sfstderr, 0); + } + + return rv; } + diff --git a/lib/gvpr/gvpr.h b/lib/gvpr/gvpr.h new file mode 100644 index 000000000..925daf69f --- /dev/null +++ b/lib/gvpr/gvpr.h @@ -0,0 +1,48 @@ +/* $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 GVPR_H +#define GVPR_H + +#include "cgraph.h" + + /* If set, gvpr calls exit() on errors */ +#define GV_USE_EXIT 1 + /* If set, gvpr stores output graphs in gvpropts */ +#define GV_USE_OUTGRAPH 2 + +typedef ssize_t (*gvprwr) (void*, const char *buf, size_t nbyte, void*); + +typedef struct { + Agraph_t** ingraphs; /* NULL-terminated array of input graphs */ + int n_outgraphs; /* if GV_USE_OUTGRAPH set, output graphs */ + Agraph_t** outgraphs; + gvprwr out; /* write function for stdout */ + gvprwr err; /* write function for stderr */ + int flags; +} gvpropts; + + extern int gvpr (int argc, char *argv[], gvpropts* opts); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/gvpr/libgvpr.pc.in b/lib/gvpr/libgvpr.pc.in new file mode 100644 index 000000000..7bdfe0a7e --- /dev/null +++ b/lib/gvpr/libgvpr.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/@PACKAGE@ + +Name: libgvpr +Description: The GVPR library +Version: @VERSION@ +Libs: -L${libdir} -lgvpr -lcgraph -lcdt +Cflags: -I${includedir} + diff --git a/cmd/gvpr/mkdefs.c b/lib/gvpr/mkdefs.c similarity index 100% rename from cmd/gvpr/mkdefs.c rename to lib/gvpr/mkdefs.c diff --git a/cmd/gvpr/parse.c b/lib/gvpr/parse.c similarity index 87% rename from cmd/gvpr/parse.c rename to lib/gvpr/parse.c index 2ae2af6be..5628a0176 100644 --- a/cmd/gvpr/parse.c +++ b/lib/gvpr/parse.c @@ -209,10 +209,12 @@ static case_t parseKind(Sfio_t * str) c = skipWS(str); if (c < 0) return Eof; - if (!isalpha(c)) - error(ERROR_FATAL, + if (!isalpha(c)) { + error(ERROR_ERROR, "expected keyword BEGIN/END/N/E...; found '%c', line %d", c, lineno); + return Error; + } kwLine = lineno; parseID(str, c, buf, BSIZE); @@ -237,7 +239,7 @@ static case_t parseKind(Sfio_t * str) break; } if (cs == Error) - error(ERROR_FATAL, "unexpected keyword \"%s\", line %d", buf, + error(ERROR_ERROR, "unexpected keyword \"%s\", line %d", buf, kwLine); return cs; } @@ -247,7 +249,7 @@ static case_t parseKind(Sfio_t * str) * up to and including a terminating character ec * that is not escaped with a back quote. */ -static void endString(Sfio_t * ins, Sfio_t * outs, char ec) +static int endString(Sfio_t * ins, Sfio_t * outs, char ec) { int sline = lineno; int c; @@ -257,13 +259,16 @@ static void endString(Sfio_t * ins, Sfio_t * outs, char ec) sfputc(outs, c); c = sfgetc(ins); } - if (c < 0) - error(ERROR_FATAL, "unclosed string, start line %d", sline); + if (c < 0) { + error(ERROR_ERROR, "unclosed string, start line %d", sline); + return c; + } if (c == '\n') lineno++; sfputc(outs, (char) c); } sfputc(outs, c); + return 0; } /* endBracket: @@ -290,7 +295,7 @@ static int endBracket(Sfio_t * ins, Sfio_t * outs, char bc, char ec) sfputc(outs, (char) c); } else if ((c == '\'') || (c == '"')) { sfputc(outs, (char) c); - endString(ins, outs, c); + if (endString(ins, outs, c)) return -1; } else sfputc(outs, (char) c); } @@ -314,11 +319,15 @@ static char *parseBracket(Sfio_t * str, Sfio_t * buf, int bc, int ec) } startLine = lineno; c = endBracket(str, buf, bc, ec); - if (c < 0) - error(ERROR_FATAL, + if (c < 0) { + if (!getErrorErrors()) + error(ERROR_ERROR, "unclosed bracket %c%c expression, start line %d", bc, ec, startLine); - return strdup(sfstruse(buf)); + return 0; + } + else + return strdup(sfstruse(buf)); } /* parseAction: @@ -352,6 +361,7 @@ parseCase(Sfio_t * str, char **guard, int *gline, char **action, int *aline) { case_t kind; + Sfio_t *buf = sfstropen(); kind = parseKind(str); @@ -362,13 +372,19 @@ parseCase(Sfio_t * str, char **guard, int *gline, char **action, case EndG: *action = parseAction(str, buf); *aline = startLine; + if (getErrorErrors ()) + kind = Error; break; case Edge: case Node: *guard = parseGuard(str, buf); *gline = startLine; - *action = parseAction(str, buf); - *aline = startLine; + if (!getErrorErrors ()) { + *action = parseAction(str, buf); + *aline = startLine; + } + if (getErrorErrors ()) + kind = Error; break; case Eof: case Error: /* to silence warnings */ @@ -421,7 +437,7 @@ bindAction(case_t cs, char *action, int aline, char **ap, int *lp) error(ERROR_WARNING, "%s with no action, line %d - ignored", caseStr(cs), kwLine); else if (*ap) - error(ERROR_FATAL, "additional %s section, line %d", caseStr(cs), + error(ERROR_ERROR, "additional %s section, line %d", caseStr(cs), kwLine); else { *ap = action; @@ -431,7 +447,6 @@ bindAction(case_t cs, char *action, int aline, char **ap, int *lp) /* parseProg: * Parses input into gpr sections. - * Only returns if successful. */ parse_prog *parseProg(char *input, int isFile) { @@ -451,7 +466,8 @@ parse_prog *parseProg(char *input, int isFile) prog = newof(0, parse_prog, 1, 0); if (!prog) { - error(ERROR_FATAL, "parseProg: out of memory"); + error(ERROR_ERROR, "parseProg: out of memory"); + return 0; } if (isFile) { @@ -465,9 +481,11 @@ parse_prog *parseProg(char *input, int isFile) str = sfopen(0, input, mode); if (!str) { if (isFile) - error(ERROR_FATAL, "could not open %s for reading", input); + error(ERROR_ERROR, "could not open %s for reading", input); else - error(ERROR_FATAL, "parseProg : unable to create sfio stream"); + error(ERROR_ERROR, "parseProg : unable to create sfio stream"); + free (prog); + return 0; } more = 1; @@ -503,6 +521,7 @@ parse_prog *parseProg(char *input, int isFile) edgelist = edgel; break; case Error: /* to silence warnings */ + more = 0; break; } } @@ -514,5 +533,37 @@ parse_prog *parseProg(char *input, int isFile) sfclose(str); + if (getErrorErrors ()) { + freeParseProg (prog); + prog = 0; + } + return prog; } + +static void +freeCaseList (case_info* ip) +{ + case_info* nxt; + while (ip) { + nxt = ip->next; + free (ip->guard); + free (ip->action); + free (ip); + ip = nxt; + } +} + +void +freeParseProg (parse_prog * prog) +{ + if (!prog) return; + free (prog->begin_stmt); + free (prog->begg_stmt); + freeCaseList (prog->node_stmts); + freeCaseList (prog->edge_stmts); + free (prog->endg_stmt); + free (prog->end_stmt); + free (prog); +} + diff --git a/cmd/gvpr/parse.h b/lib/gvpr/parse.h similarity index 96% rename from cmd/gvpr/parse.h rename to lib/gvpr/parse.h index 7e84435fe..da348726d 100644 --- a/cmd/gvpr/parse.h +++ b/lib/gvpr/parse.h @@ -47,6 +47,7 @@ extern "C" { extern parse_prog *parseProg(char *, int); + extern void freeParseProg (parse_prog *); #endif diff --git a/cmd/gvpr/queue.c b/lib/gvpr/queue.c similarity index 100% rename from cmd/gvpr/queue.c rename to lib/gvpr/queue.c diff --git a/cmd/gvpr/queue.h b/lib/gvpr/queue.h similarity index 100% rename from cmd/gvpr/queue.h rename to lib/gvpr/queue.h diff --git a/lib/gvpr/trie.c b/lib/gvpr/trie.c new file mode 100644 index 000000000..aff27b248 --- /dev/null +++ b/lib/gvpr/trie.c @@ -0,0 +1,136 @@ +#define UNDERLINE + +#include "trieFA.h" + +TrieState TrieStateTbl[70] = { + { -1, 0, 0x3b8620 }, + { -1, 9, 0x440 }, + { -1, 11, 0x100 }, + { -1, 12, 0x80000 }, + { -1, 13, 0x40 }, + { -1, 14, 0x40 }, + { Y(V), 15, 0x0 }, + { -1, 15, 0x80000 }, + { -1, 16, 0x40 }, + { -1, 17, 0x10 }, + { -1, 18, 0x200000 }, + { -1, 19, 0x40 }, + { -1, 20, 0x20 }, + { Y(G), 21, 0x0 }, + { -1, 21, 0x40 }, + { -1, 22, 0x4 }, + { -1, 23, 0x20 }, + { Y(E), 24, 0x0 }, + { -1, 24, 0x8000 }, + { -1, 25, 0x20 }, + { -1, 26, 0x40 }, + { -1, 27, 0x100 }, + { -1, 28, 0x80000 }, + { -1, 29, 0x40 }, + { -1, 30, 0x40 }, + { Y(V), 31, 0x0 }, + { -1, 31, 0x5 }, + { -1, 33, 0x8040 }, + { -1, 35, 0x20 }, + { -1, 36, 0x100 }, + { -1, 37, 0x40 }, + { -1, 38, 0x100000 }, + { Y(G), 39, 0x0 }, + { -1, 39, 0x10000 }, + { -1, 40, 0x20 }, + { -1, 41, 0x40 }, + { -1, 42, 0x100000 }, + { Y(G), 43, 0x0 }, + { -1, 43, 0x4000 }, + { -1, 44, 0x40 }, + { YALL, 45, 0x0 }, + { -1, 45, 0x400000 }, + { -1, 46, 0x200000 }, + { -1, 47, 0x20 }, + { -1, 48, 0x40 }, + { -1, 49, 0x100 }, + { -1, 50, 0x80000 }, + { -1, 51, 0x40 }, + { -1, 52, 0x40 }, + { Y(V), 53, 0x0 }, + { -1, 53, 0x4 }, + { -1, 54, 0x80000 }, + { -1, 55, 0x40 }, + { -1, 56, 0x8000 }, + { -1, 57, 0x200000 }, + { Y(G), 58, 0x0 }, + { -1, 58, 0x10000 }, + { -1, 59, 0x10000 }, + { -1, 60, 0x200000 }, + { YALL, 61, 0x0 }, + { -1, 61, 0x200000 }, + { -1, 62, 0x80000 }, + { -1, 63, 0x400 }, + { -1, 64, 0x10 }, + { -1, 65, 0x200000 }, + { Y(G), 66, 0x0 }, + { -1, 66, 0x4 }, + { -1, 67, 0x400 }, + { -1, 68, 0x2000 }, + { Y(E), 69, 0x0 }, +}; +TrieTrans TrieTransTbl[69] = { + /* State 0 */ { 'd', 1 }, { 'h', 14 }, { 'i', 18 }, { 'n', 26 }, { 'o', 41 }, { 'p', 50 }, { 'r', 56 }, { 's', 60 }, { 't', 66 }, + /* State 1 */ { 'e', 2 }, { 'i', 7 }, + /* State 2 */ { 'g', 3 }, + /* State 3 */ { 'r', 4 }, + /* State 4 */ { 'e', 5 }, + /* State 5 */ { 'e', 6 }, + /* State 7 */ { 'r', 8 }, + /* State 8 */ { 'e', 9 }, + /* State 9 */ { 'c', 10 }, + /* State 10 */ { 't', 11 }, + /* State 11 */ { 'e', 12 }, + /* State 12 */ { 'd', 13 }, + /* State 14 */ { 'e', 15 }, + /* State 15 */ { 'a', 16 }, + /* State 16 */ { 'd', 17 }, + /* State 18 */ { 'n', 19 }, + /* State 19 */ { 'd', 20 }, + /* State 20 */ { 'e', 21 }, + /* State 21 */ { 'g', 22 }, + /* State 22 */ { 'r', 23 }, + /* State 23 */ { 'e', 24 }, + /* State 24 */ { 'e', 25 }, + /* State 26 */ { '_', 27 }, { 'a', 38 }, + /* State 27 */ { 'e', 28 }, { 'n', 33 }, + /* State 28 */ { 'd', 29 }, + /* State 29 */ { 'g', 30 }, + /* State 30 */ { 'e', 31 }, + /* State 31 */ { 's', 32 }, + /* State 33 */ { 'o', 34 }, + /* State 34 */ { 'd', 35 }, + /* State 35 */ { 'e', 36 }, + /* State 36 */ { 's', 37 }, + /* State 38 */ { 'm', 39 }, + /* State 39 */ { 'e', 40 }, + /* State 41 */ { 'u', 42 }, + /* State 42 */ { 't', 43 }, + /* State 43 */ { 'd', 44 }, + /* State 44 */ { 'e', 45 }, + /* State 45 */ { 'g', 46 }, + /* State 46 */ { 'r', 47 }, + /* State 47 */ { 'e', 48 }, + /* State 48 */ { 'e', 49 }, + /* State 50 */ { 'a', 51 }, + /* State 51 */ { 'r', 52 }, + /* State 52 */ { 'e', 53 }, + /* State 53 */ { 'n', 54 }, + /* State 54 */ { 't', 55 }, + /* State 56 */ { 'o', 57 }, + /* State 57 */ { 'o', 58 }, + /* State 58 */ { 't', 59 }, + /* State 60 */ { 't', 61 }, + /* State 61 */ { 'r', 62 }, + /* State 62 */ { 'i', 63 }, + /* State 63 */ { 'c', 64 }, + /* State 64 */ { 't', 65 }, + /* State 66 */ { 'a', 67 }, + /* State 67 */ { 'i', 68 }, + /* State 68 */ { 'l', 69 }, +}; diff --git a/lib/gvpr/trieFA.h b/lib/gvpr/trieFA.h new file mode 100644 index 000000000..6369e4ad8 --- /dev/null +++ b/lib/gvpr/trieFA.h @@ -0,0 +1,87 @@ +/* File - trieFA.h + * + * This file contains code to be included in the scanner file using a + * generated trie-based FA. + */ + +typedef struct { /* 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. */ +}TrieState ; + +typedef struct { /* An entry in the FA transition table. */ + short c; /* The transition character (lowercase).*/ + short next_state; /* The next state. */ +}TrieTrans ; + +#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. + */ +#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) -- 2.40.0