⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccdecl.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -