various improvements
authordick <none@none>
Fri, 8 Jul 1988 22:24:06 +0000 (22:24 +0000)
committerdick <none@none>
Fri, 8 Jul 1988 22:24:06 +0000 (22:24 +0000)
lang/cem/lint/lpass2/ChangeLog
lang/cem/lint/lpass2/Makefile
lang/cem/lint/lpass2/inpdef.str
lang/cem/lint/lpass2/lpass2.c
lang/cem/lint/lpass2/read.c [new file with mode: 0644]

index da2df7d..7853c69 100644 (file)
@@ -1,3 +1,28 @@
+ 8-Jul-88  Dick Grune (dick) at dick
+       Added a special meta-type (also in lpaas1) for non-negative
+       constant actual arguments, because these may match both the signed
+       and unsigned versions of the type.
+
+ 4-Jul-88  Dick Grune (dick) at dick
+       Added a scope number, to avoid problems with static object defined
+       in a .h file and used in the main file.  These should match but
+       they didn't, since scope was checked by comparing file names.
+
+28-Jun-88  Dick Grune (dick) at dick
+       Do not print messages that originate from files whose names start
+       with a /.
+
+24-Jun-88  Dick Grune (dick) at dick
+       Introduced a format %L to print location indications like
+       "aap.c", line 31. report() does a printf-like analysis now.
+
+18-Jun-88  Dick Grune (dick) at dick
+       Rewrote messages (originals were copies of lint).
+
+13-Jun-88  Dick Grune (dick) at dick
+       Moved the file name to the end of the intermediate records, to
+       avoid problems with files with : in their names.
+
 11-May-88  Dick Grune (dick) at dick
        Received sources from Frans Kunst.
 
index 34e8dc9..a81e055 100644 (file)
@@ -19,18 +19,27 @@ CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
 .str.h:
        $(LPASS1)/make.allocd <$*.str >$*.h
 
-lpass2:        lpass2.o makefile next.o
-       $(CC) $(COPTIONS) $(LDFLAGS) lpass2.o next.o $(LLIBS) -o lpass2
+SRC =  lpass2.c read.c
+OBJ =  lpass2.o read.o
+
+test:  lpass2
+       make lint
+
+lpass2:        $(OBJ) Makefile next.o
+       $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) next.o $(LLIBS) -o lpass2
        size lpass2
 
 lint:
-       lint $(CFLAGS) lpass2.c next.c
+       ../lint $(CFLAGS) $(SRC) next.c #???
 
 next.c:        inpdef.str
        $(LPASS1)/make.next inpdef.str > next.c
 
+tags:  $(SRC)
+       ctags $(SRC)
+
 clean:
-       rm -f a.out core next.c inpdef.h lpass2.o next.o
+       rm -f a.out core next.c inpdef.h $(OBJ) next.o
 
 #----------------------------------------------------------------
-lpass2.o: ../lpass1/errout.h ../lpass1/lint.h ../lpass1/manifest.h inpdef.h
+lpass2.o: ../lpass1/errout.h ../lpass1/lint.h ../lpass1/l_class.h inpdef.h
index 18b2656..7c85d18 100644 (file)
@@ -8,7 +8,7 @@ struct inpdef {
        int id_class;
        char id_name[NAMESIZE];
        char id_file[FNAMESIZE];
-       unsigned int id_line;
+       int id_line;
        int id_nrargs;
        char id_argtps[ARGTPSSIZE];
        int id_returns;
@@ -19,4 +19,6 @@ struct inpdef {
        int id_voided;
 };
 
+#define        is_def(id)      (is_def_class(id->id_class))
+
 /* ALLOCDEF "inpdef" 10 */
index 658a906..4f42089 100644 (file)
@@ -1,31 +1,27 @@
-#include "../lpass1/lint.h"
-#include "../lpass1/manifest.h"
-#include "inpdef.h"
-#include <ctype.h>     /* for efficient definition of isdigit */
+#include       <varargs.h>
 
-#define INP_NPUSHBACK 2
+#include       "../lpass1/l_lint.h"
+#include       "../lpass1/l_class.h"
+#include       "inpdef.h"
 
-#include <inp_pkg.spec>
-#include <inp_pkg.body>
+#include       <alloc.h>
+#include       <system.h>
 
-#define min(a, b) ((a) <= (b) ? (a) : (b))
-#define same_name() !strcmp(cur_name, next_id->id_name)
+#define        MSGOUT          STDERR  /* filedes on which to write the messages */
+#define        ERROUT          STDERR  /* filedes on which to write the panics */
 
-#define ReadUnsigned ReadInt   /* for the time being ??? */
+#define        streq(s1,s2)    (strcmp(s1, s2) == 0)
+#define        min(a,b)        ((a) <= (b) ? (a) : (b))
+
+#define        type_equal(s1,s2)       (streq(s1, s2))
 
 char *cur_name;
-struct inpdef *next_id,
+struct inpdef *dot_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--
 
+#define        same_name()     streq(cur_name, dot_id->id_name)
 
 main(argc, argv)
        char *argv[];
@@ -33,10 +29,12 @@ main(argc, argv)
        struct inpdef *id;
 
        init(argc, argv);
-       while (next_id) {
-               cur_name = next_id->id_name;
+
+       get_dot_id();
+       while (dot_id) {
+               cur_name = dot_id->id_name;
                read_defs();
-               while (next_id && same_name()) {
+               while (dot_id && same_name()) {
                        id = id_read();
                        check(id);
                        free_inpdef(id);
@@ -53,46 +51,47 @@ init(argc, argv)
        char *argv[];
 {
 /* Prepare standard input for reading using the input-package
- * Read first inpdef into next_id
+ * Read first inpdef into dot_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++)
+       while (argc > 1 && *argv[1] == '-') {
                switch (argv[1][1]) {
                case 'u':
-               /* don't give warnings like "used but not defined"
+               /* don't report situations like "used but not defined"
                 * and "defined but never used"
                 */
+               case 'X':               /* ??? prints incoming inpdefs */
                        options[argv[1][1]] = 1;
                        break;
                default:
                        /* ready to extend */
                        break;
                }
+               argc--, argv++;
+       }
+
+       if (!InsertFile((char *)0, table, &result))
+               panic("InsertFile() fails");
 }
 
 read_defs()
 {
        struct inpdef *id;
 
-       while (next_id && same_name() && next_id->id_class <= LVDF) {
+       if (ext_def || static_def)
+               panic("read_defs: slate not clean");/*???*/
+
+       while (dot_id && same_name() && is_def(dot_id)) {
                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);
+                               report("%L: %s also defined at %L",
+                                       id, id->id_name, ext_def);
                                free_inpdef(id);
                        }
                        else {
@@ -102,8 +101,8 @@ read_defs()
                case SFDF:
                case SVDF:
                        if (ext_def) {
-                               warning("%s multiply defined", id->id_name);
-                               places(id, ext_def);
+                               report("%L: %s also defined at %L",
+                                       id, id->id_name, ext_def);
                                free_inpdef(id);
                        }
                        else {
@@ -116,12 +115,9 @@ read_defs()
                                /* 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);
+                               if (is_lib_class(ext_def->id_class)) {
+                                       report("%L: %s redefined in library %L",
+                                               id, id->id_name, ext_def);
                                }
                                free_inpdef(id);
                        }
@@ -138,160 +134,29 @@ read_defs()
 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.
+/* Returns the value of dot_id if present, 0 otherwise.
+ * Reads a new inpdef ahead, to which dot_id will be pointing.
  * Cur_name will be pointing to id_name of the returned inpdef.
  */
        struct inpdef *old_id;
 
-       if (!next_id)
+       if (!dot_id)
                return (0);
-       old_id = next_id;
+       old_id = dot_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;
-       }
+       get_dot_id();
        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;
+get_dot_id()
 {
-/* 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++ = ':';
+/* Allocates a new inpdef, calls it dot_id and fills it */
+       dot_id = new_inpdef();
+       if (!get_id(dot_id)) {
+               free_inpdef(dot_id);
+               cur_name = "";
+               dot_id = 0;
        }
-       *buf = '\0';
-       return (!EOI);
 }
 
 struct inpdef *definition();
@@ -308,73 +173,69 @@ check(id)
        switch (id->id_class) {
        case EFDC:
                if (!idef) {
-                       uwarning("%s declared but never defined", id->id_name);
-                       unewline();
+                       if (!options['u']) {
+                               report("%L: %s declared but never defined",
+                                       id, id->id_name);
+                       }
                        discard_defs();
                        break;
                }
                if (idef->id_class == EVDF || idef->id_class == LVDF) {
-                       warning("%s value declared inconsistently",
-                               id->id_name);
-                       places(id, idef);
+                       report("%L: function %s declared as variable at %L",
+                               id, id->id_name, idef);
                        break;
                }
-               if (strcmp(id->id_type, idef->id_type)) {
-                       warning("%s value declared inconsistently",
-                               id->id_name);
-                       places(id, idef);
+               if (!type_equal(id->id_type, idef->id_type)) {
+                       report("%L: value of function %s declared differently at %L",
+                               id, id->id_name, idef);
                }
                break;
        case EVDC:
                if (!idef) {
-                       uwarning("%s declared but never defined", id->id_name);
-                       unewline();
+                       if (!options['u']) {
+                               report("%L: %s declared but never defined",
+                                       id, id->id_name);
+                       }
                        discard_defs();
                        break;
                }
                if (idef->id_class == EFDF || idef->id_class == LFDF) {
-                       warning("%s value declared inconsistently",
-                               id->id_name);
-                       places(id, idef);
+                       report("%L: variable %s declared as function at %L",
+                               id, id->id_name, idef);
                        break;
                }
-               if (strcmp(id->id_type, idef->id_type)) {
-                       warning("%s value declared inconsistently",
-                               id->id_name);
-                       places(id, idef);
+               if (!type_equal(id->id_type, idef->id_type)) {
+                       report("%L: variable %s declared differently at %L",
+                               id, id->id_name, 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);
+                       report("%L: function %s declared as variable at %L",
+                               id, id->id_name, idef);
                        break;
                }
-               if (strcmp(id->id_type, idef->id_type)) {
-                       warning("%s implicitly declared inconsistently",
-                               id->id_name);
-                       places(id, idef);
+               if (!type_equal(id->id_type, idef->id_type)) {
+                       report("%L: function value of %s declared differently at %L",
+                               id, id->id_name, idef);
                }
                break;
        case FC:
-       case VU:
                if (!idef) {
-                       uwarning("%s used but not defined", id->id_name);
-                       unewline();
+                       if (!options['u']) {
+                               report("%L: function %s used but not defined",
+                                       id, id->id_name);
+                       }
                        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);
+                       report("%L: value of %s is used, but none is returned at %L",
+                               id, id->id_name, idef);
                }
                switch (id->id_returns) {
                case USED:
@@ -390,6 +251,25 @@ check(id)
                        panic("invalid id->id_returns in check");
                }
                break;
+       case VU:
+               if (!idef) {
+                       if (!options['u']) {
+                               report("%L: variable %s used but not defined",
+                                       id, id->id_name);
+                       }
+                       discard_defs();
+                       break;
+               }
+               idef->id_called = 1;
+               break;
+       case EFDF:
+       case SFDF:
+       case EVDF:
+       case SVDF:
+       case LFDF:
+       case LVDF:
+               panic("check() called for a definition");
+               break;
        default:
                panic("invalid class (%c) in check", id->id_class);
                break;
@@ -402,7 +282,7 @@ discard_defs()
 
        struct inpdef *id;
 
-       while (next_id && same_name()) {
+       while (dot_id && same_name()) {
                id = id_read();
                free_inpdef(id);
        }
@@ -411,46 +291,88 @@ discard_defs()
 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;
+       register char *act_tp = id->id_argtps;
+       register char *def_tp = idef->id_argtps;
+       register int i;
+       register int nrargs;            /* # of args to be type-checked */
+       register int varargs;
 
+       /* determine nrargs */
        if (idef->id_nrargs < 0) {
                varargs = 1;
-               n = -idef->id_nrargs - 1;
+               nrargs = -idef->id_nrargs - 1;
        }
        else {
-               n = idef->id_nrargs;
+               varargs = 0;
+               nrargs = idef->id_nrargs;
        }
+
+       /* adjust nrargs, if necessary */
        if (varargs) {
-               if (n > id->id_nrargs) {
-                       warning("%s variable # of args", id->id_name);
-                       places(id, idef);
-                       n = id->id_nrargs;
+               if (nrargs > id->id_nrargs) {
+                       report("%L: number of args to %s differs from %L",
+                               id, id->id_name, idef);
+                       nrargs = 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);
+               if (nrargs != id->id_nrargs) {
+                       report("%L: number of args to %s differs from %L",
+                               id, id->id_name, idef);
+                       nrargs = min(nrargs, id->id_nrargs);
                }
        }
-       for (i = 1; i <= n; i++) {
-               while (*argtps1 == *argtps2 && *argtps1 != ':') {
-                       argtps1++;
-                       argtps2++;
+
+       for (i = 1; i <= nrargs; i++) {
+               register char *act = act_tp;
+               register char *def = def_tp;
+
+               /* isolate actual argument type */
+               while (*act_tp) {
+                       if (*act_tp == ':') {
+                               *act_tp = '\0';
+                               break;
+                       }
+                       act_tp++;
                }
-               if (*argtps1 != *argtps2) {
-                       warning("%s, arg %d used inconsistently",
-                               id->id_name, i);
-                       places(id, idef);
+               /* isolate formal argument type */
+               while (*def_tp) {
+                       if (*def_tp == ':') {
+                               *def_tp = '\0';
+                               break;
+                       }
+                       def_tp++;
                }
-               while (*argtps1++ != ':') ;
-               while (*argtps2++ != ':') ;
+
+               if (!type_match(act, def)) {
+                       report("%L: arg %d of %s differs from that at %L",
+                               id, i, id->id_name, idef);
+               }
+               *act_tp++ = ':';
+               *def_tp++ = ':';
        }
 }
 
+int
+type_match(act, def)
+       char *act, *def;
+{
+       if (type_equal(act, def))
+               return 1;
+       if (act[0] == '+') {
+               /* a non-negative constant */
+               /* might be signed or unsigned */
+               if (type_equal(&act[1], def))
+                       return 1;
+               if (    strncmp(def, "unsigned ", 9)
+               &&      type_equal(&act[1], &def[10])
+               ) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 check_usage()
 {
 /* Checks if the defined function or variable is used.
@@ -470,24 +392,27 @@ check_usage()
 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_called) {
+               if (streq(id->id_name, "main")) {
+                       /* silent */
+               }
+               else if (ext_def && is_lib_class(ext_def->id_class)) {
+                       /* silent */
+               }
+               else {
+                       if (!options['u']) {
+                               report("%L: %s defined but never used",
+                                       id, id->id_name);
+                       }
+               }
        }
-       if (    id->id_class == EFDF
-       ||      id->id_class == SFDF
-       ||      id->id_class == LFDF
-       ) {
+
+       if (is_fundef_class(id->id_class)) {
                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();
+                       report("%L: %s returns value which is %s ignored",
+                               id, id->id_name,
+                               (id->id_used || id->id_voided) ?
+                                               "sometimes" : "always");
                }
        }
 }
@@ -513,7 +438,7 @@ definition(id)
        struct inpdef *sd = static_def;
 
        while (sd) {
-               if (!strcmp(id->id_file, sd->id_file))
+               if (id->id_statnr == sd->id_statnr)
                        return (sd);
                sd = sd->next;
        }
@@ -536,46 +461,74 @@ free_defs()
        }
 }
 
-#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;
+/* VARARGS */
+report(va_alist)
+       va_dcl
 {
-       if (!options['u'])
-               doprnt(ERROUT, fmt, &args);
-}
-
-newline()
-{
-       fprint(ERROUT, "\n");
-}
-
-unewline()
-{
-       if (!options['u'])
-               fprint(ERROUT, "\n");
+       va_list ap;
+
+       va_start(ap);
+       {
+               char *fmt = va_arg(ap, char*);
+               register char *f = fmt;
+               register char fc;
+
+               /*      First see if the first arg is an inpdef with
+                       a global file name; if so, skip this message.
+               */
+               if (f[0] == '%' && f[1] == 'L') {
+                       /* it is an inpdef */
+                       register struct inpdef *id =
+                               va_arg(ap, struct inpdef *);
+
+                       f += 2;
+                       /* is the file name global? */
+                       if (id->id_file[0] == '/')
+                               return;
+                       /*      if no, we have used up the argument,
+                               so print it here
+                       */
+                       fprint(MSGOUT, "\"%s\", line %d",
+                               id->id_file, id->id_line);
+               }
+               while ((fc = *f++)) {
+                       if (fc == '%') {
+                               switch (*f++) {
+                                       register struct inpdef *id;
+                                       register char *s;
+                                       register int i;
+                               case 'L':       /* a location item */
+                                       id = va_arg(ap, struct inpdef *);
+                                       fprint(MSGOUT, "\"%s\", line %d",
+                                               id->id_file, id->id_line);
+                                       break;
+                               case 's':       /* a string item */
+                                       s = va_arg(ap, char *);
+                                       fprint(MSGOUT, "%s", s);
+                                       break;
+                               case 'd':       /* an int item */
+                                       i = va_arg(ap, int);
+                                       fprint(MSGOUT, "%d", i);
+                                       break;
+                               default:
+                                       panic("bad format %s", fmt);
+                                       break;
+                               }
+                       }
+                       else {
+                               fprint(MSGOUT, "%c", fc);
+                       }
+               }
+               fprint(MSGOUT, "\n");
+       }
+       va_end(ap);
 }
 
 /* VARARGS1 */
 panic(fmt, args)
        char *fmt;
 {
-       fprint(ERROUT, "PANIC: ");
+       fprint(ERROUT, "PANIC, lint, pass2: ");
        doprnt(ERROUT, fmt, &args);
        fprint(ERROUT, "\n");
        exit(1);
@@ -585,9 +538,21 @@ panic(fmt, args)
 print_id(id)
        struct inpdef *id;
 {
-       print("%c, %s, %s, %u, %d, %s, %d, %s\n",
-               id->id_class,
+       print("inpdef: %s, %s, %04d, \"%s\", %d, %d, %s, %d, %s\n",
+               id->id_class == EFDF ? "EFDF" :
+               id->id_class == SFDF ? "SFDF" :
+               id->id_class == EVDF ? "EVDF" :
+               id->id_class == SVDF ? "SVDF" :
+               id->id_class == LFDF ? "LFDF" :
+               id->id_class == LVDF ? "LVDF" :
+               id->id_class == EFDC ? "EFDC" :
+               id->id_class == EVDC ? "EVDC" :
+               id->id_class == IFDC ? "IFDC" :
+               id->id_class == FC ? "FC" :
+               id->id_class == VU ? "VU" :
+               id->id_class == ERRCL ? "ERRCL" : "<BADCLASS>",
                id->id_name,
+               id->id_statnr,
                id->id_file,
                id->id_line,
                id->id_nrargs,
@@ -595,3 +560,4 @@ print_id(id)
                id->id_returns,
                id->id_type);
 }
+
diff --git a/lang/cem/lint/lpass2/read.c b/lang/cem/lint/lpass2/read.c
new file mode 100644 (file)
index 0000000..1c979d8
--- /dev/null
@@ -0,0 +1,170 @@
+#include "../lpass1/l_class.h"
+#include "inpdef.h"
+
+#include <ctype.h>
+
+#define        INP_NPUSHBACK 2
+
+#include <inp_pkg.spec>
+#include <inp_pkg.body>
+
+PRIVATE 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--
+
+PRIVATE int ReadString();
+PRIVATE int ReadInt();
+PRIVATE SkipChar();
+PRIVATE int ReadArgs();
+
+int
+get_id(id)
+       struct inpdef *id;
+{
+/* A low-level function which just reads a definition */
+
+       if (!ReadString(id->id_name, ':', NAMESIZE))
+               return 0;
+       if (!ReadInt(&id->id_statnr))
+               return 0;
+       SkipChar(':');
+       loadchar(id->id_class);
+       if (id->id_class == EOI)
+               return 0;
+       SkipChar(':');
+       switch (id->id_class) {
+       case EFDF:
+       case SFDF:
+       case LFDF:
+       case FC:
+               if (!ReadInt(&id->id_nrargs))
+                       return 0;
+               SkipChar(':');
+               if (!ReadArgs(id->id_nrargs, id->id_argtps))
+                       return 0;
+               if (!ReadInt(&id->id_returns))
+                       return 0;
+               SkipChar(':');
+               break;
+       }
+       if (!ReadString(id->id_type, ':', TYPESIZE))
+               return 0;
+       if (!ReadInt(&id->id_line))
+               return 0;
+       SkipChar(':');
+       if (!ReadString(id->id_file, '\n', FNAMESIZE))
+               return 0;
+       {       extern char options[];
+               if (options['X'])
+                       print_id(id);/*???*/
+       }
+       return (1);
+}
+
+PRIVATE int
+ReadString(buf, delim, maxsize)
+       char *buf;
+{
+/* Reads a string until 'delim' is encountered.
+ * Delim is discarded.
+ * If 'maxsize-1' is exceeded, "string too long" is written by panic().
+ * A '\0' is appended to the string.
+ * At EOI 0 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 0;
+               if (ch == delim)
+                       break;
+               buf[nread++] = (char)ch;
+       }
+       if (ch != delim) {
+               panic("line %d: string too long: %s", LineNr, buf);
+               /*NOTREACHED*/
+       }
+       buf[nread++] = '\0';
+       return (nread);
+}
+
+PRIVATE 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 0 is returned, else 1.
+ */
+       int ch;
+       int negative = 0;
+       int res = 0;
+
+       do {
+               loadchar(ch);
+       } while (!isdigit(ch) && ch != '-');
+       if (ch == EOI)
+               return 0;
+       if (ch == '-')
+               negative = 1;
+       else
+               res = ch - '0';
+       loadchar(ch);
+       while (isdigit(ch)) {
+               res = 10*res + ch - '0';
+               loadchar(ch);
+       }
+       pushback(ch);
+       *ip = negative ? -res : res;
+       return 1;
+}
+
+PRIVATE SkipChar(ch)
+{
+       int c;
+
+       loadchar(c);
+       if (c != ch) {
+               panic("line %d: bad format, '%c' expected; '%c' read",
+                               LineNr, ch, c);
+               /*NOTREACHED*/
+       }
+}
+
+PRIVATE int
+ReadArgs(nrargs, buf)
+       char *buf;
+{
+/* Reads a string into buf with format <type1>:<type2>: ... :<typeN>: */
+
+       int i;
+       int charcount = 1;
+       int n;
+
+       if (nrargs < 0) {
+               /* variable # of args */
+               nrargs = -nrargs - 1;
+       }
+       *buf = '\0';
+       for (i = 0; i < nrargs; i++) {
+               if (!ReadString(buf, ':', ARGTPSSIZE-charcount-1))
+                       return 0;
+               n = strlen(buf) + 1;
+               charcount += n;
+               buf += n - 1;
+               *buf++ = ':';
+       }
+       *buf = '\0';
+       return 1;
+}
+