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

📄 ccstmt.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
	error("Comma operator in constant expression");

    s = NULL;				/* start with chain empty, expr in t */
    while (1)				/* until we break out with return */
	{
	e = convarrfn(e);
	s = ndef(N_EXPRLIST, e->Ntype, 0, s, e); /* chain expr */
	if (token != T_COMMA)		/* If no comma, that's it */
	    break;	/* return s */
	/* Set flag to indicate that 1st operand of comma expression can
	** have its value discarded.  This gets set for both the list
	** structure node (N_EXPRLIST) and the expression itself.
	*/
	if ((s->Nright = ediscifok(e)) == NULL)	/* If expr flushed, */
	    {
	    s = s->Nleft;			/* forget structure too. */
	    }
	else
	    s->Nflag |= NF_DISCARD;		/* Else just add flag */

	nextoken();			/* pass over comma */
	e = asgnexpr();			/* parse another expression */
	}
    return s;
}

/*
** ASGNEXPR - Parse assignment expression
** Ref. [1] A.9.1
**	[H&S 7.2.1]
**
**	<assignment-expr> ::= <conditional-expr>
**			  ::= <unary-expr> <asop> <assignment-expr>
**
**	<asop> ::= one of:
**			= += -= *= /= %= <<= >>= &= ^= |=
*/

NODE *
asgnexpr()
{
    NODE *l, *r, *b;
    TYPE *restype;
    int op;

    b = condexpr();			/* parse lower priority part of expr */
    if (tok[token].tktype == TKTY_ASOP) /* if we now have an assignment op */
	{
	if (constexpr)
	    error("Assignment op in constant expression");

	/* See if left operand is a modifiable lvalue */
	if (!(b->Nflag & NF_LVALUE))	/* make sure can asgn to left side */
	    /* Nope, check for common mistake of (c ? t : f = x) */
	    {
	    if (b->Nop == Q_QUERY && !(b->Nflag & NF_INPARENS))
		advise("= in 3rd operand of (?:) has lower precedence -- use parentheses");
	    error("Lvalue required as left operand of assignment");
	    }
	else if (tisconst(b->Ntype) || tisstructiconst(b->Ntype))
	    error("Left operand of assignment must be modifiable");
	else if (b->Ntype->Tspec == TS_ARRAY)
	    error("Left operand of assignment cannot be array");
	else if (sizetype(b->Ntype) == 0)
	    error("Left operand of assignment cannot be incomplete type");

	op = token;			/* get the assignment op */
	nextoken();			/* and move on in the token world */
	r = asgnexpr();			/* parse right side of assignment */

	l = b;				/* Save ptr to left-hand side */

	if (l->Nop == Q_IDENT)
	    l->Nid->Sinit = 1;		/* Set flag to show initialization */

	restype = l->Ntype;		/* Remember what result type shd be */
	b = ndef(op, restype, 0, l, r);	/* Set up operator node */

	switch (op)
	    {
	    case Q_ASPLUS:			/* +=	*/
	    case Q_ASMINUS:			/* -=	*/
	    /* Left op can be scalar type (arith, pointer, enum) but if
	    ** pointer or enum then right op must be integral.
	    */
		if (!tisscalar(l->Ntype))
		    {
		    error("Left operand must have scalar type");
		    return ndeficonst(0);
		    }
		if (!tisarith(l->Ntype))	/* Pointer or enum? */
		    {
		    if (!tisinteg(r->Ntype))
			{
			error("Right operand must have integral type");
			return ndeficonst(0);
			}
		    b = chkadd(op == Q_ASPLUS ? Q_PLUS : Q_MINUS, b);
		    }
		else if (!tisarith(r->Ntype))
		    {
		    error("Right operand must have arithmetic type");
		    return ndeficonst(0);
		    }
		else
		    b = convbinary(b);		/* Normal binary conversions */
		break;

	    case Q_ASMPLY:			/* *=	*/
	    case Q_ASDIV:			/* /=	*/
		if (!tisarith(l->Ntype) || !tisarith(r->Ntype))
		    {
		    error("Operands must have arithmetic type");
		    return ndeficonst(0);
		    }
		b = convbinary(b);		/* Apply binary convs */
		break;

	    case Q_ASMOD:			/* %=	*/
	    case Q_ASRSH:			/* >>=	*/
	    case Q_ASLSH:			/* <<=	*/
	    case Q_ASAND:			/* &=	*/
	    case Q_ASXOR:			/* ^=	*/
	    case Q_ASOR:			/* |=	*/
		if (!tisinteg(l->Ntype) || !tisinteg(r->Ntype))
		    {
		    error("Operands must have integral type");
		    return ndeficonst(0);
		    }
		b = convbinary(b);		/* Apply binary convs */
		break;

	    case Q_ASGN:			/* =  Simple assignment */
		b->Nright = convasgn(restype, r);
		break;

	    default:
		int_error("asgnexpr: bad asop %Q", op);
		return ndeficonst(0);
	    }

	/* Now see whether an additional type conversion needs to be
	** specified when assigning the result to the left operand.
	** This is a little bit inefficient but permits code sharing.
	*/
	b->Nascast = CAST_NONE;		/* Default is no conversion */
	if (b->Ntype != restype)	/* If type isn't what it should be, */
	    {
	    b = convasgn(restype, b);	/* then apply assignment convs */
	    if (b->Nop == N_CAST)		/* If a cast was done, */
		{
		b->Nleft->Nascast = b->Ncast;	/* remember cast op type */
		b = b->Nleft;		/* and remove the cast operator. */
		b->Ntype = restype;	/* and force type to that desired. */
		}
	    }
	}
    return b;
}

/* CONDEXPR - Parse conditional expression (ternary)
**	[H&S 7.7]
**		<cond-expr> ::= <binary-expr> '?' <expr> ':' <cond-expr>
**
** One of the following must apply:
**	Both operands have arithmetic type
**	Both have compatible struct or union type
**	Both have void type
**	Both are pointers to {un}qualified versions of compatible types
**	One is a pointer and the other is a null ptr constant
**	One is a pointer and the other is a ptr to {un}qualified (void).
*/

static NODE *
condexpr()
{
    NODE *c, *n;

    c = binary(1);		/* Should check out this precedence */
    if (token != Q_QUERY)
	return c;		/* Not a conditional expression */

    /* Conditional expression, have the conditional.  Check it. */
    nextoken();
    if (!tisscalar(c->Ntype))
	{
	error("First operand of (?:) must have scalar type");
	c = ndeficonst(0);
	}

    /* Get "true" expression */
    n = expression();
    if (n->Nop == N_EXPRLIST && !(n->Nflag & NF_INPARENS))
	advise("Comma inside (?:) has lower precedence -- use parentheses");
    expect(T_COLON);

    /* Now get "false" expression, bind together */
    n = ndeflr(N_NODE, n, condexpr());

    /* Now fix up types.  Things are REAL hairy for this operator.
    */
    n = convbinary(n);		/* First apply binary conversions. */
    if (n->Nleft->Ntype == n->Nright->Ntype)	/* Types OK? */
	n->Ntype = n->Nleft->Ntype;		/* Yep, use that type */
    else
	{
	if ((n->Ntype = convternaryt(n)) == NULL) /* Try pointer hackery */
	    /* Failed.  Maybe later do more checking and just warn instead if
	    ** it is possible to do an implicit conversion -- but to
	    ** which type, left-hand or right-hand??
	    */
	    {
	    error("Operands of (?:) have incompatible types");
	    n->Ntype = n->Nleft->Ntype;		/* Use type of left */
	    n->Nleft = n->Nright = ndeficonst(0);
	    }
	}

    return ndef(Q_QUERY, n->Ntype, 0, c, n);
}

/* BINARY - Parse binary (or logical) expression
**	Ref.[1] A.18.1
**	[H&S 7.5, 7.6]
**
**		<binary-expr> ::=  <cast-expr> {<op> <binary-expr>}
**
** where <op> is one of:
**				Optypes	Convs	Result	Lvalue
**	Multiplicative:	* /	arith	bin	cvops	no
**			%	integ	bin	cvops	no
**	Additive:	+ -	*	bin	*	no
**	Shift:		<< >>	integ	un,sep	cvlftop	no
**	Inequality:  < <= > >=	*	bin	int(0/1) no
**	Equality:	== !=	*	bin	int(0/1) no
**	Bitwise:	& | ^	integ	bin	cvops	no
** and <logical-op> is:
**	Logical:	&& ||	scalar	*	int(0/1) no
*/

static NODE *
binary(prec)
{
    int nprec, op, typ;
    NODE *lx, *rx, *bx;	/* Left, right, and binary expressions */

    lx = castexpr();	/* First get a left-hand <cast-expr> expression */

    /* Then, if a binary operator follows it, handle the binary expression */
    while ((typ = tok[token].tktype) == TKTY_BINOP || typ == TKTY_BOOLOP)
	{
	if ((nprec = tok[token].tkprec) <= prec)
	    break;		/* New op has lower prec than current, stop */
	op = token;		/* Save op */
	nextoken();
	rx = binary(nprec);	/* Now get right-hand side of expression */

	bx = ndef(op, voidtype, 0, lx, rx);	/* No type, must set */
	switch (op)
	    {
	    default:
		int_error("binary: illegal op %Q", op);
		return ndeficonst(0);

	    case Q_LAND:	/* && Logical AND */
	    case Q_LOR:		/* || Logical OR */
		/* Check to ensure operands are scalar */
		lx = convarrfn(lx);	/* Apply array/funct convs */
		rx = convarrfn(rx);
		if (!tisscalar(lx->Ntype) || !tisscalar(rx->Ntype))
		    {
		    error("Operands of && or || must have scalar type");
		    lx = ndeficonst(0);
		    continue;	/* Skip rest of stuff, restart loop */
		    }
		/* Technically no further conversions are required.
		** However, it makes life easier for the code generation if
		** it only has to deal with full integers.
		** If the code generation is beefed up then these two calls
		** can be removed.
		*/
		bx->Nleft = convunary(lx);	/* Apply promotions if any */
		bx->Nright = convunary(rx);
		bx->Ntype = inttype;
		break;

	    case Q_EQUAL:
	    case Q_NEQ:
		/* Operands must have same type, and must be one of
		** arith, pointer, or enum (i.e. scalar)
		** EXCEPT for case where one is ptr and other is 0.
		** ANSI also allows comparing any ptr to a (void *) ptr.
		*/

	    case Q_LEQ:
	    case Q_GEQ:
	    case Q_LESS:
	    case Q_GREAT:
		/* Operands must have same type, and must be one of
		** arith, pointer, or enum (i.e. scalar)
		*/
		bx = convbinary(bx);		/* Apply binary convs */
		if (op == Q_EQUAL || op == Q_NEQ)
		    {
		    bx = convnullcomb(bx);	/* Also check ptr + null */
		    bx = convvoidptr(bx);	/* Also check ptr + void* */
		    }
		if (!tisscalar(bx->Ntype))
		    {
		    error("Operands of comparison must have scalar type");
		    lx = ndeficonst(0);
		    continue;
		    }
		/* If types not now same, this is only okay if both are
		** pointers to compatible unqualified types.
		*/
		if (bx->Nleft->Ntype != bx->Nright->Ntype	/* Not same? */
		  && ( bx->Nleft->Ntype->Tspec == TS_PTR	/* L ptr? */
		    && bx->Nright->Ntype->Tspec == TS_PTR	/* R ptr? */
		    && !cmputype(bx->Nleft->Ntype->Tsubt,	/* Compat? */
				bx->Nright->Ntype->Tsubt)))
		    {
		    error("Operands of comparison must have same type");
		    lx = ndeficonst(0);
		    continue;
		    }
		bx->Ntype = inttype;	/* OK, type of result is always int */
		break;

	    case Q_MPLY:
	    case Q_DIV:
		bx = convbinary(bx);	/* Apply usual binary convs */
		if (!tisarith(bx->Ntype)
			|| bx->Nleft->Ntype != bx->Nright->Ntype)
		    {
		    error("Mult/div operands must have arithmetic type");
		    lx = ndeficonst(0);
		    continue;
		    }
		break;

	    case Q_MOD:
		bx = convbinary(bx);	/* Apply usual binary convs */
		if (!tisinteg(bx->Ntype)
			|| bx->Nleft->Ntype != bx->Nright->Ntype)
		    {
		    error("Remainder operands must have integral type");
		    lx = ndeficonst(0);
		    continue;
		    }
		break;

	    case Q_PLUS:
	    case Q_MINUS:
		bx = chkadd(op, bx);		/* Do heavy checking */
		break;

	    case Q_LSHFT:
	    case Q_RSHFT:
		/* Not the usual binary conversions!! */
		bx->Nleft = convunary(lx);
		bx->Nright = convunary(rx);
		if (!tisinteg(bx->Nleft->Ntype)
			|| !tisinteg(bx->Nright->Ntype))
		    {
		    error("Shift operands must have integral type");
		    lx = ndeficonst(0);
		    continue;
		    }
		bx->Ntype = bx->Nleft->Ntype;	/* Type is whatever left is */
		break;

	    case Q_ANDT:
	    case Q_XORT:
	    case Q_OR:
		bx = convbinary(bx);
		if (!tisinteg(bx->Ntype)
			|| bx->Nleft->Ntype != bx->Nright->Ntype)
		    {
		    error("Bitwise operands must have integral type");
		    lx = ndeficonst(0);
		    continue;
		    }
		break;		/* Type already set up OK */
	    }

	lx = bx->Nleft;		/* For more convenient checking below */
	rx = bx->Nright;
	if (lx->Ntype->Tspec == TS_VOID || rx->Ntype->Tspec == TS_VOID)
	    {
	    error("Binary operand cannot have void type");
	    lx->Ntype = rx->Ntype = bx->Ntype = inttype;
	    }
	if (typ == TKTY_BOOLOP)	/* stack is safe from comparisons */
	    {
	    if (lx->Nflag & NF_STKREF)
		stackrefs--;
	    if (rx->Nflag & NF_STKREF)
		stackrefs--;
	    bx->Nflag |= NF_WASCOMP;	/* remember comparison */
	    }
	if ((bx->Nop == Q_ANDT || bx->Nop == Q_OR) &&
	    (((lx->Nflag & NF_WASCOMP) && !(lx->Nflag & NF_INPARENS)) ||
	     ((rx->Nflag & NF_WASCOMP) && !(rx->Nflag & NF_INPARENS))))
			/* likely lossage with & precedence */
	    advise("Bitwise operation on result of comparison -- use parentheses");

	lx = bx;		/* Binary expr becomes new left-hand operand */
	}
    return lx;
}

/* CASTEXPR and UNARY - Parse cast and unary expressions
**
**	[H&S 7.4]  Note that the BNF in the text of H&S 7.4 is faulty.
** The following revised BNF corresponds to the LALR(1) grammar in Appendix C,
** and should be correct.  Note in particular:
**	(1) All unary operators have equal precedence, except for the
** postfix operators (which have a special BNF definition).
**	(2) A special check is made in the code for the case of
** "sizeof(<type-name>)" in order to parse it on the spot and remove
** a possible ambiguity (referred to by H&S 7.4.2).  This is not reflected
** in the BNF, although H&S App. C deals with it by moving the syntax to
** primary-expression level.
**
**	<unary-expr> ::= <cast-expr>
**			| <prefix-expr>
**
**	<cast-expr> ::=  '(' <type-name> ')' <unary-expr>
**
**	<prefix-expr> ::= <postfix-expr>
**			| <sizeof-expr>
**			| '-' <unary-expr>	(unary minus)
**			| '!' <unary-expr>	(logical negation)
**			| '~' <unary-expr>	(bitwise negation)
**			| '&' <unary-expr>	(address operator)
**			| '*' <unary-expr>	(indirection)
**			| '++' <unary-expr>	(preincrement)
**			| '--' <unary-expr>	(predecrement)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -