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

📄 expr.c

📁 一款拥有一定历史的C语言编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
	    case 'j':
		tp = tp_int;
		break;
	    case 't':
		tp = tp_ptrdiff;
		break;
	    case 'z':
		tp = tp_size;
		break;
	    default:
		tp = tp_uint;
		break;
	    }
	    check_parameter (fname, num, ptp, promote_type (tp));
	    return fstr + 1;
	case 'a':
	case 'e':
	case 'E':
	case 'f':
	case 'g':
	case 'G':
	    switch (optional) {
	    case 'L':
		tp = tp_longdouble;
		break;
	    default:
		tp = tp_double;
		break;
	    }
	    check_parameter (fname, num, ptp, tp);
	    return fstr + 1;
	case 's':
	    tp = tp_string;
	    check_parameter (fname, num, ptp, tp);
	    return fstr + 1;
	case 'p':
	    tp = tp_pointer;
	    check_parameter (fname, num, ptp, tp);
	    return fstr + 1;
	case 'n':
	    switch (optional) {
	    case 'l':
		tp = tp_long;
		break;
	    case 'h':
		tp = tp_short;
		break;
	    default:
		tp = tp_int;
		break;
	    }
	    check_pointer_parameter (fname, num, ptp, tp);
	    return fstr + 1;
	default:
	    break;
	}
	break;
    default:
	CANNOT_REACH_HERE ();
	break;
    }
    return fstr;
}

static const CHAR *check_scanf P5 (const CHAR *, fname, int, num,
				   const CHAR *, fstr, enum fpos *, pos,
				   const TYP *, ptp)
{
    int     suppress;
    CHAR    optional;
    TYP    *tp;

    if (fstr == NIL_CHAR || *fstr == (CHAR) 0) {
	if (ptp != NIL_TYP) {
	    message (WARN_COUNTPARAM, fname);
	}
	return NIL_CHAR;
    }
    pos = pos;			/* stops compilers generating warning about pos not being used */

    for (; *fstr; fstr++) {
	suppress = 0;
	switch (*fstr) {
	case '%':
	    fstr++;
	    /* optional assignment-suppressing character */
	    if (*fstr == (CHAR) '*') {
		suppress++;
		fstr++;
	    }
	    /* optional decimal integer that specifies maximum field width */
	    while (('0' <= *fstr) && (*fstr <= '9')) {
		fstr++;
	    }

	    /* optional size of object */
	    switch (*fstr) {
	    case 'h':
	    case 'l':
	    case 'L':
		optional = *fstr++;
		break;
	    default:
		optional = (CHAR) 0;
		break;
	    }

	    /* type of conversion */
	    switch (*fstr) {
	    case 'd':
	    case 'i':
	    case 'n':
		switch (optional) {
		case 'l':
		    tp = tp_long;
		    break;
		case 'h':
		    tp = tp_short;
		    break;
		default:
		    tp = tp_int;
		    break;
		}
		if (suppress) {
		    continue;
		}
		check_pointer_parameter (fname, num, ptp, tp);
		return fstr + 1;
	    case 'o':
	    case 'u':
	    case 'x':
		switch (optional) {
		case 'l':
		    tp = tp_ulong;
		    break;
		case 'h':
		    tp = tp_ushort;
		    break;
		default:
		    tp = tp_uint;
		    break;
		}
		if (suppress) {
		    continue;
		}
		check_pointer_parameter (fname, num, ptp, tp);
		return fstr + 1;
	    case 'e':
	    case 'f':
	    case 'g':
		if (suppress) {
		    continue;
		}
		switch (optional) {
		case 'L':
		    tp = tp_longdouble;
		    break;
		case 'l':
		    tp = tp_double;
		    break;
		default:
		    tp = tp_float;
		    break;
		}
		check_pointer_parameter (fname, num, ptp, tp);
		return fstr + 1;
	    case '[':
		fstr++;
		if (*fstr == (CHAR) '^') {
		    fstr++;
		}
		if (*fstr == (CHAR) ']') {
		    fstr++;
		}
		while (*fstr && *fstr != (CHAR) ']') {
		    fstr++;
		}
		/*lint -fallthrough */
	    case 'c':
	    case 's':
		if (suppress) {
		    continue;
		}
		check_array_parameter (fname, num, ptp);
		return fstr + 1;
	    case 'P':
		if (suppress) {
		    continue;
		}
		tp = tp_pointer;
		check_pointer_parameter (fname, num, ptp, tp);
		return fstr + 1;
	    default:
		break;
	    }
	    break;
	default:
	    break;
	}
    }
    return NIL_CHAR;
}
#endif /* SYNTAX_CORRECT */
#endif /* FORMAT_CHECK */

/*
 * parmlist will build a list of parameter expressions in a function call and
 * return a pointer to the last expression parsed. since parameters are
 * generally pushed from right to left we get just what we asked for...
 */
static EXPR *parmlist P2 (const EXPR *, ep, const BLOCK *, block)
{
    SYM    *sp = block ? symbolsof (block) : NIL_SYM;
    SYM    *sp1 = sp;
    EXPR   *ep1, *ep2;
    TYP    *tp, *tp2;
    int     pnum = 0;
    const CHAR *fname =
	ep->nodetype == en_sym ? nameof (ep->v.sp) : (const CHAR *) "";

#ifndef SYNTAX_CORRECT
#ifdef FORMAT_CHECK
    enum fpos format_position;
    const CHAR *fstr = NIL_CHAR;
    struct pflike
    {
	const CHAR **name;
	int     num;
	const CHAR *(*func)
	    P_ ((const CHAR *, int, const CHAR *, enum fpos *, const TYP *));
    };
    struct pflike *pf = NULL;
    static struct pflike printflike[] = {
	{&fprintf_name, 2, check_printf},
	{&printf_name, 1, check_printf},
	{&sprintf_name, 2, check_printf},
	{&fscanf_name, 2, check_scanf},
	{&scanf_name, 1, check_scanf},
	{&sscanf_name, 2, check_scanf},
	{(const CHAR **) NULL, 0, NULL}
    };


    if (format_option) {
	for (pf = &printflike[0]; pf->name; pf++) {
	    if (fname == *(pf->name)) {
		break;
	    }
	}
    }
#endif /*FORMAT_CHECK */
    if ((lang_option >= LANG_C90) && sp == NIL_SYM) {
	message (WARN_NOPROTO, fname);
    }
#endif /* SYNTAX_CORRECT */
    ep1 = NIL_EXPR;
    while (lastst != tk_closepa) {
	pnum++;
	ep2 = exprnc ();	/* evaluate a parameter */
	if (ep2 == NIL_EXPR) {
	    return NIL_EXPR;
	}
	check_set (ep2);
	check_sequence_accessed (ep2);
	tp2 = tp = ep2->etp;
#ifndef SYNTAX_CORRECT
	if (is_void (tp)) {
	    message (ERR_VOIDPARM, fname);
	    break;
	}
#endif /* SYNTAX_CORRECT */
	if (sp != NIL_SYM) {	/* do prototype checking */
	    /* skip enumeration constants etc. */
	    while ((sp1 != NIL_SYM) && (is_const (sp1) || is_member (sp1)))
		sp1 = nextsym (sp1);

	    if (sp1 == NIL_SYM || is_void (typeof (sp1))) {
#ifndef SYNTAX_CORRECT
		message (ERR_COUNTPARAM, fname);
#endif /* SYNTAX_CORRECT */
	    } else if (!promoteparam_option && !is_ellipsis (typeof (sp1))) {
		if (is_array_type (typeof (sp1))) {
		    ep2 = implicit_castop (ep2, tp_pointer);
		} else {
		    ep2 = implicit_castop (ep2, typeof (sp1));
		}
	    }
	}
	/*
	 * do the default promotions
	 */
	switch (tp->type) {
	case bt_char:
	case bt_charu:
	case bt_uchar:
	case bt_schar:
	case bt_short:
	case bt_ushort:
	case bt_float:
	    if (sp1 == NIL_SYM || promoteparam_option
		|| is_ellipsis (typeof (sp1))) {
		TYP    *tp1 = promote_type (tp);

#ifndef SYNTAX_CORRECT
		if ((lang_option >= LANG_C90) && (sp1 == NIL_SYM)
		    && (tp->size < tp1->size)) {
		    message (WARN_PROMOTE, pnum, fname, nameoftype (tp1));
		}
#endif /* SYNTAX_CORRECT */
		ep2 = implicit_castop (ep2, tp1);
	    }
	    break;
	case bt_double:
	case bt_longdouble:
	case bt_struct:
	case bt_union:
	    /* trap struct assigns */
	    uses_structassign = TRUE;
	    break;
	default:
	    break;
	}

#ifndef SYNTAX_CORRECT
#ifdef FORMAT_CHECK
	if (format_option && (pf != NULL)) {
	    if ((pf->num == pnum) && (ep2->nodetype == en_labcon)) {
		fstr = get_stringlit (ep2->v.l);
		format_position = format_start;
	    } else if (fstr != NULL) {
		fstr =
		    (pf->func) (fname, pnum, fstr, &format_position,
				ep2->etp);
	    }
	}
#endif /*FORMAT_CHECK */
#endif /* SYNTAX_CORRECT */

	if (sp1 != NIL_SYM && !is_ellipsis (typeof (sp1))) {
	    /*
	     * Check to see if this would cause a problem if compiled by a
	     * K&R compiler.
	     */
	    tp = promote_type (typeof (sp1));
	    tp2 = promote_type (tp2);
	    if (is_array_type (tp)) {
		tp = tp_pointer;
	    }
	    if (is_array_type (tp2)) {
		tp2 = tp_pointer;
	    }
#ifndef SYNTAX_CORRECT
	    if (!is_same_size (tp, tp2)) {
		message (WARN_PARAMSIZE, pnum, fname);
	    }
#endif /* SYNTAX_CORRECT */
	    sp1 = nextsym (sp1);
	}
	ep1 = mk_node (en_list, ep2, ep1, tp_void);
	if (lastst != tk_comma) {
	    break;
	}
	getsym ();
    }
#ifndef SYNTAX_CORRECT
    /* skip enumeration constants etc. */
    while ((sp1 != NIL_SYM) && (is_const (sp1) || is_member (sp1)))
	sp1 = nextsym (sp1);
    if (sp1 != NIL_SYM && !is_ellipsis (typeof (sp1))
	&& !is_void (typeof (sp1))) {
	message (ERR_COUNTPARAM, fname);
    }
#ifdef FORMAT_CHECK
    else if (format_option && (fstr != NIL_CHAR) && (pf != NULL)) {
	VOIDCAST (pf->func) (fname, pnum, fstr, &format_position, NIL_TYP);
    }
#endif /* FORMAT_CHECK */
#endif /* SYNTAX_CORRECT */
    return ep1;
}

/*
 * primary will parse a primary expression and set the node pointer returning
 * the type of the expression parsed. primary expressions are any of:
 * id
 * constant
 * string
 * ( expression )
 * primary[ expression ]
 * primary.id
 * primary->id
 * primary( parameter list )
 * primary++
 * primary--
 * ( type-name ) { initializer-list }
 * ( type-name ) { initializer-list , }
 * -- or just a semicolon, yields empty expression --
 *
 */
static EXPR *primary P0 (void)
{
    EXPR   *ep, *ep1, *ep2;
    SYM    *sp;
    TYP    *tp, *tp1;

    switch (lastst) {
    case tk_id:
	ep = nameref ();
	if (ep == NIL_EXPR) {
	    return NIL_EXPR;
	}
	/*
	 * function names alone are pointers to functions.
	 * If followed by '(', the reference is stripped off
	 * later.
	 */
	if (is_func (ep->etp)) {
	    ep->etp = mk_type (tp_pointer, ep->etp);
	}
	break;
    case tk_iconst:
	tp = tp_int;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_uconst:
	tp = tp_uint;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_lconst:
	tp = tp_long;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_ulconst:
	tp = tp_ulong;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_llconst:
	tp = tp_longlong;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_ullconst:
	tp = tp_ulonglong;
	goto const1;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_wconst:
	tp = tp_wchar;
      const1:
	ep = mk_icon ((IVAL) ival, tp);
	getsym ();
	break;
#ifdef FLOAT_SUPPORT
    case tk_fconst:
	tp = tp_float;
	goto const2;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_rconst:
	tp = tp_double;
	goto const2;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_lrconst:
	tp = tp_longdouble;
      const2:
	ep = mk_fcon (&rval, tp);
	getsym ();
	break;
#endif /* FLOAT_SUPPORT */
    case tk_wsconst:
	tp = tp_wstring;
	goto string;	    /*lint !e801*/  /* use of goto is deprecated */
    case tk_sconst:
	tp = tp_string;
      string:
	if (sizeof_flag) {
	    ep = mk_node (en_size, NIL_EXPR, NIL_EXPR, tp);
	    ep->v.i = (IVAL) lastsymlen + 1L;
	} else {
	    ep = mk_stringlit (lastsym, (size_t) lastsymlen);
	    ep->etp = tp;
	}
	getsym ();
	break;
    case tk_openpa:
	getsym ();
	if (is_type_name (lastst)) {
	    tp = type_name ();
	    needpunc (tk_closepa);
	    switch (lastst) {
	    case tk_begin:
		if (lang_option >= LANG_C99) {
		    /*
		     *      A postfix expression that consists of a
		     *      parenthesized type name followed by a
		     *      brace-enclosed list of initializers is a
		     *      compound literal.  It provides an unnamed
		     *      object whose value is given by the initializer
		     *      list.
		     *
		     *      The type name shall specify an object type or
		     *      an array of unknown size, but not a variable
		     *      length array type.
		     */
		    if (is_object_type (tp)) {
			if (is_variable_array_type (tp)) {
			    message (ERR_VARRAY);
			}
		    } else {
			message (ERR_OBJECT);
		    }

		    getsym ();
		    /*
		     *      If the compound literal occurs outside the body
		     *      of a function, the object has static storage
		     *      duration; otherwise, it has automatic storage
		     *      duration associated with the enclosing block.
		     */
		    ep =
			initializer_list (tp, 0L,
					  (global_flag ? sc_static :
					   sc_auto));
		    ep =
			mk_node (en_literal, ep, mk_size (tp->size, tp_size),
				 tp);
		    if (lastst == tk_comma)
			getsym ();
		    needpunc (tk_end);
		    return ep;
		}
		/*lint -fallthrough */
	    default:
		ep = unary ();
#ifndef SYNTAX_CORRECT
		if (ep == NIL_EXPR) {
		    message (ERR_IDEXPECT);
		    return NIL_EXPR;
		}
#endif /* SYNTAX_CORRECT */
		ep = explicit_castop (ep, tp);
		break;
	    }
	} else {
	    ep = expression ();
	    needpunc (tk_closepa);
	    if (ep == NIL_EXPR) {
		return NIL_EXPR;
	    }
	}
	break;
    default:
	return NIL_EXPR;
    }
    for (;;) {
	switch (lastst) {
	case tk_openbr:	/* build a subscript reference */
	    getsym ();
	    /*
	     * a[b] is defined as *(a+b), such exactly one of (a,b) must be a
	     * pointer and one of (a,b) must be an integer expression
	     */
	    if (is_pointer_type (ep->etp)) {
		ep2 = expression ();
		ep1 = ep;
	    } else {
		ep2 = ep;
		ep1 = expression ();

⌨️ 快捷键说明

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