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
EMHOME = /usr/em
LPASS1 = ../lpass1
LPASS1 = $(EMHOME)/lang/cem/cemcom
# Libraries and EM interface definitions
SYSLIB = $(EMHOME)/modules/lib/libsystem.a
@ -24,12 +24,13 @@ CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
.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

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
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)

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();
#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();
@ -32,8 +30,6 @@ PRIVATE one_func_call();
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))
@ -67,7 +63,7 @@ main(argc, argv)
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
@ -199,6 +195,7 @@ PRIVATE one_ext_decl(kind, other_kind, other_class)
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;
}
@ -264,7 +261,7 @@ PRIVATE one_func_call(def)
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
) {
@ -284,7 +281,7 @@ PRIVATE one_func_call(def)
def->id_voided = 1;
break;
default:
panic("invalid dot->id_valused in check");
panic("invalid dot->id_valused in one_func_call()");
break;
}
@ -326,7 +323,7 @@ PRIVATE statics()
stat_def(stnr);
usage(stnr);
if (sta)
check_def(sta);
chk_def(sta);
if (same_obj(stnr))
panic("sequence error in input");
@ -360,7 +357,7 @@ PRIVATE stat_def(stnr)
}
}
PRIVATE check_def(def)
PRIVATE chk_def(def)
struct inpdef *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 ********/
print_id(name, id)

View file

@ -17,7 +17,7 @@
#include "private.h"
PRIVATE int LineNr = 1;
int LineNr = 1;
/* Two dangerous macro's. They replace a single statement by
* two statements
@ -25,10 +25,13 @@ PRIVATE int LineNr = 1;
#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)
@ -79,20 +82,18 @@ 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;
@ -104,14 +105,18 @@ ReadString(buf, delim, maxsize)
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
@ -123,7 +128,6 @@ ReadInt(ip)
* 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;
@ -148,24 +152,12 @@ ReadInt(ip)
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;
@ -179,7 +171,7 @@ ReadArgs(nrargs, buf)
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;
@ -190,3 +182,40 @@ ReadArgs(nrargs, buf)
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 ERROUT STDERR /* filedes on which to write the panics */
extern int LineNr;
PRIVATE rep_loc();
/* VARARGS */
@ -90,6 +92,11 @@ PRIVATE
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);
}
@ -103,7 +110,7 @@ rep_loc(id)
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);