Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/kcc/ccstmt.c
There are 8 other files named ccstmt.c in the archive. Click here to see a list.
/* <KCC.CC>CCSTMT.C.97, 3-Jul-85 10:55:02, Edit by KRONJ */
/* Warn about unique but global struct members */
/* <KCC.CC>CCSTMT.C.93, 30-Jun-85 14:32:56, Edit by KRONJ */
/* Make x[y] work more like *(x+y) -- don't force x ptr, y int */
/* <KCC.CC>CCSTMT.C.91, 27-Jun-85 14:17:22, Edit by KRONJ */
/* Make & op in function/array ident explicit in parse tree */
/* <KCC.CC>CCSTMT.C.90, 26-Jun-85 18:11:41, Edit by KRONJ */
/* Warn about (w? x, y : z) -- precedence of comma is lower than (?:) */
/* <KCC.CC>CCSTMT.C.88, 26-Jun-85 13:43:04, Edit by KRONJ */
/* array ident isn't lvalue */
/*
** ccstmt - Statement and expression parser for KCC
** (C) 1981 K. Chen
*/
#include "cc.h"
extern struct TY *typename(), *findtype();
extern node typecheck();
extern struct SYMBOL *creatloc(), *newlabel();
node defnode(), conditional(), whilestmt(), dostmt(), forstmt(), switchstmt(),
casestmt(), defaultstmt(), returnstmt(), unary(), compound(), gotostmt();
/*
** Parse expression
** Ref. [1] A.9.1
*/
node expression()
{
struct NODE *ternary(), *l, *r, *fold();
int op;
l = ternary(); /* parse lower priority part of expr */
if (tok[token].ttype == ASOP) { /* if we now have an assignment op */
if (!(l->nflag & LVALUE)) /* make sure can asgn to left side */
error (ELVALUE, "left operand of assignment"); /* not, complain */
op = token; /* get the assignment op */
nextoken(); /* and move on in the token world */
r = expression(); /* parse right side of assignment */
if (r->ntype->ttype == VOID) { /* make sure we have a real value */
error (EVOID, "right operand of assignment"); /* not, complain */
r->ntype = deftype; /* and fix up for next check */
}
l = typecheck(defnode(N3, op, l->ntype, 0, l, r));
}
return fold(l); /* rearrange a bit, fix consts */
}
/*
** Parse expression list
** Ref. [1] A.7.1
*/
node exprlist()
{
node s, t;
t = expression(); /* get first expression */
optexpr (t); /* rearrange some */
if (token != COMMA) return t; /* if no comma, that's it */
/*
** We have an expression followed by a comma, parse the whole list.
**
** We terminate it with a NULL (as with LISP lists) to distinguish
** ((1, 2), 3) from (1, 2, 3) in function call argument lists.
*/
s = NULL; /* start with chain empty, expr in t */
while (1) { /* until we break out with return */
s = defnode (N3, EXPRESS, t->ntype, 0, s, t); /* chain expr */
if (token != COMMA) return s; /* if no comma, that's it */
nextoken(); /* pass over comma */
t = expression(); /* parse another expression */
optexpr (t); /* and rearrange it some */
}
}
/*
** Parse statement
** Ref. [1] A.9
*/
node statement()
{
struct SYMBOL *sym, *nlabel, *plabel();
node s;
int tokn;
sym = csymbol; /* get last symbol if any */
tokn = token; /* and last token */
nextoken(); /* now we can move on to next one */
switch (tokn) { /* look at the token we were at */
case CASE: return casestmt(); /* stmts with parser fns: case */
case DEFAULT: return defaultstmt(); /* and default */
case DO: return dostmt(); /* and do */
case FOR: return forstmt(); /* and for */
case IF: return conditional(); /* and if */
case RETURN: return returnstmt(); /* and return */
case SWITCH: return switchstmt(); /* and switch */
case WHILE: return whilestmt(); /* and while */
case GOTO: return gotostmt(); /* and goto */
case LBRACE: return compound(); /* open bracket, parse compound stmt */
case SCOLON: return NULL; /* semicolon is just null statement */
case BREAK: case CONTINUE: /* break and continue are similar */
if (breaklevel == 0) error (tokn == BREAK? EBREAK : ECONTINUE);
expect(SCOLON); /* it's followed by a semicolon */
return defnode (N1, tokn); /* that's all for break */
case IDENT: /* identifier might be label */
if (token == COLON) { /* it is if followed by colon */
nextoken(); /* skip over lab: */
nlabel = plabel (sym, 1); /* get label symbol number */
return defnode (N3, LABEL, 0, nlabel, statement()); /* make lab */
} /* otherwise fall through to expr */
default:
tokpush (tokn, sym); /* not stmt token, assume expression */
s = exprlist(); /* push back and parse expr list */
expect (SCOLON); /* followed by semicolon */
return s;
case EOF: /* catch premature EOF */
fatal (EEOF); /* complain and die */
}
}
/*
** Define a parse tree node
**
** The first argument is how many of the type, flag, llink, and rlink fields
** are actually given with this call:
** N1 -- none of them are given (arg list ends with op)
** N2 -- type, flag, and llink are given but not rlink
** N3 -- all four of type, flag, llink, and rlink are given
*/
node defnode (n, op, type, flag, llink, rlink)
node llink, rlink;
struct TY *type;
{
node nd;
nd = &nodes[maxnode++]; /* get a new node from the list */
if (maxnode >= MAXNODE) fatal (EBIGFN); /* make sure we didn't run out */
nd->nop = op; /* always put operation in */
nd->endlab = 0; /* nowhere to go yet */
switch (n) {
case N1: /* op without operands (e.g. BREAK) */
nd->ntype = NULL; /* has no type */
nd->nflag = 0; /* or flag */
nd->left = nd->right = NULL; /* or left and right pointers */
return nd;
case N2: /* op with one operand (e.g. INC) */
nd->ntype = type; /* set type */
nd->nflag = flag; /* and flag */
nd->left = llink; /* and llink from arguments */
nd->right = NULL; /* but no rlink is wanted or given */
return nd;
case N3: /* op with two operands (e.g. PLUS) */
nd->ntype = type; /* set type */
nd->nflag = flag; /* and flag */
nd->left = llink; /* and llink */
nd->right = rlink; /* and rlink from arguments */
return nd;
}
}
/* ----------------------------------------------- */
/* conditional statement Ref.[1] A.9.3 */
/* ----------------------------------------------- */
node conditional()
{
struct NODE *cond, *then, *elsec;
expect(LPAREN);
cond = exprlist();
expect(RPAREN);
if (tsize (cond->ntype) != 1) error (EINT, "if condition");
then = statement();
if (token == ELSE) {
nextoken();
elsec = statement();
} else elsec = NULL;
return defnode(N3, IF, NULL, 0, cond,
defnode(N3, 0, NULL, 0, then, elsec));
}
/* ----------------------------------------- */
/* while statement Ref.[1] A.9.4 */
/* ----------------------------------------- */
node whilestmt()
{
struct NODE *cond, *stmt;
expect(LPAREN);
cond = exprlist();
if (tsize (cond->ntype) != 1) error (EINT, "while condition");
expect(RPAREN);
breaklevel++;
contlevel++;
stmt = statement();
breaklevel--;
contlevel--;
return defnode(N3, WHILE, NULL, 0, cond, stmt);
}
/* -------------------------------------- */
/* do statement Ref.[1] A.9.5 */
/* -------------------------------------- */
node dostmt()
{
struct NODE *cond, *stmt;
contlevel++;
breaklevel++;
stmt = statement();
breaklevel--;
contlevel--;
expect(WHILE);
expect(LPAREN);
cond = exprlist();
if (tsize (cond->ntype) != 1) error (EINT, "do condition");
expect(RPAREN);
expect(SCOLON);
return defnode(N3, DO, NULL, 0, cond, stmt);
}
/* --------------------------------------- */
/* for statement Ref.[1] A.9.6 */
/* --------------------------------------- */
node forstmt()
{
struct NODE *preamble, *e1, *e2, *e3, *s;
e1 = e2 = e3 = NULL;
expect(LPAREN);
if (token != SCOLON) e1 = exprlist();
expect(SCOLON);
if (token != SCOLON) e2 = exprlist();
if (e2 != NULL && tsize (e2->ntype) != 1) error (EINT, "for condition");
expect(SCOLON);
if (token != RPAREN) e3 = exprlist();
expect(RPAREN);
contlevel++;
breaklevel++;
s = statement();
breaklevel--;
contlevel--;
preamble = defnode(N3, 0, NULL, 0, e1, e2);
preamble = defnode(N3, 0, NULL, 0, preamble, defnode(N2, 0, NULL, 0, e3));
return defnode(N3, FOR, NULL, 0, preamble, s);
}
/* ------------------------------------------ */
/* switch statement Ref.[1] A.9.7 */
/* ------------------------------------------ */
node switchstmt()
{
node cond, stmt, savdef, savcase;
int savrange;
expect(LPAREN);
cond = exprlist();
expect(RPAREN);
if (tsize (cond->ntype) != 1) error (EINT, "switch value");
caselevel++;
breaklevel++;
savdef = swdefault;
savcase = swcases;
savrange = swrange;
swdefault = swcases = NULL;
swrange = -1; /* all bits for now */
if (cond->nop == ANDT) { /* but check for const AND */
if (cond->left->nop == ICONST) swrange &= cond->left->niconst;
if (cond->right->nop == ICONST) swrange &= cond->right->niconst;
}
stmt = statement();
caselevel--;
breaklevel--;
swdefault = savdef;
swcases = savcase;
swrange = savrange;
return defnode(N3, SWITCH, NULL, 0, cond, stmt);
}
/*
** Parse case label
** Ref. [1] A.9.7
*/
node casestmt()
{
node n, this, old;
n = exprlist(); /* parse value for this case */
if (caselevel == 0) { /* make sure in switch stmt */
error (ECASE); /* not, so give error */
n = NULL; /* and disable further checks */
}
this = defnode (N3, CASE, deftype, 0, NULL, swcases);
/*
** Perform various checks on the new case value.
**
** If it's NULL, then there was some error that's already been reported.
** Otherwise, it must be a constant, and one that hasn't been seen before
** in this switch(). We also make sure that, if the value being tested
** is a bitwise AND with a constant, the case value can happen as a result.
*/
if (n == NULL) ; /* already complained, don't redo */
else if (n->nop != ICONST) error (ECONST); /* make sure we have constant */
else { /* do, can perform further checks */
for (old = swcases; old != NULL; old = old->right) /* go through */
if (old->nflag == n->niconst) { /* checking for same value */
error (EDUPCASE, n->niconst); /* complain if duplicate */
break; /* but only complain once */
}
if (old == NULL) { /* do this unless it was a dup */
if ((n->niconst & swrange) != n->niconst)
warn (ECASERNG, n->niconst); /* check range of AND */
this->nflag = n->niconst; /* now safe to set case value */
swcases = this; /* add to list of known cases */
}
}
/* checked value and set in list of cases, parse rest of case statement */
expect (COLON); /* colon comes after expression */
this->left = statement(); /* only parse after setting swcases */
return this; /* return with whole of case stmt */
}
/*
** Parse default label for switch
** Ref. [1] A.9.7
*/
node defaultstmt()
{
node n;
if (caselevel == 0) error (ECASE);
else if (swdefault != NULL) error (EDUPDEF);
expect(COLON);
swdefault = n = defnode (N2, DEFAULT, deftype, 0, NULL);
n->left = statement();
return n;
}
/* ------------------------------------------- */
/* return statement Ref.[1] A.9.10 */
/* ------------------------------------------- */
node returnstmt()
{
node e;
if (token == SCOLON) e = defnode (N1, RETURN);
else e = typecheck (defnode (N3, RETURN, NULL, 0, NULL, exprlist()));
expect(SCOLON);
return e;
}
/* -------------------------- */
/* primary operator */
/* -------------------------- */
node primary()
{
int op, ty, off;
char temp[16];
node n, s;
struct TY *tp;
struct SMEM *sm;
struct SYMBOL *sy, *findsym();
switch (token) {
case IDENT:
sy = csymbol;
nextoken();
switch (sy->sclass) {
case SENUM:
n = defnode(N2, ICONST, deftype, 0, NULL);
n->niconst = sy->svalue;
break;
case SUNDEF:
if (token != LPAREN) {
n = NULL;
error(EUNDEF, sy->sname);
freesym(sy);
break;
}
sy->sptr = findtype (FUNCTION, PTRSIZE, deftype);
sy->sclass = SEXTERN;
sy->svalue = 0;
default:
n = defnode(N2, IDENT, sy->sptr, 0, sy);
if (sy->sclass != SAUTO && sy->sclass != SARG) n->nflag |= GLOBAL;
n->nflag |= LVALUE;
if (sy->sptr->ttype == ARRAY || sy->sptr->ttype == FUNCTION) {
n = defnode (N2, ADDR, NULL, 0, n);
if (sy->sptr->ttype == ARRAY)
n->ntype = findtype (PTR, sy->sptr->tsize, sy->sptr->tptr);
else n->ntype = findtype (PTR, 0, sy->sptr);
if (!(n->left->nflag & GLOBAL)) { /* make explicit addr op */
stackrefs++; /* and count stack ref if necess */
n->nflag |= STKREF;
}
}
}
break;
case CONST:
n = defnode(N2, CONST, constant.ctype, 0, NULL);
switch (constant.ctype->ttype) {
case INT:
n->nop = ICONST;
n->niconst = constant.cvalue;
break;
case PTR:
n->nop = SCONST;
n->nsconst = constant.csptr; /* get pointer */
n->nsclen = constant.cvalue; /* and num chars */
n->ntype = strtype;
break;
case FLOAT:
n->nop = DCONST;
n->nmantissa = constant.cmantissa;
n->nexponent = constant.cexponent;
}
nextoken();
break;
case LPAREN:
/* first check for type coercion */
nextoken();
if (csymbol != NULL) switch (csymbol->sclass) {
case SRW: /* res word might be coercion */
if (csymbol->skey != TYPESPEC && csymbol->skey != SUSPEC) break;
case STYPEDEF: /* typedef is always coercion */
tp = typename(); /* get result type */
expect(RPAREN); /* followed by close paren */
n = unary(); /* parse expression to coerce */
op = coertype(tp, n->ntype); /* find out which coercion to use */
if (op != NOCOER) {
n = defnode(N2, COERCE, tp, 0, n); /* make coercion */
n->nc = op; /* of given type */
} else n->ntype = tp; /* or set type in null coercion */
return n; /* and return with the node */
}
/* not a coercion, parse parenthesized expr */
n = exprlist(); /* get expr list in parens */
n->nflag |= INPARENS; /* no longer bare comma or whatever */
expect(RPAREN); /* followed by close paren */
break;
default:
error(EPRIM);
return;
}
while (1) {
switch (token) {
case LPAREN:
nextoken();
n = typecheck(defnode(N3, FNCALL, n->ntype, 0, n,
(token != RPAREN) ? exprlist() : NULL));
expect(RPAREN);
break;
case LBRACK:
nextoken();
n = typecheck (defnode (N3, PLUS, n->ntype,
n->nflag, exprlist(), n));
tp = n->ntype; /* get type back, make sure ptr */
if (tp->ttype != ARRAY && tp->ttype != PTR) error (EARRAY);
tp = tp->tptr; /* deref so only care what it pts to */
if (tp->ttype == ARRAY) n->ntype = tp; /* take out lvl of array */
else {
if (n->nflag & STKREF) { /* if we had a stack address */
stackrefs--; /* forget about it */
n->nflag &=~ STKREF; /* but don't do it twice */
} else n->nflag |= GLOBAL; /* not stack, stay off stack */
n = defnode(N2, PTR, tp, n->nflag | LVALUE, n);
}
expect(RBRACK);
break;
case DOT:
case MEMBER:
op = token;
nextoken();
if (token != IDENT) error(EMEMBER);
else {
/* check that identifiers are indeed usable */
tp = n->ntype;
if (op == MEMBER) tp = tp->tptr;
if (tp->ttype != STRUCT && tp->ttype != UNION)
error ((op == MEMBER? EPSTRUCT : ESTRUCT), csymbol->sname);
/* look up member name in symbol table */
symcpy(temp, "#"); /* change identifier into a member */
symapp(temp, csymbol->sname); /* with the same name */
if (csymbol->sclass == SUNDEF) freesym(csymbol);
csymbol = findsym(temp);
if (csymbol->sclass != SMEMBER) { /* not a known member? */
error(EUNKMEM, temp + 1); /* no, complain */
if (csymbol->sclass == SUNDEF) freesym (csymbol);
off = 0; /* no offset for missing symbol */
tp = deftype; /* use integer for type of result */
} else {
/*
** Find type and offset of member
**
** If all uses of this structure member have the same
** type and offset, we are safe in using K&R style
** global structure member addressing (however we still
** give a warning to discourage this practice).
**
** Otherwise (if the given offset is AMBIGMEM) we must
** use new style addressing where each offset is local
** to a given struct type, and can't be used in any
** other struct type.
*/
for (sm = SMEMS(tp); ; sm = sm->smnext) {
if (sm == NULL) { /* not found in any of them */
off = csymbol->svalue; /* so get global value */
tp = csymbol->sptr; /* and type */
if (off == AMBIGMEM) /* global, maybe ambiguous */
error (EDMEM, csymbol->sname + 1);
else warn (EGMEM, csymbol->sname + 1);
} else if (sm->smem == csymbol) {
tp = sm->smtype;
off = sm->smoffset;
} else continue; /* no match, search on */
break; /* null or found, exit loop */
}
}
/*
** Define the dot or member op
**
** The flags remain the same for DOT, but MEMBER involves
** a deferencing and so can undo a stackref or make a
** non-stackref safe from future address-taking.
*/
n = defnode (N3, op, tp, n->nflag, n, off);
if (op == MEMBER) {
n->nflag |= LVALUE; /* address of a->b can be taken */
if (n->nflag & STKREF) {
stackrefs--; /* (&x)->y for x on stack */
n->nflag &=~ STKREF; /* dereferences address op */
} else n->nflag |= GLOBAL; /* otherwise not on stack */
}
/*
** Do special handling for member type == ARRAY
**
** If the struct was returned from some function,
** we can't take the addresses of parts of it.
** It should be possible to do foo().x[i] even
** though we can't do foo().x, but it's too hard
** to do right, so we don't do it at all.
**
** If the struct is local, we have to adjust stackrefs.
*/
if (tp->ttype == ARRAY) {
if (!(n->nflag & LVALUE)) /* must be able to take addr */
error (ELVALUE, "array ref in struct");
n->nflag &=~ LVALUE;
if (!(n->nflag & GLOBAL)) {
stackrefs++; /* and count stack ref if necess */
n->nflag |= STKREF;
}
n = defnode (N2, ADDR, findtype (PTR, tp->tsize, tp->tptr),
n->nflag &~ LVALUE, n);
}
nextoken(); /* now safe to skip over token */
}
break;
case INC:
case DEC:
tp = n->ntype->tptr;
n = defnode(N2, token, n->ntype, 0, n);
n->nsize = (tp == NULL) ? 1 : tsize(tp);
nextoken();
break;
default:
return n;
}
}
return n;
}
/* ------------------------- */
/* unary operators */
/* ------------------------- */
node unary()
{
struct SYMBOL *tag, *findsym();
struct TY *typename(), *typespec(), *t;
struct NODE *n, *m;
int op, scl, k, s;
char sname[32];
switch (token) {
case MPLY: /* unary asterisk */
op = PTR;
break;
case ANDT: /* unary ampersand */
op = ADDR;
break;
case MINUS:
op = NEG;
break;
case INC:
op = PINC;
break;
case DEC:
op = PDEC;
break;
case NOT:
case COMPL:
op = token;
break;
case SIZEOF:
nextoken();
if (token == LPAREN) {
nextoken();
switch (csymbol->skey) {
case TYPESPEC:
case SUSPEC:
t = typename();
break;
default:
if (token == IDENT && csymbol->sclass == STYPEDEF) {
t = typename();
} else {
n = exprlist();
t = n->ntype;
}
}
expect(RPAREN);
} else {
n = unary();
t = n->ntype;
}
n = defnode(N1, ICONST); /* get node for integer constant */
n->ntype = deftype;
if (t->ttype == PTR && t->tsize != 0) /* if array made up as pointer */
t = findtype (ARRAY, t->tsize, t->tptr); /* make array again */
if (t->ttype == CHAR) n->niconst = 1; /* char takes one byte */
else if (chararray(t)) n->niconst = bsize(t); /* char array, n bytes */
else n->niconst = tsize(t)*NBYTES; /* all else, times bytes per word */
return n; /* return the filled in const node */
default:
return primary();
}
nextoken();
n = unary();
if (n->ntype->ttype == VOID) error (EVOID, "unary operand");
n = defnode(N2, op, n->ntype, 0, n);
switch (op) {
case NOT:
case COMPL:
return typecheck (n);
case ADDR:
if (!(n->left->nflag & GLOBAL)) { /* address of something not known */
stackrefs++; /* to be non-stack, so count as a */
n->nflag |= STKREF; /* stack reference */
}
if (!(n->left->nflag & LVALUE)) error(ELVALUE, "operand of &(.)");
n->ntype = findtype (PTR, 0, n->ntype); /* add ref to type */
break;
case PTR:
if (n->ntype->ttype != PTR && n->ntype->ttype != ARRAY) error(EPTR);
else n->ntype = n->ntype->tptr;
if (n->left->nflag & STKREF) stackrefs--; /* ptr cancels addr */
else n->nflag |= GLOBAL; /* not stack addr so must be global */
n->nflag |= LVALUE; /* ptr is always lvalue */
break;
case PINC: case PDEC:
t = n->ntype->tptr;
n->nsize = (t == NULL) ? 1 : tsize(t);
}
return n;
}
/* ----------------------------------------- */
/* binary operator Ref.[1] A.18.1 */
/* ----------------------------------------- */
node binary(prec)
{
int r, op, typ;
struct NODE *f;
f = unary();
while ((typ = tok[token].ttype) == BINOP || typ == BOOLOP) {
if ((r = tok[token].tprec) <= prec) break;
op = token;
nextoken();
f = typecheck(defnode(N3, op, f->ntype, 0, f, binary(r)));
if (f->left->ntype->ttype == VOID || f->right->ntype->ttype == VOID) {
error (EVOID, "binary operand");
f->left->ntype = f->right->ntype = f->ntype = deftype;
}
if (typ == BOOLOP) { /* stack is safe from comparisons */
if (f->left->nflag & STKREF) stackrefs--;
if (f->right->nflag & STKREF) stackrefs--;
f->nflag |= WASCOMP; /* remember comparison */
}
if ((f->nop == ANDT || f->nop == OR) &&
(((f->left->nflag & WASCOMP) && !(f->left->nflag & INPARENS)) ||
((f->right->nflag & WASCOMP) && !(f->right->nflag & INPARENS))))
warn (EBITPREC); /* likely lossage with & precedence */
}
return f;
}
integral(t)
struct TY *t;
{
switch (t->ttype) {
case INT: case CHAR: case SHORT: case LONG:
return 1;
default:
return 0;
}
}
/* -------------------------- */
/* ternary operator */
/* -------------------------- */
node ternary()
{
struct NODE *c, *t;
c = binary(1);
if (token != QUERY) return c;
nextoken();
if (tsize (c->ntype) != 1) error(EINT, "(?:) selector");
t = exprlist();
if (t->nop == EXPRESS && !(t->nflag & INPARENS)) warn (ETERNPREC);
expect(COLON);
return defnode(N3, QUERY, t->ntype, 0, c,
defnode(N3, 0, t->ntype, 0, t, expression()));
}
/* -------------------------------------------- */
/* compound statement Ref.[1] A.9.2 */
/* -------------------------------------------- */
node compound()
{
struct SYMBOL *savemin;
struct NODE *u;
decls = NULL;
savemin = loctail;
decllist();
u = decls;
while (token != RBRACE) u = defnode(N3,STATEMENT,NULL,0,statement(),u);
nextoken();
scopeauto(savemin);
return u;
}
/* ----------------------------------------- */
/* goto statement Ref.[1] A.9.11 */
/* ----------------------------------------- */
node gotostmt()
{
node n;
struct SYMBOL *s;
s = csymbol;
expect(IDENT); /* goto lab */
n = defnode(N2, GOTO, NULL, plabel(s, 0), NULL);
expect(SCOLON); /* goto lab; */
return n;
}
/* --------------------- */
/* parse label */
/* --------------------- */
static struct SYMBOL *
plabel (sym, defp)
struct SYMBOL *sym;
{
char s[32];
if (sym == NULL) return 0; /* already lost, don't barf twice */
symcpy(s, "@");
symapp(s, sym->sname); /* look up real goto name */
if (sym->sclass == SUNDEF) /* if undefined */
freesym(sym); /* get rid of the global symbol */
sym = findsym(s); /* find label symbol */
if (sym == NULL) { /* no such symbol, create it */
sym = creatloc(s);
sym->sclass = SULABEL;
sym->sval.ssym = newlabel (1); /* give it a real label number */
}
if (defp) {
if (sym->sclass == SLABEL) /* previously defined? */
error(EDUPLAB, sym->sname+1);
else
sym->sclass = SLABEL; /* if being defined, remember so */
}
return sym->sval.ssym; /* return the label symbol */
}
/* ------------------------------- */
/* return an lvalue flag */
/* ------------------------------- */
lvalue(s)
struct SYMBOL *s;
{
if (s->sclass == SENUM) return 0; /* enum tags are r-values */
return LVALUE; /* all other symbols are l-values */
}
/* --------------------------------- */
/* decide on type coercion */
/* --------------------------------- */
coertype(t,u)
struct TY *t, *u;
{
if (t == u) return NOCOER; /* don't coerce to self */
switch (t->ttype) { /* destination */
case ARRAY:
case PTR:
t = t->tptr;
case FUNCTION:
case FNDEF:
switch (u->ttype) { /* source */
case ARRAY:
case PTR:
u = u->tptr;
case FUNCTION:
case FNDEF:
if (t == u) return NOCOER;
if (t == chartype) return PI_PC;
if (u == chartype) return PC_PI;
return NOCOER;
case FLOAT:
case DOUBLE:
error(ECOER); /* pointer to floating point?? */
default:
return NOCOER; /* integer to pointer, ignore */
}
case FLOAT:
switch (u->ttype) { /* source */
case ARRAY:
case PTR:
case FUNCTION:
case FNDEF:
error(ECOER);
case FLOAT:
return NOCOER;
case DOUBLE:
return DF_FL;
default:
return INT_FL;
}
case DOUBLE:
switch (u->ttype) { /* source */
case ARRAY:
case PTR:
case FUNCTION:
case FNDEF:
error(ECOER);
case DOUBLE:
return NOCOER;
case FLOAT:
return FL_DF;
default:
return INT_DF;
}
default:
switch (u->ttype) { /* source */
case FLOAT:
return FL_INT;
case DOUBLE:
return DF_INT;
default:
return NOCOER;
}
}
}