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

📄 expr.c

📁 一款拥有一定历史的C语言编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
		ep = ep1;
#ifndef SYNTAX_CORRECT
		if (is_char (ep->etp)) {
		    message (WARN_CHARINDEX);
		}
#endif /* SYNTAX_CORRECT */
	    }

	    /*
	     * now, ep1 describes the pointer,
	     *              ep2 describes the integral value
	     */
	    check_integral (ep2);

	    tp = ep1->etp;
	    if (is_pointer_type (tp)) {
		tp = referenced_type (tp);
#ifndef SYNTAX_CORRECT
		check_complete (tp);
	    } else {
		message (ERR_NOPOINTER);
#endif /* SYNTAX_CORRECT */
	    }

	    tp1 = is_same_size (tp_pointer, tp_ulong) ? tp_ulong : tp_ushort;

	    ep = mk_icon ((IVAL) tp->size, tp1);
	    /*
	     * ep is the size of the referenced object
	     */
	    ep2 = explicit_castop (ep2, tp1);
	    ep = mk_node (en_mul, ep, ep2, tp1);
	    ep = explicit_castop (ep, tp1);
	    ep = mk_node (en_add, ep, ep1, ep1->etp);
	    ep = cond_deref (ep, tp);
	    needpunc (tk_closebr);
	    break;
	case tk_pointsto:
	    check_set (ep);
	    check_sequence_accessed (ep);
	    tp = ep->etp;
	    if (is_pointer_type (tp)) {
		tp = referenced_type (tp);
#ifndef SYNTAX_CORRECT
	    } else {
		message (ERR_NOPOINTER);
#endif /* SYNTAX_CORRECT */
	    }
	    /*
	     * tp->type should be bt_struct or bt_union
	     * the ref node will be stripped off in a minute
	     */
	    ep = cond_deref (ep, tp);
	    /*lint -fallthrough */
	case tk_dot:
	    getsym ();		/* past -> or . */
	    tp = ep->etp;
	    if (lastst == tk_id) {
		if (is_structure_type (tp) &&
		    (members (tp) != NIL_BLOCK) &&
		    ((sp = search (lastsym, &(members (tp)->symbols))) !=
		     NIL_SYM)) {
		    /* strip off the en_ref node on top */
		    if (ep->nodetype == en_ref) {
			ep = ep->v.p[0];
			ep->etp = tp_pointer;
		    } else {
			ep = mk_node (en_deref, ep, NIL_EXPR, tp_pointer);
		    }
		    tp = qualify_type (typeof (sp),
				       (QUALIFIER) (tp->qual |
						    typeof (sp)->qual));
		    ep1 = mk_icon (sp->value.i, tp_long);
		    ep = mk_node (en_add, ep, ep1, mk_type (tp_pointer, tp));
		    ep = cond_deref (ep, tp);
#ifndef SYNTAX_CORRECT
		} else {
		    message (ERR_NOMEMBER, lastsym);
#endif /* SYNTAX_CORRECT */
		}
		getsym ();	/* past id */
#ifndef SYNTAX_CORRECT
	    } else {
		message (ERR_IDEXPECT);
#endif /* SYNTAX_CORRECT */
	    }
	    break;
	case tk_openpa:	/* function reference */
	    getsym ();
	    tp = ep->etp;
	    if (is_function_type (tp)) {
		/*
		 * the '*' may be omitted with pointers to functions
		 * we have included another indirection (see above,
		 * case id:)
		 */
		if (is_pointer_type (tp)) {
		    tp = referenced_type (tp);
		}
		/*
		 * This hack lets us remember that this function itself
		 * calls other functions.
		 * The code generator might use this information to
		 * generate safer register-pop-off code.
		 */
		is_leaf_function = FALSE;

		ep2 = parmlist (ep, parameters (tp));
		sequence_point ();
		tp1 = tp;
		tp = returned_type (tp);
#ifndef SYNTAX_CORRECT
		if (tp == NIL_TYP) {
		    tp = tp_void;	/* this happens on an error path! */
		}
		if (is_structure_type (tp)) {
		    check_complete (tp);
		}
#endif /* SYNTAX_CORRECT */
		switch (funckind (tp1))
		{
		case fc_normal:
		    ep = mk_node (en_fcall, ep, ep2, tp);
		    break;
		case fc_user:
		    ep = mk_enode (en_str, tp_pointer);
		    ep->v.str = funccall (tp1);
		    ep = mk_node (en_usercall, ep, ep2, tp);
		    break;
		default:
		    CANNOT_REACH_HERE ();
		}
		needpunc (tk_closepa);
#ifndef SYNTAX_CORRECT
	    } else {
		message (ERR_NOFUNC);
#endif /* SYNTAX_CORRECT */
	    }
	    break;
	case tk_autodec:
	case tk_autoinc:
	    check_set (ep);
	    check_sequence_modified (ep);
	    check_modifiable_lvalue (ep);
	    check_scalar (ep);
	    tp = ep->etp;
	    check_complete (tp);
#ifdef FLOAT_SUPPORT
	    if (is_real_floating_type (tp)) {
		ep1 = mk_fcon (&F_one, tp);
	    } else
#endif
	    {
		SIZE    size;

		if (is_pointer_type (tp)) {
		    check_object (ep);
		    check_complete (referenced_type (tp));
		    size = referenced_type (tp)->size;
		} else {
		    size = 1L;
		}
		ep1 = mk_icon ((IVAL) size, tp_longlong);
	    }
	    if (lastst == tk_autodec) {
		ep = mk_node (en_adec, ep, ep1, tp);
	    } else {
		ep = mk_node (en_ainc, ep, ep1, tp);
	    }
	    getsym ();
	    if ((lang_option == LANG_KANDR) && lastst == tk_pointsto) {
		needpunc ((TOKEN) (lastst + 1));	/* force an error as K&R doesn't allow this */
	    }
	    break;
	default:
	    return ep;
	}
    }
}

/*
 * unary evaluates unary expressions and returns the type of the expression
 * evaluated. unary expressions are any of:
 *
 * primary
 * !unary
 * ~unary
 * ++unary
 * --unary
 * +unary
 * -unary
 * *unary
 * &unary
 * (typecast)unary
 * sizeof(typecast)
 * sizeof unary
 *
 */
static EXPR *unary P0 (void)
{
    TYP    *tp;
    EXPR   *ep, *ep1;
    BOOL    flag = FALSE;
    SIZE    size;
    TYP    *typeof_tp;

    switch (lastst) {
    case tk_autodec:
	flag = TRUE;
	/*lint -fallthrough */
    case tk_autoinc:
	getsym ();
	ep = unary ();
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
#endif /* SYNTAX_CORRECT */
	check_modifiable_lvalue (ep);
	check_scalar (ep);
	check_sequence_modified (ep);
	tp = ep->etp;
	check_complete (tp);
#ifdef FLOAT_SUPPORT
	if (is_real_floating_type (tp)) {
	    ep1 = mk_fcon (&F_one, tp);
	} else
#endif /* FLOAT_SUPPORT */
	{
	    if (is_pointer_type (tp)) {
		check_object (ep);
		check_complete (referenced_type (tp));
		size = referenced_type (tp)->size;
	    } else {
		size = 1L;
	    }
	    ep1 = mk_size (size, tp_long);
	}
	ep = mk_node ((EXPRTYPE) (flag ? en_assub : en_asadd), ep, ep1, tp);
	break;
    case tk_plus:
	if (lang_option == LANG_KANDR) {
	    /* only ANSI C allows the unary + operator */
	    ep = primary ();
	    break;
	}
	flag = TRUE;
	/*lint -fallthrough */
    case tk_minus:
	getsym ();
	ep = unary ();
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
	check_arithmetic (ep);
	check_set (ep);
	check_sequence_accessed (ep);
	if (!flag && is_unsigned_type (ep->etp)) {
	    message (WARN_MINUS);
	}
#endif /* SYNTAX_CORRECT */
	ep = integral_promotion (ep);

	if (!flag) {
	    /* don't bother about unary plus */
	    ep = mk_node (en_uminus, ep, NIL_EXPR, ep->etp);
	}
	break;
    case tk_not:
	getsym ();
	ep = unary ();
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
	check_scalar (ep);
	check_set (ep);
	check_sequence_accessed (ep);
	if (is_constexpr (ep)) {
	    message (WARN_NOT);
	}
#endif /* SYNTAX_CORRECT */
	ep = mk_node (en_not, ep, NIL_EXPR, tp_int);
	break;
    case tk_compl:
	getsym ();
	ep = unary ();
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
	check_integral (ep);
	check_set (ep);
	check_sequence_accessed (ep);
#endif /* SYNTAX_CORRECT */
	ep = integral_promotion (ep);
#ifndef SYNTAX_CORRECT
	if (is_signed_type (ep->etp)) {
	    message (WARN_UNDEFINED, "~");
	}
#endif /* SYNTAX_CORRECT */
	ep = mk_node (en_compl, ep, NIL_EXPR, ep->etp);
	break;
    case tk_star:
	getsym ();
	ep = unary ();
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
	check_set (ep);
	check_sequence_accessed (ep);
#endif /* SYNTAX_CORRECT */
	tp = ep->etp;
	if (referenced_type (tp)) {
	    /*
	     * ANSI C specifies that the function identifier will be converted
	     * to a pointer to function if necessary.
	     */
	    if (!is_func (tp)) {
		tp = referenced_type (tp);
	    }
#ifndef SYNTAX_CORRECT
	} else {
	    message (ERR_DEREF);
#endif /* SYNTAX_CORRECT */
	}
	ep = cond_deref (ep, tp);
	break;
    case tk_and:
	getsym ();
	address_flag = TRUE;
	ep = unary ();
	address_flag = FALSE;
#ifndef SYNTAX_CORRECT
	if (ep == NIL_EXPR) {
	    message (ERR_IDEXPECT);
	    return NIL_EXPR;
	}
#endif /* SYNTAX_CORRECT */
	if (is_function_type (ep->etp) && is_derived_type (ep->etp)) {
	    if (is_func (ep->etp)) {
		/* functions are implicitly converted to pointers to functions */
		ep->etp = mk_type (tp_pointer, ep->etp);
	    }
	} else if (is_lvalue (ep)) {
#ifndef SYNTAX_CORRECT
	    if (ep->nodetype == en_fieldref) {
		message (ERR_BITFIELD);
		break;
	    }
#endif /* SYNTAX_CORRECT */
	    tp = ep->etp;
	    ep = ep->v.p[0];
	    ep->etp = mk_type (tp_pointer, tp);
	    if (ep->nodetype == en_size) {
		ep->v.i = (IVAL) ep->etp->size;
	    }
#ifdef CPU_DEFINED
	    /*
	     * possibly remove a variable which is a candidate for a
	     * register.  This is done in the analyze module normally,
	     * but the use of the address operator may be hidden due
	     * to optimisations.
	     * imagine '(char *)(&len) + 2'
	     */
	    if (is_sym (ep) &&
		(is_auto (ep->v.sp) ||
		 is_parms (ep->v.sp) || is_register (ep->v.sp))) {
		deloptinfo (ep);
	    }
#endif /* CPU_DEFINED */
	} else if (is_pointer_type (ep->etp)) {
	    if (is_func (referenced_type (ep->etp))) {
#ifndef SYNTAX_CORRECT
		message (WARN_ADDFUNC);
#endif /* SYNTAX_CORRECT */
	    } else if (is_array_type (ep->etp)) {
		ep->etp = mk_type (tp_pointer, ep->etp);
#ifndef SYNTAX_CORRECT
	    } else {
		message (ERR_LVALUE);
#endif /* SYNTAX_CORRECT */
	    }
#ifndef SYNTAX_CORRECT
	} else {
	    message (ERR_LVALUE);
#endif /* SYNTAX_CORRECT */
	}
	break;
    case kw_sizeof:
	getsym ();
	/*
	 * This is a mess.
	 * Normally, we treat array names just as pointers, but with sizeof,
	 * we want to get the real array size. So, the 'real' size is stored
	 * in an en_size node in v.i
	 */
	if (lastst == tk_openpa) {
	    getsym ();
	    if (is_type_name (lastst)) {
		tp = type_name ();
#ifndef SYNTAX_CORRECT
		if (is_func (tp)) {
		    message (ERR_ILLSIZEOF);
		}
#endif /* SYNTAX_CORRECT */
		size = tp->size;
		ep = NIL_EXPR;
	    } else {
		/* '(' met -- so any expression allowed */
		sizeof_flag++;
		ep = expression ();
		sizeof_flag--;
		if (ep == NIL_EXPR) {
#ifndef SYNTAX_CORRECT
		    message (ERR_ILLSIZEOF);
#endif /* SYNTAX_CORRECT */
		    size = (SIZE) 1;
		} else if (ep->nodetype == en_size) {
		    size = (SIZE) ep->v.i;
		} else {
		    size = ep->etp->size;
		}
	    }
	    needpunc (tk_closepa);
	} else {
	    sizeof_flag++;
	    ep = unary ();
	    sizeof_flag--;
#ifndef SYNTAX_CORRECT
	    if (ep == NIL_EXPR) {
		message (ERR_ILLSIZEOF);
		size = (SIZE) 1;
	    } else
#endif /* SYNTAX_CORRECT */
	    if (ep->nodetype == en_size) {
		size = (SIZE) ep->v.i;
	    } else {
		size = ep->etp->size;
	    }
	}
	check_sizeof (ep, size);
	ep = mk_size (size, tp_size);
	break;
#ifdef TYPEOF
    case kw_typeof:
	getsym ();
	/*
	 * This is a mess.
	 * Normally, we treat array names just as pointers, but with sizeof,
	 * we want to get the real array size. So, the 'real' size is stored
	 * in an en_size node in v.i
	 */
	if (lastst == tk_openpa) {
	    getsym ();
	    if (is_type_name (lastst)) {
		tp = type_name ();
#ifndef SYNTAX_CORRECT
		if (is_func (tp)) {
		    message (ERR_ILLTYPEOF);
		}
#endif /* SYNTAX_CORRECT */
		typeof_tp = tp;
		ep = NIL_EXPR;
	    } else {
		/* '(' met -- so any expression allowed */
		ep = expression ();
		if (ep == NIL_EXPR) {
#ifndef SYNTAX_CORRECT
		    message (ERR_ILLTYPEOF);
#endif /* SYNTAX_CORRECT */
		    typeof_tp = tp_void;
		} else {
		    typeof_tp = ep->etp;
		}
	    }
	    needpunc (tk_closepa);
	} else {
	    ep = unary ();
#ifndef SYNTAX_CORRECT
	    if (ep == NIL_EXPR) {
		message (ERR_ILLTYPEOF);
		typeof_tp = tp_void;
	    } else
#endif /* SYNTAX_CORRECT */
	    {
		typeof_tp = ep->etp;
	    }
	}
	if (is_function_type (typeof_tp))
	    typeof_tp = tp_func;
	ep = mk_icon ((IVAL)typeof_tp->type, tp_int);
	break;
#endif /* TYPEOF */
    default:
	ep = primary ();
	break;
    }
    ep = opt0 (ep);
    return ep;
}

/*
 * arithmetic_conversion will coerce the nodes passed into compatible
 * types and return the type of the resulting expression.
 */
static TYP *arithmetic_conversion P2 (EXPR **, node1, EXPR **, node2)
{
    EXPR   *ep1 = *node1;
    EXPR   *ep2 = *node2;
    TYP    *tp1 = ep1->etp;
    TYP    *tp2 = ep2->etp;
    TYP    *tp;

    /* pointers may be combined with integer constant 0 */
    ep1 = opt0 (ep1);
    ep2 = opt0 (ep2);
    if (is_pointer_type (tp1) && is_null_pointer (ep2)) {
	return tp1;
    }
    if (is_pointer_type (tp2) && is_null_pointer (ep1)) {
	return tp2;
    }
    if (is_pointer_type (tp1) && is_pointer_type (tp2)) {
	return tp1;
    }
    /*
     * if either operand has type long double, the other operand is
     * converted to long double.
     */
    tp = tp_longdouble;
    if (is_same_type (tp1, tp) || is_same_type (tp2, tp)) {
	*node2 = implicit_castop (ep2, tp);
	*node1 = implicit_castop (ep1, tp);
	return tp;
    }
    /*
     * if either operand has type double the other operand is converted
     * to double.
     */
    tp = tp_double;
    if (is_same_type (tp1, tp) || is_same_type (tp2, tp)) {
	*node2 = implicit_castop (ep2, tp);
	*node1 = implicit_castop (ep1, tp);
	return tp;
    }
    /*
     * if either operand has type float the other operand is converted
     * to float.
     *

⌨️ 快捷键说明

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