📄 expr.c
字号:
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 + -