many improvements
This commit is contained in:
parent
5581bdad15
commit
56fff3d6cd
8 changed files with 535 additions and 429 deletions
|
@ -1,3 +1,21 @@
|
|||
7-Aug-88 Dick Grune (dick) at dick
|
||||
About the class of an inpdef, often set-like questions are asked.
|
||||
To speed up answering these questions, a mapping has been created
|
||||
of the values of `class' onto answers to these questions. See
|
||||
class.[ch].
|
||||
|
||||
5-Aug-88 Dick Grune (dick) at dick
|
||||
Streamlined the program by rearranging the input sequence:
|
||||
- library
|
||||
- external defs
|
||||
- external decls
|
||||
- external usage
|
||||
- static defs
|
||||
- static usage
|
||||
This change to a much more natural order has been possible by the
|
||||
introduction of the static file number. Many pieces of code could
|
||||
now be taken together and the program is much cleaner now.
|
||||
|
||||
8-Jul-88 Dick Grune (dick) at dick
|
||||
Added a special meta-type (also in lpaas1) for non-negative
|
||||
constant actual arguments, because these may match both the signed
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
# M A K E F I L E F O R L P A S S 2
|
||||
|
||||
# Machine and environ dependent definitions
|
||||
EMHOME = /usr/em
|
||||
LPASS1 = ../lpass1
|
||||
EMHOME = /usr/em
|
||||
LPASS1 = ../lpass1
|
||||
|
||||
# Libraries and EM interface definitions
|
||||
SYSLIB = $(EMHOME)/modules/lib/libsystem.a
|
||||
STRLIB = $(EMHOME)/modules/lib/libstring.a
|
||||
PRTLIB = $(EMHOME)/modules/lib/libprint.a
|
||||
INPLIB = $(EMHOME)/modules/lib/libinput.a
|
||||
ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
|
||||
MALLOC = $(EMHOME)/modules/lib/malloc.o
|
||||
LLIBS = $(INPLIB) $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
|
||||
SYSLIB = $(EMHOME)/modules/lib/libsystem.a
|
||||
STRLIB = $(EMHOME)/modules/lib/libstring.a
|
||||
PRTLIB = $(EMHOME)/modules/lib/libprint.a
|
||||
INPLIB = $(EMHOME)/modules/lib/libinput.a
|
||||
ALLOCLIB = $(EMHOME)/modules/lib/liballoc.a
|
||||
MALLOC = $(EMHOME)/modules/lib/malloc.o
|
||||
LLIBS = $(INPLIB) $(PRTLIB) $(STRLIB) $(ALLOCLIB) $(MALLOC) $(SYSLIB)
|
||||
|
||||
CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
|
||||
CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
|
||||
|
||||
.SUFFIXES: .str .h
|
||||
.str.h:
|
||||
$(LPASS1)/make.allocd <$*.str >$*.h
|
||||
|
||||
SRC = lpass2.c read.c
|
||||
OBJ = lpass2.o read.o
|
||||
SRC = lpass2.c read.c report.c class.c
|
||||
OBJ = lpass2.o read.o report.o class.o
|
||||
|
||||
test: lpass2
|
||||
make lint
|
||||
|
@ -32,7 +32,7 @@ lpass2: $(OBJ) Makefile next.o
|
|||
lint:
|
||||
../lint $(CFLAGS) $(SRC) next.c #???
|
||||
|
||||
next.c: inpdef.str
|
||||
next.c: $(LPASS1)/make.next inpdef.str
|
||||
$(LPASS1)/make.next inpdef.str > next.c
|
||||
|
||||
tags: $(SRC)
|
||||
|
@ -42,4 +42,7 @@ clean:
|
|||
rm -f a.out core next.c inpdef.h $(OBJ) next.o
|
||||
|
||||
#----------------------------------------------------------------
|
||||
lpass2.o: ../lpass1/errout.h ../lpass1/lint.h ../lpass1/l_class.h inpdef.h
|
||||
class.o: class.h
|
||||
lpass2.o: ../lpass1/l_class.h ../lpass1/l_lint.h class.h inpdef.h
|
||||
read.o: ../lpass1/l_class.h class.h inpdef.h
|
||||
report.o: inpdef.h
|
||||
|
|
47
lang/cem/lint/lpass2/class.c
Normal file
47
lang/cem/lint/lpass2/class.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "../lpass1/l_class.h"
|
||||
#include "class.h"
|
||||
|
||||
int class[] = {
|
||||
/* mapping of class values onto bit patterns */
|
||||
/* LFDF */ CL_LIB|CL_FUNC|CL_DEF,
|
||||
/* LVDF */ CL_LIB|CL_VAR|CL_DEF,
|
||||
/* EFDF */ CL_EXT|CL_FUNC|CL_DEF,
|
||||
/* EVDF */ CL_EXT|CL_VAR|CL_DEF,
|
||||
/* EFDC */ CL_EXT|CL_FUNC|CL_DECL,
|
||||
/* EVDC */ CL_EXT|CL_VAR|CL_DECL,
|
||||
/* IFDC */ CL_IMPL|CL_FUNC|CL_DECL,
|
||||
/* SFDF */ CL_STAT|CL_FUNC|CL_DEF,
|
||||
/* SVDF */ CL_STAT|CL_VAR|CL_DEF,
|
||||
/* FC */ CL_FUNC|CL_USAGE,
|
||||
/* VU */ CL_VAR|CL_USAGE
|
||||
};
|
||||
|
||||
static int val[] = {
|
||||
LFDF,
|
||||
LVDF,
|
||||
EFDF,
|
||||
EVDF,
|
||||
EFDC,
|
||||
EVDC,
|
||||
IFDC,
|
||||
SFDF,
|
||||
SVDF,
|
||||
FC,
|
||||
VU
|
||||
};
|
||||
|
||||
init_class()
|
||||
{
|
||||
/* The initialization of class[] has been taken care of above.
|
||||
For it to work, we have to test that the class values are
|
||||
in the right order. This is also necessary for the scanning
|
||||
sequence in lpass2.c to work properly.
|
||||
*/
|
||||
int i;
|
||||
|
||||
for (i = 0; i+1 < sizeof(val)/sizeof(val[0]); i++) {
|
||||
if (val[i] >= val[i+1])
|
||||
panic("class values out of sequence");
|
||||
}
|
||||
}
|
||||
|
16
lang/cem/lint/lpass2/class.h
Normal file
16
lang/cem/lint/lpass2/class.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#define CL_DEF (1<<0)
|
||||
#define CL_DECL (1<<1)
|
||||
#define CL_USAGE (1<<2)
|
||||
|
||||
#define CL_FUNC (1<<3)
|
||||
#define CL_VAR (1<<4)
|
||||
|
||||
#define CL_LIB (1<<5)
|
||||
#define CL_EXT (1<<6)
|
||||
#define CL_IMPL (1<<7)
|
||||
#define CL_STAT (1<<8)
|
||||
|
||||
extern int class[];
|
||||
|
||||
#define is_class(id,cl) ((class[(id)->id_class-'a'] & (cl)) == (cl))
|
||||
|
|
@ -5,14 +5,22 @@
|
|||
|
||||
struct inpdef {
|
||||
struct inpdef *next;
|
||||
int id_class;
|
||||
|
||||
/* filled by get_id() */
|
||||
int id_class; /* see ../lpass1/l_class.h */
|
||||
char id_name[NAMESIZE];
|
||||
int id_statnr;
|
||||
char id_file[FNAMESIZE];
|
||||
int id_line;
|
||||
int id_nrargs;
|
||||
char id_argtps[ARGTPSSIZE];
|
||||
int id_returns;
|
||||
char id_type[TYPESIZE];
|
||||
|
||||
int id_args; /* set if arguments given */
|
||||
int id_nrargs; /* number of args, neg. for varargs */
|
||||
char id_argtps[ARGTPSSIZE]; /* argument types, colon separated */
|
||||
int id_valreturned; /* for def/decl, set if val returned */
|
||||
int id_valused; /* for FC, see ../lpass1/l_lint.h */
|
||||
|
||||
/* not filled by get_id() */
|
||||
int id_called;
|
||||
int id_used;
|
||||
int id_ignored;
|
||||
|
|
|
@ -1,46 +1,55 @@
|
|||
#include <varargs.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "../lpass1/l_lint.h"
|
||||
#include "../lpass1/l_class.h"
|
||||
#include "class.h"
|
||||
#include "inpdef.h"
|
||||
|
||||
#include <alloc.h>
|
||||
#include <system.h>
|
||||
|
||||
#define MSGOUT STDERR /* filedes on which to write the messages */
|
||||
#define ERROUT STDERR /* filedes on which to write the panics */
|
||||
|
||||
#define streq(s1,s2) (strcmp(s1, s2) == 0)
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
|
||||
#define type_equal(s1,s2) (streq(s1, s2))
|
||||
char cur_name[NAMESIZE];
|
||||
struct inpdef *dot, *lib, *ext, *sta;
|
||||
|
||||
char *cur_name;
|
||||
struct inpdef *dot_id,
|
||||
*ext_def,
|
||||
*static_def;
|
||||
struct inpdef *id_read();
|
||||
#define same_name() (dot && streq(cur_name, dot->id_name))
|
||||
#define same_obj(stnr) (same_name() && dot->id_statnr == stnr)
|
||||
|
||||
#define same_name() streq(cur_name, dot_id->id_name)
|
||||
#define defdec(id) (is_class(id, CL_DEF) ? "defined" : "declared")
|
||||
|
||||
|
||||
/******** M A I N ********/
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
struct inpdef *id;
|
||||
|
||||
init(argc, argv);
|
||||
|
||||
get_dot_id();
|
||||
while (dot_id) {
|
||||
cur_name = dot_id->id_name;
|
||||
read_defs();
|
||||
while (dot_id && same_name()) {
|
||||
id = id_read();
|
||||
check(id);
|
||||
free_inpdef(id);
|
||||
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();
|
||||
/* inpdefs of class ERRCL are never generated */
|
||||
if (same_name()) {
|
||||
/* there are more lines for this name that have
|
||||
not been absorbed
|
||||
*/
|
||||
panic("sequence error in intermediate file");
|
||||
}
|
||||
check_usage();
|
||||
free_defs();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,13 +59,14 @@ static char *table[] = {0};
|
|||
init(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
/* Prepare standard input for reading using the input-package
|
||||
* Read first inpdef into dot_id
|
||||
/*
|
||||
* Parse options
|
||||
* Prepare standard input for reading using the input-package
|
||||
*/
|
||||
|
||||
char *result;
|
||||
|
||||
init_class();
|
||||
|
||||
while (argc > 1 && *argv[1] == '-') {
|
||||
switch (argv[1][1]) {
|
||||
case 'u':
|
||||
|
@ -67,7 +77,7 @@ init(argc, argv)
|
|||
options[argv[1][1]] = 1;
|
||||
break;
|
||||
default:
|
||||
/* ready to extend */
|
||||
/* ready to be extended */
|
||||
break;
|
||||
}
|
||||
argc--, argv++;
|
||||
|
@ -77,248 +87,295 @@ init(argc, argv)
|
|||
panic("InsertFile() fails");
|
||||
}
|
||||
|
||||
read_defs()
|
||||
get_dot()
|
||||
{
|
||||
struct inpdef *id;
|
||||
|
||||
if (ext_def || static_def)
|
||||
panic("read_defs: slate not clean");/*???*/
|
||||
|
||||
while (dot_id && same_name() && is_def(dot_id)) {
|
||||
id = id_read();
|
||||
switch (id->id_class) {
|
||||
case EFDF:
|
||||
case EVDF:
|
||||
if (ext_def) {
|
||||
report("%L: %s also defined at %L",
|
||||
id, id->id_name, ext_def);
|
||||
free_inpdef(id);
|
||||
}
|
||||
else {
|
||||
ext_def = id;
|
||||
}
|
||||
break;
|
||||
case SFDF:
|
||||
case SVDF:
|
||||
if (ext_def) {
|
||||
report("%L: %s also defined at %L",
|
||||
id, id->id_name, ext_def);
|
||||
free_inpdef(id);
|
||||
}
|
||||
else {
|
||||
static_in_list(id);
|
||||
}
|
||||
break;
|
||||
case LFDF:
|
||||
case LVDF:
|
||||
if (ext_def) {
|
||||
/* Some libraries contain more than one
|
||||
* definition
|
||||
*/
|
||||
if (is_lib_class(ext_def->id_class)) {
|
||||
report("%L: %s redefined in library %L",
|
||||
id, id->id_name, ext_def);
|
||||
}
|
||||
free_inpdef(id);
|
||||
}
|
||||
else {
|
||||
ext_def = id;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
panic("invalid class (%c) in read_defs", id->id_class);
|
||||
}
|
||||
if (!get_id(dot)) {
|
||||
free_inpdef(dot);
|
||||
dot = 0;
|
||||
cur_name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
struct inpdef *
|
||||
id_read()
|
||||
{
|
||||
/* Returns the value of dot_id if present, 0 otherwise.
|
||||
* Reads a new inpdef ahead, to which dot_id will be pointing.
|
||||
* Cur_name will be pointing to id_name of the returned inpdef.
|
||||
*/
|
||||
struct inpdef *old_id;
|
||||
|
||||
if (!dot_id)
|
||||
return (0);
|
||||
old_id = dot_id;
|
||||
cur_name = old_id->id_name;
|
||||
get_dot_id();
|
||||
return (old_id);
|
||||
}
|
||||
/******** L I B R A R Y ********/
|
||||
|
||||
get_dot_id()
|
||||
lib_def()
|
||||
{
|
||||
/* Allocates a new inpdef, calls it dot_id and fills it */
|
||||
dot_id = new_inpdef();
|
||||
if (!get_id(dot_id)) {
|
||||
free_inpdef(dot_id);
|
||||
cur_name = "";
|
||||
dot_id = 0;
|
||||
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)) {
|
||||
report("%L: multiple definition of %s in library",
|
||||
dot, dot->id_name);
|
||||
get_dot();
|
||||
}
|
||||
}
|
||||
|
||||
struct inpdef *definition();
|
||||
|
||||
check(id)
|
||||
struct inpdef *id;
|
||||
/******** E X T E R N ********/
|
||||
|
||||
ext_def()
|
||||
{
|
||||
/* Checks a declaration, function call or variable usage, described by id,
|
||||
* against the definitions.
|
||||
*/
|
||||
struct inpdef *idef;
|
||||
if (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
|
||||
if (lib) {
|
||||
report("%L: %s also defined in library %L",
|
||||
dot, dot->id_name, lib);
|
||||
}
|
||||
ext = dot;
|
||||
dot = new_inpdef();
|
||||
get_dot();
|
||||
}
|
||||
|
||||
idef = definition(id);
|
||||
switch (id->id_class) {
|
||||
case EFDC:
|
||||
if (!idef) {
|
||||
if (!options['u']) {
|
||||
report("%L: %s declared but never defined",
|
||||
id, id->id_name);
|
||||
}
|
||||
discard_defs();
|
||||
break;
|
||||
while (same_obj(0) && is_class(dot, CL_EXT|CL_DEF)) {
|
||||
report("%L: %s also defined at %L",
|
||||
dot, dot->id_name, ext);
|
||||
get_dot();
|
||||
}
|
||||
}
|
||||
|
||||
ext_decls()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
one_ext_decl(kind, other_kind, other_class)
|
||||
char *kind;
|
||||
char *other_kind;
|
||||
int other_class;
|
||||
{
|
||||
struct inpdef *def = ext ? ext : lib ? lib : 0;
|
||||
|
||||
if (!def) {
|
||||
/* the declaration will have to serve */
|
||||
if (!is_class(dot, CL_IMPL) && !options['u']) {
|
||||
report("%L: %s %s declared but never defined",
|
||||
dot, dot->id_name, kind);
|
||||
}
|
||||
if (idef->id_class == EVDF || idef->id_class == LVDF) {
|
||||
report("%L: function %s declared as variable at %L",
|
||||
id, id->id_name, idef);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/******** U S A G E ********/
|
||||
|
||||
usage(stnr)
|
||||
int stnr;
|
||||
{
|
||||
struct inpdef *def = stnr ? sta : ext ? ext : lib ? lib : 0;
|
||||
|
||||
while (same_obj(stnr) && dot->id_class == FC) {
|
||||
one_func_call(def);
|
||||
}
|
||||
|
||||
while (same_obj(stnr) && dot->id_class == VU) {
|
||||
one_var_usage(def);
|
||||
}
|
||||
}
|
||||
|
||||
one_func_call(def)
|
||||
struct inpdef *def;
|
||||
{
|
||||
if (!def) {
|
||||
if (!options['u']) {
|
||||
report("%L: function %s used but not defined",
|
||||
dot, dot->id_name);
|
||||
}
|
||||
if (!type_equal(id->id_type, idef->id_type)) {
|
||||
report("%L: value of function %s declared differently at %L",
|
||||
id, id->id_name, idef);
|
||||
}
|
||||
break;
|
||||
case EVDC:
|
||||
if (!idef) {
|
||||
if (!options['u']) {
|
||||
report("%L: %s declared but never defined",
|
||||
id, id->id_name);
|
||||
}
|
||||
discard_defs();
|
||||
break;
|
||||
}
|
||||
if (idef->id_class == EFDF || idef->id_class == LFDF) {
|
||||
report("%L: variable %s declared as function at %L",
|
||||
id, id->id_name, idef);
|
||||
break;
|
||||
}
|
||||
if (!type_equal(id->id_type, idef->id_type)) {
|
||||
report("%L: variable %s declared differently at %L",
|
||||
id, id->id_name, idef);
|
||||
}
|
||||
break;
|
||||
case IFDC:
|
||||
if (!idef)
|
||||
break; /* used but not defined */
|
||||
if (idef->id_class == EVDF || idef->id_class == LVDF) {
|
||||
report("%L: function %s declared as variable at %L",
|
||||
id, id->id_name, idef);
|
||||
break;
|
||||
}
|
||||
if (!type_equal(id->id_type, idef->id_type)) {
|
||||
report("%L: function value of %s declared differently at %L",
|
||||
id, id->id_name, idef);
|
||||
}
|
||||
break;
|
||||
case FC:
|
||||
if (!idef) {
|
||||
if (!options['u']) {
|
||||
report("%L: function %s used but not defined",
|
||||
id, id->id_name);
|
||||
}
|
||||
discard_defs();
|
||||
break;
|
||||
}
|
||||
idef->id_called = 1;
|
||||
check_args(id, idef);
|
||||
if (id->id_returns == USED && !idef->id_returns) {
|
||||
get_dot();
|
||||
return;
|
||||
}
|
||||
|
||||
def->id_called = 1;
|
||||
|
||||
if (def->id_args) {
|
||||
check_args(dot, def);
|
||||
if (dot->id_valused == USED && !def->id_valreturned) {
|
||||
report("%L: value of %s is used, but none is returned at %L",
|
||||
id, id->id_name, idef);
|
||||
}
|
||||
switch (id->id_returns) {
|
||||
case USED:
|
||||
idef->id_used = 1;
|
||||
break;
|
||||
case IGNORED:
|
||||
idef->id_ignored = 1;
|
||||
break;
|
||||
case VOIDED:
|
||||
idef->id_voided = 1;
|
||||
break;
|
||||
default:
|
||||
panic("invalid id->id_returns in check");
|
||||
dot, dot->id_name, def);
|
||||
}
|
||||
}
|
||||
|
||||
switch (dot->id_valused) {
|
||||
case USED:
|
||||
def->id_used = 1;
|
||||
break;
|
||||
case VU:
|
||||
if (!idef) {
|
||||
if (!options['u']) {
|
||||
report("%L: variable %s used but not defined",
|
||||
id, id->id_name);
|
||||
}
|
||||
discard_defs();
|
||||
break;
|
||||
}
|
||||
idef->id_called = 1;
|
||||
case IGNORED:
|
||||
def->id_ignored = 1;
|
||||
break;
|
||||
case EFDF:
|
||||
case SFDF:
|
||||
case EVDF:
|
||||
case SVDF:
|
||||
case LFDF:
|
||||
case LVDF:
|
||||
panic("check() called for a definition");
|
||||
case VOIDED:
|
||||
def->id_voided = 1;
|
||||
break;
|
||||
default:
|
||||
panic("invalid class (%c) in check", id->id_class);
|
||||
panic("invalid dot->id_valused in check");
|
||||
break;
|
||||
}
|
||||
|
||||
get_dot();
|
||||
}
|
||||
|
||||
discard_defs()
|
||||
one_var_usage(def)
|
||||
struct inpdef *def;
|
||||
{
|
||||
/* Read until a definition having another name */
|
||||
if (!def) {
|
||||
if (!options['u']) {
|
||||
report("%L: variable %s used but not defined",
|
||||
dot, dot->id_name);
|
||||
}
|
||||
get_dot();
|
||||
return;
|
||||
}
|
||||
|
||||
struct inpdef *id;
|
||||
def->id_called = 1;
|
||||
|
||||
while (dot_id && same_name()) {
|
||||
id = id_read();
|
||||
free_inpdef(id);
|
||||
get_dot();
|
||||
}
|
||||
|
||||
|
||||
/******** S T A T I C ********/
|
||||
|
||||
statics()
|
||||
{
|
||||
while (same_name() && dot->id_statnr != 0) {
|
||||
one_static(dot->id_statnr);
|
||||
}
|
||||
}
|
||||
|
||||
check_args(id, idef)
|
||||
struct inpdef *id, *idef;
|
||||
one_static(stnr)
|
||||
int stnr;
|
||||
{
|
||||
while (same_obj(stnr)) {
|
||||
if (sta) {
|
||||
free_inpdef(sta);
|
||||
sta = 0;
|
||||
}
|
||||
stat_def(stnr);
|
||||
usage(stnr);
|
||||
if (sta)
|
||||
check_def(sta);
|
||||
get_dot();
|
||||
}
|
||||
}
|
||||
|
||||
stat_def(stnr)
|
||||
int stnr;
|
||||
{
|
||||
if (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
|
||||
if (lib) {
|
||||
report("%L: %s also defined in library %L",
|
||||
dot, dot->id_name, lib);
|
||||
}
|
||||
if (ext) {
|
||||
report("%L: %s also %s at %L",
|
||||
dot, dot->id_name, defdec(ext), ext);
|
||||
}
|
||||
sta = dot;
|
||||
dot = new_inpdef();
|
||||
get_dot();
|
||||
}
|
||||
|
||||
while (same_obj(stnr) && is_class(dot, CL_STAT|CL_DEF)) {
|
||||
report("%L: %s also defined at %L",
|
||||
dot, dot->id_name, sta);
|
||||
get_dot();
|
||||
}
|
||||
}
|
||||
|
||||
check_def(def)
|
||||
struct inpdef *def;
|
||||
{
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
if (!def->id_called) {
|
||||
if (streq(def->id_name, "main")) {
|
||||
/* silent */
|
||||
}
|
||||
else if (ext && is_class(ext, CL_LIB)) {
|
||||
/* silent */
|
||||
}
|
||||
else {
|
||||
if (!options['u']) {
|
||||
report("%L: %s %s but never used",
|
||||
def, def->id_name, defdec(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_class(def, CL_DEF|CL_FUNC)) {
|
||||
if (def->id_valreturned && def->id_called && def->id_ignored) {
|
||||
report("%L: %s returns value which is %s ignored",
|
||||
def, def->id_name,
|
||||
(def->id_used || def->id_voided) ?
|
||||
"sometimes" : "always");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******** T Y P E C H E C K I N G ********/
|
||||
|
||||
check_args(id, def)
|
||||
struct inpdef *id, *def;
|
||||
{
|
||||
register char *act_tp = id->id_argtps;
|
||||
register char *def_tp = idef->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 (idef->id_nrargs < 0) {
|
||||
if (def->id_nrargs < 0) {
|
||||
varargs = 1;
|
||||
nrargs = -idef->id_nrargs - 1;
|
||||
nrargs = -def->id_nrargs - 1;
|
||||
}
|
||||
else {
|
||||
varargs = 0;
|
||||
nrargs = idef->id_nrargs;
|
||||
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, idef);
|
||||
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, idef);
|
||||
id, id->id_name, def);
|
||||
nrargs = min(nrargs, id->id_nrargs);
|
||||
}
|
||||
}
|
||||
|
@ -346,19 +403,27 @@ check_args(id, idef)
|
|||
|
||||
if (!type_match(act, def)) {
|
||||
report("%L: arg %d of %s differs from that at %L",
|
||||
id, i, id->id_name, idef);
|
||||
id, i, id->id_name, def);
|
||||
}
|
||||
*act_tp++ = ':';
|
||||
*def_tp++ = ':';
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
type_equal(act, def)
|
||||
char *act, *def;
|
||||
{
|
||||
return streq(act, def);
|
||||
}
|
||||
|
||||
int
|
||||
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 */
|
||||
|
@ -373,181 +438,22 @@ type_match(act, def)
|
|||
return 0;
|
||||
}
|
||||
|
||||
check_usage()
|
||||
{
|
||||
/* Checks if the defined function or variable is used.
|
||||
* There can be several static definitions.
|
||||
*/
|
||||
|
||||
struct inpdef *sd = static_def;
|
||||
/******** D E B U G G I N G ********/
|
||||
|
||||
if (ext_def)
|
||||
check_def(ext_def);
|
||||
while (sd) {
|
||||
check_def(sd);
|
||||
sd = sd->next;
|
||||
}
|
||||
}
|
||||
|
||||
check_def(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
if (!id->id_called) {
|
||||
if (streq(id->id_name, "main")) {
|
||||
/* silent */
|
||||
}
|
||||
else if (ext_def && is_lib_class(ext_def->id_class)) {
|
||||
/* silent */
|
||||
}
|
||||
else {
|
||||
if (!options['u']) {
|
||||
report("%L: %s defined but never used",
|
||||
id, id->id_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_fundef_class(id->id_class)) {
|
||||
if (id->id_returns && id->id_called && id->id_ignored) {
|
||||
report("%L: %s returns value which is %s ignored",
|
||||
id, id->id_name,
|
||||
(id->id_used || id->id_voided) ?
|
||||
"sometimes" : "always");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static_in_list(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
/* Put id in the list of static definitions.
|
||||
* static_def points to the first element.
|
||||
*/
|
||||
id->next = static_def;
|
||||
static_def = id;
|
||||
}
|
||||
|
||||
struct inpdef *
|
||||
definition(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
/* If there is a static definition that comes from the same file, a pointer
|
||||
* to this definition will be returned.
|
||||
* Otherwise a pointer to the ext_def is returned (which may be null).
|
||||
*/
|
||||
struct inpdef *sd = static_def;
|
||||
|
||||
while (sd) {
|
||||
if (id->id_statnr == sd->id_statnr)
|
||||
return (sd);
|
||||
sd = sd->next;
|
||||
}
|
||||
return (ext_def);
|
||||
}
|
||||
|
||||
free_defs()
|
||||
{
|
||||
/* Dispose the external definition and the static definitions. */
|
||||
struct inpdef *sd;
|
||||
|
||||
if (ext_def) {
|
||||
free_inpdef(ext_def);
|
||||
ext_def = 0;
|
||||
}
|
||||
while (static_def) {
|
||||
sd = static_def;
|
||||
static_def = static_def->next;
|
||||
free_inpdef(sd);
|
||||
}
|
||||
}
|
||||
|
||||
/* VARARGS */
|
||||
report(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap);
|
||||
{
|
||||
char *fmt = va_arg(ap, char*);
|
||||
register char *f = fmt;
|
||||
register char fc;
|
||||
|
||||
/* First see if the first arg is an inpdef with
|
||||
a global file name; if so, skip this message.
|
||||
*/
|
||||
if (f[0] == '%' && f[1] == 'L') {
|
||||
/* it is an inpdef */
|
||||
register struct inpdef *id =
|
||||
va_arg(ap, struct inpdef *);
|
||||
|
||||
f += 2;
|
||||
/* is the file name global? */
|
||||
if (id->id_file[0] == '/')
|
||||
return;
|
||||
/* if no, we have used up the argument,
|
||||
so print it here
|
||||
*/
|
||||
fprint(MSGOUT, "\"%s\", line %d",
|
||||
id->id_file, id->id_line);
|
||||
}
|
||||
while ((fc = *f++)) {
|
||||
if (fc == '%') {
|
||||
switch (*f++) {
|
||||
register struct inpdef *id;
|
||||
register char *s;
|
||||
register int i;
|
||||
case 'L': /* a location item */
|
||||
id = va_arg(ap, struct inpdef *);
|
||||
fprint(MSGOUT, "\"%s\", line %d",
|
||||
id->id_file, id->id_line);
|
||||
break;
|
||||
case 's': /* a string item */
|
||||
s = va_arg(ap, char *);
|
||||
fprint(MSGOUT, "%s", s);
|
||||
break;
|
||||
case 'd': /* an int item */
|
||||
i = va_arg(ap, int);
|
||||
fprint(MSGOUT, "%d", i);
|
||||
break;
|
||||
default:
|
||||
panic("bad format %s", fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprint(MSGOUT, "%c", fc);
|
||||
}
|
||||
}
|
||||
fprint(MSGOUT, "\n");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
panic(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
fprint(ERROUT, "PANIC, lint, pass2: ");
|
||||
doprnt(ERROUT, fmt, &args);
|
||||
fprint(ERROUT, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* for DEBUGGING */
|
||||
print_id(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
print("inpdef: %s, %s, %04d, \"%s\", %d, %d, %s, %d, %s\n",
|
||||
id->id_class == EFDF ? "EFDF" :
|
||||
id->id_class == SFDF ? "SFDF" :
|
||||
id->id_class == EVDF ? "EVDF" :
|
||||
id->id_class == SVDF ? "SVDF" :
|
||||
print("inpdef: %s, %s, %04d, \"%s\", %d, %s",
|
||||
id->id_class == LFDF ? "LFDF" :
|
||||
id->id_class == LVDF ? "LVDF" :
|
||||
id->id_class == EFDF ? "EFDF" :
|
||||
id->id_class == EVDF ? "EVDF" :
|
||||
id->id_class == EFDC ? "EFDC" :
|
||||
id->id_class == EVDC ? "EVDC" :
|
||||
id->id_class == IFDC ? "IFDC" :
|
||||
id->id_class == SFDF ? "SFDF" :
|
||||
id->id_class == SVDF ? "SVDF" :
|
||||
id->id_class == FC ? "FC" :
|
||||
id->id_class == VU ? "VU" :
|
||||
id->id_class == ERRCL ? "ERRCL" : "<BADCLASS>",
|
||||
|
@ -555,9 +461,21 @@ print_id(id)
|
|||
id->id_statnr,
|
||||
id->id_file,
|
||||
id->id_line,
|
||||
id->id_nrargs,
|
||||
((id->id_nrargs == 0) ? "" : id->id_argtps),
|
||||
id->id_returns,
|
||||
id->id_type);
|
||||
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>")
|
||||
: (id->id_valreturned ? "VALRETURNED" :
|
||||
"NOVALRETURNED")
|
||||
);
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include "../lpass1/l_class.h"
|
||||
#include "inpdef.h"
|
||||
#include "../lpass1/l_class.h"
|
||||
#include "class.h"
|
||||
#include "inpdef.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define INP_NPUSHBACK 2
|
||||
|
||||
#include <inp_pkg.spec>
|
||||
#include <inp_pkg.body>
|
||||
#include <inp_pkg.spec>
|
||||
#include <inp_pkg.body>
|
||||
|
||||
PRIVATE int LineNr = 1;
|
||||
|
||||
|
@ -25,37 +26,49 @@ int
|
|||
get_id(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
/* A low-level function which just reads a definition */
|
||||
/* A low-level function which just reads a definition */
|
||||
|
||||
if (!ReadString(id->id_name, ':', NAMESIZE))
|
||||
return 0;
|
||||
if (!ReadInt(&id->id_statnr))
|
||||
return 0;
|
||||
SkipChar(':');
|
||||
|
||||
loadchar(id->id_class);
|
||||
if (id->id_class == EOI)
|
||||
return 0;
|
||||
SkipChar(':');
|
||||
switch (id->id_class) {
|
||||
case EFDF:
|
||||
case SFDF:
|
||||
case LFDF:
|
||||
case FC:
|
||||
|
||||
if (is_class(id, CL_FUNC|CL_DEF) || is_class(id, CL_FUNC|CL_USAGE)) {
|
||||
/* read the argument information */
|
||||
id->id_args = 1;
|
||||
if (!ReadInt(&id->id_nrargs))
|
||||
return 0;
|
||||
SkipChar(':');
|
||||
if (!ReadArgs(id->id_nrargs, id->id_argtps))
|
||||
return 0;
|
||||
if (!ReadInt(&id->id_returns))
|
||||
return 0;
|
||||
if (id->id_class == FC) {
|
||||
/* function call */
|
||||
if (!ReadInt(&id->id_valused))
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* function definition */
|
||||
if (!ReadInt(&id->id_valreturned))
|
||||
return 0;
|
||||
}
|
||||
SkipChar(':');
|
||||
break;
|
||||
}
|
||||
else {
|
||||
id->id_args = 0;
|
||||
}
|
||||
|
||||
if (!ReadString(id->id_type, ':', TYPESIZE))
|
||||
return 0;
|
||||
if (!ReadInt(&id->id_line))
|
||||
return 0;
|
||||
SkipChar(':');
|
||||
|
||||
if (!ReadString(id->id_file, '\n', FNAMESIZE))
|
||||
return 0;
|
||||
{ extern char options[];
|
||||
|
@ -69,14 +82,16 @@ 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().
|
||||
* 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;
|
||||
/* Reads a string until 'delim' is encountered.
|
||||
Delim is discarded.
|
||||
If 'maxsize-1' is exceeded, "string too long" is written
|
||||
by panic().
|
||||
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 nread = 0;
|
||||
|
||||
while (nread < maxsize - 1) {
|
||||
|
@ -87,11 +102,11 @@ ReadString(buf, delim, maxsize)
|
|||
break;
|
||||
buf[nread++] = (char)ch;
|
||||
}
|
||||
buf[nread++] = '\0';
|
||||
if (ch != delim) {
|
||||
panic("line %d: string too long: %s", LineNr, buf);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
buf[nread++] = '\0';
|
||||
return (nread);
|
||||
}
|
||||
|
||||
|
|
81
lang/cem/lint/lpass2/report.c
Normal file
81
lang/cem/lint/lpass2/report.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include <varargs.h>
|
||||
|
||||
#include <system.h>
|
||||
#include "inpdef.h"
|
||||
|
||||
#define MSGOUT STDERR /* filedes on which to write the messages */
|
||||
#define ERROUT STDERR /* filedes on which to write the panics */
|
||||
|
||||
/* VARARGS */
|
||||
report(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap);
|
||||
{
|
||||
char *fmt = va_arg(ap, char*);
|
||||
register char *f = fmt;
|
||||
register char fc;
|
||||
|
||||
/* First see if the first arg is an inpdef with
|
||||
a global file name; if so, skip this message.
|
||||
*/
|
||||
if (f[0] == '%' && f[1] == 'L') {
|
||||
/* it is an inpdef */
|
||||
register struct inpdef *id =
|
||||
va_arg(ap, struct inpdef *);
|
||||
|
||||
f += 2;
|
||||
/* is the file name global? */
|
||||
if (id->id_file[0] == '/')
|
||||
return;
|
||||
/* if no, we have used up the argument,
|
||||
so print it here
|
||||
*/
|
||||
fprint(MSGOUT, "\"%s\", line %d",
|
||||
id->id_file, id->id_line);
|
||||
}
|
||||
while ((fc = *f++)) {
|
||||
if (fc == '%') {
|
||||
switch (*f++) {
|
||||
register struct inpdef *id;
|
||||
register char *s;
|
||||
register int i;
|
||||
case 'L': /* a location item */
|
||||
id = va_arg(ap, struct inpdef *);
|
||||
fprint(MSGOUT, "\"%s\", line %d",
|
||||
id->id_file, id->id_line);
|
||||
break;
|
||||
case 's': /* a string item */
|
||||
s = va_arg(ap, char *);
|
||||
fprint(MSGOUT, "%s", s);
|
||||
break;
|
||||
case 'd': /* an int item */
|
||||
i = va_arg(ap, int);
|
||||
fprint(MSGOUT, "%d", i);
|
||||
break;
|
||||
default:
|
||||
panic("bad format %s", fmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprint(MSGOUT, "%c", fc);
|
||||
}
|
||||
}
|
||||
fprint(MSGOUT, "\n");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
panic(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
fprint(ERROUT, "PANIC, lint, pass2: ");
|
||||
doprnt(ERROUT, fmt, &args);
|
||||
fprint(ERROUT, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
Loading…
Reference in a new issue