/* * NAME: optimize->asgnexp() * DESCRIPTION: optimize an assignment expression */ static Uint opt_asgnexp(node **m, bool pop) { node *n, *t; Uint d1, d2; n = *m; d2 = opt_expr(&n->r.right, FALSE); if ((n->r.right->type == N_INT || n->r.right->type == N_FLOAT) && n->l.left->mod == n->r.right->mod) { switch (n->type) { case N_ADD_EQ: case N_ADD_EQ_FLOAT: if (NFLT_ISZERO(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } if (NFLT_ISONE(n->r.right)) { n->type = N_ADD_EQ_1_FLOAT; return opt_lvalue(n->l.left) + 1; } if (NFLT_ISMONE(n->r.right)) { n->type = N_SUB_EQ_1_FLOAT; return opt_lvalue(n->l.left) + 1; } break; case N_ADD_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == 1) { n->type = N_ADD_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } if (n->r.right->l.number == -1) { n->type = N_SUB_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } break; case N_AND_EQ_INT: if (n->r.right->l.number == 0) { n->type = N_ASSIGN; return opt_expr(m, pop); } if (n->r.right->l.number == -1) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MULT_EQ: case N_MULT_EQ_FLOAT: if (NFLT_ISZERO(n->r.right)) { n->type = N_ASSIGN; return opt_expr(m, pop); } /* fall through */ case N_DIV_EQ: case N_DIV_EQ_FLOAT: if (NFLT_ISONE(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MULT_EQ_INT: if (n->r.right->l.number == 0) { n->type = N_ASSIGN; return opt_expr(m, pop); } /* fall through */ case N_DIV_EQ_INT: if (n->r.right->l.number == 1) { *m = n->l.left; return opt_expr(m, pop); } break; case N_LSHIFT_EQ_INT: case N_RSHIFT_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MOD_EQ_INT: if (n->r.right->l.number == 1) { n->type = N_ASSIGN; n->r.right->l.number = 0; return opt_expr(m, pop); } break; case N_OR_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == -1) { n->type = N_ASSIGN; return opt_expr(m, pop); } break; case N_SUB_EQ: case N_SUB_EQ_FLOAT: if (NFLT_ISZERO(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } if (NFLT_ISONE(n->r.right)) { n->type = N_SUB_EQ_1_FLOAT; return opt_lvalue(n->l.left) + 1; } if (NFLT_ISMONE(n->r.right)) { n->type = N_ADD_EQ_1_FLOAT; return opt_lvalue(n->l.left) + 1; } break; case N_SUB_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == 1) { n->type = N_SUB_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } if (n->r.right->l.number == -1) { n->type = N_ADD_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } break; case N_XOR_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } break; } } d1 = opt_lvalue(n->l.left) + 1; if (n->type == N_SUM_EQ) { d1++; return max2(d1, ((d1 < 6) ? d1 : 6) + d2); } if (n->type == N_ADD_EQ && (n->mod == T_STRING || (n->mod & T_REF) != 0) && (n->r.right->mod == T_STRING || (n->r.right->mod & T_REF) != 0 || n->r.right->type == N_RANGE)) { /* * see if the summand operator can be used */ switch (n->r.right->type) { case N_ADD: n->r.right->type = N_SUM; d2 += 2; /* SUM_SIMPLE on both sides */ if (n->r.right->l.left->type == N_RANGE) { d1++; } n->type = N_SUM_EQ; d1++; /* add SUM_SIMPLE */ return max2(d1, ((d1 < 6) ? d1 : 6) + d2); case N_AGGR: d2++; /* add SUM_SIMPLE */ n->type = N_SUM_EQ; d1++; /* add SUM_SIMPLE */ return max2(d1, ((d1 < 6) ? d1 : 6) + d2); case N_RANGE: d2 = max2(d2, 3); /* at least 3 */ /* fall through */ case N_SUM: n->type = N_SUM_EQ; d1++; /* add SUM_SIMPLE */ return max2(d1, ((d1 < 6) ? d1 : 6) + d2); case N_FUNC: if (n->r.right->r.number == kd_allocate || n->r.right->r.number == kd_allocate_int || n->r.right->r.number == kd_allocate_float) { t = n->r.right->l.left->r.right; if (t != (node *) NULL && t->type != N_PAIR && t->type != N_SPREAD && t->mod == T_INT) { d2++; /* add SUM_ALLOCATE */ n->type = N_SUM_EQ; d1++; /* add SUM_SIMPLE */ return max2(d1, ((d1 < 6) ? d1 : 6) + d2); } } break; } } return max2(d1, ((d1 < 5) ? d1 : 5) + d2); }
/* * NAME: optimize->expr() * DESCRIPTION: optimize an expression */ static Uint opt_expr(node **m, bool pop) { Uint d1, d2, i; node *n; node **oldside, *side; Uint olddepth; n = *m; switch (n->type) { case N_FLOAT: case N_GLOBAL: case N_INT: case N_LOCAL: case N_STR: case N_NIL: return !pop; case N_TOINT: case N_CAST: return opt_expr(&n->l.left, FALSE); case N_NEG: case N_UMIN: return max2(opt_expr(&n->l.left, FALSE), 2); case N_CATCH: oldside = side_start(&side, &olddepth); d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { n->l.left = (node *) NULL; } d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth)); if (d1 == 0) { *m = node_nil(); (*m)->line = n->line; return !pop; } return d1; case N_TOFLOAT: if (n->l.left->mod != T_INT) { return opt_expr(&n->l.left, FALSE); } /* fall through */ case N_NOT: case N_TST: if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } return opt_expr(&n->l.left, FALSE); case N_TOSTRING: if (pop && (n->l.left->mod == T_INT || n->l.left->mod == T_FLOAT)) { *m = n->l.left; return opt_expr(m, TRUE); } return opt_expr(&n->l.left, FALSE); case N_LVALUE: return opt_lvalue(n->l.left); case N_ADD_EQ_1: case N_ADD_EQ_1_INT: case N_ADD_EQ_1_FLOAT: case N_SUB_EQ_1: case N_SUB_EQ_1_INT: case N_SUB_EQ_1_FLOAT: return opt_lvalue(n->l.left) + 1; case N_MIN_MIN: if (pop) { n->type = N_SUB_EQ_1; } return opt_lvalue(n->l.left) + 1; case N_MIN_MIN_INT: if (pop) { n->type = N_SUB_EQ_1_INT; } return opt_lvalue(n->l.left) + 1; case N_MIN_MIN_FLOAT: if (pop) { n->type = N_SUB_EQ_1_FLOAT; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS: if (pop) { n->type = N_ADD_EQ_1; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS_INT: if (pop) { n->type = N_ADD_EQ_1_INT; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS_FLOAT: if (pop) { n->type = N_ADD_EQ_1_FLOAT; } return opt_lvalue(n->l.left) + 1; case N_FUNC: m = &n->l.left->r.right; n = *m; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; ) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); m = &n->r.right; n = n->l.left; i += (n->type == N_LVALUE || (n->type == N_COMMA && n->r.right->type == N_LVALUE)) ? 6 : 1; n = *m; } if (n->type == N_SPREAD) { m = &n->l.left; } oldside = side_start(&side, &olddepth); d2 = opt_expr(m, FALSE); d1 = max3(d1, i + d2, i + side_end(m, side, oldside, olddepth)); n = *m; if (n->type == N_LVALUE || (n->type == N_COMMA && n->r.right->type == N_LVALUE)) { d1 += 2; } return d1; case N_INSTANCEOF: return opt_expr(&n->l.left, FALSE) + 1; case N_GE: case N_GT: case N_LE: case N_LT: if (n->l.left->mod != n->r.right->mod) { return max2(opt_expr(&n->l.left, FALSE), opt_expr(&n->r.right, FALSE) + 1); } /* fall through */ case N_EQ: case N_NE: if (pop) { d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { *m = n->r.right; return opt_expr(m, TRUE); } d2 = opt_expr(&n->r.right, TRUE); if (d2 == 0) { *m = n->l.left; return d1; } n->type = N_COMMA; side_add(m, d1); return d2; } return opt_binop(m); case N_DIV_INT: case N_MOD_INT: if (n->r.right->type == N_INT && n->r.right->l.number == 0) { d1 = opt_binop(m); return (d1 == 1) ? !pop : d1; } /* fall through */ case N_ADD_INT: case N_ADD_FLOAT: case N_AND_INT: case N_DIV_FLOAT: case N_EQ_INT: case N_EQ_FLOAT: case N_GE_INT: case N_GE_FLOAT: case N_GT_INT: case N_GT_FLOAT: case N_LE_INT: case N_LE_FLOAT: case N_LSHIFT_INT: case N_LT_INT: case N_LT_FLOAT: case N_MULT_INT: case N_MULT_FLOAT: case N_NE_INT: case N_NE_FLOAT: case N_OR_INT: case N_RSHIFT_INT: case N_SUB_INT: case N_SUB_FLOAT: case N_XOR_INT: if (pop) { d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { *m = n->r.right; return opt_expr(m, TRUE); } d2 = opt_expr(&n->r.right, TRUE); if (d2 == 0) { *m = n->l.left; return d1; } n->type = N_COMMA; side_add(m, d1); return d2; } /* fall through */ case N_ADD: case N_AND: case N_DIV: case N_LSHIFT: case N_MOD: case N_MULT: case N_OR: case N_RSHIFT: case N_SUB: case N_SUM: case N_XOR: d1 = opt_binop(m); return (d1 == 1) ? !pop : d1; case N_INDEX: if (n->l.left->type == N_STR && n->r.right->type == N_INT) { if (n->r.right->l.number < 0 || n->r.right->l.number >= (long) n->l.left->l.string->len) { return 2; } node_toint(n, (Int) str_index(n->l.left->l.string, (long) n->r.right->l.number)); return !pop; } if (n->l.left->type == N_FUNC && n->r.right->mod == T_INT) { if (n->l.left->r.number == kd_status) { n->type = N_FUNC; if (n->l.left->l.left->r.right != (node *) NULL) { /* status(obj)[i] */ n = n->l.left; n->type = N_STR; n->r.right = n->l.left; n->l.string = n->l.left->l.string; n = n->r.right; n->type = N_PAIR; n->l.left = n->r.right; n->r.right = (*m)->r.right; (*m)->r.number = ((long) KFCALL << 24) | KF_STATUSO_IDX; } else { /* status()[i] */ n->l.left = n->l.left->l.left; n->l.left->r.right = n->r.right; n->r.number = ((long) KFCALL << 24) | KF_STATUS_IDX; } return opt_expr(m, pop); } if (n->l.left->r.number == kd_call_trace) { /* call_trace()[i] */ n->type = N_FUNC; n->l.left = n->l.left->l.left; n->l.left->r.right = n->r.right; n->r.number = ((long) KFCALL << 24) | KF_CALLTR_IDX; return opt_expr(m, pop); } } return max3(opt_expr(&n->l.left, FALSE), opt_expr(&n->r.right, FALSE) + 1, 3); case N_ADD_EQ: case N_ADD_EQ_INT: case N_ADD_EQ_FLOAT: case N_AND_EQ: case N_AND_EQ_INT: case N_DIV_EQ: case N_DIV_EQ_INT: case N_DIV_EQ_FLOAT: case N_LSHIFT_EQ: case N_LSHIFT_EQ_INT: case N_MOD_EQ: case N_MOD_EQ_INT: case N_MULT_EQ: case N_MULT_EQ_INT: case N_MULT_EQ_FLOAT: case N_OR_EQ: case N_OR_EQ_INT: case N_RSHIFT_EQ: case N_RSHIFT_EQ_INT: case N_SUB_EQ: case N_SUB_EQ_INT: case N_SUB_EQ_FLOAT: case N_SUM_EQ: case N_XOR_EQ: case N_XOR_EQ_INT: return opt_asgnexp(m, pop); case N_ASSIGN: if (n->l.left->type == N_AGGR) { d2 = 0; for (n = n->l.left->l.left; n->type == N_PAIR; n = n->r.right) { d1 = opt_lvalue(n->l.left); d2 += 2 + ((d1 < 4) ? d1 : 4); } d1 = opt_lvalue(n); d2 += 2 + ((d1 < 4) ? d1 : 4); return d2 + max2(2, opt_expr(&(*m)->r.right, FALSE)); } else { d1 = opt_lvalue(n->l.left); return max2(d1, ((d1 < 4) ? d1 : 4) + opt_expr(&n->r.right, FALSE)); } case N_COMMA: side_add(m, opt_expr(&n->l.left, TRUE)); return opt_expr(m, pop); case N_LAND: d1 = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (!opt_ctest(n->l.left)) { /* false && x */ *m = n->l.left; return !pop; } /* true && x */ n->type = N_TST; n->l.left = n->r.right; return opt_expr(m, pop); } oldside = side_start(&side, &olddepth); d2 = opt_cond(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { *m = n->l.left; return opt_expr(m, TRUE); } if (n->r.right->flags & F_CONST) { if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } if (!opt_ctest(n->r.right)) { /* x && false */ n->type = N_COMMA; return opt_expr(m, FALSE); } /* x && true */ n->type = N_TST; return d1; } if (n->r.right->type == N_COMMA) { n = n->r.right; if ((n->r.right->flags & F_CONST) && !opt_ctest(n->r.right)) { /* x && (y, false) --> (x && y, false) */ (*m)->r.right = n->l.left; n->l.left = *m; *m = n; return opt_expr(m, pop); } } return max2(d1, d2); case N_LOR: d1 = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (opt_ctest(n->l.left)) { /* true || x */ *m = n->l.left; return !pop; } /* false || x */ n->type = N_TST; n->l.left = n->r.right; return opt_expr(m, pop); } oldside = side_start(&side, &olddepth); d2 = opt_cond(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { *m = n->l.left; return opt_expr(m, TRUE); } if (n->r.right->flags & F_CONST) { if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } if (opt_ctest(n->r.right)) { /* x || true */ n->type = N_COMMA; return opt_expr(m, FALSE); } /* x || false */ n->type = N_TST; return d1; } if (n->r.right->type == N_COMMA) { n = n->r.right; if ((n->r.right->flags & F_CONST) && opt_ctest(n->r.right)) { /* x || (y, true) --> (x || y, true) */ (*m)->r.right = n->l.left; n->l.left = *m; *m = n; return opt_expr(m, pop); } } return max2(d1, d2); case N_QUEST: i = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (opt_ctest(n->l.left)) { *m = n->r.right->l.left; } else { *m = n->r.right->r.right; } return opt_expr(m, pop); } if (n->l.left->type == N_COMMA && (n->l.left->r.right->flags & F_CONST)) { side_add(&n->l.left, i); if (opt_ctest(n->l.left)) { *m = n->r.right->l.left; } else { *m = n->r.right->r.right; } return opt_expr(m, pop); } n = n->r.right; oldside = side_start(&side, &olddepth); d1 = opt_expr(&n->l.left, pop); if (d1 == 0) { n->l.left = (node *) NULL; } d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth)); if (d1 == 0) { n->l.left = (node *) NULL; } oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { n->r.right = (node *) NULL; } return max3(i, d1, d2); case N_RANGE: d1 = opt_expr(&n->l.left, FALSE); d2 = 1; if (n->r.right->l.left != (node *) NULL) { d2 = opt_expr(&n->r.right->l.left, FALSE); if ((n->l.left->mod == T_STRING || (n->l.left->mod & T_REF) != 0) && n->r.right->l.left->type == N_INT && n->r.right->l.left->l.number == 0) { /* * str[0 .. x] or arr[0 .. x] */ n->r.right->l.left = (node *) NULL; d2 = 1; } else { d1 = max2(d1, d2 + 1); d2 = 2; } } if (n->r.right->r.right != (node *) NULL) { d1 = max2(d1, d2 + opt_expr(&n->r.right->r.right, FALSE)); } if (n->l.left->type == N_STR) { long from, to; if (n->r.right->l.left == (node *) NULL) { from = 0; } else { if (n->r.right->l.left->type != N_INT) { return d1; } from = n->r.right->l.left->l.number; } if (n->r.right->r.right == (node *) NULL) { to = n->l.left->l.string->len - 1; } else { if (n->r.right->r.right->type != N_INT) { return d1; } to = n->r.right->r.right->l.number; } if (from >= 0 && from <= to + 1 && to < (long) n->l.left->l.string->len) { node_tostr(n, str_range(n->l.left->l.string, from, to)); return !pop; } return d1; } return max2(d1, 3); case N_AGGR: if (n->mod == T_MAPPING) { n = n->l.left; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; i += 2) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left->l.left, side, oldside, olddepth)); oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left->r.right, FALSE); d1 = max3(d1, i + 1 + d2, i + 1 + side_end(&n->l.left->r.right, side, oldside, olddepth)); n = n->r.right; } oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->r.right, FALSE); return max3(d1, i + 1 + d2, i + 1 + side_end(&n->r.right, side, oldside, olddepth)); } else { m = &n->l.left; n = *m; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; i++) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); m = &n->r.right; n = *m; } oldside = side_start(&side, &olddepth); d2 = opt_expr(m, FALSE); return max3(d1, i + d2, i + side_end(m, side, oldside, olddepth)); } } # ifdef DEBUG fatal("unknown expression type %d", n->type); # endif return 0; }
/* * NAME: optimize->asgnexp() * DESCRIPTION: optimize an assignment expression */ static Uint opt_asgnexp(node **m, bool pop) { node *n; Uint d1, d2; n = *m; d2 = opt_expr(&n->r.right, FALSE); if ((n->r.right->type == N_INT || n->r.right->type == N_FLOAT) && n->l.left->mod == n->r.right->mod) { switch (n->type) { case N_ADD_EQ: if (NFLT_ISZERO(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } if (NFLT_ISONE(n->r.right)) { n->type = N_ADD_EQ_1; return opt_lvalue(n->l.left) + 1; } if (NFLT_ISMONE(n->r.right)) { n->type = N_SUB_EQ_1; return opt_lvalue(n->l.left) + 1; } break; case N_ADD_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == 1) { n->type = N_ADD_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } if (n->r.right->l.number == -1) { n->type = N_SUB_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } break; case N_AND_EQ_INT: if (n->r.right->l.number == 0) { n->type = N_ASSIGN; return opt_expr(m, pop); } if (n->r.right->l.number == -1) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MULT_EQ: if (NFLT_ISZERO(n->r.right)) { n->type = N_ASSIGN; return opt_expr(m, pop); } /* fall through */ case N_DIV_EQ: if (NFLT_ISONE(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MULT_EQ_INT: if (n->r.right->l.number == 0) { n->type = N_ASSIGN; return opt_expr(m, pop); } /* fall through */ case N_DIV_EQ_INT: if (n->r.right->l.number == 1) { *m = n->l.left; return opt_expr(m, pop); } break; case N_LSHIFT_EQ_INT: case N_RSHIFT_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } break; case N_MOD_EQ_INT: if (n->r.right->l.number == 1) { n->type = N_ASSIGN; n->r.right->l.number = 0; return opt_expr(m, pop); } break; case N_OR_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == -1) { n->type = N_ASSIGN; return opt_expr(m, pop); } break; case N_SUB_EQ: if (NFLT_ISZERO(n->r.right)) { *m = n->l.left; return opt_expr(m, pop); } if (NFLT_ISONE(n->r.right)) { n->type = N_SUB_EQ_1; return opt_lvalue(n->l.left) + 1; } if (NFLT_ISMONE(n->r.right)) { n->type = N_ADD_EQ_1; return opt_lvalue(n->l.left) + 1; } break; case N_SUB_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } if (n->r.right->l.number == 1) { n->type = N_SUB_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } if (n->r.right->l.number == -1) { n->type = N_ADD_EQ_1_INT; return opt_lvalue(n->l.left) + 1; } break; case N_XOR_EQ_INT: if (n->r.right->l.number == 0) { *m = n->l.left; return opt_expr(m, pop); } break; } } d1 = opt_lvalue(n->l.left) + 1; if (n->type == N_SUM_EQ) { d1++; return max2(d1, ((d1 < 5) ? d1 : 5) + d2); } if (n->type == N_ADD_EQ && (n->mod == T_STRING || (n->mod & T_REF) != 0) && (n->r.right->mod == T_STRING || (n->r.right->mod & T_REF) != 0 || n->r.right->type == N_RANGE)) { /* * see if the summand operator can be used */ switch (n->r.right->type) { case N_ADD: n->r.right->type = N_SUM; d2 += 2; /* (-2) on both sides */ if (n->r.right->l.left->type == N_RANGE) { d1++; } n->type = N_SUM_EQ; d1++; /* add (-2) */ return max2(d1, ((d1 < 5) ? d1 : 5) + d2); case N_AGGR: d2++; /* add (-2) */ n->type = N_SUM_EQ; d1++; /* add (-2) */ return max2(d1, ((d1 < 5) ? d1 : 5) + d2); case N_RANGE: d2 = max2(d2, 3); /* at least 3 */ /* fall through */ case N_SUM: n->type = N_SUM_EQ; d1++; /* add (-2) */ return max2(d1, ((d1 < 5) ? d1 : 5) + d2); } } return max2(d1, ((d1 < 4) ? d1 : 4) + d2); }