}
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
NoUnstack++;
LoadChar(c);
#ifdef LINT
- lint_comment(-2);
- lint_comment(c);
+ lint_start_comment();
+ lint_comment_char(c);
#endif LINT
do {
while (c != '*') {
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--;
}
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
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
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
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.
*/
ex->VL_CLASS = Label;
ex->VL_LBL = lbl;
ex->VL_VALUE = (arith)0;
+#endif LINT
}
opnd2integral(expp, oper)
static struct string_cst *str_list = 0;
+#ifndef LINT
code_string(val, len, dlb)
char *val;
int len;
sc->sc_len = len;
sc->sc_dlb = dlb;
}
+#endif LINT
def_strings(sc)
register struct string_cst *sc;
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;
}
/* 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;
}
*/
static int name_cnt;
char buff[100];
- char *sprint();
sprint(buff, "#%d in %s, line %u",
++name_cnt, dot.tk_file, dot.tk_line);
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:
/* $Header$ */
/* Lint-specific comment handling */
+#include <ctype.h>
+
#include "lint.h"
#ifdef LINT
+#include <alloc.h>
#include "arith.h"
#include "l_state.h"
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)
+lint_comment_function()
{
- varargsN = n;
-}
+ f_ARGSUSED = argsused;
+ argsused = 0;
-move_VAR2f()
-{
f_VARARGSn = varargsN;
varargsN = -1;
-}
-set_argsused(n)
-{
- argsused = n;
+ f_FORMATn = formatN;
+ formatN = 0;
+ f_FORMAT = format;
+ if (format)
+ prev_format = format;
+ format = 0;
}
-move_ARG2f()
+static char buf[1000];
+static char *bufpos; /* next free position in buf */
+
+lint_start_comment()
{
- f_ARGSUSED = argsused;
- argsused = 0;
+ bufpos = &buf[0];
}
-set_lintlib()
+lint_comment_char(c)
+ int c;
{
- LINTLIB = 1;
+/* This function is called with every character between /_* and *_/ */
+ if (bufpos - &buf[0] < sizeof(buf)-1)
+ *bufpos++ = (char)c;
}
-#define IN_SPACE 0
-#define IN_WORD 1
-#define IN_COMMENT 2
-
-lint_comment(c)
- int c;
+lint_end_comment()
{
-/* 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 */
+ *bufpos++ = '\0';
+ bufpos = &buf[0];
- if (c == -2) {
- position = IN_SPACE;
- i = 0;
- return;
+ /* skip initial blanks */
+ while (*bufpos && isspace(*bufpos)) {
+ bufpos++;
}
- if (position == IN_COMMENT)
- return;
-
- if (position == IN_SPACE) {
- if (c == ' ' || c == '\t')
- return;
- position = IN_WORD;
+ /* now test for one of the pseudo-comments */
+ if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
+ notreached = 1;
}
- /* position == IN_WORD */
- if (c == ' ' || c == '\t' || c == '*') {
- position = IN_COMMENT;
- check_pseudo(buf, i);
+ else
+ if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
+ argsused = 1;
}
else
- if (i < 12)
- buf[i++] = (char)c;
+ if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
+ LINTLIB = 1;
+ }
else
- position = IN_COMMENT;
+ 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]);
+
+ }
}
-#include <ctype.h>
+/* We use a small FSA to skip layout inside formats, but to preserve
+ a space between letters and digits.
+*/
-static
-check_pseudo(buf, i)
- char *buf;
+#define NONE 0
+#define LETGIT 1
+#define LETGITSPACE 2
+
+make_format(argn, oldf)
+ int argn;
+ char *oldf;
{
-/* 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();
+ register char *newf;
+ register int last_stat;
+
+ while (*oldf && *oldf != '$') {
+ oldf++;
}
- else if (strcmp(buf, "ARGSUSED") == 0) {
- set_argsused(1);
+ if (!*oldf) {
+ /* no format given, repeat previous format */
+ if (!prev_format) {
+ warning("format missing and no previous format");
+ }
+ formatN = argn;
+ format = prev_format;
+ return;
}
- else if (strcmp(buf, "LINTLIBRARY") == 0) {
- set_lintlib();
+ if (*oldf++ != '$') {
+ warning("no format in FORMAT pseudo-comment");
+ format = 0;
+ return;
}
- else if (strncmp(buf, "VARARGS", 7) == 0) {
- if (i == 8) {
- set_varargs(0);
+
+ /* 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 if (i == 9 && isdigit(buf[7])) {
- set_varargs(atoi(&buf[7]));
+ else {
+ last_stat = NONE;
+ *newf++ = ch;
}
}
+ if (*oldf != '$') {
+ warning("no end of format in FORMAT pseudo-comment");
+ format = 0;
+ return;
+ }
+ *newf++ = '\0';
}
#endif LINT
--- /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$ */
+
+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;
+
#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;
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,
want to duplicate the whole of expression handling
for lint.
*/
+ switch (type->tp_fund) {
case CHAR:
case SHORT:
type = int_type;
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)
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:
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:
/*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,
*/
printf("*");
}
- tmp = te;
- te = te->next;
- free_tp_entry(tmp);
+ break;
+
+ default:
+ NOTREACHED();
+ /*NOTREACHED*/
}
- /* remove the remaining entries */
- while (te) {
- tmp = te;
- te = te->next;
- free_tp_entry(tmp);
+}
+
+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);
}
-outtype(tp)
+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;
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);
}
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 */
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++;
}
/* $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;
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 */
#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))
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;
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);
}
lint_start_function()
{
lint_return_stmt(-1); /* initialization */
- move_ARG2f();
- move_VAR2f();
+ lint_comment_function();
}
lint_end_function()