formats introduced

This commit is contained in:
dick 1988-10-12 15:49:11 +00:00
parent bcb3b108a5
commit ac21f8d98a
7 changed files with 355 additions and 141 deletions

View file

@ -7,7 +7,7 @@
# Machine and environ dependent definitions # Machine and environ dependent definitions
EMHOME = /usr/em EMHOME = /usr/em
LPASS1 = ../lpass1 LPASS1 = $(EMHOME)/lang/cem/cemcom
# Libraries and EM interface definitions # Libraries and EM interface definitions
SYSLIB = $(EMHOME)/modules/lib/libsystem.a SYSLIB = $(EMHOME)/modules/lib/libsystem.a
@ -24,12 +24,13 @@ CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
.str.h: .str.h:
$(LPASS1)/make.allocd <$*.str >$*.h $(LPASS1)/make.allocd <$*.str >$*.h
SRC = lpass2.c read.c report.c class.c SRC = lpass2.c checkargs.c read.c report.c class.c l_print3ack.c
OBJ = lpass2.o read.o report.o class.o OBJ = lpass2.o checkargs.o read.o report.o class.o l_print3ack.o
test: lpass2 test: lpass2
make lint lpass2 -xh <.i
# lpass2 -xh <.i # make lint
lpass2: $(OBJ) Makefile next.o lpass2: $(OBJ) Makefile next.o
$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) next.o $(LLIBS) -o lpass2 $(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) next.o $(LLIBS) -o lpass2

View file

@ -0,0 +1,248 @@
/*
* (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';
}

View file

@ -9,7 +9,7 @@
class[] contains a bit pattern for each letter, with those bits set class[] contains a bit pattern for each letter, with those bits set
that correspond to the lint class meaning of the letter. 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) #define CL_DEF (1<<0)

View file

@ -0,0 +1,30 @@
/*
* (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

View file

@ -15,13 +15,11 @@
extern char *strcpy(); extern char *strcpy();
#define streq(s1,s2) (strcmp(s1, s2) == 0) #define streq(s1,s2) (strcmp(s1, s2) == 0)
#define min(a,b) ((a) <= (b) ? (a) : (b))
PRIVATE char cur_name[NAMESIZE]; PRIVATE char cur_name[NAMESIZE];
PRIVATE struct inpdef *dot, *lib, *ext, *sta; PRIVATE struct inpdef *dot, *lib, *ext, *sta;
PRIVATE check_args(); PRIVATE chk_def();
PRIVATE check_def();
PRIVATE ext_decls(); PRIVATE ext_decls();
PRIVATE ext_def(); PRIVATE ext_def();
PRIVATE get_dot(); PRIVATE get_dot();
@ -32,8 +30,6 @@ PRIVATE one_func_call();
PRIVATE one_var_usage(); PRIVATE one_var_usage();
PRIVATE stat_def(); PRIVATE stat_def();
PRIVATE statics(); PRIVATE statics();
PRIVATE int type_equal();
PRIVATE int type_match();
PRIVATE usage(); PRIVATE usage();
#define same_name() (dot && streq(cur_name, dot->id_name)) #define same_name() (dot && streq(cur_name, dot->id_name))
@ -67,7 +63,7 @@ main(argc, argv)
ext_decls(); ext_decls();
usage(0); usage(0);
if (ext) if (ext)
check_def(ext); chk_def(ext);
statics(); statics();
if (same_name()) { if (same_name()) {
/* there are more lines for this name that have /* there are more lines for this name that have
@ -199,6 +195,7 @@ PRIVATE one_ext_decl(kind, other_kind, other_class)
report("%L: %s %s %s as %s at %L", report("%L: %s %s %s as %s at %L",
dot, kind, dot->id_name, defdec(def), other_kind, def); dot, kind, dot->id_name, defdec(def), other_kind, def);
/* no further testing possible */ /* no further testing possible */
get_dot();
return; return;
} }
@ -264,7 +261,7 @@ PRIVATE one_func_call(def)
def->id_called = 1; def->id_called = 1;
if (def->id_args) { if (def->id_args) {
check_args(dot, def); chk_args(dot, def);
if ( dot->id_valused == USED if ( dot->id_valused == USED
&& def->id_valreturned == NOVALRETURNED && def->id_valreturned == NOVALRETURNED
) { ) {
@ -284,7 +281,7 @@ PRIVATE one_func_call(def)
def->id_voided = 1; def->id_voided = 1;
break; break;
default: default:
panic("invalid dot->id_valused in check"); panic("invalid dot->id_valused in one_func_call()");
break; break;
} }
@ -326,7 +323,7 @@ PRIVATE statics()
stat_def(stnr); stat_def(stnr);
usage(stnr); usage(stnr);
if (sta) if (sta)
check_def(sta); chk_def(sta);
if (same_obj(stnr)) if (same_obj(stnr))
panic("sequence error in input"); panic("sequence error in input");
@ -360,7 +357,7 @@ PRIVATE stat_def(stnr)
} }
} }
PRIVATE check_def(def) PRIVATE chk_def(def)
struct inpdef *def; struct inpdef *def;
{ {
if (!def) if (!def)
@ -396,104 +393,6 @@ PRIVATE check_def(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 ********/ /******** D E B U G G I N G ********/
print_id(name, id) print_id(name, id)

View file

@ -17,7 +17,7 @@
#include "private.h" #include "private.h"
PRIVATE int LineNr = 1; int LineNr = 1;
/* Two dangerous macro's. They replace a single statement by /* Two dangerous macro's. They replace a single statement by
* two statements * two statements
@ -25,10 +25,13 @@ PRIVATE int LineNr = 1;
#define loadchar(ch) LoadChar(ch); if (ch=='\n') LineNr++ #define loadchar(ch) LoadChar(ch); if (ch=='\n') LineNr++
#define pushback(ch) PushBack(); 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 ReadString();
PRIVATE int ReadInt(); PRIVATE int ReadInt();
PRIVATE SkipChar();
PRIVATE int ReadArgs(); PRIVATE int ReadArgs();
PRIVATE int ReadArg();
PRIVATE SkipChar();
int int
get_id(id) get_id(id)
@ -79,20 +82,18 @@ get_id(id)
if (!ReadString(id->id_file, '\n', FNAMESIZE)) if (!ReadString(id->id_file, '\n', FNAMESIZE))
return 0; return 0;
return (1); return 1;
} }
PRIVATE int PRIVATE int
ReadString(buf, delim, maxsize) ReadString(buf, delim, maxsize)
char *buf; char *buf;
{ {
/* Reads a string until 'delim' is encountered. /* Reads a string until 'delim' is encountered; delim is
Delim is discarded. discarded.
If 'maxsize-1' is exceeded, "string too long" is written If 'maxsize-1' is exceeded or the string contains a newline
by panic(). (which is not delim), panic() is called.
A '\0' is appended to the string. 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; int ch = 0;
@ -104,14 +105,18 @@ ReadString(buf, delim, maxsize)
return 0; return 0;
if (ch == delim) if (ch == delim)
break; break;
if (ch == '\n') {
panic("newline in string");
/*NOTREACHED*/
}
buf[nread++] = (char)ch; buf[nread++] = (char)ch;
} }
buf[nread++] = '\0'; buf[nread++] = '\0';
if (ch != delim) { if (ch != delim) {
panic("line %d: string too long: %s", LineNr, buf); panic("string too long");
/*NOTREACHED*/ /*NOTREACHED*/
} }
return (nread); return 1;
} }
PRIVATE int PRIVATE int
@ -123,7 +128,6 @@ ReadInt(ip)
* Non-digits except minus-sign in front of the number are discarded. * Non-digits except minus-sign in front of the number are discarded.
* Doesn't check on overflow. * Doesn't check on overflow.
* Just a minus-sign is interpreted as 0. (To prevent a look-ahead.) * Just a minus-sign is interpreted as 0. (To prevent a look-ahead.)
* At EOI 0 is returned, else 1.
*/ */
int ch; int ch;
int negative = 0; int negative = 0;
@ -148,24 +152,12 @@ ReadInt(ip)
return 1; 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 PRIVATE int
ReadArgs(nrargs, buf) ReadArgs(nrargs, buf)
char *buf; char *buf;
{ {
/* Reads a string into buf with format /* Reads a string into buf with format
<type1>:<type2>: ... :<typeN>: <type1>:<type2>: ... :<typeN>:\0
Note: format must include the final colon. Note: format must include the final colon.
*/ */
int i; int i;
@ -179,7 +171,7 @@ ReadArgs(nrargs, buf)
for (i = 0; i < nrargs; i++) { for (i = 0; i < nrargs; i++) {
int n; int n;
if (!ReadString(buf, ':', ARGTPSSIZE-charcount-1)) if (!ReadArg(buf, ARGTPSSIZE-charcount-1))
return 0; return 0;
n = strlen(buf) + 1; n = strlen(buf) + 1;
charcount += n; charcount += n;
@ -190,3 +182,40 @@ ReadArgs(nrargs, buf)
return 1; 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*/
}
}

View file

@ -14,6 +14,8 @@
#define MSGOUT STDERR /* filedes on which to write the messages */ #define MSGOUT STDERR /* filedes on which to write the messages */
#define ERROUT STDERR /* filedes on which to write the panics */ #define ERROUT STDERR /* filedes on which to write the panics */
extern int LineNr;
PRIVATE rep_loc(); PRIVATE rep_loc();
/* VARARGS */ /* VARARGS */
@ -90,6 +92,11 @@ PRIVATE
rep_loc(id) rep_loc(id)
struct inpdef *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)) { if (is_class(id, CL_LIB)) {
fprint(MSGOUT, "library file %s", id->id_file); fprint(MSGOUT, "library file %s", id->id_file);
} }
@ -103,7 +110,7 @@ rep_loc(id)
panic(fmt, args) panic(fmt, args)
char *fmt; char *fmt;
{ {
fprint(ERROUT, "PANIC, lint, pass2: "); fprint(ERROUT, "PANIC, lint, pass2: line %d: ", LineNr);
doprnt(ERROUT, fmt, &args); doprnt(ERROUT, fmt, &args);
fprint(ERROUT, "\n"); fprint(ERROUT, "\n");
exit(1); exit(1);