Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
/* 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;
}