formats introduced in lint

This commit is contained in:
dick 1988-10-12 16:05:17 +00:00
parent ac21f8d98a
commit e66f3adc06
13 changed files with 325 additions and 166 deletions

View file

@ -74,7 +74,7 @@ LLlex()
}
else { /* read ahead and return the old one */
#ifdef LINT
move_NOT2s();
lint_comment_ahead();
#endif LINT
dot = ahead;
/* the following test is performed due to the dual
@ -477,8 +477,8 @@ skipcomment()
NoUnstack++;
LoadChar(c);
#ifdef LINT
lint_comment(-2);
lint_comment(c);
lint_start_comment();
lint_comment_char(c);
#endif LINT
do {
while (c != '*') {
@ -487,18 +487,24 @@ skipcomment()
else
if (c == EOI) {
NoUnstack--;
#ifdef LINT
lint_end_comment();
#endif LINT
return;
}
LoadChar(c);
#ifdef LINT
lint_comment(c);
lint_comment_char(c);
#endif LINT
} /* last Character seen was '*' */
LoadChar(c);
#ifdef LINT
lint_comment(c);
lint_comment_char(c);
#endif LINT
} while (c != '/');
#ifdef LINT
lint_end_comment();
#endif LINT
NoUnstack--;
}

View file

@ -448,6 +448,7 @@ arith.o: expr.h
arith.o: field.h
arith.o: idf.h
arith.o: label.h
arith.o: lint.h
arith.o: mes.h
arith.o: noRoption.h
arith.o: nobitfield.h
@ -821,6 +822,7 @@ l_states.o: expr.h
l_states.o: file_info.h
l_states.o: idf.h
l_states.o: l_brace.h
l_states.o: l_comment.h
l_states.o: l_lint.h
l_states.o: l_outdef.h
l_states.o: l_state.h
@ -883,6 +885,7 @@ l_outdef.o: field.h
l_outdef.o: file_info.h
l_outdef.o: idf.h
l_outdef.o: l_class.h
l_outdef.o: l_comment.h
l_outdef.o: l_lint.h
l_outdef.o: l_outdef.h
l_outdef.o: label.h

View file

@ -339,6 +339,7 @@ function2pointer(exp)
string2pointer(ex)
register struct expr *ex;
{
#ifndef LINT
/* The expression, which must be a string constant, is converted
to a pointer to the string-containing area.
*/
@ -349,6 +350,7 @@ string2pointer(ex)
ex->VL_CLASS = Label;
ex->VL_LBL = lbl;
ex->VL_VALUE = (arith)0;
#endif LINT
}
opnd2integral(expp, oper)

View file

@ -74,6 +74,7 @@ init_code(dst_file)
static struct string_cst *str_list = 0;
#ifndef LINT
code_string(val, len, dlb)
char *val;
int len;
@ -88,6 +89,7 @@ code_string(val, len, dlb)
sc->sc_len = len;
sc->sc_dlb = dlb;
}
#endif LINT
def_strings(sc)
register struct string_cst *sc;

View file

@ -365,8 +365,9 @@ p1_expr(lvl, expr)
char *bts2str();
print(
"%s\n",
bts2str(expr->SG_VALUE, expr->SG_LEN, next_transient())
"\"%s\"\n",
bts2str(expr->SG_VALUE, expr->SG_LEN-1,
next_transient())
);
break;
}

View file

@ -462,6 +462,10 @@ is_ld_cst(expr)
/* An expression is a `load-time constant' if it is of the form
<idf> +/- <integral> or <integral>.
*/
#ifdef LINT
if (expr->ex_class == String)
return 1;
#endif LINT
return expr->ex_lvalue == 0 && expr->ex_class == Value;
}

View file

@ -146,7 +146,6 @@ gen_idf()
*/
static int name_cnt;
char buff[100];
char *sprint();
sprint(buff, "#%d in %s, line %u",
++name_cnt, dot.tk_file, dot.tk_line);

View file

@ -489,10 +489,12 @@ check_ival(expp, tp)
else /* e.g., int a; int *p = &a; */
C_con_dnam(idf->id_text, expr->VL_VALUE);
}
#ifndef LINT
else {
ASSERT(expr->VL_CLASS == Label);
C_con_dlb(expr->VL_LBL, expr->VL_VALUE);
}
#endif LINT
break;
#ifndef NOFLOAT
case FLOAT:

View file

@ -5,10 +5,13 @@
/* $Header$ */
/* Lint-specific comment handling */
#include <ctype.h>
#include "lint.h"
#ifdef LINT
#include <alloc.h>
#include "arith.h"
#include "l_state.h"
@ -21,124 +24,162 @@
static int notreached;
static int varargsN = -1;
static int argsused;
static check_pseudo();
static int formatN;
static char *format;
static char *prev_format;
int LINTLIB; /* file is lint library */
int s_NOTREACHED; /* statement not reached */
int f_VARARGSn; /* function with variable # of args */
int f_ARGSUSED; /* function does not use all args */
int f_FORMATn; /* argument f_FORMATn is f_FORMAT */
char *f_FORMAT;
set_not_reached()
{
notreached = 1;
}
move_NOT2s()
lint_comment_ahead()
{
s_NOTREACHED = notreached;
notreached = 0;
}
set_varargs(n)
{
varargsN = n;
}
move_VAR2f()
{
f_VARARGSn = varargsN;
varargsN = -1;
}
set_argsused(n)
{
argsused = n;
}
move_ARG2f()
lint_comment_function()
{
f_ARGSUSED = argsused;
argsused = 0;
f_VARARGSn = varargsN;
varargsN = -1;
f_FORMATn = formatN;
formatN = 0;
f_FORMAT = format;
if (format)
prev_format = format;
format = 0;
}
set_lintlib()
static char buf[1000];
static char *bufpos; /* next free position in buf */
lint_start_comment()
{
LINTLIB = 1;
bufpos = &buf[0];
}
#define IN_SPACE 0
#define IN_WORD 1
#define IN_COMMENT 2
lint_comment(c)
lint_comment_char(c)
int c;
{
/* This function is called with every character between /_* and *_/ (the
* _underscores are used because comment in C doesn't nest).
* It looks for pseudocomments.
* In this version it is allowed that 'keyword' is followed by rubbish.
* At the start of each comment the function should be initialized by
* calling it with c = -2.
* I am not sure if this way of information hiding is a good solution.
*/
static int position; /* IN_SPACE, IN_WORD, IN_COMMENT */
static char buf[12];
static int i; /* next free position in buf */
if (c == -2) {
position = IN_SPACE;
i = 0;
return;
}
if (position == IN_COMMENT)
return;
if (position == IN_SPACE) {
if (c == ' ' || c == '\t')
return;
position = IN_WORD;
}
/* position == IN_WORD */
if (c == ' ' || c == '\t' || c == '*') {
position = IN_COMMENT;
check_pseudo(buf, i);
}
else
if (i < 12)
buf[i++] = (char)c;
else
position = IN_COMMENT;
/* This function is called with every character between /_* and *_/ */
if (bufpos - &buf[0] < sizeof(buf)-1)
*bufpos++ = (char)c;
}
#include <ctype.h>
static
check_pseudo(buf, i)
char *buf;
lint_end_comment()
{
/* Look if the i characters in buf are aequivalent with one of the
* strings N_OTREACHED, V_ARARGS[n], A_RGSUSED, L_INTLIBRARY
* (the u_nderscores are there to not confuse (UNIX) lint)
*/
buf[i++] = '\0';
if (strcmp(buf, "NOTREACHED") == 0) {
set_not_reached();
*bufpos++ = '\0';
bufpos = &buf[0];
/* skip initial blanks */
while (*bufpos && isspace(*bufpos)) {
bufpos++;
}
else if (strcmp(buf, "ARGSUSED") == 0) {
set_argsused(1);
/* now test for one of the pseudo-comments */
if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
notreached = 1;
}
else if (strcmp(buf, "LINTLIBRARY") == 0) {
set_lintlib();
else
if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
argsused = 1;
}
else if (strncmp(buf, "VARARGS", 7) == 0) {
if (i == 8) {
set_varargs(0);
else
if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
LINTLIB = 1;
}
else
if (strncmp(bufpos, "VARARGS", 7) == 0) {
varargsN = isdigit(bufpos[7]) ? atoi(&bufpos[7]) : 0;
}
else
if (strncmp(bufpos, "FORMAT", 6) == 0 && isdigit(bufpos[6])) {
int argn = bufpos[6] - '0';
varargsN = argn + 1;
make_format(argn, &bufpos[7]);
}
}
/* We use a small FSA to skip layout inside formats, but to preserve
a space between letters and digits.
*/
#define NONE 0
#define LETGIT 1
#define LETGITSPACE 2
make_format(argn, oldf)
int argn;
char *oldf;
{
register char *newf;
register int last_stat;
while (*oldf && *oldf != '$') {
oldf++;
}
if (!*oldf) {
/* no format given, repeat previous format */
if (!prev_format) {
warning("format missing and no previous format");
}
else if (i == 9 && isdigit(buf[7])) {
set_varargs(atoi(&buf[7]));
formatN = argn;
format = prev_format;
return;
}
if (*oldf++ != '$') {
warning("no format in FORMAT pseudo-comment");
format = 0;
return;
}
/* there is a new format to be composed */
newf = Malloc(strlen(oldf));
/* certainly enough and probably not overly too much */
formatN = argn;
format = newf;
last_stat = NONE;
while (*oldf && *oldf != '$') {
register char ch = *oldf++;
if (isspace(ch)) {
if (last_stat == LETGIT)
last_stat = LETGITSPACE;
}
else
if (isalnum(ch)) {
switch (last_stat) {
case NONE:
last_stat = LETGIT;
break;
case LETGITSPACE:
*newf++ = ' ';
last_stat = LETGIT;
break;
}
*newf++ = ch;
}
else {
last_stat = NONE;
*newf++ = ch;
}
}
if (*oldf != '$') {
warning("no end of format in FORMAT pseudo-comment");
format = 0;
return;
}
*newf++ = '\0';
}
#endif LINT

View file

@ -0,0 +1,13 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
extern int LINTLIB; /* file is lint library */
extern int s_NOTREACHED; /* statement not reached */
extern int f_VARARGSn; /* function with variable # of args */
extern int f_ARGSUSED; /* function does not use all args */
extern int f_FORMATn; /* argument f_FORMATn is f_FORMAT */
extern char *f_FORMAT;

View file

@ -24,12 +24,13 @@
#include "label.h"
#include "expr.h"
#include "l_lint.h"
#include "l_comment.h"
#include "l_outdef.h"
#include "l_class.h"
extern char *bts2str();
extern char *symbol2str();
extern int f_VARARGSn, LINTLIB;
int stat_number = 9999; /* static scope number */
struct outdef OutDef, OutCall;
@ -127,17 +128,16 @@ local_EFDC(idf)
lint_formals()
{
/* Make a list of tp_entries containing the types of the formal
* parameters of the function definition currently parsed.
* parameters of the function definition just parsed.
*/
register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
register struct tp_entry **hook = &OutDef.od_entry;
register struct argument **hook = &OutDef.od_arg;
register int nrargs = 0;
OutDef.od_nrargs = 0;
while (se) {
register struct type *type = se->se_idf->id_def->df_type;
register struct tp_entry *te = new_tp_entry();
register struct argument *arg = new_argument();
switch (type->tp_fund) {
/* Do the conversions on the formals that could not be
done in declare_idf().
It is, unfortunately, impossible not to do them,
@ -146,6 +146,7 @@ lint_formals()
want to duplicate the whole of expression handling
for lint.
*/
switch (type->tp_fund) {
case CHAR:
case SHORT:
type = int_type;
@ -154,19 +155,45 @@ lint_formals()
type = double_type;
break;
}
te->te_type = type;
te->te_class = !Const;
*hook = te;
hook = &te->next;
OutDef.od_nrargs++;
if (f_FORMAT && nrargs == f_FORMATn) {
if ( type->tp_fund != POINTER
|| type->tp_up->tp_fund != CHAR
) {
warning("format parameter %d is not pointer to char",
nrargs);
}
arg->ar_type = string_type;
arg->ar_class = ArgString;
arg->CAS_VALUE = f_FORMAT;
arg->CAS_LEN = strlen(f_FORMAT);
f_FORMAT = 0;
}
else {
arg->ar_type = type;
arg->ar_class = ArgFormal;
}
*hook = arg;
hook = &arg->next;
nrargs++;
se = se->next;
}
if (f_VARARGSn > OutDef.od_nrargs) {
warning("VARARGS%d function has only %d arguments",
f_VARARGSn, OutDef.od_nrargs);
f_VARARGSn = OutDef.od_nrargs;
if (f_VARARGSn > nrargs) {
warning("VARARGS%d function has only %d argument%s",
f_VARARGSn, nrargs, nrargs == 1 ? "" : "s"
);
f_VARARGSn = nrargs;
}
if (f_FORMAT) {
warning("FORMAT%d function has only %d argument%s",
f_FORMATn, nrargs, nrargs == 1 ? "" : "s"
);
f_FORMAT = 0;
}
OutDef.od_nrargs = nrargs;
}
output_use(idf)
@ -212,10 +239,10 @@ output_def(od)
break;
case SFDF:
/* remove tp_entries */
while (od->od_entry) {
register struct tp_entry *tmp = od->od_entry;
od->od_entry = od->od_entry->next;
free_tp_entry(tmp);
while (od->od_arg) {
register struct argument *tmp = od->od_arg;
od->od_arg = od->od_arg->next;
free_argument(tmp);
}
return;
default:
@ -229,19 +256,19 @@ output_def(od)
case LFDF:
if (f_VARARGSn != -1) {
printf(":%d", -1 - f_VARARGSn);
outtypes(od->od_entry, f_VARARGSn);
outargs(od->od_arg, f_VARARGSn);
}
else {
printf(":%d", od->od_nrargs);
outtypes(od->od_entry, od->od_nrargs);
outargs(od->od_arg, od->od_nrargs);
}
od->od_entry = 0;
od->od_arg = 0;
printf(":%d", od->od_valreturned);
break;
case FC:
printf(":%d", od->od_nrargs);
outtypes(od->od_entry, od->od_nrargs);
od->od_entry = 0;
outargs(od->od_arg, od->od_nrargs);
od->od_arg = 0;
printf(":%d", od->od_valused);
break;
case EVDF:
@ -257,26 +284,53 @@ output_def(od)
/*NOTREACHED*/
}
printf(":");
outtype(od->od_type);
outargtype(od->od_type);
printf(":%u:%s\n", od->od_line, od->od_file);
}
outtypes(te, n)
struct tp_entry *te;
outargs(arg, n)
struct argument *arg;
{
/* Output n types in the tp_entry-list and remove all the entries */
/* Output the n arguments in the argument list and remove them */
register struct tp_entry *tmp;
register struct argument *tmp;
while (n--) {
ASSERT(te);
printf(":");
if (te->te_class == Const && te->te_value >= 0) {
ASSERT(arg);
outarg(arg);
tmp = arg;
arg = arg->next;
free_argument(tmp);
}
/* remove the remaining entries */
while (arg) {
tmp = arg;
arg = arg->next;
free_argument(tmp);
}
}
outarg(arg)
struct argument *arg;
{
printf(":");
switch (arg->ar_class) {
case ArgConst:
if (arg->CAA_VALUE >= 0) {
/* constant non-negative actual parameter */
printf("+");
}
outtype(te->te_type);
if (te->te_type->tp_fund == FUNCTION) {
outargtype(arg->ar_type);
break;
case ArgString:
outargstring(arg);
break;
case ArgFormal:
case ArgExpr:
outargtype(arg->ar_type);
if (arg->ar_type->tp_fund == FUNCTION) {
/* UGLY PATCH !!! ??? */
/* function names as operands are sometimes
FUNCTION and sometimes POINTER to FUNCTION,
@ -286,34 +340,44 @@ outtypes(te, n)
*/
printf("*");
}
tmp = te;
te = te->next;
free_tp_entry(tmp);
}
/* remove the remaining entries */
while (te) {
tmp = te;
te = te->next;
free_tp_entry(tmp);
break;
default:
NOTREACHED();
/*NOTREACHED*/
}
}
outtype(tp)
outargstring(arg)
struct argument *arg;
{
char buff[1000];
register char *p;
bts2str(arg->CAS_VALUE, arg->CAS_LEN, buff);
for (p = &buff[0]; *p; p++) {
if (*p == '"' || *p == ':')
*p = ' ';
}
printf("\"%s\"", buff);
}
outargtype(tp)
struct type *tp;
{
switch (tp->tp_fund) {
case POINTER:
outtype(tp->tp_up);
outargtype(tp->tp_up);
printf("*");
break;
case ARRAY:
outtype(tp->tp_up);
outargtype(tp->tp_up);
printf("*"); /* compatible with [] */
break;
case FUNCTION:
outtype(tp->tp_up);
outargtype(tp->tp_up);
printf("()");
break;
@ -365,7 +429,8 @@ fill_outcall(ex, used)
register struct idf *idf = ex->OP_LEFT->VL_IDF;
register struct def *def = idf->id_def;
if (def->df_sc == IMPLICIT) {
if (def->df_sc == IMPLICIT && !idf->id_def->df_used) {
/* IFDC, first time */
implicit_func_decl(idf, ex->ex_file, ex->ex_line);
}
@ -375,7 +440,7 @@ fill_outcall(ex, used)
OutCall.od_name = idf->id_text;
OutCall.od_file = ex->ex_file;
OutCall.od_line = ex->ex_line;
OutCall.od_entry = (struct tp_entry *)0;
OutCall.od_arg = (struct argument *)0;
OutCall.od_nrargs = 0;
if ((ex = ex->OP_RIGHT) != 0) { /* function call with arguments */
@ -392,20 +457,24 @@ fill_outcall(ex, used)
fill_arg(e)
struct expr *e;
{
register struct tp_entry *te;
register struct argument *arg;
te = new_tp_entry();
te->te_type = e->ex_type;
arg = new_argument();
arg->ar_type = e->ex_type;
if (is_cp_cst(e)) {
te->te_class = Const;
te->te_value = e->VL_VALUE;
arg->ar_class = ArgConst;
arg->CAA_VALUE = e->VL_VALUE;
}
else if (e->ex_class == String) {
arg->ar_class = ArgString;
arg->CAS_VALUE = e->SG_VALUE;
arg->CAS_LEN = e->SG_LEN - 1; /* SG_LEN includes the \0 */
}
else {
te->te_class = !Const;
te->te_value = (arith) 0;
arg->ar_class = ArgExpr;
}
te->next = OutCall.od_entry;
OutCall.od_entry = te;
arg->next = OutCall.od_arg;
OutCall.od_arg = arg;
OutCall.od_nrargs++;
}

View file

@ -5,14 +5,30 @@
/* $Header$ */
/* Lint output definition */
struct tp_entry {
struct tp_entry *next;
struct type *te_type;
int te_class; /* for constant parameters */
arith te_value;
/* Values for ar_class */
#define ArgFormal 0
#define ArgExpr 1 /* actual */
#define ArgConst 2 /* integer constant */
#define ArgString 3 /* string */
struct argument {
struct argument *next;
struct type *ar_type;
int ar_class; /* for constant parameters */
union const_arg {
arith ca_value;
struct {
char *cas_value;
int cas_len;
} ca_string;
} ar_object;
};
/* ALLOCDEF "tp_entry" 10 */
#define CAA_VALUE ar_object.ca_value
#define CAS_VALUE ar_object.ca_string.cas_value
#define CAS_LEN ar_object.ca_string.cas_len
/* ALLOCDEF "argument" 10 */
struct outdef {
char od_class;
@ -21,7 +37,7 @@ struct outdef {
char *od_file;
unsigned int od_line;
int od_nrargs;
struct tp_entry *od_entry; /* a list of the types of the
struct argument *od_arg; /* a list of the types of the
* formal parameters */
int od_valreturned;
/* NOVALRETURNED, VALRETURNED, NORETURN; see l_lint.h */

View file

@ -26,6 +26,7 @@
#include "l_lint.h"
#include "l_brace.h"
#include "l_state.h"
#include "l_comment.h"
#include "l_outdef.h"
#define min(a, b) ((a) < (b) ? (a) : (b))
@ -35,7 +36,6 @@ extern char *func_name;
extern struct type *func_type;
extern int func_notypegiven;
extern char loptions[];
extern int s_NOTREACHED;
/* global variables for the lint_stack */
struct lint_stack_entry stack_bottom;
@ -326,13 +326,15 @@ check_autos()
check_args_used()
{
register struct stack_entry *se = local_level->sl_entry;
extern int f_ARGSUSED;
ASSERT(level == L_FORMAL1);
while (se) {
register struct def *def = se->se_idf->id_def;
if (def && !def->df_used && !loptions['v'] && !f_ARGSUSED) {
if ( (def && !def->df_used)
&& !loptions['v']
&& !(f_ARGSUSED || LINTLIB)
) {
def_warning(def, "argument %s not used in function %s",
se->se_idf->id_text, func_name);
}
@ -861,8 +863,7 @@ lint_break_stmt()
lint_start_function()
{
lint_return_stmt(-1); /* initialization */
move_ARG2f();
move_VAR2f();
lint_comment_function();
}
lint_end_function()