# Machine and environ dependent definitions
EMHOME = /usr/em
-LPASS1 = ../lpass1
+LPASS1 = $(EMHOME)/lang/cem/cemcom
# Libraries and EM interface definitions
SYSLIB = $(EMHOME)/modules/lib/libsystem.a
.str.h:
$(LPASS1)/make.allocd <$*.str >$*.h
-SRC = lpass2.c read.c report.c class.c
-OBJ = lpass2.o read.o report.o class.o
+SRC = lpass2.c checkargs.c read.c report.c class.c l_print3ack.c
+OBJ = lpass2.o checkargs.o read.o report.o class.o l_print3ack.o
test: lpass2
- make lint
-# lpass2 -xh <.i
+ lpass2 -xh <.i
+# make lint
+
lpass2: $(OBJ) Makefile next.o
$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) next.o $(LLIBS) -o lpass2
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/******** A R G U M E N T T Y P E C H E C K I N G ********/
+
+#include "private.h"
+#include "inpdef.h"
+
+extern char *strcpy();
+
+#define streq(s1,s2) (strcmp(s1, s2) == 0)
+
+/* a format is developed into a normal parameter definition */
+PRIVATE int is_formatargs; /* present or not */
+PRIVATE char formatargs[1000]; /* the definitions */
+
+PRIVATE chk_argtps();
+PRIVATE char *next_atype();
+PRIVATE int type_match();
+
+int
+type_equal(act, form)
+ char *act, *form;
+{
+ return streq(act, form)
+ || streq(act, "erroneous")
+ || streq(form, "erroneous");
+}
+
+chk_args(id, def)
+ struct inpdef *id, *def;
+{
+ char *act_tp = id->id_argtps;
+ int nrargs = 0; /* number of args */
+
+ /* clear format */
+ is_formatargs = 0;
+
+ /* check normal arguments */
+ chk_argtps(id, def, &nrargs, act_tp, def->id_argtps);
+
+ if (is_formatargs) {
+ /* there was a format */
+ register int i;
+
+ /* skip over the actuals already covered */
+ for (i = 0; i < nrargs; i++) {
+ act_tp = next_atype(act_tp);
+ }
+
+ /* and check the format arguments */
+ chk_argtps(id, (struct inpdef *)0, &nrargs,
+ act_tp, &formatargs[0]);
+ }
+}
+
+PRIVATE chk_argtps(id, def, nrargs, act_tp, form_tp)
+ struct inpdef *id; /* the actual call */
+ struct inpdef *def; /* 0 for format-derived definition */
+ int *nrargs; /* in-out parameter, counting */
+ char *act_tp; /* actual types */
+ char *form_tp; /* formal type definitions */
+{
+ while (*act_tp && *form_tp) {
+ register char *act_start = act_tp;
+ register char *form_start = form_tp;
+
+ /* isolate actual argument type */
+ act_tp = next_atype(act_tp);
+ act_tp[-1] = '\0';
+
+ /* isolate formal argument type */
+ form_tp = next_atype(form_tp);
+ form_tp[-1] = '\0';
+
+ (*nrargs)++;
+ if (!type_match(id, act_start, form_start)) {
+ report("%L: arg %d of %s differs from that in %L",
+ id, *nrargs, id->id_name, def);
+ }
+ act_tp[-1] = ':';
+ form_tp[-1] = ':';
+ }
+
+ if (*form_tp) {
+ /* formal type definitions not exhausted */
+ report("%L: %s has fewer arguments than in %L",
+ id, id->id_name, def);
+ }
+ if (*act_tp) {
+ /* actual types not exhausted */
+ if (def && def->id_nrargs < 0) {
+ /* the function had VARARGS */
+ }
+ else {
+ report("%L: %s has more arguments than in %L",
+ id, id->id_name, def);
+ }
+ }
+}
+
+PRIVATE char *
+next_atype(tp)
+ char *tp;
+{
+ while (*tp && *tp != ':') {
+ tp++;
+ }
+ if (*tp == ':') {
+ tp++;
+ }
+ return tp;
+}
+
+int
+PRIVATE type_match(id, act, form)
+ struct inpdef *id;
+ char *act, *form;
+{
+ if (form[0] == '"' && act[0] == '"') {
+ conv_format(id, act, form);
+ return 1;
+ }
+
+ if ( (form[0] == '"' && streq(act, "char*"))
+ || (act[0] == '"' && streq(form, "char*"))
+ ) {
+ return 1;
+ }
+
+ if (type_equal(act, form))
+ return 1;
+
+ if (act[0] == '+') {
+ /* a non-negative constant */
+ /* might be signed or unsigned */
+ if (type_equal(&act[1], form))
+ return 1;
+ if ( strncmp(form, "unsigned ", strlen("unsigned ")) == 0
+ && type_equal(&act[1], &form[strlen("unsigned ")])
+ ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+PRIVATE conv_format(id, act, form)
+ struct inpdef *id;
+ char *act, *form;
+{
+ /* convert the actual format into a def-list, using the
+ formal format (form) as a map to convert from %X to type
+ */
+ register char *fmt = &formatargs[0];
+
+ is_formatargs = 1;
+ while (*act) {
+ register char *map;
+
+ /* find next conversion specification */
+ while (*act && *act != '%') {
+ act++;
+ }
+ if (*act++ != '%')
+ break;
+ if (*act == '%') {
+ /* %% */
+ act++;
+ continue;
+ }
+
+ /* process options */
+ if (*act && *act == '-') {
+ act++;
+ }
+ while (*act && ('0' <= *act && *act <= '9')) {
+ act++;
+ }
+ if (*act == '*') {
+ act++;
+ strcpy(fmt, "int:");
+ fmt += 4;
+ }
+ if (*act && *act == '.') {
+ act++;
+ }
+ while (*act && ('0' <= *act && *act <= '9')) {
+ act++;
+ }
+ if (*act == '*') {
+ act++;
+ strcpy(fmt, "int:");
+ fmt += 4;
+ }
+
+ map = form;
+ while (*map) {
+ register char *cs = act;
+
+ /* find next conversion mapping */
+ while (*map && *map != '%') {
+ map++;
+ }
+ if (*map++ != '%') {
+ /* we ran off the map */
+ report("%L: unknown conversion specification in format",
+ id);
+ break;
+ }
+
+ while (*map && *map != '=') {
+ register int match = 0;
+
+ if (*map == '[') {
+ while (*map && *map != ']') {
+ if (*map == *cs) {
+ match = 1;
+ }
+ map++;
+ }
+ }
+ else {
+ match = (*map == *cs);
+ }
+
+ if (match) {
+ map++, cs++;
+ }
+ else break;
+ }
+ if (*map++ == '=') {
+ /* found the type belonging to %*cs */
+ while (*map && *map != '%' && *map != '"') {
+ *fmt++ = *map++;
+ }
+ *fmt++ = ':';
+ act = cs;
+ break;
+ }
+ }
+ }
+ *fmt++ = '\0';
+}
+
class[] contains a bit pattern for each letter, with those bits set
that correspond to the lint class meaning of the letter.
- This facility is used through the macro is_class(inpdef_var, CL_???)
+ This facility is used through the macro is_class(inpdef_var, CL_XXX)
*/
#define CL_DEF (1<<0)
--- /dev/null
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Header$ */
+
+/* A C K P R I N T M O D U L E D E F I N T I O N S */
+
+#ifdef lint
+
+#include <system.h>
+
+/* LINTLIBRARY */
+
+/* FORMAT0 $
+ %[bdox] = int %l[bdox] = long
+ %c = int %s = char *
+ %u = unsigned int
+$ */
+print(format) char *format; { ; }
+
+/* FORMAT1 */
+fprint(filep, format) File *filep; char *format; { ; }
+/* FORMAT1 */
+sprint(s, format) char *s; char *format; { ; }
+/* FORMAT1 */
+doprnt(filep, format) File *filep; char *format; { ; }
+
+#endif lint
+
extern char *strcpy();
#define streq(s1,s2) (strcmp(s1, s2) == 0)
-#define min(a,b) ((a) <= (b) ? (a) : (b))
PRIVATE char cur_name[NAMESIZE];
PRIVATE struct inpdef *dot, *lib, *ext, *sta;
-PRIVATE check_args();
-PRIVATE check_def();
+PRIVATE chk_def();
PRIVATE ext_decls();
PRIVATE ext_def();
PRIVATE get_dot();
PRIVATE one_var_usage();
PRIVATE stat_def();
PRIVATE statics();
-PRIVATE int type_equal();
-PRIVATE int type_match();
PRIVATE usage();
#define same_name() (dot && streq(cur_name, dot->id_name))
ext_decls();
usage(0);
if (ext)
- check_def(ext);
+ chk_def(ext);
statics();
if (same_name()) {
/* there are more lines for this name that have
report("%L: %s %s %s as %s at %L",
dot, kind, dot->id_name, defdec(def), other_kind, def);
/* no further testing possible */
+ get_dot();
return;
}
def->id_called = 1;
if (def->id_args) {
- check_args(dot, def);
+ chk_args(dot, def);
if ( dot->id_valused == USED
&& def->id_valreturned == NOVALRETURNED
) {
def->id_voided = 1;
break;
default:
- panic("invalid dot->id_valused in check");
+ panic("invalid dot->id_valused in one_func_call()");
break;
}
stat_def(stnr);
usage(stnr);
if (sta)
- check_def(sta);
+ chk_def(sta);
if (same_obj(stnr))
panic("sequence error in input");
}
}
-PRIVATE check_def(def)
+PRIVATE chk_def(def)
struct inpdef *def;
{
if (!def)
}
-/******** T Y P E C H E C K I N G ********/
-
-PRIVATE check_args(id, def)
- struct inpdef *id, *def;
-{
- register char *act_tp = id->id_argtps;
- register char *def_tp = def->id_argtps;
- register int i;
- register int nrargs; /* # of args to be type-checked */
- register int varargs;
-
- /* determine nrargs */
- if (def->id_nrargs < 0) {
- varargs = 1;
- nrargs = -def->id_nrargs - 1;
- }
- else {
- varargs = 0;
- nrargs = def->id_nrargs;
- }
-
- /* adjust nrargs, if necessary */
- if (varargs) {
- if (nrargs > id->id_nrargs) {
- report("%L: number of args to %s differs from %L",
- id, id->id_name, def);
- nrargs = id->id_nrargs;
- }
- }
- else {
- if (nrargs != id->id_nrargs) {
- report("%L: number of args to %s differs from %L",
- id, id->id_name, def);
- nrargs = min(nrargs, id->id_nrargs);
- }
- }
-
- for (i = 1; i <= nrargs; i++) {
- register char *act_par = act_tp;
- register char *def_par = def_tp;
-
- /* isolate actual argument type */
- while (*act_tp) {
- if (*act_tp == ':') {
- *act_tp = '\0';
- break;
- }
- act_tp++;
- }
- /* isolate formal argument type */
- while (*def_tp) {
- if (*def_tp == ':') {
- *def_tp = '\0';
- break;
- }
- def_tp++;
- }
-
- if (!type_match(act_par, def_par)) {
- report("%L: arg %d of %s differs from that at %L",
- id, i, id->id_name, def);
- }
- *act_tp++ = ':';
- *def_tp++ = ':';
- }
-}
-
-int
-PRIVATE type_equal(act, def)
- char *act, *def;
-{
- return streq(act, def)
- || streq(act, "erroneous")
- || streq(def, "erroneous");
-}
-
-int
-PRIVATE 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 ", strlen("unsigned ")) == 0
- && type_equal(&act[1], &def[strlen("unsigned ")])
- ) {
- return 1;
- }
- }
- return 0;
-}
-
-
/******** D E B U G G I N G ********/
print_id(name, id)
#include "private.h"
-PRIVATE int LineNr = 1;
+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--
+/* all the ReadX() functions return 0 upon EOI */
PRIVATE int ReadString();
PRIVATE int ReadInt();
-PRIVATE SkipChar();
PRIVATE int ReadArgs();
+PRIVATE int ReadArg();
+
+PRIVATE SkipChar();
int
get_id(id)
if (!ReadString(id->id_file, '\n', FNAMESIZE))
return 0;
- return (1);
+ 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().
+ /* Reads a string until 'delim' is encountered; delim is
+ discarded.
+ If 'maxsize-1' is exceeded or the string contains a newline
+ (which is not delim), panic() is called.
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 = 0;
return 0;
if (ch == delim)
break;
+ if (ch == '\n') {
+ panic("newline in string");
+ /*NOTREACHED*/
+ }
buf[nread++] = (char)ch;
}
buf[nread++] = '\0';
if (ch != delim) {
- panic("line %d: string too long: %s", LineNr, buf);
+ panic("string too long");
/*NOTREACHED*/
}
- return (nread);
+ return 1;
}
PRIVATE int
* 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;
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>:
+ <type1>:<type2>: ... :<typeN>:\0
Note: format must include the final colon.
*/
int i;
for (i = 0; i < nrargs; i++) {
int n;
- if (!ReadString(buf, ':', ARGTPSSIZE-charcount-1))
+ if (!ReadArg(buf, ARGTPSSIZE-charcount-1))
return 0;
n = strlen(buf) + 1;
charcount += n;
return 1;
}
+PRIVATE int
+ReadArg(buf, size)
+ char *buf;
+ int size;
+{
+ int ch;
+
+ loadchar(ch);
+ switch (ch) {
+ case '"': /* formal format or actual string */
+ *buf++ = ch;
+ if (!ReadString(buf, ch, size-1))
+ return 0;
+ buf += strlen(buf);
+ *buf++ = ch;
+ *buf++ = '\0';
+ SkipChar(':');
+ return 1;
+ default: /* normal type */
+ pushback(ch);
+ return ReadString(buf, ':', size);
+ case EOI:
+ return 0;
+ }
+}
+
+PRIVATE SkipChar(ch)
+{
+ int c;
+
+ loadchar(c);
+ if (c != ch) {
+ panic("bad format, '%c' expected; '%c' read", ch, c);
+ /*NOTREACHED*/
+ }
+}
+
#define MSGOUT STDERR /* filedes on which to write the messages */
#define ERROUT STDERR /* filedes on which to write the panics */
+extern int LineNr;
+
PRIVATE rep_loc();
/* VARARGS */
rep_loc(id)
struct inpdef *id;
{
+ /* a definition can come from a number of places */
+ if (!id) {
+ fprint(MSGOUT, "format");
+ }
+ else
if (is_class(id, CL_LIB)) {
fprint(MSGOUT, "library file %s", id->id_file);
}
panic(fmt, args)
char *fmt;
{
- fprint(ERROUT, "PANIC, lint, pass2: ");
+ fprint(ERROUT, "PANIC, lint, pass2: line %d: ", LineNr);
doprnt(ERROUT, fmt, &args);
fprint(ERROUT, "\n");
exit(1);