/* returns true if the expression is regarded as "simple". * Simple expressions match this criteria: * identifier (parameter, field) * integer constant * <dereference+>identifier * identifier / 2 * identifier * 2 * identifier - 1 * identifier + 1 * * */ boolean ASTP_expr_is_simple(AST_exp_n_t * exp) { if (ASTP_evaluate_expr(exp, true)) { return true; } switch(exp->exp_type) { case AST_EXP_CONSTANT: return true; case AST_EXP_BINARY_SLASH: case AST_EXP_BINARY_STAR: if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT && ASTP_expr_integer_value(exp->exp.expression.oper2) == 2) { return true; } break; case AST_EXP_BINARY_PLUS: case AST_EXP_BINARY_MINUS: if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT && ASTP_expr_integer_value(exp->exp.expression.oper2) == 1) { return true; } break; case AST_EXP_UNARY_STAR: while(exp->exp_type == AST_EXP_UNARY_STAR) exp = exp->exp.expression.oper1; if (exp->exp_type == AST_EXP_CONSTANT) { return true; } break; case AST_EXP_BINARY_AND: /* could be alignment */ if (exp->exp.expression.oper1->exp_type == AST_EXP_BINARY_PLUS && exp->exp.expression.oper2->exp_type == AST_EXP_UNARY_TILDE) { AST_exp_n_t * op1 = exp->exp.expression.oper1; AST_exp_n_t * op2 = exp->exp.expression.oper2; AST_exp_n_t * ident_exp = op1->exp.expression.oper1; long nval = ASTP_expr_integer_value(op1->exp.expression.oper2); /* allow one level of indirection for the identifier part */ if ((ident_exp->exp_type == AST_EXP_CONSTANT || ( ident_exp->exp_type == AST_EXP_UNARY_STAR && ident_exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT)) && (nval == 1 || nval == 3 || nval == 7) && ASTP_expr_integer_value(op2->exp.expression.oper1) == nval) return true; } break; } return false; }
/* evaluate the expression, reducing it down to a single constant expression * node if possible. * If constant_only is true, this routine will return false when it hits * the name of a parameter to indicate that the expression is not a constant * expression. * */ boolean ASTP_evaluate_expr ( parser_location_p location, AST_exp_n_t * exp, boolean constant_only ) { boolean result; long val, val1, val2; AST_exp_n_t * op1=NULL, *op2=NULL, *op3=NULL; if (exp == NULL) { log_warning(location->lineno, NIDL_EXP_IS_NULL, NULL); return true; } if (exp->exp_type == AST_EXP_CONSTANT) { /* resolve binding for identifiers */ if (exp->exp.constant.type == AST_nil_const_k && exp->exp.constant.val.other == NULL) { exp->exp.constant.val.other = (AST_constant_n_t*)ASTP_lookup_binding( location, exp->exp.constant.name, fe_constant_n_k, FALSE); if (exp->exp.constant.val.other == NULL) return false; } /* already reduced to the simplest form */ return true; } else if (exp->exp_type == AST_EXP_TUPLE) { op1 = exp->exp.expression.oper1; if (op1->exp.constant.type == AST_nil_const_k && op1->exp.constant.val.other == NULL) { op1->exp.constant.val.other = (AST_constant_n_t *)ASTP_lookup_binding( location, op1->exp.constant.name, fe_constant_n_k, FALSE); if (op1->exp.constant.val.other == NULL) return false; } op2 = exp->exp.expression.oper2; if (op2->exp.constant.type == AST_nil_const_k && op2->exp.constant.val.other == NULL) { op2->exp.constant.val.other = (AST_constant_n_t *)ASTP_lookup_binding( location, op2->exp.constant.name, fe_constant_n_k, FALSE); if (op2->exp.constant.val.other == NULL) return false; } return true; } /* time to evaluate some expressions. * First, reduce the operands to their simplest forms too */ result = ASTP_evaluate_expr(location, exp->exp.expression.oper1, constant_only); if (result == false) return false; op1 = exp->exp.expression.oper1; if ((exp->exp_type & AST_EXP_2_OP_MASK) != 0) { result = ASTP_evaluate_expr(location, exp->exp.expression.oper2, constant_only); if (result == false) return false; op2 = exp->exp.expression.oper2; } if ((exp->exp_type & AST_EXP_3_OP_MASK) != 0) { result = ASTP_evaluate_expr(location, exp->exp.expression.oper3, constant_only); if (result == false) return false; op3 = exp->exp.expression.oper3; } /* only reached if we are dealing with a constant expression, * and that means that we can play around with the operands */ switch(exp->exp_type) { case AST_EXP_UNARY_NOT: exp->exp.constant.val.integer = !ASTP_expr_integer_value(location, op1); break; case AST_EXP_UNARY_TILDE: exp->exp.constant.val.integer = ~ASTP_expr_integer_value(location, op1); break; case AST_EXP_UNARY_PLUS: /* why this? I can't remember what I was thinking */ exp->exp.constant.val.integer = +ASTP_expr_integer_value(location, op1); break; case AST_EXP_UNARY_MINUS: exp->exp.constant.val.integer = -ASTP_expr_integer_value(location, op1); break; case AST_EXP_UNARY_STAR: return false; case AST_EXP_BINARY_PERCENT: val = ASTP_expr_integer_value(location, op2); if (val == 0) log_error(location->lineno, NIDL_INTDIVBY0, NULL); else val = ASTP_expr_integer_value(location, op1) % val; exp->exp.constant.val.integer = val; break; case AST_EXP_BINARY_SLASH: val = ASTP_expr_integer_value(location, op2); if (val == 0) log_error(location->lineno, NIDL_INTDIVBY0, NULL); else val = ASTP_expr_integer_value(location, op1) / val; exp->exp.constant.val.integer = val; break; case AST_EXP_BINARY_STAR: val1 = ASTP_expr_integer_value(location, op1); val2 = ASTP_expr_integer_value(location, op2); val = val1 * val2; if (val < val1 && val > val2) log_error(location->lineno, NIDL_INTOVERFLOW, KEYWORDS_lookup_text(LONG_KW), NULL); exp->exp.constant.val.integer = val; break; case AST_EXP_BINARY_MINUS: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) - ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_PLUS: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) + ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_RSHIFT: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) >> ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_LSHIFT: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) << ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_GE: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) >= ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_LE: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) <= ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_GT: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) > ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_LT: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) < ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_NE: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) != ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_EQUAL: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) == ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_AND: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) & ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_OR: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) | ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_XOR: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) ^ ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_LOG_AND: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) && ASTP_expr_integer_value(location, op2); break; case AST_EXP_BINARY_LOG_OR: exp->exp.constant.val.integer = ASTP_expr_integer_value(location, op1) || ASTP_expr_integer_value(location, op2); break; case AST_EXP_TERNARY_OP: /* we want to preserve the type for this, so we short-circuit the return */ if (ASTP_expr_integer_value(location, op1)) { assert(op2 != NULL); *exp = *op2; } else { assert(op3 != NULL); *exp = *op3; } return true; default: /* NOTREACHED (hopefully!) */ break; } ASTP_free_exp(op1); ASTP_free_exp(op2); ASTP_free_exp(op3); exp->exp_type = AST_EXP_CONSTANT; exp->exp.constant.type = AST_int_const_k; return true; }