ack/lang/cem/cemcom.ansi/l_outdef.c
1991-07-05 11:55:17 +00:00

621 lines
13 KiB
C

/*
* (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"
#ifdef ANSI
#include <flt_arith.h>
#endif ANSI
#include "arith.h"
#include "assert.h"
#include "type.h"
#include "proto.h"
#include "declar.h"
#include "decspecs.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();
extern char *strindex();
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 add_expr_arg();
PRIVATE def2decl();
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_non_function_decl(ds, dc)
struct decspecs *ds;
struct declarator *dc;
{
register struct def *def = dc->dc_idf->id_def;
register int is_function = def->df_type->tp_fund == FUNCTION;
if (is_function)
def2decl(ds->ds_sc);
if (def->df_sc != TYPEDEF)
outdef();
}
lint_ext_def(idf, sc)
struct idf *idf;
{
/* At this place the following fields of the output definition can be
* filled:
* od_name, od_statnr, od_class, od_file, od_line, od_type.
* For variable definitions and declarations this will be all.
* For functions the fields od_nrargs and od_arg are filled after parsing
* the arguments.
* The od_valreturned 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;
}
PRIVATE
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 'struct argument's 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();
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_proto(idf, def)
struct idf *idf;
struct def *def;
{
/* fund == FUNCTION && sc != STATIC */
register struct proto *pl = def->df_type->tp_proto;
register int nrargs = 0;
if (!pl) return;
OutDef.od_name = idf->id_text;
OutDef.od_statnr = 0;
OutDef.od_class = PFDF;
OutDef.od_file = def->df_file;
OutDef.od_line = def->df_line;
OutDef.od_type = def->df_type->tp_up;
OutDef.od_valreturned = NORETURN;/*???*/
while (pl) {
register struct type *type = pl->pl_type;
register struct argument *arg = new_argument();
if (type) {
arg->ar_type = type;
arg->ar_class = ArgFormal;
}
else {
arg->ar_class = ArgEllipsis;
}
arg->next = OutDef.od_arg;
OutDef.od_arg = arg;
nrargs++;
pl = pl->next;
}
OutDef.od_nrargs = nrargs;
outdef();
}
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 'struct argument's are freed, because they
* are then not needed anymore.
*/
if (od->od_class == XXDF || !od->od_name || od->od_name[0] == '#')
return;
if (LINTLIB) {
switch (od->od_class) {
case EFDF:
od->od_class = LFDF;
break;
case EVDF:
od->od_class = LVDF;
break;
case SFDF:
/* free the 'struct argument's */
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 LFDF:
case PFDF:
case EFDF:
case SFDF:
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;
case ArgEllipsis:
printf("."); /* one is enough for computers */
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:
/* watch out for anonymous identifiers; the count field does
not have to be the same for all compilation units.
Remove it, so that pass 2 does not see it. The only
problem with this is that pass2 will not see a difference
between two non-tagged types declared on the same line.
*/
printf("%s ", symbol2str(tp->tp_fund));
if (is_anon_idf(tp->tp_idf)) {
/* skip the #<num>, replace it by '#anonymous id' */
printf("#anonymous id%s",
strindex(tp->tp_idf->id_text, ' ')
);
}
else {
printf(tp->tp_idf->id_text);
}
break;
case CHAR:
case INT:
case SHORT:
case LONG:
case ULONG:
case FLOAT:
case DOUBLE:
case LNGDBL:
case VOID:
case ERRONEOUS:
if (tp->tp_unsigned) {
printf("unsigned ");
}
printf("%s", symbol2str(tp->tp_fund));
break;
default:
NOTREACHED();
/*NOTREACHED*/
}
}
#ifdef IMPLICIT
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. */
}
#endif IMPLICIT
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;
#ifdef IMPLICIT
if (def->df_sc == IMPLICIT && !idf->id_def->df_used) {
/* IFDC, first time */
implicit_func_decl(idf, ex->ex_file, ex->ex_line);
}
#endif IMPLICIT
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 'struct argument's */
while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
add_expr_arg(ex->OP_RIGHT);
ex = ex->OP_LEFT;
}
add_expr_arg(ex);
}
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
}
PRIVATE
add_expr_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_type == string_type
&& 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