1989-02-07 11:04:05 +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$ */
|
|
|
|
/* P R O T O T Y P E F I D D L I N G */
|
|
|
|
|
|
|
|
#include "lint.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "idfsize.h"
|
|
|
|
#include "nparams.h"
|
|
|
|
#include "botch_free.h"
|
|
|
|
#include <alloc.h>
|
|
|
|
#include "Lpars.h"
|
|
|
|
#include "level.h"
|
1989-09-19 16:13:23 +00:00
|
|
|
#include <flt_arith.h>
|
1989-02-07 11:04:05 +00:00
|
|
|
#include "arith.h"
|
|
|
|
#include "align.h"
|
|
|
|
#include "stack.h"
|
|
|
|
#include "idf.h"
|
|
|
|
#include "def.h"
|
|
|
|
#include "type.h"
|
|
|
|
#include "struct.h"
|
|
|
|
#include "label.h"
|
|
|
|
#include "expr.h"
|
|
|
|
#include "declar.h"
|
|
|
|
#include "decspecs.h"
|
|
|
|
#include "proto.h"
|
|
|
|
#include "assert.h"
|
|
|
|
|
|
|
|
extern char options[];
|
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
check_for_void(pl)
|
|
|
|
register struct proto *pl;
|
|
|
|
{
|
|
|
|
register int errcnt = 0;
|
|
|
|
|
|
|
|
if (!pl) return;
|
|
|
|
if ((pl->pl_flag & PL_VOID) && !(pl->next)) return;
|
|
|
|
|
|
|
|
while (pl) {
|
|
|
|
if (pl->pl_flag & PL_VOID) {
|
|
|
|
if (!errcnt && !(pl->pl_flag & PL_ERRGIVEN))
|
|
|
|
error("illegal use of void in argument list");
|
|
|
|
pl->pl_flag |= PL_ERRGIVEN;
|
|
|
|
errcnt++;
|
|
|
|
}
|
|
|
|
pl = pl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
add_proto(pl, ds, dc, level)
|
|
|
|
struct proto *pl;
|
|
|
|
struct decspecs *ds;
|
|
|
|
struct declarator *dc;
|
|
|
|
int level;
|
|
|
|
{
|
|
|
|
/* The full typed identifier or abstract type, described
|
|
|
|
by the structures decspecs and declarator are turned
|
|
|
|
a into parameter type list structure.
|
|
|
|
The parameters will be declared at level L_FORMAL2,
|
|
|
|
later on it's decided whether they were prototypes
|
|
|
|
or actual declarations.
|
|
|
|
*/
|
|
|
|
register struct idf *idf;
|
|
|
|
register struct def *def = (struct def *)0;
|
|
|
|
register int sc = ds->ds_sc;
|
|
|
|
register struct type *type;
|
|
|
|
char formal_array = 0;
|
|
|
|
|
|
|
|
ASSERT(ds->ds_type != (struct type *)0);
|
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
pl->pl_flag = PL_FORMAL;
|
1989-02-07 11:04:05 +00:00
|
|
|
if ((idf = dc->dc_idf) != (struct idf *)0)
|
|
|
|
def = idf->id_def;
|
|
|
|
type = declare_type(ds->ds_type, dc);
|
|
|
|
if (type->tp_size < (arith)0 && actual_declaration(sc, type)) {
|
|
|
|
extern char *symbol2str();
|
|
|
|
error("unknown %s-type", symbol2str(type->tp_fund));
|
|
|
|
} else if (type->tp_size == 0) {
|
|
|
|
if (idf != (struct idf *)0)
|
1989-09-19 16:13:23 +00:00
|
|
|
error("illegal use of void in argument list");
|
|
|
|
else pl->pl_flag = PL_VOID;
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform some special conversions for parameters.
|
|
|
|
*/
|
|
|
|
if (type->tp_fund == FUNCTION) {
|
|
|
|
if (type->tp_proto)
|
|
|
|
remove_proto_idfs(type->tp_proto);
|
|
|
|
type = construct_type(POINTER, type, 0, (arith) 0, NO_PROTO);
|
|
|
|
} else if (type->tp_fund == ARRAY) {
|
1989-09-19 16:13:23 +00:00
|
|
|
type = construct_type(POINTER, type->tp_up, 0, (arith) 0, NO_PROTO);
|
1989-02-07 11:04:05 +00:00
|
|
|
formal_array = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* According to the standard we should ignore the storage
|
|
|
|
class of a parameter, unless it's part of a function
|
|
|
|
definition.
|
|
|
|
However, in the routine declare_protos we don't know decspecs,
|
|
|
|
and therefore we can't complain up there. So we build up the
|
|
|
|
storage class, and keep quiet until we reach declare_protos.
|
|
|
|
*/
|
|
|
|
sc = (ds->ds_sc_given && ds->ds_sc != REGISTER) ?
|
|
|
|
0 : sc == 0 ? FORMAL : REGISTER;
|
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
if (def && (def->df_level == level /* || def->df_level < L_PROTO */ )) {
|
1989-02-07 11:04:05 +00:00
|
|
|
/* redeclaration at the same level */
|
|
|
|
error("parameter %s redeclared", idf->id_text);
|
|
|
|
} else if (idf != (struct idf *)0) {
|
|
|
|
/* New definition, redefinition hides earlier one
|
|
|
|
*/
|
|
|
|
register struct def *newdef = new_def();
|
|
|
|
|
|
|
|
newdef->next = def;
|
|
|
|
newdef->df_level = level;
|
|
|
|
newdef->df_sc = sc;
|
|
|
|
newdef->df_type = type;
|
|
|
|
newdef->df_formal_array = formal_array;
|
|
|
|
newdef->df_file = idf->id_file;
|
|
|
|
newdef->df_line = idf->id_line;
|
|
|
|
#ifdef LINT
|
|
|
|
newdef->df_set = (type->tp_fund == ARRAY);
|
|
|
|
newdef->df_firstbrace = 0;
|
|
|
|
#endif
|
|
|
|
/* We can't put the idf onto the stack, since these kinds
|
|
|
|
of declaration may occurs at any level, and the idf
|
|
|
|
does not necessarily go at this level. E.g.
|
|
|
|
|
|
|
|
f() {
|
|
|
|
...
|
|
|
|
{ int func(int a, int b);
|
|
|
|
...
|
1989-09-19 16:13:23 +00:00
|
|
|
}
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
The idf's a and b declared in the prototype declaration
|
|
|
|
do not go at any level, they are simply ignored.
|
|
|
|
However, in
|
|
|
|
|
|
|
|
f(int a, int b) {
|
|
|
|
...
|
1989-09-19 16:13:23 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
They should go at level L_FORMAL2. But at this stage
|
|
|
|
we don't know whether we have a prototype or function
|
|
|
|
definition. So, this process is postponed.
|
|
|
|
*/
|
|
|
|
idf->id_def = newdef;
|
|
|
|
update_ahead(idf);
|
|
|
|
}
|
|
|
|
|
|
|
|
pl->pl_idf = idf;
|
|
|
|
pl->pl_type = type;
|
|
|
|
}
|
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
struct tag *
|
|
|
|
gettag(tp, idpp)
|
|
|
|
struct type *tp;
|
|
|
|
struct idf **idpp;
|
|
|
|
{
|
|
|
|
struct tag *tg;
|
|
|
|
|
|
|
|
while (tp->tp_up) tp = tp->tp_up;
|
|
|
|
*idpp = tp->tp_idf;
|
|
|
|
switch(tp->tp_fund) {
|
|
|
|
case ENUM: tg = tp->tp_idf->id_enum; break;
|
|
|
|
case UNION:
|
|
|
|
case STRUCT: tg = tp->tp_idf->id_struct; break;
|
|
|
|
default: return (struct tag *)0;
|
|
|
|
}
|
|
|
|
return tg;
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_protos(dc)
|
1989-02-07 11:04:05 +00:00
|
|
|
register struct declarator *dc;
|
|
|
|
{
|
|
|
|
/* At this points we know that the idf's in protolist are formal
|
|
|
|
parameters. So it's time to declare them at level L_FORMAL2.
|
|
|
|
*/
|
|
|
|
struct stack_level *stl = stack_level_of(L_FORMAL1);
|
|
|
|
register struct decl_unary *du;
|
|
|
|
register struct type *type;
|
|
|
|
register struct proto *pl;
|
|
|
|
register struct def *def;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (options['t'])
|
|
|
|
dumpidftab("start declare_protos", 0);
|
|
|
|
#endif DEBUG
|
|
|
|
du = dc->dc_decl_unary;
|
|
|
|
while (du && du->du_fund != FUNCTION)
|
|
|
|
du = du->next;
|
|
|
|
pl = du ? du->du_proto : NO_PROTO;
|
|
|
|
if (pl) {
|
1989-09-19 16:13:23 +00:00
|
|
|
#if 0 /* the id_proto member is deleted (???) */
|
1989-02-07 11:04:05 +00:00
|
|
|
idf->id_proto = 0;
|
1989-09-19 16:13:23 +00:00
|
|
|
#endif /* 0 */
|
1989-02-07 11:04:05 +00:00
|
|
|
do {
|
1989-09-19 16:13:23 +00:00
|
|
|
struct tag *tg;
|
|
|
|
struct idf *idp = 0;
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
type = pl->pl_type;
|
|
|
|
|
|
|
|
/* `...' only for type checking */
|
1989-09-19 16:13:23 +00:00
|
|
|
if (pl->pl_flag & PL_ELLIPSIS) {
|
1989-02-07 11:04:05 +00:00
|
|
|
pl = pl->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* special case: int f(void) { ; } */
|
|
|
|
if (type->tp_fund == VOID)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!pl->pl_idf || !(def = pl->pl_idf->id_def)) {
|
1989-02-07 13:16:02 +00:00
|
|
|
error("no parameter identifier supplied");
|
1989-02-07 11:04:05 +00:00
|
|
|
pl = pl->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Postponed storage class checking.
|
|
|
|
*/
|
|
|
|
if (def->df_sc == 0)
|
|
|
|
error("illegal storage class in parameter declaration");
|
|
|
|
|
|
|
|
def->df_level = L_FORMAL2;
|
|
|
|
stack_idf(pl->pl_idf, stl);
|
|
|
|
pl = pl->next;
|
1989-09-19 16:13:23 +00:00
|
|
|
|
|
|
|
tg = gettag(type, &idp);
|
|
|
|
if (tg && tg->tg_level <= L_PROTO) {
|
|
|
|
tg->tg_level = L_FORMAL2;
|
|
|
|
stack_idf(idp, stl);
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
} while (pl);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (options['t'])
|
|
|
|
dumpidftab("end declare_protos", 0);
|
|
|
|
#endif DEBUG
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def_proto(dc)
|
|
|
|
register struct declarator *dc;
|
|
|
|
{
|
|
|
|
/* Prototype declarations may have arguments, but the idf's
|
|
|
|
in the parameter type list can be ignored.
|
|
|
|
*/
|
|
|
|
register struct decl_unary *du = dc->dc_decl_unary;
|
|
|
|
|
|
|
|
while (du) {
|
|
|
|
if (du->du_fund == FUNCTION)
|
|
|
|
remove_proto_idfs(du->du_proto);
|
|
|
|
du = du->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update_proto(tp, otp)
|
|
|
|
register struct type *tp, *otp;
|
|
|
|
{
|
|
|
|
/* This routine performs the proto type updates.
|
|
|
|
Consider the following code:
|
|
|
|
|
|
|
|
int f(double g());
|
|
|
|
int f(double g(int f(), int));
|
|
|
|
int f(double g(int f(long double), int));
|
|
|
|
|
|
|
|
The most accurate definition is the third line.
|
|
|
|
This routine will silently update all lists,
|
|
|
|
and removes the redundant occupied space.
|
|
|
|
*/
|
|
|
|
register struct proto *pl, *opl;
|
|
|
|
|
|
|
|
if (tp == otp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!tp || !otp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (tp && tp->tp_fund != FUNCTION) {
|
|
|
|
tp = tp->tp_up;
|
|
|
|
otp = otp->tp_up;
|
|
|
|
if (!tp) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pl = tp->tp_proto;
|
|
|
|
opl = otp->tp_proto;
|
|
|
|
if (pl && opl) {
|
|
|
|
/* both have prototypes */
|
|
|
|
while (pl && opl) {
|
|
|
|
update_proto(pl->pl_type, opl->pl_type);
|
|
|
|
pl = pl->next;
|
1989-02-07 13:16:02 +00:00
|
|
|
opl = opl->next;
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
1989-02-07 13:16:02 +00:00
|
|
|
free_proto_list(otp->tp_proto);
|
|
|
|
otp->tp_proto = tp->tp_proto;
|
1989-02-07 11:04:05 +00:00
|
|
|
} else if (opl) {
|
|
|
|
/* old decl has type */
|
|
|
|
} else if (pl) {
|
|
|
|
/* new decl has type */
|
|
|
|
otp->tp_proto = pl;
|
1989-02-07 13:16:02 +00:00
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
update_proto(tp->tp_up, otp->tp_up);
|
|
|
|
}
|
|
|
|
|
|
|
|
free_proto_list(pl)
|
|
|
|
register struct proto *pl;
|
|
|
|
{
|
|
|
|
while (pl) {
|
1989-02-07 13:16:02 +00:00
|
|
|
struct proto *tmp = pl->next;
|
1989-02-07 11:04:05 +00:00
|
|
|
free_proto(pl);
|
|
|
|
pl = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1989-09-19 16:13:23 +00:00
|
|
|
/* struct/union and enum tags can be declared inside prototypes
|
|
|
|
* remove them from the symbol-table
|
|
|
|
*/
|
|
|
|
remove_proto_tag(tp)
|
|
|
|
struct type *tp;
|
|
|
|
{
|
|
|
|
struct idf *ident;
|
|
|
|
struct tag *tg, *otg = 0;
|
|
|
|
|
|
|
|
while(tp->tp_up) tp = tp->tp_up;
|
|
|
|
|
|
|
|
ident = tp->tp_idf;
|
|
|
|
switch(tp->tp_fund) {
|
|
|
|
case ENUM: tg = ident->id_enum; break;
|
|
|
|
case UNION:
|
|
|
|
case STRUCT: tg = ident->id_struct; break;
|
|
|
|
default: return;
|
|
|
|
}
|
|
|
|
while (tg && tg->tg_type != tp) {
|
|
|
|
otg = tg;
|
|
|
|
tg = tg->next;
|
|
|
|
}
|
|
|
|
if (tg ->tg_level > L_PROTO) return;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (options['t'])
|
|
|
|
print("Removing idf %s from list\n",
|
|
|
|
ident->id_text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!otg) {
|
|
|
|
switch(tp->tp_fund) {
|
|
|
|
case ENUM: ident->id_enum = tg->next; break;
|
|
|
|
case UNION:
|
|
|
|
case STRUCT: ident->id_struct = tg->next; break;
|
|
|
|
}
|
|
|
|
free_tag(tg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
otg->next = tg->next;
|
|
|
|
free_tag(tg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1989-02-07 11:04:05 +00:00
|
|
|
remove_proto_idfs(pl)
|
|
|
|
register struct proto *pl;
|
|
|
|
{
|
|
|
|
/* Remove all the identifier definitions from the
|
|
|
|
prototype list. Keep in account the recursive
|
|
|
|
function definitions.
|
|
|
|
*/
|
|
|
|
register struct def *def;
|
|
|
|
|
|
|
|
while (pl) {
|
|
|
|
if (pl->pl_idf) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (options['t'])
|
|
|
|
print("Removing idf %s from list\n",
|
|
|
|
pl->pl_idf->id_text);
|
|
|
|
#endif
|
|
|
|
/* Remove all the definitions made within
|
|
|
|
a prototype.
|
1989-09-19 16:13:23 +00:00
|
|
|
??? is this really necessary (Hans)
|
|
|
|
wasn't this done before in the declaration
|
1989-02-07 11:04:05 +00:00
|
|
|
*/
|
1989-09-19 16:13:23 +00:00
|
|
|
#if 0
|
|
|
|
if (pl->pl_flag & PL_FORMAL) {
|
1989-02-07 11:04:05 +00:00
|
|
|
register struct type *tp = pl->pl_type;
|
|
|
|
|
|
|
|
while (tp && tp->tp_fund != FUNCTION)
|
|
|
|
tp = tp->tp_up;
|
|
|
|
if (tp)
|
1989-09-19 16:13:23 +00:00
|
|
|
debug("remove_proto_idfs(tp->tp_proto)");
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
1989-09-19 16:13:23 +00:00
|
|
|
#endif
|
1989-02-07 11:04:05 +00:00
|
|
|
def = pl->pl_idf->id_def;
|
|
|
|
if (def && def->df_level <= L_PROTO){
|
|
|
|
pl->pl_idf->id_def = def->next;
|
|
|
|
free_def(def);
|
|
|
|
}
|
|
|
|
pl->pl_idf = (struct idf *) 0;
|
|
|
|
}
|
1989-09-19 16:13:23 +00:00
|
|
|
if (pl->pl_type) {
|
|
|
|
remove_proto_tag(pl->pl_type);
|
|
|
|
}
|
1989-02-07 11:04:05 +00:00
|
|
|
pl = pl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
call_proto(expp)
|
|
|
|
register struct expr **expp;
|
|
|
|
{
|
|
|
|
/* If the function specified by (*expp)->OP_LEFT has a prototype,
|
|
|
|
the parameters are converted according the rules specified in
|
|
|
|
par. 3.3.2.2. E.i. the parameters are converted to the prototype
|
|
|
|
counter parts as if by assignment. For the parameters falling
|
|
|
|
under ellipsis clause the old parameters conversion stuff
|
|
|
|
applies.
|
|
|
|
*/
|
|
|
|
register struct expr *left = (*expp)->OP_LEFT;
|
|
|
|
register struct expr *right = (*expp)->OP_RIGHT;
|
|
|
|
register struct proto *pl = NO_PROTO;
|
1989-09-19 16:13:23 +00:00
|
|
|
static struct proto ellipsis = { 0, 0, 0, PL_ELLIPSIS };
|
1989-02-07 11:04:05 +00:00
|
|
|
|
|
|
|
if (left != NILEXPR) { /* in case of an error */
|
|
|
|
register struct type *tp = left->ex_type;
|
|
|
|
|
|
|
|
while (tp && tp->tp_fund != FUNCTION)
|
|
|
|
tp = tp->tp_up;
|
|
|
|
pl = (tp && tp->tp_proto) ? tp->tp_proto : NO_PROTO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (right != NILEXPR) { /* function call with parameters */
|
|
|
|
register struct expr *ex = right;
|
|
|
|
register struct expr **ep = &((*expp)->OP_RIGHT);
|
|
|
|
register int ecnt = 0, pcnt = 0;
|
|
|
|
struct expr **estack[NPARAMS];
|
|
|
|
struct proto *pstack[NPARAMS];
|
|
|
|
|
|
|
|
/* stack up the parameter expressions */
|
|
|
|
while (ex->ex_class == Oper && ex->OP_OPER == PARCOMMA) {
|
|
|
|
if (ecnt == STDC_NPARAMS)
|
|
|
|
strict("number of parameters exceeds ANSI limit");
|
|
|
|
if (ecnt >= NPARAMS-1) {
|
|
|
|
error("too many parameters");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
estack[ecnt++] = &(ex->OP_RIGHT);
|
|
|
|
ep = &(ex->OP_LEFT);
|
|
|
|
ex = ex->OP_LEFT;
|
|
|
|
}
|
|
|
|
estack[ecnt++] = ep;
|
|
|
|
|
|
|
|
/* Declarations like int f(void) do not expect any
|
|
|
|
parameters.
|
|
|
|
*/
|
1989-09-19 16:13:23 +00:00
|
|
|
if (pl && pl->pl_flag & PL_VOID) {
|
1989-02-07 11:04:05 +00:00
|
|
|
strict("no parameters expected");
|
1989-02-07 13:16:02 +00:00
|
|
|
pl = NO_PROTO;
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* stack up the prototypes */
|
1989-02-07 13:16:02 +00:00
|
|
|
if (pl) {
|
|
|
|
do {
|
|
|
|
/* stack prototypes */
|
|
|
|
pstack[pcnt++] = pl;
|
|
|
|
pl = pl->next;
|
|
|
|
} while (pl);
|
|
|
|
pcnt--;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pcnt = 0;
|
|
|
|
pstack[0] = &ellipsis;
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (--ecnt; ecnt >= 0; ecnt--) {
|
|
|
|
/* Only the parameters specified in the prototype
|
|
|
|
are checked and converted. The parameters that
|
|
|
|
fall under the ellipsis clause are neither
|
|
|
|
checked nor converted !
|
|
|
|
*/
|
|
|
|
if (pcnt < 0) {
|
|
|
|
error("more parameters than specified in prototype");
|
|
|
|
break;
|
|
|
|
}
|
1989-09-19 16:13:23 +00:00
|
|
|
else if (!(pstack[pcnt]->pl_flag & PL_ELLIPSIS)) {
|
1989-09-25 14:28:10 +00:00
|
|
|
ch3cast(estack[ecnt],CASTAB,pstack[pcnt]->pl_type);
|
1989-02-07 11:04:05 +00:00
|
|
|
pcnt--;
|
|
|
|
} else
|
1989-02-07 13:16:02 +00:00
|
|
|
any2parameter(estack[ecnt]);
|
1989-02-07 11:04:05 +00:00
|
|
|
}
|
1989-09-19 16:13:23 +00:00
|
|
|
if (pcnt >= 0 && !(pstack[0]->pl_flag & PL_ELLIPSIS))
|
1989-02-07 11:04:05 +00:00
|
|
|
error("less parameters than specified in prototype");
|
|
|
|
|
|
|
|
} else {
|
1989-09-19 16:13:23 +00:00
|
|
|
if (pl && !(pl->pl_flag & PL_VOID))
|
1989-02-07 11:04:05 +00:00
|
|
|
error("less parameters than specified in prototype");
|
|
|
|
}
|
|
|
|
}
|