-#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();
}
}
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':
options[argv[1][1]] = 1;
break;
default:
- /* ready to extend */
+ /* ready to be extended */
break;
}
argc--, argv++;
panic("InsertFile() fails");
}
-read_defs()
+get_dot()
{
- struct inpdef *id;
+ if (!get_id(dot)) {
+ free_inpdef(dot);
+ dot = 0;
+ cur_name[0] = '\0';
+ }
+}
- 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);
+
+/******** L I B R A R Y ********/
+
+lib_def()
+{
+ 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();
+ }
+}
+
+
+/******** E X T E R N ********/
+
+ext_def()
+{
+ 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();
+ }
+
+ 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();
}
}
-struct inpdef *
-id_read()
+ext_decls()
{
-/* 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);
+ 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);
+ }
}
-get_dot_id()
+one_ext_decl(kind, other_kind, other_class)
+ char *kind;
+ char *other_kind;
+ int other_class;
{
-/* 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;
+ 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);
+ }
+ 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();
}
-struct inpdef *definition();
-check(id)
- struct inpdef *id;
+/******** U S A G E ********/
+
+usage(stnr)
+ int stnr;
{
-/* Checks a declaration, function call or variable usage, described by id,
- * against the definitions.
- */
- struct inpdef *idef;
+ struct inpdef *def = stnr ? sta : ext ? ext : lib ? lib : 0;
- 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;
- }
- if (idef->id_class == EVDF || idef->id_class == LVDF) {
- report("%L: function %s declared as variable at %L",
- id, id->id_name, idef);
- break;
+ 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);
+ 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",
+ dot, dot->id_name, def);
}
+ }
+
+ switch (dot->id_valused) {
+ case USED:
+ def->id_used = 1;
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);
- }
+ case IGNORED:
+ def->id_ignored = 1;
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);
- }
+ case VOIDED:
+ def->id_voided = 1;
break;
- case FC:
- if (!idef) {
- if (!options['u']) {
- report("%L: function %s used but not defined",
- id, id->id_name);
- }
- discard_defs();
- break;
+ default:
+ panic("invalid dot->id_valused in check");
+ break;
+ }
+
+ get_dot();
+}
+
+one_var_usage(def)
+ struct inpdef *def;
+{
+ if (!def) {
+ if (!options['u']) {
+ report("%L: variable %s used but not defined",
+ dot, dot->id_name);
}
- idef->id_called = 1;
- check_args(id, idef);
- if (id->id_returns == USED && !idef->id_returns) {
- report("%L: value of %s is used, but none is returned at %L",
- id, id->id_name, idef);
+ get_dot();
+ return;
+ }
+
+ def->id_called = 1;
+
+ get_dot();
+}
+
+
+/******** S T A T I C ********/
+
+statics()
+{
+ while (same_name() && dot->id_statnr != 0) {
+ one_static(dot->id_statnr);
+ }
+}
+
+one_static(stnr)
+ int stnr;
+{
+ while (same_obj(stnr)) {
+ if (sta) {
+ free_inpdef(sta);
+ sta = 0;
}
- 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");
+ 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);
}
- break;
- case VU:
- if (!idef) {
- if (!options['u']) {
- report("%L: variable %s used but not defined",
- id, id->id_name);
- }
- discard_defs();
- break;
+ if (ext) {
+ report("%L: %s also %s at %L",
+ dot, dot->id_name, defdec(ext), ext);
}
- idef->id_called = 1;
- break;
- case EFDF:
- case SFDF:
- case EVDF:
- case SVDF:
- case LFDF:
- case LVDF:
- panic("check() called for a definition");
- break;
- default:
- panic("invalid class (%c) in check", id->id_class);
- break;
+ 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();
}
}
-discard_defs()
+check_def(def)
+ struct inpdef *def;
{
-/* Read until a definition having another name */
+ if (!def)
+ return;
- struct inpdef *id;
+ 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));
+ }
+ }
+ }
- while (dot_id && same_name()) {
- id = id_read();
- free_inpdef(id);
+ 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");
+ }
}
}
-check_args(id, idef)
- struct inpdef *id, *idef;
+
+/******** 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);
}
}
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 */
return 0;
}
-check_usage()
-{
-/* Checks if the defined function or variable is used.
- * There can be several static definitions.
- */
- struct inpdef *sd = static_def;
-
- if (ext_def)
- check_def(ext_def);
- while (sd) {
- check_def(sd);
- sd = sd->next;
- }
-}
+/******** D E B U G G I N G ********/
-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>",
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");
}