📄 ccdecl.c
字号:
/* CCDECL.C - Declaration Parser
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.371, 28-May-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.154, 8-Aug-1985
**
** Original version (C) 1981 K. Chen
*/
#define _DEF_CHAR8 0 /* define this to default char to char8 */
#include <limits.h> /* for INT_MAX */
#include "cc.h"
int strcmp (const char *, const char *);
extern SYMBOL *lsymhead; /* CCSYM - var indicating loc sym blk */
/* Imported functions */
extern SYMBOL *symfidstr(char *), *creatsym(char *), *uniqsym(SYMBOL *); /* CCSYM */
extern SYMBOL *findgsym(SYMBOL *); /* CCSYM */
extern SYMBOL *newlabel(void); /* CCSYM */
extern SYMBOL *symfxext(SYMBOL *); /* CCSYM */
extern SYMBOL *symftag(SYMBOL *); /* CCSYM */
extern SYMBOL *symfmember(SYMBOL *, SYMBOL *); /* CCSYM */
extern SYMBOL *symqcreat(SYMBOL *); /* CCSYM */
extern SYMBOL *isdupsym(SYMBOL *); /* CCSYM */
extern SYMBOL *beglsym(void); /* CCSYM */
extern TYPE *findctype(int, INT, unsigned INT, TYPE *),
*findtype(int, TYPE *), /* CCSYM */
*findftype(TYPE *, TYPE *), /* CCSYM */
*findptype(int, TYPE *, TYPE *); /* CCSYM */
extern TYPE *tcomposite(TYPE *, TYPE *); /* CCSYM */
extern int cmptype(TYPE *, TYPE *), cmputype(TYPE *, TYPE *); /* CCSYM */
extern INT sizetype(TYPE *); /* CCSYM */
extern void copysym(SYMBOL *, SYMBOL *), ridlsym(SYMBOL *); /* CCSYM */
extern void mapintsym(SYMBOL *); /* CCSYM */
extern int mapextsym(SYMBOL *); /* CCSYM */
extern void freesym(SYMBOL *); /* CCSYM */
extern NODE *evalexpr(NODE *); /* CCEVAL */
extern NODE *funstmt(void), *asgnexpr(void); /* CCSTMT */
extern NODE *exprconst(void); /* CCSTMT */
extern long pconst(void); /* CCSTMT */
extern NODE *convasgn(TYPE *, NODE *); /* CCTYPE */
extern TYPE *convfparam(TYPE *); /* CCTYPE */
extern int nextoken(void); /* CCLEX */
extern int expect (int); /* CCERR */
/* Exported functions */
void initpar(void); /* Called by CC mainline */
NODE *extdef(void); /* Called by CC mainline */
NODE *tntdef(void); /* Called by CC mainline */
NODE *ldecllist(void); /* CCSTMT for inner block declarations */
TYPE *typename(void); /* CCSTMT for cast and sizeof exprs */
SYMBOL *defauto(char *, TYPE *); /* CCSTMT for invisible struct return obj */
SYMBOL *funchk(int, int, SYMBOL *, SYMBOL *); /* CCSTMT for calls to undeclared functions */
struct protostate /* State block for prototype parse */
{
int nparams;
SYMBOL *shead, *stail; /* Parameter symbol list */
SYMBOL decl;
};
/* Internal functions */
static NODE *funcdef(SYMBOL *, SYMBOL *, SYMBOL *),
*datadef(SYMBOL *, SYMBOL *, SYMBOL *);
static void pdecllist(void), sdeclenum(SYMBOL *),
decllist(SYMBOL *,SYMBOL *,SYMBOL *,SYMBOL *,NODE **,NODE **);
static INT sdeclstruct(SYMBOL *, int), fldsize(int, INT *, int *),
pbase(SYMBOL *);
static TYPE *qualarray (TYPE *type, int flags, int *oldflags);
static int isdecl(void);
static TYPE *fundecl(SYMBOL *, int),
*paramlist(struct protostate
*),
*mkproto(SYMBOL *);
static void pidentlist(struct protostate
*);
static void plcmpare(TYPE *, TYPE *, int),
plcmpold(SYMBOL *, TYPE *, TYPE *), plcheck(TYPE *);
static NODE *dodecl(int, SYMBOL *, SYMBOL *);
static SYMBOL *declarator(SYMBOL *);
static TYPE *addpp(TYPE *, TYPE *), *pushsztype(int, INT, INT, TYPE *),
*tagspec(int);
static SYMBOL *sdeclaration(SYMBOL *, SYMBOL *, INT *, int *, int *);
static NODE *pizer(SYMBOL *);
static void errtwotyp(SYMBOL *, SYMBOL *), errdupsym(SYMBOL *);
static TYPE *mkprox(SYMBOL *);
static int nsetjmps(void);
static NODE *piztype(TYPE *, int), *chkarith(TYPE *, NODE *, int, int),
*pizstruct(TYPE *, int, int), *pizarray(TYPE *, int),
*pexizer(int), *pizlist(void);
static void pizflush(int);
static int isauto(SYMBOL *), nisconst(NODE *);
static void Set_Register(SYMBOL *, int, int);
/* Internal data */
static int paramok; /* True if OK to parse parameter list for a function
** definition. Only true when at top
** level and parsing the first declarator.
*/
static int inproto; /* True when parsing a function prototype list.
** This is bumped to indicate level.
*/
static NODE *statdecls, /* Pointer to list of static decls within current fn */
*stattail; /* Pointer to tail of statdecls list */
static int nsdefs; /* # of enum/struct/union side effect definitions seen.
** The exact number doesn't matter; this is only used
** to tell when a type-specifier has had the side
** effect of defining a tag or enum constant.
*/
static int itags; /* # of internal tags defined. This is used only
** to create unique names for internal tags.
*/
static int tntcnt; /* # of tentative defs output. Only used to initialize
** tntdef(), by setting to -1.
*/
#if 0
/* Flags returned from pbase(). */
/* These aren't really used yet, maybe should be flushed. */
#define BASEF_SC 01 /* Storage class parsed */
#define BASEF_TS 02 /* Type-specifier parsed */
#define BASEF_TAG 04 /* enum/struct/union tag was defined as side effect */
/* Also not really used yet */
typedef struct
{
int Dflags;
SYMBOL *Dpnext, *Dpsblk;
SYMBOL s;
}
declsym;
#define DSname s.Sname
#define DSvalue s.Svalue
#define DSclass s.Sclass
#define DStype s.Stype
#endif
/* INITPAR - Initialize parser
** Called once for each file compiled.
*/
void
initpar(void)
{
nodeinit(); /* No parse-tree nodes used */
curfn = NULL; /* Not in any function yet */
itags = 0; /* Reset internal tag count for gensyms */
nsdefs = 0; /* Reset side-effect def count for neatness */
tntcnt = -1; /* Reset tntdef() */
}
/* EXTDEF() - Parse top-level declaration or definition
** [dpANS 3.7, 3.5]
**
** <external-decl> ::= <function-definition> | <decl>
**
** <function-definition> ::=
** {decl-specs} <declor> {decl-list} <compound-stmt>
**
** <decl> ::= <decl-specs> {init-decl-list} ';'
**
** <init-decl-list> ::= <init-declor> {',' init-decl-list}
** <init-declor> ::= <declor> {'=' izer}
**
** This is the main entry to input parser. Current token is the
** first one of the <external-decl>. Since both possibilities (function
** def or a decl) can start with <decl-specs>, we parse for that first.
** If there was nothing but <decl-specs>, we can just return. Otherwise
** the initially parsed "base" needs to be passed on for further parsing.
*/
NODE*
extdef (void)
{
SYMBOL* s;
SYMBOL tempsym;
SYMBOL base;
/* Do top level initializations */
paramok = 1; /* OK to parse a function parameter list */
inproto = 0; /* Not in prototype scope */
curfnnew = fline; /* Remember line in file where funct started*/
_reg_count = 0; /* Count of "preserved" registers used */
/* for register variables */
pbase(&base); /* Parse base (storage class & type) */
if (token == T_SCOLON) /* Only got a type (struct)? */
{
if ((base.Sflags&SF_SIDEFF) == 0) /* If no side effs, */
error("Null declaration");
switch (base.Sclass)
{
case SC_UNDEF:
break; /* None given */
case SC_AUTO:
case SC_RAUTO:
error("Illegal storage class");
break;
default:
note("Useless storage class");
break;
}
nextoken(); /* Skip over the semicolon */
return NULL; /* and stop doing this def */
}
/* Parsed <decl-specs>, now look for <declor> to determine whether
** we're doing a function def or not.
*/
copysym(&tempsym, &base); /* Copy base storage class & type */
if (tempsym.Sclass == SC_UNDEF) /* Set up for defaults */
tempsym.Sclass = SC_EXLINK; /* Default stg class: extern */
if (tempsym.Stype == NULL)
tempsym.Stype = deftype; /* Default type: int */
while ((s = declarator(&tempsym)) == NULL)/* Until we find declarator */
/* No declarator found, may want to loop. */
{
error("Null declarator, expecting ident");
if (tempsym.Spmnext) /* Flush param syms if any (in case)*/
ridlsym((SYMBOL *)NULL);
if (token == T_COMMA) /* Only continue if hit comma */
{
nextoken(); /* in which case skip over it */
continue; /* and try again */
}
if (token != T_SCOLON) /* Else give up on it */
error("Bad syntax for top-level declaration");
/* 9/91 infinite loop if test for T_RBRACE also (SPR 9579) */
while (token != T_EOF && token != T_SCOLON)
nextoken(); /* Flush to probable end of stmt */
return NULL;
}
paramok = 0; /* No longer OK to parse function param list */
/* If function type, need to examine more closely to see whether this
** is a definition or just a forward-reference declaration.
** It is a definition only if the current token is one of:
** Left brace (start of function body)
** A type-specifier keyword (a function parameter declaration).
** The "register" keyword (only permissible storage class for
** function parameter declarations).
** We permit any storage class here, for better error diagnostics later.
*/
if (tempsym.Stype->Tspec == TS_FUNCT)
{
if (token == T_LBRACE || isdecl())
return funcdef(&base, &tempsym, s); /* Parse funct def */
}
/* Not a function definition, so is either a function reference, or a
** data definition/reference.
*/
return datadef(&base, &tempsym, s); /* data def/ref or function ref */
}
/* TNTDEF - Return next remaining tentative definition, if any.
** This is only invoked by the CC mainline after all input parsing
** is completed for a file. It scans for all tentative definitions
** with internal or external linkage, and for each one returns a
** node that defines it with a zero initializer.
*/
NODE *
tntdef(void)
{
static SYMBOL *s;
if (++tntcnt == 0) /* If first time, */
s = symbol; /* start scanning global sym list */
while ((s = s->Snext) != NULL)
{
switch (s->Sclass)
{
default:
continue;
case SC_INTREF: /* Should only exist for functions */
if (s->Srefs)
error("Static function %S not defined", s);
else
note("Static function %S not defined or used", s);
continue;
case SC_INTDEF: /* May be function or object */
if (s->Srefs == 0)
note("Static %s %S never used",
(s->Stype->Tspec != TS_FUNCT ? "object" : "function"),
s);
continue;
case SC_INLINK:
s->Sclass = SC_INTDEF;
if (s->Srefs) /* Ensure internal object was used */
break; /* Yup, go define it */
note("Static object %S never used, not emitted", s);
continue;
case SC_EXLINK:
s->Sclass = SC_EXTDEF; /* Always do it if external linkage */
break;
}
/* Set up a Q_IDENT and a null izer definition for it */
return ndefl(N_DATA, ndefl(N_IZ, ndefident(s)));
}
return NULL;
}
/* FUNCDEF() - Parse function definition
** [dpANS 3.7.1]
** <function-definition> ::=
** {decl-specs} <declor> {decl-list} <compound-stmt>
**
** Only called from extdef() when a function declaration turns out
** to be the start of a definition. At this point, the current token
** is the first one past the <declor>.
**
** The first two pointer args always point to temporary symbol
** structures not in the symbol table. However, the parameter list
** symbols ARE in the table, chained as local symbols.
*/
static NODE *
funcdef(SYMBOL *b, SYMBOL *d, SYMBOL *syment)
/* Base, contains parsed <decl-specs>,
* Defaulted <decl-specs> plus <declor> type
* Identifier's symtab entry
*/
{
INT n, siz;
int nsjmps;
NODE *nnode, *header;
SYMBOL *s1;
SYMBOL *args = d->Spmnext; /* List of parameter syms */
int npartypes = (int) d->Svalue; /* # of params if new-style proto */
int nparidents = 0;
NODE *nreg;
/* "syment" points to the function name's symtab entry.
** Lexer will have created the symtab entry with
** class SC_UNDEF if it didn't already exist.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -