📄 ccdecl.c
字号:
if (strcmp(syment->Sname, "main") == 0)
fn_main = (char) ~0; // FW KCC-NT
else
fn_main = 0;
if (!args) /*If no arglist, need to open local sym blk */
(void) beglsym(); /* (needn't remember start) */
curfnloc = curfnnew;
/* Remember context for error messages */
curfn = syment = funchk(1, b->Sclass, d, syment); /* Do funct decl */
/* which may update symbol and may also */
/* do old-style <decl-list> parse! */
/* Now that types are set, add up sizes and determine offsets for
** each parameter. Also, for new-style function prototype defs, make
** sure that every parameter had an identifier associated with it.
** We do this by comparing the # of identifiers on the paramlist with
** the # of parameters that paramlist() actually parsed while building
** the prototype.
*/
n = 0; /* set up for first arg */
siz = sizetype(syment->Stype->Tsubt); /* get size of return val */
if (siz > 2) /* If returning too-large object, */
n = 1; /* just use struct-return pointer */
while (args != NULL)
{
nparidents++; /* Count # of param idents */
s1 = args; /* get arg symbol */
args = args->Spmnext; /* Move on before zapping it! */
n += sizetype(s1->Stype); /* count off by size */
s1->Svalue = n; /* set offset */
}
if (npartypes && (npartypes-1 != nparidents))
error("Missing identifier for parameter in function def");
maxauto = 0; /* no local variables yet */
stackrefs = 0; /* and therefore no refs to them */
nsjmps = nsetjmps(); /* Remember # of setjmp refs */
statdecls = stattail = NULL; /* No static declarations yet */
/* The big call. Parse function statement, having already set up a
** local symbol block with the parameters in it. On return, this
** block will have been ended, and the current token will be the
** T_RBRACE ('}') terminating the function body. See CCSTMT's
** compound() for further discussion.
*/
nnode = funstmt(); /* Parse function statement */
expect(T_RBRACE); /* Now safe to flush the right brace
** and set up new current token.
** See CCSTMT's compound() for discussion of this.
*/
stkgoto = (nsjmps != nsetjmps()); /* Say whether any setjmps in funct */
header = ndefop(N_NODE); /* Put together the function header */
header->Nright = statdecls; /* Point to any static decls found */
header->Nleft = ndefident(syment); /* Point to Q_IDENT function name */
/* Return completed parse tree */
nreg = ndeflr(N_FUNCTION, header, nnode);
nreg->Nreg = _reg_count;
return nreg;
}
/* NSETJMPS - Auxiliary to find current # of references to the "setjmp"
** function. Any functions which contain calls to setjmp have to
** avoid using tail recursion.
*/
static int
nsetjmps(void)
{
SYMBOL *s;
if ((s = symfidstr("setjmp")) != NULL)
{
--(s->Srefs); /* Not a real reference */
switch (s->Sclass)
{
case SC_EXTREF:
case SC_XEXTREF:
case SC_EXTDEF:
if (s->Stype->Tspec == TS_FUNCT)
return s->Srefs;
}
}
return 0;
}
/* FUNCHK - Check out a function definition or reference for
** proper use of storage class and type specifier.
** Called from funcdef() for a definition and dodecl() for a reference.
** Also called from CCSTMT's primary() to handle the pretend-declaration
** done for a call to an undeclared function.
**
** The parsed declarator symbol struct will have the following special
** members set (by fundecl()) if called from funcdef():
** Svalue - 0 if an old-style function identlist, N+1 if new-style proto,
** where N is the # of real parameters in the prototype.
** Spmnext - if non-NULL, points to a list of parameter identifiers
** and there is still a local symbol block active for the
** prototype scope. This block needs to be closed and the
** symbols flushed if this was only a reference.
** Spmhead - what beglsym() returned for the prototype scope block.
** These syms should be NULL if called from dodecl(), which flushes the
** prototype scope block itself.
**
** May parse the function's <decl-list> if doing an old-style definition.
** Returns with the symbol table entry completely set up, and returns
** pointer to the symbol since it may have changed.
*/
SYMBOL *
funchk(int def, int baseclass, SYMBOL *d, SYMBOL *s)
/* True if a definition
* Parsed base storage class
* Parsed declarator (Sclass and Stype)
* Symtab entry for parsed identifier
*/
{
/* Check out storage class.
** Parsing should have resulted in only one of the following three
** things: SC_UNDEF (none), SC_EXTREF (extern), SC_INTREF (static).
** For existing function def/refs, there are 5
** possible symbol classes:
** SC_EXTREF, SC_EXTDEF, SC_INTREF, SC_INTDEF, plus special case of
** normally invisible SC_XEXTREF.
*/
s = symfxext(s); /* Make SC_XEXTREF visible if any */
switch (baseclass) /* Not all storage classes are allowed */
{
default:
error("Illegal storage class for function, assuming \"extern\"");
return funchk(def, SC_EXTREF, d, s); /* Just call again */
case SC_INTREF: /* Explicit "static" */
/* dpANS: identifier always has internal linkage.
** Note this must not appear within block scope!
*/
if (!lsymhead || def)
{
/* At file-scope level, so "s" will be global */
d->Sclass = (def ? SC_INTDEF : SC_INTREF);
if (s->Sclass == SC_UNDEF /* No old sym */
|| s->Sclass == SC_INTREF /* Or not defined */
|| s->Sclass == SC_INTDEF) /* Or defd, reffing */
break; /* Linkage matches OK */
if (s->Sclass != SC_EXTREF && s->Sclass != SC_EXTDEF
&& s->Sclass != SC_XEXTREF)
{
error("Storage class conflict for \"%s\"", s->Sname);
break; /* Keep internal linkage */
}
warn("Linkage conflict for %S, is external", s);
/* Else fall thru as if SC_EXTREF */
}
else if (!def)
warn("Storage class for function decl in block must be \"extern\"");
/* Drop thru to assume extern and carry on */
case SC_UNDEF: /* dpANS: default same as explicit "extern" */
case SC_EXTREF: /* Explicit "extern" */
/* dpANS: linkage is same as any visible decl of this identifier
** with file scope (ie global). If none, linkage is external.
** If there is already an expired external reference (SC_XEXTREF)
** then we use that in order to emit advisory warnings if the type
** isn't the same.
*/
/* If doing a reference in block scope and function ident already
** belongs to a block-scope symbol, we:
** (1) see if a file-scope symbol exists (if so, use that one)
** (2) see if existing sym is external ref (if so, use that)
** (this includes SC_XEXTREF)
** (3) generate new file-scope symbol with SC_EXTREF.
*/
if (!def && (s->Sflags&SF_LOCAL))
{
SYMBOL *ns;
if ((ns = findgsym(s)) != NULL)/* If file-scope def/ref exists, */
s = ns; /* use that! */
else if (s->Sclass == SC_EXTREF)
; /* OK if a block-scope extern ref */
else
{
if (isdupsym(s)) /* If was defined in this block, */
errdupsym(s); /* barf! */
s = uniqsym(s); /* Create/re-use sym, now SC_UNDEF */
}
}
/* "s" now points to the sym linked to. If it has any linkage, we
** copy that, otherwise we use external linkage.
*/
switch (s->Sclass)
{
case SC_INTDEF:
case SC_INTREF:
d->Sclass = (def ? SC_INTDEF : SC_INTREF);
break;
default:
errdupsym(s);
s->Sclass = SC_UNDEF; /* Sigh! Smash it. */
/* Fall thru to handle as if extern */
case SC_XEXTREF:
case SC_EXTDEF:
case SC_EXTREF:
case SC_UNDEF:
d->Sclass = (def ? SC_EXTDEF : SC_EXTREF);
break;
}
break;
}
/* Check for duplicate function def */
if (def && (s->Sclass == SC_EXTDEF || s->Sclass == SC_INTDEF))
{
error("Duplicate function definition");
s->Sclass = SC_UNDEF; /* Wipe out previous definition! */
}
/* Handle simple case where sym hasn't yet been defined. */
if (s->Sclass == SC_UNDEF) /* Symbol not defined yet? */
{
if (!def)
s = uniqsym(s); /* No, ensure local if needed */
s->Sclass = d->Sclass; /* Copy the parsed class */
s->Stype = d->Stype; /* and the type specification */
s->Srefs = 0; /* and reset usage cnt in case a ref */
if (s->Sclass == SC_INTDEF || s->Sclass == SC_INTREF)
mapintsym(s); /* Set Smaplab (internal unique) */
else if (!mapextsym(s)) /* Else check external map */
error("External link name duplicated: %S", s);
if (def && !s->Stype->Tproto) /* If an old-style definition, */
{
pdecllist(); /* parse parameter declarations! */
s->Shproto = mkproto(d->Spmnext); /* Build invisible prototype */
}
else
s->Shproto = NULL; /* Say no hidden prototype */
return s; /* All done! */
}
/* There is an existing symbol for this identifier, with a matching
** storage class. Must now do lots of hairy type checking.
** First we see if old sym is a function returning a
** compatible type, then maybe check parameter list compatibility.
**
** If both are old-style, no param checking needed.
** If both are new-style, check their param lists.
** If one sym is old-style ref and other is new-style ref/def,
** just do simple check of the proto list.
** If one sym is old-style DEF, then:
** If this is more recent sym, parse decl-list into prototype
** and then compare param lists as if both were new-style.
** Else is previous sym -- compare with "hidden" prototype
** that was generated during the old-style function def.
*/
/* First make sure that basic type is also "function returning ..."
** and that return types are compatible.
*/
if (s->Stype->Tspec != TS_FUNCT
|| !cmptype(d->Stype->Tsubt, s->Stype->Tsubt))
{
/* Earlier ref/def conflicts with current one, smash to current. */
errtwotyp(d, s); /* Complain */
s->Stype = d->Stype; /* Skip prototype testing */
}
/* If doing an old-style definition, OK to parse decl-list now.
** The main reason for not doing this earlier is so error messages
** from the previous checks will show the most helpful context,
** i.e. errors are announced as soon as it is possible to detect them.
*/
if (def && !d->Stype->Tproto) /* If no proto was declared, */
{
pdecllist(); /* parse old-style decl-list */
s->Shproto = mkproto(d->Spmnext); /* Build invisible prototype */
}
/* Now see if the parameter lists need to be checked.
** Test for both old-style, or both with identical prototypes.
*/
if (d->Stype->Tproto != s->Stype->Tproto)
{
TYPE *tc;
if (d->Stype->Tproto && s->Stype->Tproto) /* Compare 2 protos? */
{
tc = tcomposite(d->Stype, s->Stype); /* Get composite */
if (tc)
d->Stype = tc; /* If won, use it! */
else
plcmpare(d->Stype->Tproto, s->Stype->Tproto, 0); /* Give err */
}
else if (d->Stype->Tproto)
{
/* Compare existing non-proto ref/def with new prototype */
if (s->Sclass == SC_EXTDEF || s->Sclass == SC_INTDEF)
{
/* Old-style DEF followed by new-style REF, use hidden proto */
if (!tcomposite(d->Stype, s->Stype)) /* If not compatible */
plcmpare(d->Stype->Tproto, s->Shproto, 1); /* Give err */
/* Don't use composite type, just the new prototype, so
** leave d->Stype alone.
*/
}
else /* Old-style REF followed by new-style proto */
plcheck(d->Stype->Tproto); /* Check new proto */
}
else
{
/* Compare existing proto with new non-proto ref/def */
if (def)
{
/* New-style REF followed by old-style DEF, compare params */
plcmpold(d->Spmnext, s->Shproto, s->Stype->Tproto);
}
else /* New-style ref/def followed by old-style REF */
plcheck(s->Stype->Tproto); /* Check previous proto */
d->Stype = s->Stype; /* Ensure proto retained */
}
}
/* Force the symbol table entry to match current declaration.
** Note that Srefs was incremented by the symbol lookup, hence needs
** to be set back if this was only a ref-type declaration.
** Also, if the existing symbol was a definition, don't change its
** class.
*/
s->Stype = d->Stype; /* Force the type specification */
if (!def) /* If this decl was just a ref, */
--(s->Srefs); /* then usage count to undo lookup bump */
if (s->Sclass != SC_EXTDEF && s->Sclass != SC_INTDEF)
s->Sclass = d->Sclass; /* Force the storage class */
return s;
}
/* PLCMPARE - Compare two prototype parameter lists.
*/
static void
plcmpare(TYPE *t1, TYPE *t2, int flag)
/* flag is 0 if both protos, 1 if t2 is fake proto */
{
int n;
if (t1 == t2)
return;
/* If pointers don't match, prototypes aren't compatible. Examine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -