Initial version
authordick <none@none>
Mon, 30 May 1988 17:17:16 +0000 (17:17 +0000)
committerdick <none@none>
Mon, 30 May 1988 17:17:16 +0000 (17:17 +0000)
lang/cem/lint/lpass2/ChangeLog [new file with mode: 0644]
lang/cem/lint/lpass2/Makefile [new file with mode: 0644]
lang/cem/lint/lpass2/inpdef.str [new file with mode: 0644]
lang/cem/lint/lpass2/lpass2.c [new file with mode: 0644]

diff --git a/lang/cem/lint/lpass2/ChangeLog b/lang/cem/lint/lpass2/ChangeLog
new file mode 100644 (file)
index 0000000..da2df7d
--- /dev/null
@@ -0,0 +1,3 @@
+11-May-88  Dick Grune (dick) at dick
+       Received sources from Frans Kunst.
+
diff --git a/lang/cem/lint/lpass2/Makefile b/lang/cem/lint/lpass2/Makefile
new file mode 100644 (file)
index 0000000..34e8dc9
--- /dev/null
@@ -0,0 +1,36 @@
+#      M A K E F I L E   F O R   L P A S S 2
+
+# Machine and environ dependent definitions
+EMHOME = /usr/em
+LPASS1 = ../lpass1
+
+# Libraries and EM interface definitions
+SYSLIB = $(EMHOME)/modules/lib/libsystem.a
+STRLIB = $(EMHOME)/modules/lib/libstring.a
+PRTLIB = $(EMHOME)/modules/lib/libprint.a
+INPLIB = $(EMHOME)/modules/lib/libinput.a
+ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
+MALLOC = $(EMHOME)/modules/lib/malloc.o
+LLIBS = $(INPLIB) $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
+
+CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
+
+.SUFFIXES: .str .h
+.str.h:
+       $(LPASS1)/make.allocd <$*.str >$*.h
+
+lpass2:        lpass2.o makefile next.o
+       $(CC) $(COPTIONS) $(LDFLAGS) lpass2.o next.o $(LLIBS) -o lpass2
+       size lpass2
+
+lint:
+       lint $(CFLAGS) lpass2.c next.c
+
+next.c:        inpdef.str
+       $(LPASS1)/make.next inpdef.str > next.c
+
+clean:
+       rm -f a.out core next.c inpdef.h lpass2.o next.o
+
+#----------------------------------------------------------------
+lpass2.o: ../lpass1/errout.h ../lpass1/lint.h ../lpass1/manifest.h inpdef.h
diff --git a/lang/cem/lint/lpass2/inpdef.str b/lang/cem/lint/lpass2/inpdef.str
new file mode 100644 (file)
index 0000000..18b2656
--- /dev/null
@@ -0,0 +1,22 @@
+#define NAMESIZE 100
+#define FNAMESIZE 100
+#define ARGTPSSIZE 2000
+#define TYPESIZE 1000
+
+struct inpdef {
+       struct inpdef *next;
+       int id_class;
+       char id_name[NAMESIZE];
+       char id_file[FNAMESIZE];
+       unsigned int id_line;
+       int id_nrargs;
+       char id_argtps[ARGTPSSIZE];
+       int id_returns;
+       char id_type[TYPESIZE];
+       int id_called;
+       int id_used;
+       int id_ignored;
+       int id_voided;
+};
+
+/* ALLOCDEF "inpdef" 10 */
diff --git a/lang/cem/lint/lpass2/lpass2.c b/lang/cem/lint/lpass2/lpass2.c
new file mode 100644 (file)
index 0000000..658a906
--- /dev/null
@@ -0,0 +1,597 @@
+#include "../lpass1/lint.h"
+#include "../lpass1/manifest.h"
+#include "inpdef.h"
+#include <ctype.h>     /* for efficient definition of isdigit */
+
+#define INP_NPUSHBACK 2
+
+#include <inp_pkg.spec>
+#include <inp_pkg.body>
+
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+#define same_name() !strcmp(cur_name, next_id->id_name)
+
+#define ReadUnsigned ReadInt   /* for the time being ??? */
+
+char *cur_name;
+struct inpdef *next_id,
+       *ext_def,
+       *static_def;
+struct inpdef *id_read();
+static int LineNr = 1;
+
+/* Two dangerous macro's. They replace a single statement by
+ * two statements
+ */
+#define loadchar(ch) LoadChar(ch); if (ch=='\n') LineNr++
+#define pushback(ch) PushBack(); if (ch=='\n') LineNr--
+
+
+main(argc, argv)
+       char *argv[];
+{
+       struct inpdef *id;
+
+       init(argc, argv);
+       while (next_id) {
+               cur_name = next_id->id_name;
+               read_defs();
+               while (next_id && same_name()) {
+                       id = id_read();
+                       check(id);
+                       free_inpdef(id);
+               }
+               check_usage();
+               free_defs();
+       }
+}
+
+char options[128];
+static char *table[] = {0};
+
+init(argc, argv)
+       char *argv[];
+{
+/* Prepare standard input for reading using the input-package
+ * Read first inpdef into next_id
+ * Parse options
+ */
+
+       char *result;
+
+       if (!InsertFile((char *)0, table, &result))
+               panic("InsertFile() fails");
+       next_id = new_inpdef();
+       if (get_id(next_id) == EOI) {
+               free_inpdef(next_id);
+               next_id = 0;
+               return;
+       }
+       for (;argc > 1 && *argv[1] == '-'; argc--, argv++)
+               switch (argv[1][1]) {
+               case 'u':
+               /* don't give warnings like "used but not defined"
+                * and "defined but never used"
+                */
+                       options[argv[1][1]] = 1;
+                       break;
+               default:
+                       /* ready to extend */
+                       break;
+               }
+}
+
+read_defs()
+{
+       struct inpdef *id;
+
+       while (next_id && same_name() && next_id->id_class <= LVDF) {
+               id = id_read();
+               switch (id->id_class) {
+               case EFDF:
+               case EVDF:
+                       if (ext_def) {
+                               warning("%s multiply defined", id->id_name);
+                               places(id, ext_def);
+                               free_inpdef(id);
+                       }
+                       else {
+                               ext_def = id;
+                       }
+                       break;
+               case SFDF:
+               case SVDF:
+                       if (ext_def) {
+                               warning("%s multiply defined", id->id_name);
+                               places(id, ext_def);
+                               free_inpdef(id);
+                       }
+                       else {
+                               static_in_list(id);
+                       }
+                       break;
+               case LFDF:
+               case LVDF:
+                       if (ext_def) {
+                               /* Some libraries contain more than one
+                                * definition
+                                */
+                               if (    ext_def->id_class != LFDF
+                               &&      ext_def->id_class != LVDF
+                               ) {
+                                       warning("%s also defined in library",
+                                               id->id_name);
+                                       places(id, ext_def);
+                               }
+                               free_inpdef(id);
+                       }
+                       else {
+                               ext_def = id;
+                       }
+                       break;
+               default:
+                       panic("invalid class (%c) in read_defs", id->id_class);
+               }
+       }
+}
+
+struct inpdef *
+id_read()
+{
+/* Returns the value of next_id if present, 0 otherwise.
+ * Reads a new inpdef ahead, to which next_id will be pointing.
+ * Cur_name will be pointing to id_name of the returned inpdef.
+ */
+       struct inpdef *old_id;
+
+       if (!next_id)
+               return (0);
+       old_id = next_id;
+       cur_name = old_id->id_name;
+       next_id = new_inpdef();
+       if (get_id(next_id) == EOI) {
+               free_inpdef(next_id);
+               cur_name = "";
+               next_id = 0;
+       }
+       return (old_id);
+}
+
+int
+get_id(id)
+       struct inpdef *id;
+{
+/* A low-level function which just reads a definition */
+
+       int eoi;
+
+       if (ReadString(id->id_name, ':', NAMESIZE) == EOI)
+               return (EOI);
+       loadchar(id->id_class);
+       if (id->id_class == EOI)
+               return (EOI);
+       SkipChar(':');
+       if (ReadString(id->id_file, ':', FNAMESIZE) == EOI)
+               return (EOI);
+       if (ReadUnsigned(&id->id_line) == EOI)
+               return (EOI);
+       SkipChar(':');
+       switch (id->id_class) {
+       case EFDF:
+       case SFDF:
+       case LFDF:
+       case FC:
+               if (ReadInt(&id->id_nrargs) == EOI)
+                       return (EOI);
+               SkipChar(':');
+               eoi = args_read(
+                       (id->id_nrargs < 0 ? -id->id_nrargs-1 : id->id_nrargs),
+                       id->id_argtps);
+               if (eoi == EOI)
+                       return (EOI);
+               if (ReadInt(&id->id_returns) == EOI)
+                       return (EOI);
+               SkipChar(':');
+               break;
+       }
+       return (ReadString(id->id_type, '\n', TYPESIZE));
+}
+
+int
+ReadString(buf, delim, maxsize)
+       char *buf;
+{
+/* Reads a string until 'delim' is encountered.
+ * Delim is discarded.
+ * If 'maxsize-1' is exeded, "string too long" is written by panic().
+ * A '\0' is appended to the string.
+ * At EOI EOI is returned, else the length of the string (including
+ * the appended '\0') is returned.
+ */
+       int ch;
+       int nread = 0;
+
+       while (nread < maxsize - 1) {
+               loadchar(ch);
+               if (ch == EOI)
+                       return (EOI);
+               if (ch == delim)
+                       break;
+               buf[nread++] = (char)ch;
+       }
+       if (ch != delim) {
+               buf[nread] = '\0';
+               panic("line %d: string too long: %s", LineNr, buf);
+       }
+       buf[nread++] = '\0';
+       return (nread);
+}
+
+int
+ReadInt(ip)
+       int *ip;
+{
+/* Reads a decimal integer until a character which is not
+ * a digit is encountered.
+ * Non-digits except minus-sign in front of the number are discarded.
+ * Doesn't check on overflow.
+ * Just a minus-sign is interpreted as 0. (To prevent a look-ahead.)
+ * At EOI EOI is returned.
+ */
+       int ch;
+       int negative = 0;
+       int i = 0;
+
+       do {
+               loadchar(ch);
+       }       /* {} needed because of the loadchar-macro; yack */
+       while (!isdigit(ch) && ch != '-');
+       if (ch == EOI)
+               return (EOI);
+       if (ch == '-')
+               negative = 1;
+       else
+               i = ch - '0';
+       loadchar(ch);
+       while (isdigit(ch)) {
+               i = 10*i + ch - '0';
+               loadchar(ch);
+       }
+       pushback(ch);
+       *ip = negative ? -i : i;
+       return (!EOI);
+}
+
+SkipChar(ch)
+{
+       int c;
+
+       loadchar(c);
+       if (c != ch)
+               panic("line %d: bad format, '%c' expected; '%c' read",
+                               LineNr, ch, c);
+}
+
+int
+args_read(nrargs, buf)
+char *buf;
+{
+/* Reads a string into buf with format <type1>:<type2>: ... :<typen>: */
+
+       int i;
+       int charcount = 1;
+       int n;
+
+       *buf = '\0';
+       for (i = 0; i < nrargs; i++) {
+               if ((n = ReadString(buf, ':', ARGTPSSIZE-charcount-1)) == EOI)
+                       return (EOI);
+               charcount += n;
+               buf += n - 1;
+               *buf++ = ':';
+       }
+       *buf = '\0';
+       return (!EOI);
+}
+
+struct inpdef *definition();
+
+check(id)
+       struct inpdef *id;
+{
+/* Checks a declaration, function call or variable usage, described by id,
+ * against the definitions.
+ */
+       struct inpdef *idef;
+
+       idef = definition(id);
+       switch (id->id_class) {
+       case EFDC:
+               if (!idef) {
+                       uwarning("%s declared but never defined", id->id_name);
+                       unewline();
+                       discard_defs();
+                       break;
+               }
+               if (idef->id_class == EVDF || idef->id_class == LVDF) {
+                       warning("%s value declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+                       break;
+               }
+               if (strcmp(id->id_type, idef->id_type)) {
+                       warning("%s value declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+               }
+               break;
+       case EVDC:
+               if (!idef) {
+                       uwarning("%s declared but never defined", id->id_name);
+                       unewline();
+                       discard_defs();
+                       break;
+               }
+               if (idef->id_class == EFDF || idef->id_class == LFDF) {
+                       warning("%s value declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+                       break;
+               }
+               if (strcmp(id->id_type, idef->id_type)) {
+                       warning("%s value declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+               }
+               break;
+       case IFDC:
+               if (!idef)
+                       break;          /* used but not defined */
+               if (idef->id_class == EVDF || idef->id_class == LVDF) {
+                       warning("%s value declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+                       break;
+               }
+               if (strcmp(id->id_type, idef->id_type)) {
+                       warning("%s implicitly declared inconsistently",
+                               id->id_name);
+                       places(id, idef);
+               }
+               break;
+       case FC:
+       case VU:
+               if (!idef) {
+                       uwarning("%s used but not defined", id->id_name);
+                       unewline();
+                       discard_defs();
+                       break;
+               }
+               idef->id_called = 1;
+               if (id->id_class == VU)
+                       break;
+               check_args(id, idef);
+               if (id->id_returns == USED && !idef->id_returns) {
+                       warning("%s value is used, but none is returned",
+                               id->id_name);
+                       places(id, idef);
+               }
+               switch (id->id_returns) {
+               case USED:
+                       idef->id_used = 1;
+                       break;
+               case IGNORED:
+                       idef->id_ignored = 1;
+                       break;
+               case VOIDED:
+                       idef->id_voided = 1;
+                       break;
+               default:
+                       panic("invalid id->id_returns in check");
+               }
+               break;
+       default:
+               panic("invalid class (%c) in check", id->id_class);
+               break;
+       }
+}
+
+discard_defs()
+{
+/* Read until a definition having another name */
+
+       struct inpdef *id;
+
+       while (next_id && same_name()) {
+               id = id_read();
+               free_inpdef(id);
+       }
+}
+
+check_args(id, idef)
+       struct inpdef *id, *idef;
+{
+       register char *argtps1 = id->id_argtps;
+       register char *argtps2 = idef->id_argtps;
+       int i, n, varargs = 0;
+
+       if (idef->id_nrargs < 0) {
+               varargs = 1;
+               n = -idef->id_nrargs - 1;
+       }
+       else {
+               n = idef->id_nrargs;
+       }
+       if (varargs) {
+               if (n > id->id_nrargs) {
+                       warning("%s variable # of args", id->id_name);
+                       places(id, idef);
+                       n = id->id_nrargs;
+               }
+       }
+       else {
+               if (n != id->id_nrargs) {
+                       warning("%s variable # of args", id->id_name);
+                       places(id, idef);
+                       n = min(n, id->id_nrargs);
+               }
+       }
+       for (i = 1; i <= n; i++) {
+               while (*argtps1 == *argtps2 && *argtps1 != ':') {
+                       argtps1++;
+                       argtps2++;
+               }
+               if (*argtps1 != *argtps2) {
+                       warning("%s, arg %d used inconsistently",
+                               id->id_name, i);
+                       places(id, idef);
+               }
+               while (*argtps1++ != ':') ;
+               while (*argtps2++ != ':') ;
+       }
+}
+
+check_usage()
+{
+/* Checks if the defined function or variable is used.
+ * There can be several static definitions.
+ */
+
+       struct inpdef *sd = static_def;
+
+       if (ext_def)
+               check_def(ext_def);
+       while (sd) {
+               check_def(sd);
+               sd = sd->next;
+       }
+}
+
+check_def(id)
+       struct inpdef *id;
+{
+       if (    !id->id_called && strcmp(id->id_name, "main")
+       &&      ext_def->id_class != LFDF
+       &&      ext_def->id_class != LVDF
+       ) {
+               uwarning("%s defined (%s(%u)) but never used",
+                       id->id_name, id->id_file, id->id_line);
+               unewline();
+       }
+       if (    id->id_class == EFDF
+       ||      id->id_class == SFDF
+       ||      id->id_class == LFDF
+       ) {
+               if (id->id_returns && id->id_called && id->id_ignored) {
+                       warning("%s returns value which is %s ignored",
+                               id->id_name,
+                               id->id_used || id->id_voided ?
+                               "sometimes" : "always");
+                       newline();
+               }
+       }
+}
+
+static_in_list(id)
+       struct inpdef *id;
+{
+/* Put id in the list of static definitions.
+ * static_def points to the first element.
+ */
+       id->next = static_def;
+       static_def = id;
+}
+
+struct inpdef *
+definition(id)
+       struct inpdef *id;
+{
+/* If there is a static definition that comes from the same file, a pointer
+ * to this definition will be returned.
+ * Otherwise a pointer to the ext_def is returned (which may be null).
+ */
+       struct inpdef *sd = static_def;
+
+       while (sd) {
+               if (!strcmp(id->id_file, sd->id_file))
+                       return (sd);
+               sd = sd->next;
+       }
+       return (ext_def);
+}
+
+free_defs()
+{
+/* Dispose the external definition and the static definitions. */
+       struct inpdef *sd;
+
+       if (ext_def) {
+               free_inpdef(ext_def);
+               ext_def = 0;
+       }
+       while (static_def) {
+               sd = static_def;
+               static_def = static_def->next;
+               free_inpdef(sd);
+       }
+}
+
+#include "../lpass1/errout.h"  /* for definition of ERROUT */
+
+places(id1, id2)
+       struct inpdef *id1, *id2;
+{
+       fprint(ERROUT, "\t%s(%u) :: %s(%u)\n",
+               id1->id_file, id1->id_line, id2->id_file, id2->id_line);
+}
+
+/* VARARGS1 */
+warning(fmt, args)
+       char *fmt;
+{
+       doprnt(ERROUT, fmt, &args);
+}
+
+/* VARARGS1 */
+uwarning(fmt, args)
+       char *fmt;
+{
+       if (!options['u'])
+               doprnt(ERROUT, fmt, &args);
+}
+
+newline()
+{
+       fprint(ERROUT, "\n");
+}
+
+unewline()
+{
+       if (!options['u'])
+               fprint(ERROUT, "\n");
+}
+
+/* VARARGS1 */
+panic(fmt, args)
+       char *fmt;
+{
+       fprint(ERROUT, "PANIC: ");
+       doprnt(ERROUT, fmt, &args);
+       fprint(ERROUT, "\n");
+       exit(1);
+}
+
+/* for DEBUGGING */
+print_id(id)
+       struct inpdef *id;
+{
+       print("%c, %s, %s, %u, %d, %s, %d, %s\n",
+               id->id_class,
+               id->id_name,
+               id->id_file,
+               id->id_line,
+               id->id_nrargs,
+               ((id->id_nrargs == 0) ? "" : id->id_argtps),
+               id->id_returns,
+               id->id_type);
+}