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

📄 ccstmt.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
			int_error("postexpr: Fn retval too large");
		/* Make unique ident and then a local variable for type */
		    sprintf(temp,"%cstruct%d", SPC_IAUTO, ++cntr);
		    n->Nretstruct = defauto(temp, n->Ntype);
		    }
		else
		    n->Nretstruct = NULL;

		ra_expr = 1;		/* Turn on checking mechanism for */
					/* usage before init.             */

	    /* Parse argument list if any */
		n->Nright = parglist(sy, tp);	/* Get arglist (may be NULL) */
		break;			/* Results aren't checked further. */

	    case T_LBRACK:
	    /*
	    ** Parse array subscript ::= <postfix-expr> '[' <expr> ']'
	    **
	    **	This is implemented by converting it into
	    **		*(<postfix-expr> + <expr>)
	    */
		nextoken();			/* Move on to expr */
		n = ndeflr(Q_PLUS, expression(), n);
		n = chkadd(Q_PLUS, n);	/* Do type checking etc */
		tp = n->Ntype;		/* get type back, make sure ptr */
		if (tp->Tspec != TS_PTR)
		    error("Array or pointer type required");
		expect(T_RBRACK);

	    /* Propagate flags (global & stkref only) */
		n->Nflag = (n->Nleft->Nflag | n->Nright->Nflag)
			     & (NF_STKREF | NF_GLOBAL);


	    /* Now apply *() to the result, unless it will be an array.
	    ** If the result of the * is going to be an array (ie it will
	    ** remain a pointer) then skip this step to save the overhead
	    ** of a pointless pair of "*" and "&" nodes, and put the result
	    ** type directly into the Q_PLUS node.
	    */
		if (tp->Tsubt->Tspec == TS_ARRAY)
		    {
		    n->Ntype = tp->Tsubt;		/* Make result be that array */
#if 0
		    n->Nflag &= ~NF_LVALUE;		/* Make sure not an lvalue */
#else
		    n->Nflag |= NF_LVALUE;		/* Make sure not an lvalue */
#endif
		    }
		else
		    n = ptrapply(n);	/* Not array, apply * to result */
		break;

	    case Q_DOT:
	    case Q_MEMBER:
	/* Parse struct/union component selection
	**			::= <postfix-expr> '.'  <ident>
	**			  | <postfix-expr> "->" <ident>
	**
	** For ".", the first operand must be a qualified
	** or unqualified struct/union type, and the second operand
	** must name a member of that type.
	** The result is an lvalue if the first expression is, and has
	** the type of the member with the struct's qualifiers added.
	**
	** For "->", the first operand must be a pointer (quals are flushed
	** by standard lvalue mungage, [dpANS 3.2.2.1]) to the same thing
	** as ".", ditto second operand.
	** The result is always an lvalue, and the type is as for ".".
	*/
		op = token;		/* Remember which kind of selection it is */

	/* Check that type of preceding expr is correct */
		n = convarrfn(n);		/* Apply array/funct convs if any */
		tp = n->Ntype;			/* (if no conv, qualifiers intact!) */
		if (op == Q_MEMBER)
		    {
		    if (tp->Tspec != TS_PTR || (tp=tp->Tsubt) == NULL
			 || (tp->Tspec != TS_STRUCT && tp->Tspec != TS_UNION))
			{
			error("Left operand of -> must be pointer to struct or union");
			if ((tp=n->Ntype)->Tspec == TS_STRUCT || tp->Tspec == TS_UNION)
			    {
			    op = Q_DOT;	/* Pretend "." seen instead */
			    }
			else
			    tp = NULL;
			}
		    }
		else if (tp->Tspec != TS_STRUCT && tp->Tspec != TS_UNION)
		    {
		    error("Left operand of . must be struct or union");
		    if (tp->Tspec == TS_PTR && (tp=tp->Tsubt) == NULL
		      && (tp->Tspec == TS_STRUCT || tp->Tspec == TS_UNION))
			{
			op = Q_MEMBER;	/* Pretend "->" seen instead */
			}
		    else
			tp = NULL;
		    }
		if (nextoken() != Q_IDENT)
		    {
		    error("Struct or union member expected");
		    break;			/* Give up now, leave expr as is */
		    }

	/* Check that component name is OK */
	/* look up member name in symbol table */
	/* Get right name for a member identifier by adding prefix */
		sy = symfmember(csymbol, (tp ? tp->Tsmtag : NULL));
		if (sy == NULL)		/* Not a known member? */
		    {
		    error("Unknown struct/union component %S", csymbol);
		    off = 0;			/* No offset for missing symbol */
		    mt = deftype;		/* Use default (int) type of result */
		    }
		else
		    {
		    off = sy->Ssmoff;
		    mt = sy->Stype;
		    }
		if (csymbol->Sclass == SC_UNDEF)
		    freesym(csymbol);

	/* Now ensure that any type qualifiers for the struct are also
	** applied to the type of the member we just selected.
	** If the struct/union was not an lvalue (as can happen for Q_DOT)
	** then all qualifiers will be flushed by whatever uses this
	** expression farther on.
	*/
		if (tp && tisqualif(tp))	/* Add any type qualifiers needed */
		    mt = findqtype(mt, tp->Tflag & TF_QUALS);

	/* The flags remain the same for Q_DOT - this is how lvalueness is
	** passed on.
	** Q_MEMBER, however, involves
	** a deferencing and so can undo a stackref or make a
	** non-stackref safe from future address-taking.
	*/
		n = ndef(op, mt, n->Nflag, n, (NODE*)NULL);
		n->Nxoff = off;
		if (op == Q_MEMBER)
		    {
		    n->Nflag |= NF_LVALUE;	/* addr of a->b can be taken */
		    if (n->Nflag & NF_STKREF)
			{
			stackrefs--;	/* (&x)->y  for x on stack */
			n->Nflag &=~ NF_STKREF; /* dereferences address op */
			}
		    else
			n->Nflag |= NF_GLOBAL; /* otherwise not on stack */

		    if (debcsi == KCC_DBG_NULL)
			{
			n->sfline = fline;
			n->Nflag |= NF_USENPD;
			}
		    }

#if 0
	/*
	** Do special handling for member type == TS_ARRAY
	**
	** If the struct was returned from some function,
	** we can't take the addresses of parts of it.
	** It should be legal 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.
	** Hopefully the ANSI C standard will clarify this.
	**
	** If the struct is local, we have to adjust stackrefs.
	*/
		if (tp->Tspec == TS_ARRAY)
		    {
		    if (!(n->Nflag & NF_LVALUE))
			{
			error("Lvalue required as array ref in struct");
			}
		    n->Nflag &= ~NF_LVALUE;	/* Array is never lvalue */
		    }
#endif
		nextoken();		/* Done, now safe to skip over token! */
		break;

	    case T_INC:
	    case T_DEC:
	/*
	** Parse post(inc/dec)rement ::= <postfix-expr> ["++" | "--"]
	**	The operand must have qualified or unqualified scalar type
	**	and must be a modifiable lvalue.
	*/
		n = pincdec(n, token == T_INC ? N_POSTINC : N_POSTDEC);
		nextoken();
		break;

	    default:			/* If token not a postfix operator, */
		return n;		/* just return what we have so far. */
	    }		/* End of switch and suffix loop */
}

/* PINCDEC - common auxiliary to handle postfix/prefix increment/decrement.
**
**	The operand must have qualified or unqualified scalar type
**	and must be a modifiable lvalue.
**
** Conversions are tricky here, since result value may not be
** of right type.  See H&S 7.4.8.
** "the type of the result is that of the operand before conversion".
** This is one of the rare instances where we let the code generation
** worry about conversions rather than telling it what to do.
*/
static NODE *
pincdec(n, op)
NODE *n;	/* Operand expression */
int op;		/* Operator (N_PREINC, N_PREDEC, N_POSTINC, N_POSTDEC) */
{
    if (constexpr)
	error("++ or -- in constant expression");

    if (!(n->Nflag&NF_LVALUE))
	error("Operand of ++ or -- must be lvalue");
    else if (!tisscalar(n->Ntype))
	error("Operand of ++ or -- must have scalar type");
    else if (tisconst(n->Ntype))
	error("Operand of ++ or -- cannot be const-qualified");
    else if (n->Ntype->Tspec == TS_PTR && n->Ntype->Tsubt->Tspec == TS_VOID)
	error("Operand of ++ or -- cannot be ptr to void");
    else if (n->Ntype->Tspec == TS_PTR && sizeptobj(n->Ntype) == 0)
	error("Pointer operand of ++ or -- must point to object of known size");
    else
	{
	if ((n->Nop == Q_IDENT) && !(n->Nid->Sinit))
	    switch (n->Nid->Sclass)
		{
		case SC_AUTO:
		case SC_RAUTO:
		case SC_ISTATIC:
		    warn("Possible usage before initialization: %s", n->Nid->Sname);
		    n->Nid->Sinit = 1;
		    break;

		default:
		    break;
		}
/*	n->Nid->Sused = 1;	*/
	return ndef(op, n->Ntype, 0, n, (NODE*)NULL); /* Success! */
	}

    /* Failure, return a suitable placeholder */
    return ndeficonst(0);	/* For now, later match type better? */
}

/* PRIMARY - Parse primary expression
**	[dpANS 3.3.1]
**
**	<primary-expr> ::= <ident>
**			| <constant>
**			| <string-literal>
**			| '(' <expr> ')'
** KCC EXTENSION:	| <asm-expr>
**			| <muuo-expr>		- KAR 1/91
**
** A <ident> must be either an object (of some type) or a function.
**	The former is an lvalue, the latter a function designator.
**	Note special case of enum constant, which is also an <ident>.
** A <constant> has a type and value as per syntax (CCLEX, [dpANS 3.1.3])
**	It is not an lvalue.
** A <string-literal> is an lvalue, normally with type "array of char",
**	per [dpANS 3.1.4].
**
** Current token must be the first token of a valid primary expression.
** On return, current token is the next one after the expression.
*/

static NODE *
primary()
{
    NODE *n;
    SYMBOL *s, d;

    switch (token)
	{
	case Q_IDENT:
	/*
	** Parse <ident>
	**	This may be an enum constant as well as an object or function.
	**	This is where we check for handling calls to undeclared functs.
	*/
	    s = csymbol;		/* Remember pointer to identifier symbol */
	    nextoken();		/* then flush token, set up next */
	    switch (s->Sclass)
		{
		case SC_ENUM:		/* If <ident> is Enumeration constant */
				/* it evaluates into an integer constant */
		    return ndeficonst(s->Svalue);	/* Note not lvalue! */

		case SC_UNDEF:		/* Undefined identifier may be function call */
		    if (token != T_LPAREN)	/* Check for function-call case */
					/* Undefined, complain */
			{
			error("Undefined identifier: %S", s);
			freesym(s);		/* Flush losing symbol */
			return ndeft(N_UNDEF, deftype);
		/* Returns special undef node so can continue processing */
			}
	    /* Pretend we declared this identifier as
	    ** "extern int ident();" in current block.
	    */
		    note("Call to undeclared function %S", s);
		    d.Sclass = SC_EXTREF;	/* Storage class as if "extern" */
		    d.Stype = findftype(inttype, (TYPE *)NULL);	/* Set type */
		    s = funchk(0, SC_EXTREF, &d, s);	/* Perform funct declaration */
		    s->Srefs++;			/* Say referenced by call */

	    /* Now can drop through to handle normally */

		default:
	    /* Normal variable or function name */
		    n = ndefident(s);		/* Make Q_IDENT node */

	    /* Now set appropriate flags for this node.  Note Nflag
	    ** was initialized to 0 by the ndefident() above.
	    */
		    if ( s->Sclass != SC_AUTO && s->Sclass != SC_RAUTO
		      && s->Sclass != SC_ARG  && s->Sclass != SC_RARG)
			n->Nflag |= NF_GLOBAL;		/* Var has static extent */

		    if (n->Ntype->Tspec != TS_FUNCT)	/* If not a function, */
			n->Nflag |= NF_LVALUE;		/* then is an lvalue! */
		}
	    break;

    /* Constants and literals [H&S 2.7] [dpANS 3.1.3]
    ** The lexer has already parsed the constant into a T_*CONST token,
    ** and left information about the constant type and value in the
    ** global struct "constant".
    */
	case T_ICONST:		/* Handle integer constant */
	case T_CCONST:		/* Handle character constant */
	    n = ndeft(N_ICONST, constant.ctype);
	    n->Niconst = constant.cvalue;
	    nextoken();
	    break;

	case T_FCONST:		/* Handle floating-point constant */
	    n = ndeft(N_FCONST, constant.ctype);
	    switch (constant.ctype->Tspec)
		{
		case TS_FLOAT:
		    n->Nfconst = constant.Cfloat;
		    break;
		case TS_DOUBLE:
		    n->Nfconst = constant.Cdouble;
		    break;
		case TS_LNGDBL:
		    n->Nfconst = constant.Clngdbl;
		    break;
		default:
		    int_error ("primary: invalide float const %d",
			    constant.ctype->Tspec);
		}
	    nextoken();
	    break;

	case T_SCONST:		/* Handle <string-literal> */
	    n = ndeft(N_SCONST, constant.ctype);
	    n->Nsconst = constant.csptr; /* get pointer */
	    n->Nsclen = constant.cslen;	/* and num chars including null */
	    nextoken();
	    break;

	case T_LPAREN:
	/*
	** Parse parenthesized expression ::= '(' <expr> ')'
	*/
	    nextoken();			/* Advance past left-paren */
	    n = expression();		/* Get expr list in parens */
	    n->Nflag |= NF_INPARENS;	/* Remember it was paren-enclosed */
	    expect(T_RPAREN);		/* followed by close paren */
	    break;

	case Q_MUUO:
	    return bin_muuo();	/* Handle "muuo" built-in, KAR 1/91 */

	case Q_ASM:			/* Handle "asm" built-in */
	    return bin_asm();

	case T_OFFSET:		/* Handle "_KCC_offsetof" built-in */
	    return bin_offsetof();

	case T_ELSE:
	    advise("Orphan 'else'");

	default:				/* Bad token... */
	    error("Primary expr expected");	/* Complain and return dummy */
	    return ndeft(N_UNDEF, deftype);
	}
    return n;
}

/* Parsing for various built-in expressions */

/* "asm" - handle built-in for assembly code inclusion
**
**	<asm-expr> ::= "asm" '(' <exprlist> ')'
**
** This is a KCC-specific feature and can only happen if
** "asm" was initialized as a keyword by CCSYM on startup.
*/
static NODE *
bin_asm()
{
    NODE *n;

    if (nextoken() != T_LPAREN)
	{
	error("Bad syntax for \"asm\" - no left paren");
	return primary();		/* Try again on this token */
	}
    n = parglist(NULL, NULL);		/* Parse args as if function call */

    /* Check out against currently supported syntax.
    ** This must be a single string literal after constant optimization.
    */
    if (!n || n->Nleft || (n = evalexpr(n->Nright)) ==NULL
	    || n->Nop != N_SCONST)
	error("Arg to \"asm\" must be a single string literal");

    return ndef(Q_ASM, voidtype, 0, n, (NODE*)NULL);
}

#define param1	temp->Nleft->Nleft->Nright
#define param2	temp->Nleft
#define param3  temp->Nright
#define param4  n->Nle

⌨️ 快捷键说明

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