ack/lang/cem/lint/lpass2/lpass2.c

542 lines
10 KiB
C
Raw Normal View History

1988-09-02 12:00:25 +00:00
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
1988-08-07 22:55:20 +00:00
#include <alloc.h>
1988-05-30 17:17:16 +00:00
1988-09-02 12:00:25 +00:00
#include "private.h"
1988-07-08 22:24:06 +00:00
#include "../lpass1/l_lint.h"
#include "../lpass1/l_class.h"
1988-08-07 22:55:20 +00:00
#include "class.h"
1988-07-08 22:24:06 +00:00
#include "inpdef.h"
1988-05-30 17:17:16 +00:00
1988-09-02 12:00:25 +00:00
extern char *strcpy();
1988-07-08 22:24:06 +00:00
#define streq(s1,s2) (strcmp(s1, s2) == 0)
#define min(a,b) ((a) <= (b) ? (a) : (b))
1988-09-02 12:00:25 +00:00
PRIVATE char cur_name[NAMESIZE];
PRIVATE struct inpdef *dot, *lib, *ext, *sta;
PRIVATE check_args();
PRIVATE check_def();
PRIVATE ext_decls();
PRIVATE ext_def();
PRIVATE get_dot();
PRIVATE init();
PRIVATE lib_def();
PRIVATE one_ext_decl();
PRIVATE one_func_call();
PRIVATE one_var_usage();
PRIVATE stat_def();
PRIVATE statics();
PRIVATE int type_equal();
PRIVATE int type_match();
PRIVATE usage();
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
#define same_name() (dot && streq(cur_name, dot->id_name))
#define same_obj(stnr) (same_name() && dot->id_statnr == stnr)
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
#define defdec(id) (is_class(id, CL_DEF) ? "defined" : "declared")
1988-09-02 12:00:25 +00:00
#define funvar(id) (is_class(id, CL_FUNC) ? "function" : "variable")
1988-08-07 22:55:20 +00:00
/******** M A I N ********/
1988-05-30 17:17:16 +00:00
main(argc, argv)
char *argv[];
{
init(argc, argv);
1988-07-08 22:24:06 +00:00
1988-08-07 22:55:20 +00:00
dot = new_inpdef();
get_dot();
while (dot) {
if (lib) {
free_inpdef(lib);
lib = 0;
}
if (ext) {
free_inpdef(ext);
ext = 0;
}
strcpy(cur_name, dot->id_name);
lib_def();
ext_def();
ext_decls();
usage(0);
if (ext)
check_def(ext);
statics();
if (same_name()) {
/* there are more lines for this name that have
not been absorbed
*/
panic("sequence error in intermediate file");
1988-05-30 17:17:16 +00:00
}
}
}
1988-09-02 12:00:25 +00:00
char loptions[128];
1988-05-30 17:17:16 +00:00
static char *table[] = {0};
1988-09-02 12:00:25 +00:00
PRIVATE init(argc, argv)
1988-05-30 17:17:16 +00:00
char *argv[];
{
1988-08-07 22:55:20 +00:00
/*
1988-05-30 17:17:16 +00:00
* Parse options
1988-08-07 22:55:20 +00:00
* Prepare standard input for reading using the input-package
1988-05-30 17:17:16 +00:00
*/
char *result;
1988-08-07 22:55:20 +00:00
init_class();
1988-09-02 12:00:25 +00:00
while (argc > 1 && argv[1][0] == '-') {
register char *arg = &argv[1][1];
register char ch;
while (ch = *arg++) {
switch (ch) {
case 'u':
/* don't report situations like
"defined/declared but not used"
*/
case 'X': /* ??? prints incoming inpdefs */
default: /* and any other */
loptions[ch] = 1;
break;
}
1988-05-30 17:17:16 +00:00
}
1988-07-08 22:24:06 +00:00
argc--, argv++;
}
if (!InsertFile((char *)0, table, &result))
panic("InsertFile() fails");
1988-05-30 17:17:16 +00:00
}
1988-09-02 12:00:25 +00:00
PRIVATE get_dot()
1988-05-30 17:17:16 +00:00
{
1988-08-07 22:55:20 +00:00
if (!get_id(dot)) {
free_inpdef(dot);
dot = 0;
cur_name[0] = '\0';
}
}
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
/******** L I B R A R Y ********/
1988-09-02 12:00:25 +00:00
PRIVATE lib_def()
1988-08-07 22:55:20 +00:00
{
if (same_obj(0) && is_class(dot, CL_LIB)) {
lib = dot;
dot = new_inpdef();
get_dot();
}
while (same_obj(0) && is_class(dot, CL_LIB)) {
1988-09-02 12:00:25 +00:00
report(">%L: multiple definition of %s in library",
1988-08-07 22:55:20 +00:00
dot, dot->id_name);
get_dot();
}
}
/******** E X T E R N ********/
1988-09-02 12:00:25 +00:00
PRIVATE ext_def()
1988-08-07 22:55:20 +00:00
{
if (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
if (lib) {
1988-09-02 12:00:25 +00:00
report("%L: %s %s also defined in library %L",
dot, funvar(dot), dot->id_name, lib);
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
ext = dot;
dot = new_inpdef();
get_dot();
}
while (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
1988-09-02 12:00:25 +00:00
report("%L: %s %s also defined at %L",
dot, funvar(dot), dot->id_name, ext);
1988-08-07 22:55:20 +00:00
get_dot();
1988-05-30 17:17:16 +00:00
}
}
1988-09-02 12:00:25 +00:00
PRIVATE ext_decls()
1988-05-30 17:17:16 +00:00
{
1988-08-07 22:55:20 +00:00
while (same_obj(0) && dot->id_class == EFDC) {
one_ext_decl("function", "variable", CL_VAR);
}
while (same_obj(0) && dot->id_class == EVDC) {
one_ext_decl("variable", "function", CL_FUNC);
}
while (same_obj(0) && dot->id_class == IFDC) {
one_ext_decl("function", "variable", CL_VAR);
}
1988-05-30 17:17:16 +00:00
}
1988-09-02 12:00:25 +00:00
PRIVATE one_ext_decl(kind, other_kind, other_class)
1988-08-07 22:55:20 +00:00
char *kind;
char *other_kind;
int other_class;
1988-05-30 17:17:16 +00:00
{
1988-08-07 22:55:20 +00:00
struct inpdef *def = ext ? ext : lib ? lib : 0;
if (!def) {
/* the declaration will have to serve */
ext = dot;
dot = new_inpdef();
get_dot();
return;
}
if (is_class(def, other_class)) {
/* e.g.: function FFF declared as variable at ... */
report("%L: %s %s %s as %s at %L",
dot, kind, dot->id_name, defdec(def), other_kind, def);
/* no further testing possible */
return;
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
if (!type_equal(dot->id_type, def->id_type)) {
/* e.g.: type of variable VVV defined differently at ... */
report("%L: type of %s %s %s differently at %L",
dot, kind, dot->id_name, defdec(def), def);
}
get_dot();
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
/******** U S A G E ********/
1988-09-02 12:00:25 +00:00
PRIVATE usage(stnr)
1988-08-07 22:55:20 +00:00
int stnr;
1988-05-30 17:17:16 +00:00
{
1988-09-02 12:00:25 +00:00
register struct inpdef *def = stnr ? sta : ext ? ext : lib ? lib : 0;
register int VU_count = 0;
register int VU_samefile = 0;
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
while (same_obj(stnr) && dot->id_class == FC) {
one_func_call(def);
}
while (same_obj(stnr) && dot->id_class == VU) {
1988-09-02 12:00:25 +00:00
VU_count++;
if (def && streq(def->id_file, dot->id_file)) {
VU_samefile++;
}
1988-08-07 22:55:20 +00:00
one_var_usage(def);
}
1988-09-02 12:00:25 +00:00
if (def && loptions['h']) {
register char *fn = def->id_file;
if ( stnr == 0
&& VU_count == 1
&& VU_samefile == 1
&& def == ext
&& !is_class(ext, CL_IMPL)
&& streq(&fn[strlen(fn)-2], ".c")
) {
report("%L: extern %s could be declared static",
def, def->id_name);
}
}
1988-08-07 22:55:20 +00:00
}
1988-09-02 12:00:25 +00:00
PRIVATE one_func_call(def)
1988-08-07 22:55:20 +00:00
struct inpdef *def;
{
if (!def) {
1988-09-02 12:00:25 +00:00
if (!loptions['u']) {
1988-08-07 22:55:20 +00:00
report("%L: function %s used but not defined",
dot, dot->id_name);
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
get_dot();
return;
}
def->id_called = 1;
if (def->id_args) {
check_args(dot, def);
1988-09-02 12:00:25 +00:00
if ( dot->id_valused == USED
&& def->id_valreturned == NOVALRETURNED
) {
1988-08-07 22:55:20 +00:00
report("%L: value of %s is used, but none is returned at %L",
dot, dot->id_name, def);
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
}
switch (dot->id_valused) {
case USED:
def->id_used = 1;
1988-05-30 17:17:16 +00:00
break;
1988-08-07 22:55:20 +00:00
case IGNORED:
def->id_ignored = 1;
1988-05-30 17:17:16 +00:00
break;
1988-08-07 22:55:20 +00:00
case VOIDED:
def->id_voided = 1;
1988-05-30 17:17:16 +00:00
break;
1988-08-07 22:55:20 +00:00
default:
panic("invalid dot->id_valused in check");
break;
}
get_dot();
}
1988-09-02 12:00:25 +00:00
PRIVATE one_var_usage(def)
1988-08-07 22:55:20 +00:00
struct inpdef *def;
{
if (!def) {
1988-09-02 12:00:25 +00:00
if (!loptions['u']) {
1988-08-07 22:55:20 +00:00
report("%L: variable %s used but not defined",
dot, dot->id_name);
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
get_dot();
return;
}
def->id_called = 1;
get_dot();
}
/******** S T A T I C ********/
1988-09-02 12:00:25 +00:00
PRIVATE statics()
1988-08-07 22:55:20 +00:00
{
1988-09-02 12:00:25 +00:00
while (same_name()) {
int stnr = dot->id_statnr;
if (stnr == 0)
panic("sequence error in input");
1988-08-07 22:55:20 +00:00
if (sta) {
free_inpdef(sta);
sta = 0;
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
stat_def(stnr);
usage(stnr);
if (sta)
check_def(sta);
1988-09-02 12:00:25 +00:00
if (same_obj(stnr))
panic("sequence error in input");
1988-08-07 22:55:20 +00:00
}
}
1988-09-02 12:00:25 +00:00
PRIVATE stat_def(stnr)
1988-08-07 22:55:20 +00:00
int stnr;
{
if (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
if (lib) {
1988-09-02 12:00:25 +00:00
report("%L: %s %s also defined in library %L",
dot, funvar(dot), dot->id_name, lib);
1988-05-30 17:17:16 +00:00
}
1988-08-07 22:55:20 +00:00
if (ext) {
1988-09-30 15:20:24 +00:00
if (!streq(dot->id_file, ext->id_file)) {
report("%L: %s %s also %s at %L",
dot, funvar(dot), dot->id_name,
defdec(ext), ext);
}
1988-07-08 22:24:06 +00:00
}
1988-08-07 22:55:20 +00:00
sta = dot;
dot = new_inpdef();
get_dot();
}
while (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
1988-09-02 12:00:25 +00:00
report("%L: %s %s also defined at %L",
dot, funvar(dot), dot->id_name, sta);
1988-08-07 22:55:20 +00:00
get_dot();
1988-05-30 17:17:16 +00:00
}
}
1988-09-02 12:00:25 +00:00
PRIVATE check_def(def)
1988-08-07 22:55:20 +00:00
struct inpdef *def;
1988-05-30 17:17:16 +00:00
{
1988-08-07 22:55:20 +00:00
if (!def)
return;
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
if (!def->id_called) {
if (streq(def->id_name, "main")) {
/* silent */
}
else if (ext && is_class(ext, CL_LIB)) {
/* silent */
}
else {
1988-09-02 12:00:25 +00:00
if (!loptions['u']) {
report("%L: %s %s %s but not used",
def, funvar(def), def->id_name,
defdec(def));
1988-08-07 22:55:20 +00:00
}
}
}
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
if (is_class(def, CL_DEF|CL_FUNC)) {
1988-09-02 12:00:25 +00:00
if ( def->id_valreturned == VALRETURNED
&& def->id_called
&& def->id_ignored
) {
1988-08-07 22:55:20 +00:00
report("%L: %s returns value which is %s ignored",
def, def->id_name,
(def->id_used || def->id_voided) ?
"sometimes" : "always");
}
1988-05-30 17:17:16 +00:00
}
}
1988-08-07 22:55:20 +00:00
/******** T Y P E C H E C K I N G ********/
1988-09-02 12:00:25 +00:00
PRIVATE check_args(id, def)
1988-08-07 22:55:20 +00:00
struct inpdef *id, *def;
1988-05-30 17:17:16 +00:00
{
1988-07-08 22:24:06 +00:00
register char *act_tp = id->id_argtps;
1988-08-07 22:55:20 +00:00
register char *def_tp = def->id_argtps;
1988-07-08 22:24:06 +00:00
register int i;
register int nrargs; /* # of args to be type-checked */
register int varargs;
1988-05-30 17:17:16 +00:00
1988-07-08 22:24:06 +00:00
/* determine nrargs */
1988-08-07 22:55:20 +00:00
if (def->id_nrargs < 0) {
1988-05-30 17:17:16 +00:00
varargs = 1;
1988-08-07 22:55:20 +00:00
nrargs = -def->id_nrargs - 1;
1988-05-30 17:17:16 +00:00
}
else {
1988-07-08 22:24:06 +00:00
varargs = 0;
1988-08-07 22:55:20 +00:00
nrargs = def->id_nrargs;
1988-05-30 17:17:16 +00:00
}
1988-07-08 22:24:06 +00:00
/* adjust nrargs, if necessary */
1988-05-30 17:17:16 +00:00
if (varargs) {
1988-07-08 22:24:06 +00:00
if (nrargs > id->id_nrargs) {
report("%L: number of args to %s differs from %L",
1988-08-07 22:55:20 +00:00
id, id->id_name, def);
1988-07-08 22:24:06 +00:00
nrargs = id->id_nrargs;
1988-05-30 17:17:16 +00:00
}
}
else {
1988-07-08 22:24:06 +00:00
if (nrargs != id->id_nrargs) {
report("%L: number of args to %s differs from %L",
1988-08-07 22:55:20 +00:00
id, id->id_name, def);
1988-07-08 22:24:06 +00:00
nrargs = min(nrargs, id->id_nrargs);
1988-05-30 17:17:16 +00:00
}
}
1988-07-08 22:24:06 +00:00
for (i = 1; i <= nrargs; i++) {
1988-09-02 12:00:25 +00:00
register char *act_par = act_tp;
register char *def_par = def_tp;
1988-07-08 22:24:06 +00:00
/* isolate actual argument type */
while (*act_tp) {
if (*act_tp == ':') {
*act_tp = '\0';
break;
}
act_tp++;
1988-05-30 17:17:16 +00:00
}
1988-07-08 22:24:06 +00:00
/* isolate formal argument type */
while (*def_tp) {
if (*def_tp == ':') {
*def_tp = '\0';
break;
}
def_tp++;
1988-05-30 17:17:16 +00:00
}
1988-07-08 22:24:06 +00:00
1988-09-02 12:00:25 +00:00
if (!type_match(act_par, def_par)) {
1988-07-08 22:24:06 +00:00
report("%L: arg %d of %s differs from that at %L",
1988-08-07 22:55:20 +00:00
id, i, id->id_name, def);
1988-07-08 22:24:06 +00:00
}
*act_tp++ = ':';
*def_tp++ = ':';
1988-05-30 17:17:16 +00:00
}
}
1988-08-07 22:55:20 +00:00
int
1988-09-02 12:00:25 +00:00
PRIVATE type_equal(act, def)
1988-08-07 22:55:20 +00:00
char *act, *def;
{
1988-09-02 12:00:25 +00:00
return streq(act, def)
|| streq(act, "erroneous")
|| streq(def, "erroneous");
1988-08-07 22:55:20 +00:00
}
1988-07-08 22:24:06 +00:00
int
1988-09-02 12:00:25 +00:00
PRIVATE type_match(act, def)
1988-07-08 22:24:06 +00:00
char *act, *def;
{
if (type_equal(act, def))
return 1;
1988-08-07 22:55:20 +00:00
1988-07-08 22:24:06 +00:00
if (act[0] == '+') {
/* a non-negative constant */
/* might be signed or unsigned */
if (type_equal(&act[1], def))
return 1;
1988-09-02 12:00:25 +00:00
if ( strncmp(def, "unsigned ", strlen("unsigned ")) == 0
&& type_equal(&act[1], &def[strlen("unsigned ")])
1988-07-08 22:24:06 +00:00
) {
return 1;
}
}
return 0;
}
1988-05-30 17:17:16 +00:00
1988-08-07 22:55:20 +00:00
/******** D E B U G G I N G ********/
1988-05-30 17:17:16 +00:00
1988-09-02 12:00:25 +00:00
print_id(name, id)
char *name;
1988-05-30 17:17:16 +00:00
struct inpdef *id;
{
1988-09-02 12:00:25 +00:00
print("%s: %s, %s, %04d, \"%s\", %d, %s", name,
1988-07-08 22:24:06 +00:00
id->id_class == LFDF ? "LFDF" :
id->id_class == LVDF ? "LVDF" :
1988-08-07 22:55:20 +00:00
id->id_class == EFDF ? "EFDF" :
id->id_class == EVDF ? "EVDF" :
1988-07-08 22:24:06 +00:00
id->id_class == EFDC ? "EFDC" :
id->id_class == EVDC ? "EVDC" :
id->id_class == IFDC ? "IFDC" :
1988-08-07 22:55:20 +00:00
id->id_class == SFDF ? "SFDF" :
id->id_class == SVDF ? "SVDF" :
1988-07-08 22:24:06 +00:00
id->id_class == FC ? "FC" :
1988-09-02 12:00:25 +00:00
id->id_class == VU ? "VU" : "<BADCLASS>",
1988-05-30 17:17:16 +00:00
id->id_name,
1988-07-08 22:24:06 +00:00
id->id_statnr,
1988-05-30 17:17:16 +00:00
id->id_file,
id->id_line,
1988-08-07 22:55:20 +00:00
id->id_type
);
if (is_class(id, CL_FUNC|CL_DEF) || is_class(id, CL_FUNC|CL_USAGE)) {
print(", %d, %s, %s",
id->id_nrargs,
id->id_nrargs == 0 ? "" : id->id_argtps,
id->id_class == FC ?
(id->id_valused == USED ? "USED" :
id->id_valused == IGNORED ? "IGNORED" :
id->id_valused == VOIDED ? "VOIDED" :
"<BAD VALUSED>")
1988-09-02 12:00:25 +00:00
: (id->id_valreturned == NOVALRETURNED ?
"NOVALRETURNED" :
id->id_valreturned == VALRETURNED ?
"VALRETURNED" :
id->id_valreturned == NORETURN ?
"NORETURN" : "<BAD VALRETURNED>"
)
1988-08-07 22:55:20 +00:00
);
}
print("\n");
1988-05-30 17:17:16 +00:00
}
1988-07-08 22:24:06 +00:00