Initial revision
This commit is contained in:
546
lang/cem/cemcom.ansi/l_outdef.c
Normal file
546
lang/cem/cemcom.ansi/l_outdef.c
Normal file
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
/* Lint outdef construction */
|
||||
|
||||
#include "lint.h"
|
||||
|
||||
#ifdef LINT
|
||||
|
||||
#include <alloc.h>
|
||||
#include "interface.h"
|
||||
#include "arith.h"
|
||||
#include "assert.h"
|
||||
#include "type.h"
|
||||
#include "LLlex.h"
|
||||
#include "Lpars.h"
|
||||
#include "stack.h"
|
||||
#include "def.h"
|
||||
#include "struct.h"
|
||||
#include "field.h"
|
||||
#include "idf.h"
|
||||
#include "level.h"
|
||||
#include "label.h"
|
||||
#include "code.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();
|
||||
|
||||
int stat_number = 9999; /* static scope number */
|
||||
struct outdef OutDef;
|
||||
|
||||
PRIVATE struct outdef OutCall;
|
||||
|
||||
PRIVATE local_EFDC();
|
||||
PRIVATE output_def();
|
||||
PRIVATE outargs();
|
||||
PRIVATE outarg();
|
||||
PRIVATE outargstring();
|
||||
PRIVATE outargtype();
|
||||
PRIVATE implicit_func_decl();
|
||||
PRIVATE fill_arg();
|
||||
|
||||
lint_declare_idf(idf, sc)
|
||||
struct idf *idf;
|
||||
int sc;
|
||||
{
|
||||
register struct def *def = idf->id_def;
|
||||
register int is_function = def->df_type->tp_fund == FUNCTION;
|
||||
|
||||
if (level == L_GLOBAL) {
|
||||
lint_ext_def(idf, sc);
|
||||
if (is_function)
|
||||
def2decl(sc);
|
||||
if (sc != TYPEDEF)
|
||||
outdef();
|
||||
}
|
||||
else
|
||||
if (level >= L_LOCAL && sc != STATIC && is_function) {
|
||||
local_EFDC(idf);
|
||||
}
|
||||
}
|
||||
|
||||
lint_ext_def(idf, sc)
|
||||
struct idf *idf;
|
||||
{
|
||||
/* At this place the following fields of the outputdefinition can be
|
||||
* filled:
|
||||
* name, stat_number, class, file, line, type.
|
||||
* For variable definitions and declarations this will be all.
|
||||
* For functions the fields nrargs and argtps are filled after parsing
|
||||
* the arguments.
|
||||
* The returns-field is known at the end of the function definition.
|
||||
* sc indicates the storage class defined by the declaration specifier.
|
||||
*/
|
||||
register struct def *def = idf->id_def;
|
||||
register struct type *type = def->df_type;
|
||||
|
||||
OutDef.od_name = idf->id_text;
|
||||
OutDef.od_statnr = (sc == STATIC ? stat_number : 0);
|
||||
|
||||
switch (type->tp_fund) {
|
||||
case ERRONEOUS:
|
||||
OutDef.od_class = XXDF;
|
||||
break;
|
||||
case FUNCTION:
|
||||
/* For the moment assume it will be a definition.
|
||||
* If no compound_statement follows, it is a declaration,
|
||||
* in which case the class will be adjusted by def2decl().
|
||||
*/
|
||||
OutDef.od_class = (sc == STATIC ? SFDF : EFDF);
|
||||
break;
|
||||
default: /* a variable */
|
||||
OutDef.od_class =
|
||||
sc == EXTERN ? EVDC :
|
||||
sc == STATIC ? SVDF : EVDF;
|
||||
break;
|
||||
}
|
||||
OutDef.od_file = def->df_file;
|
||||
OutDef.od_line = def->df_line;
|
||||
OutDef.od_type = (type->tp_fund == FUNCTION ? type->tp_up : type);
|
||||
OutDef.od_valreturned = NORETURN;
|
||||
}
|
||||
|
||||
def2decl(sc)
|
||||
int sc;
|
||||
{
|
||||
/* It was assumed we were parsing a function definition.
|
||||
* There was no compound statement following, so actually it was a
|
||||
* declaration. This function updates the class.
|
||||
*/
|
||||
OutDef.od_class = (sc == STATIC ? XXDF : EFDC);
|
||||
}
|
||||
|
||||
set_od_valreturned(n)
|
||||
{
|
||||
OutDef.od_valreturned = n;
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
local_EFDC(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
struct outdef od;
|
||||
|
||||
od.od_class = EFDC;
|
||||
od.od_statnr = 0;
|
||||
od.od_name = idf->id_text;
|
||||
od.od_file = idf->id_def->df_file;
|
||||
od.od_line = idf->id_def->df_line;
|
||||
od.od_type = idf->id_def->df_type->tp_up;
|
||||
output_def(&od);
|
||||
/* The other fields are not used for this class. */
|
||||
}
|
||||
|
||||
lint_formals()
|
||||
{
|
||||
/* Make a list of tp_entries containing the types of the formal
|
||||
* parameters of the function definition just parsed.
|
||||
*/
|
||||
register struct stack_entry *se = stack_level_of(L_FORMAL1)->sl_entry;
|
||||
register struct argument **hook = &OutDef.od_arg;
|
||||
register int nrargs = 0;
|
||||
|
||||
while (se) {
|
||||
register struct type *type = se->se_idf->id_def->df_type;
|
||||
register struct argument *arg = new_argument();
|
||||
|
||||
/* Do the conversions on the formals that could not be
|
||||
done in declare_idf().
|
||||
It is, unfortunately, impossible not to do them,
|
||||
since the corresponding actuals will have been
|
||||
converted to generate proper code and we do not
|
||||
want to duplicate the whole of expression handling
|
||||
for lint.
|
||||
*/
|
||||
switch (type->tp_fund) {
|
||||
case CHAR:
|
||||
case SHORT:
|
||||
type = int_type;
|
||||
break;
|
||||
case FLOAT:
|
||||
type = double_type;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f_FORMAT && nrargs == f_FORMATn) {
|
||||
if ( !f_FORMATvar
|
||||
&& ( 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_FORMAT) {
|
||||
/* f_FORMAT has not been consumed, perhaps due to
|
||||
a varargs-like construction; add erroneous ArgFormals
|
||||
until f_FORMATn, then an ArgString, if necessary.
|
||||
*/
|
||||
if (!f_FORMATvar) {
|
||||
warning("FORMAT%d function has only %d argument%s",
|
||||
f_FORMATn, nrargs, nrargs == 1 ? "" : "s"
|
||||
);
|
||||
}
|
||||
|
||||
while (nrargs < f_FORMATn) {
|
||||
register struct argument *arg = new_argument();
|
||||
|
||||
arg->ar_type = error_type;
|
||||
arg->ar_class = ArgFormal;
|
||||
*hook = arg;
|
||||
hook = &arg->next;
|
||||
nrargs++;
|
||||
}
|
||||
if (nrargs == f_FORMATn) {
|
||||
register struct argument *arg = new_argument();
|
||||
|
||||
arg->ar_type = string_type;
|
||||
arg->ar_class = ArgString;
|
||||
arg->CAS_VALUE = f_FORMAT;
|
||||
arg->CAS_LEN = strlen(f_FORMAT);
|
||||
f_FORMAT = 0;
|
||||
*hook = arg;
|
||||
hook = &arg->next;
|
||||
nrargs++;
|
||||
}
|
||||
/* life is full of duplicated code; this is no good */
|
||||
}
|
||||
|
||||
if (f_VARARGSn > nrargs) {
|
||||
warning("VARARGS%d function has only %d argument%s",
|
||||
f_VARARGSn, nrargs, nrargs == 1 ? "" : "s"
|
||||
);
|
||||
f_VARARGSn = nrargs;
|
||||
}
|
||||
OutDef.od_nrargs = nrargs;
|
||||
}
|
||||
|
||||
output_use(idf)
|
||||
struct idf *idf;
|
||||
{
|
||||
/* Output the usage-definition of the variable described by idf.
|
||||
*/
|
||||
OutDef.od_name = idf->id_text;
|
||||
OutDef.od_statnr = (idf->id_def->df_sc == STATIC ? stat_number : 0);
|
||||
OutDef.od_class = VU;
|
||||
OutDef.od_file = FileName;
|
||||
OutDef.od_line = LineNumber;
|
||||
OutDef.od_type = idf->id_def->df_type;
|
||||
outdef();
|
||||
}
|
||||
|
||||
outdef()
|
||||
{
|
||||
output_def(&OutDef);
|
||||
}
|
||||
|
||||
outcall()
|
||||
{
|
||||
output_def(&OutCall);
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
output_def(od)
|
||||
struct outdef *od;
|
||||
{
|
||||
/* As the types are output the tp_entries are removed, because they
|
||||
* are then not needed anymore.
|
||||
*/
|
||||
if (od->od_class == XXDF)
|
||||
return;
|
||||
|
||||
if (LINTLIB) {
|
||||
switch (od->od_class) {
|
||||
case EFDF:
|
||||
od->od_class = LFDF;
|
||||
break;
|
||||
case EVDF:
|
||||
od->od_class = LVDF;
|
||||
break;
|
||||
case SFDF:
|
||||
/* remove tp_entries */
|
||||
while (od->od_arg) {
|
||||
register struct argument *tmp = od->od_arg;
|
||||
od->od_arg = od->od_arg->next;
|
||||
free_argument(tmp);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("%s:%d:%c", od->od_name, od->od_statnr, od->od_class);
|
||||
switch (od->od_class) {
|
||||
case EFDF:
|
||||
case SFDF:
|
||||
case LFDF:
|
||||
if (f_VARARGSn != -1) {
|
||||
printf(":%d", -1 - f_VARARGSn);
|
||||
outargs(od->od_arg, f_VARARGSn);
|
||||
}
|
||||
else {
|
||||
printf(":%d", od->od_nrargs);
|
||||
outargs(od->od_arg, od->od_nrargs);
|
||||
}
|
||||
od->od_arg = 0;
|
||||
printf(":%d", od->od_valreturned);
|
||||
break;
|
||||
case FC:
|
||||
printf(":%d", od->od_nrargs);
|
||||
outargs(od->od_arg, od->od_nrargs);
|
||||
od->od_arg = 0;
|
||||
printf(":%d", od->od_valused);
|
||||
break;
|
||||
case EVDF:
|
||||
case SVDF:
|
||||
case LVDF:
|
||||
case EFDC:
|
||||
case EVDC:
|
||||
case IFDC:
|
||||
case VU:
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
printf(":");
|
||||
outargtype(od->od_type);
|
||||
printf(":%u:%s\n", od->od_line, od->od_file);
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
outargs(arg, n)
|
||||
struct argument *arg;
|
||||
{
|
||||
/* Output the n arguments in the argument list and remove them */
|
||||
|
||||
register struct argument *tmp;
|
||||
|
||||
while (n--) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
outarg(arg)
|
||||
struct argument *arg;
|
||||
{
|
||||
printf(":");
|
||||
switch (arg->ar_class) {
|
||||
case ArgConst:
|
||||
if (arg->CAA_VALUE >= 0) {
|
||||
/* constant non-negative actual parameter */
|
||||
printf("+");
|
||||
}
|
||||
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,
|
||||
depending on opaque circumstances. E.g., in
|
||||
f(main, main);
|
||||
the first main is PtF and the second is F.
|
||||
*/
|
||||
printf("*");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOTREACHED();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
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);
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
outargtype(tp)
|
||||
struct type *tp;
|
||||
{
|
||||
switch (tp->tp_fund) {
|
||||
case POINTER:
|
||||
outargtype(tp->tp_up);
|
||||
printf("*");
|
||||
break;
|
||||
|
||||
case ARRAY:
|
||||
outargtype(tp->tp_up);
|
||||
printf("*"); /* compatible with [] */
|
||||
break;
|
||||
|
||||
case FUNCTION:
|
||||
outargtype(tp->tp_up);
|
||||
printf("()");
|
||||
break;
|
||||
|
||||
case STRUCT:
|
||||
case UNION:
|
||||
case ENUM:
|
||||
printf("%s %s", symbol2str(tp->tp_fund), tp->tp_idf->id_text);
|
||||
break;
|
||||
|
||||
case CHAR:
|
||||
case INT:
|
||||
case SHORT:
|
||||
case LONG:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
case VOID:
|
||||
case ERRONEOUS:
|
||||
if (tp->tp_unsigned)
|
||||
printf("unsigned ");
|
||||
printf("%s", symbol2str(tp->tp_fund));
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
implicit_func_decl(idf, file, line)
|
||||
struct idf *idf;
|
||||
char *file;
|
||||
unsigned int line;
|
||||
{
|
||||
struct outdef od;
|
||||
|
||||
od.od_class = IFDC;
|
||||
od.od_statnr = 0;
|
||||
od.od_name = idf->id_text;
|
||||
od.od_file = file;
|
||||
od.od_line = line;
|
||||
od.od_type = idf->id_def->df_type->tp_up;
|
||||
output_def(&od);
|
||||
/* The other fields are not used for this class. */
|
||||
}
|
||||
|
||||
fill_outcall(ex, used)
|
||||
struct expr *ex;
|
||||
int used;
|
||||
{
|
||||
register struct idf *idf = ex->OP_LEFT->VL_IDF;
|
||||
register struct def *def = idf->id_def;
|
||||
|
||||
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_type = def->df_type->tp_up;
|
||||
OutCall.od_statnr = (def->df_sc == STATIC ? stat_number : 0);
|
||||
OutCall.od_class = FC;
|
||||
OutCall.od_name = idf->id_text;
|
||||
OutCall.od_file = ex->ex_file;
|
||||
OutCall.od_line = ex->ex_line;
|
||||
OutCall.od_arg = (struct argument *)0;
|
||||
OutCall.od_nrargs = 0;
|
||||
|
||||
if ((ex = ex->OP_RIGHT) != 0) { /* function call with arguments */
|
||||
/* store types of argument expressions in tp_entries */
|
||||
while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
|
||||
fill_arg(ex->OP_RIGHT);
|
||||
ex = ex->OP_LEFT;
|
||||
}
|
||||
fill_arg(ex);
|
||||
}
|
||||
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
|
||||
}
|
||||
|
||||
PRIVATE
|
||||
fill_arg(e)
|
||||
struct expr *e;
|
||||
{
|
||||
register struct argument *arg;
|
||||
|
||||
arg = new_argument();
|
||||
arg->ar_type = e->ex_type;
|
||||
if (is_cp_cst(e)) {
|
||||
arg->ar_class = ArgConst;
|
||||
arg->CAA_VALUE = e->VL_VALUE;
|
||||
}
|
||||
else if (e->ex_class == Value && e->VL_CLASS == Label) {
|
||||
/* it may be a string; let's look it up */
|
||||
register struct string_cst *sc = str_list;
|
||||
|
||||
while (sc) {
|
||||
if (sc->sc_dlb == e->VL_LBL)
|
||||
break;
|
||||
sc = sc->next;
|
||||
}
|
||||
if (sc) {
|
||||
/* it was a string */
|
||||
arg->ar_class = ArgString;
|
||||
arg->CAS_VALUE = sc->sc_value;
|
||||
arg->CAS_LEN = sc->sc_len - 1; /* included the \0 */
|
||||
}
|
||||
else {
|
||||
arg->ar_class = ArgExpr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
arg->ar_class = ArgExpr;
|
||||
}
|
||||
arg->next = OutCall.od_arg;
|
||||
OutCall.od_arg = arg;
|
||||
OutCall.od_nrargs++;
|
||||
}
|
||||
|
||||
#endif LINT
|
||||
Reference in New Issue
Block a user