📄 expr.c
字号:
* However K&R mandates that all floating point arithmetic be done as
* doubles.
*/
tp = tp_float;
if (is_same_type (tp1, tp) || is_same_type (tp2, tp)) {
if (lang_option == LANG_KANDR) {
tp = tp_double;
}
*node2 = implicit_castop (ep2, tp);
*node1 = implicit_castop (ep1, tp);
return tp;
}
/*
* The integral promotions are performed on both operands.
* If an int can represent all values of the original type, the value is
* converted to an int; otherwise it is converted to an unsigned int.
*/
ep1 = integral_promotion (ep1);
tp1 = ep1->etp;
ep2 = integral_promotion (ep2);
tp2 = ep2->etp;
/*
* is both operands have the same type, then no further
* conversion is needed.
*/
if (is_same_type (tp1, tp2)) {
*node2 = ep2;
*node1 = ep1;
return tp1;
}
/*
*if either operand has type unsigned long long int, the other operand
* is converted to unsigned long long int
*/
tp = tp_ulonglong;
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 long long int, the other operand
* is converted to long long int
*/
tp = tp_longlong;
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 unsigned long int, the other operand is
* converted to unsigned long int.
*/
tp = tp_ulong;
if (is_same_type (tp1, tp) || is_same_type (tp2, tp)) {
*node2 = implicit_castop (ep2, tp);
*node1 = implicit_castop (ep1, tp);
return tp;
}
/*
* if one operand has type long int and the other has type unsigned int,
* if a long int can represent all values of an unsigned int, the operand
* of type unsigned int is converted to long int; if a long int cannot
* represent all the values of an unsigned int, both operands are converted
* to unsigned long int.
*/
if ((tp1->type == bt_long && is_same_type (tp2, tp_uint)) ||
(tp2->type == bt_long && is_same_type (tp1, tp_uint))) {
tp = (tp_long->size > tp_uint->size) ? tp_long : tp_ulong;
*node2 = implicit_castop (ep2, tp);
*node1 = implicit_castop (ep1, tp);
return tp;
}
/*
* if either operand has type long int, the other operand is
* converted to long int.
*/
tp = tp_long;
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 unsigned int, the other operand is
* converted to unsigned int.
*/
tp = tp_uint;
if (is_same_type (tp1, tp) || is_same_type (tp2, tp)) {
*node2 = implicit_castop (ep2, tp);
*node1 = implicit_castop (ep1, tp);
return tp;
}
/*
* both operands have type int
*/
tp = tp_int;
*node2 = implicit_castop (ep2, tp);
*node1 = implicit_castop (ep1, tp);
return tp;
}
/*
* ,,arithmetic_conversion'' for comparisons:
* When comparing two char's, it is not necessary to cast
* both of them to long in advance
*
* Perhaps not strictly K&R, but more efficient.
* If you don't like it, use arithmetic_conversion in ALL cases
*/
static TYP *arithmetic_conversion2 P2 (EXPR **, node1, EXPR **, node2)
{
TYP *tp1 = (*node1)->etp;
TYP *tp2 = (*node2)->etp;
TYP *tp;
/* short cut: */
if (is_same_type (tp1, tp2)) {
return tp1;
}
/* comparison with integer constant */
*node1 = opt0 (*node1);
*node2 = opt0 (*node2);
if (is_constexpr (*node1)) {
EXPR **node = node1;
tp = tp1;
node1 = node2;
tp1 = tp2;
node2 = node;
tp2 = tp;
}
if (is_constexpr (*node2)) {
#ifndef SYNTAX_CORRECT
if (is_pointer_type (tp2) && !is_pointer_type (tp1)
&& !is_null_pointer (*node2)) {
message (ERR_MISMATCH);
}
#endif /* SYNTAX_CORRECT */
if (is_constant_in_range (*node2, tp1)) {
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
}
}
switch (tp1->type) {
/* Type of first operand */
case bt_char:
case bt_schar:
switch (tp2->type) {
case bt_char:
case bt_schar:
return tp2;
case bt_charu:
case bt_uchar:
tp = tp_short;
*node1 = implicit_castop (*node1, tp);
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_charu:
case bt_uchar:
switch (tp2->type) {
case bt_charu:
case bt_uchar:
return tp2;
case bt_char:
case bt_schar:
tp = tp_short;
*node1 = implicit_castop (*node1, tp);
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_ushort:
case bt_uint16:
if (tp_int->size == tp2->size) {
tp = tp2;
*node1 = implicit_castop (*node1, tp);
} else {
tp = tp_long;
*node1 = implicit_castop (*node1, tp);
*node2 = implicit_castop (*node2, tp);
}
return tp;
case bt_short:
case bt_int16:
if (tp_int->size == tp2->size) {
tp = tp_ushort;
*node2 = implicit_castop (*node2, tp);
} else {
tp = tp_long;
*node1 = implicit_castop (*node1, tp);
*node2 = implicit_castop (*node2, tp);
}
return tp;
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
/*
* pointers are equivalent to function names
*/
case bt_pointer16:
case bt_pointer32:
if (is_func (tp2)) {
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
}
/*lint -fallthrough */
case bt_func:
if (is_pointer_type (tp2)) {
*node1 = implicit_castop (*node1, tp2);
}
/*lint -fallthrough */
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_pointer16:
case bt_int32:
case bt_long:
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_uint32:
case bt_ulong:
case bt_pointer32:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_longlong:
case bt_ulonglong:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_pointer16:
case bt_int32:
case bt_long:
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_uint32:
case bt_ulong:
case bt_pointer32:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_float:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_double:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
case bt_float:
tp = tp1;
*node2 = implicit_castop (*node2, tp);
return tp;
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
case bt_longdouble:
switch (tp2->type) {
case bt_char:
case bt_charu:
case bt_uchar:
case bt_schar:
case bt_short:
case bt_ushort:
case bt_int16:
case bt_uint16:
case bt_int32:
case bt_uint32:
case bt_long:
case bt_ulong:
case bt_longlong:
case bt_ulonglong:
case bt_float:
case bt_double:
case bt_longdouble:
tp = tp2;
*node1 = implicit_castop (*node1, tp);
return tp;
default:
break;
}
break;
default:
break;
}
#ifndef SYNTAX_CORRECT
message (ERR_MISMATCH);
#endif /* SYNTAX_CORRECT */
return tp1;
}
/*
* multops parses the multiply priority operators. the syntax of this group
* is:
*
* unary multop * unary multop / unary multop % unary
*/
static EXPR *multops P0 (void)
{
EXPR *ep1, *ep2;
EXPRTYPE nt;
TYP *tp;
ep1 = unary ();
if (ep1 == NIL_EXPR) {
return NIL_EXPR;
}
for (;;) {
switch (lastst) {
case tk_star:
nt = en_mul;
break;
case tk_divide:
nt = en_div;
break;
case tk_mod:
nt = en_mod;
break;
default:
ep1 = opt0 (ep1);
return ep1;
}
getsym (); /* move on to next unary op */
ep2 = unary ();
if (ep2) {
switch (nt) {
case en_div:
check_zero (ep2);
/*lint -fallthrough */
case en_mul:
check_arithmetic (ep1);
check_arithmetic (ep2);
break;
case en_mod:
check_zero (ep2);
check_integral (ep1);
check_integral (ep2);
break;
default:
CANNOT_REACH_HERE ();
break;
}
check_set (ep1);
check_set (ep2);
check_sequence_accessed (ep1);
check_sequence_accessed (ep2);
tp = arithmetic_conversion (&ep1, &ep2);
ep1 = mk_node (nt, ep1, ep2, tp);
#ifndef SYNTAX_CORRECT
} else {
message (ERR_IDEXPECT);
#endif /* SYNTAX_CORRECT */
}
}
}
/*
* addops handles the addition and subtraction operators.
*/
static EXPR *addops P0 (void)
{
EXPR *ep1, *ep2, *ep3;
TYP *tp;
TYP *tp1 = is_same_size (tp_pointer, tp_ulong) ? tp_long : tp_short;
EXPRTYPE nt;
ep1 = multops ();
#ifndef SYNTAX_CORRECT
if (ep1 == NIL_EXPR) {
return NIL_EXPR;
}
#endif /* SYNTAX_CORRECT */
for (;;) {
switch (lastst) {
case tk_plus:
nt = en_add;
break;
case tk_minus:
nt = en_sub;
break;
default:
ep1 = opt0 (ep1);
return ep1;
}
getsym ();
ep2 = multops ();
#ifndef SYNTAX_CORRECT
if (ep2 == NIL_EXPR) {
message (ERR_IDEXPECT);
return ep2;
}
check_set (ep1);
check_set (ep2);
check_sequence_accessed (ep1);
check_sequence_accessed (ep2);
#endif /* SYNTAX_CORRECT */
if (is_pointer_type (ep1->etp)) {
if ((nt == en_sub) && is_pointer_type (ep2->etp)) {
/* pointer subtraction */
#ifndef SYNTAX_CORRECT
if (!is_compatible_type (ep1->etp, ep2->etp)) {
message (WARN_POINTER);
}
#endif /* SYNTAX_CORRECT */
check_object (ep1);
check_complete (ep1->etp);
check_object (ep2);
check_complete (ep2->etp);
ep1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -