/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/producers/common/construct/assign.c,v 1.7 2005/07/22 12:21:01 stefanf Exp $
*/
#include "config.h"
#include "producer.h"
#include "c_types.h"
#include "exp_ops.h"
#include "id_ops.h"
#include "off_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "assign.h"
#include "basetype.h"
#include "cast.h"
#include "construct.h"
#include "convert.h"
#include "chktype.h"
#include "expression.h"
#include "identifier.h"
#include "initialise.h"
#include "literal.h"
#include "member.h"
#include "operator.h"
#include "predict.h"
#include "syntax.h"
#include "ustring.h"
/*
* CONVERT BY ASSIGNMENT
*
* This routine converts the expression a to the type t, as if by
* assignment. The cases where t is a class type or a reference are
* handled elsewhere.
*/
EXP
convert_assign(TYPE t, EXP a, ERROR *err)
{
EXP e = cast_exp (t, a, err, CAST_IMPLICIT);
return (e);
}
/*
* CONVERT TO A CLASS TYPE BY ASSIGNMENT
*
* This routine converts the expression a to the class t, as if by
* assignment. The constructors of t are ignored, only base class
* conversions and conversion operators being considered.
*/
EXP
convert_class(TYPE t, EXP a, ERROR *err)
{
EXP e;
TYPE s = DEREF_type (exp_type (a));
if (IS_type_compound (s)) {
e = cast_class_class (t, a, err, CAST_IMPLICIT, 0);
if (!IS_NULL_exp (e)) return (e);
}
e = convert_conv (t, a, err, CAST_IMPLICIT);
return (e);
}
/*
* CONSTRUCT A POSTFIX EXPRESSION
*
* This routine constructs the expressions 'a++' and 'a--'. Note that
* in this and other assignment expressions, a cannot have array type,
* so that no bounds checks are appropriate. The result is an rvalue.
*/
EXP
make_postfix_exp(int op, EXP a)
{
EXP e;
TYPE ta;
ERROR err;
unsigned ca;
int is_bool;
/* An assignment is a side effect */
no_side_effects++;
/* Allow for reference conversions */
a = convert_reference (a, REF_NORMAL);
ta = DEREF_type (exp_type (a));
ca = type_category (&ta);
/* Check for overloading */
#if LANGUAGE_CPP
if (IS_TYPE_OVERLOAD (ca)) {
if (overload_depth == 0) {
/* Overloads as 'operator op (a, 0)' */
EXP b = make_null_exp (type_sint);
e = binary_overload (op, a, b);
return (e);
}
if (IS_TYPE_CLASS (ca)) goto error_lab;
}
#else
if (IS_TYPE_CLASS (ca)) goto error_lab;
#endif
/* Operand should be a modifiable lvalue */
err = check_modifiable (ta, a);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_post_incr_mod (op));
report (crt_loc, err);
err = NULL_err;
}
/* Operand can be arithmetic ... */
if (IS_TYPE_ARITH (ca)) {
EXP b;
TYPE t;
TYPE tb;
OFFSET off = NULL_off;
/* Allow for bitfields */
if (IS_TYPE_BITF (ca)) off = decons_bitf_exp (&a);
/* Form the result */
MAKE_exp_dummy (ta, a, LINK_NONE, off, 0, a);
b = convert_lvalue (a);
tb = DEREF_type (exp_type (b));
t = promote_type (tb);
if (IS_NULL_off (off)) {
MAKE_exp_dummy (tb, b, LINK_NONE, NULL_off, 0, b);
e = convert_promote (t, b);
} else {
b = convert_promote (t, b);
MAKE_exp_dummy (t, b, LINK_NONE, NULL_off, 0, b);
e = b;
tb = t;
}
is_bool = check_int_type (ta, btype_bool);
if (is_bool && op == lex_plus_Hplus) {
/* bool b; b++ results in b being true. */
report (crt_loc, ERR_expr_post_incr_bool_inc (op, ta));
e = make_bool_exp (BOOL_TRUE, exp_int_lit_tag);
} else {
/* Other types and bool-- */
EXP c;
if (is_bool) {
report (crt_loc, ERR_expr_post_incr_bool_dec (op, ta));
}
c = make_unit_exp (t);
if (op == lex_plus_Hplus) {
MAKE_exp_plus (t, e, c, e);
} else {
MAKE_exp_minus (t, e, c, e);
}
e = convert_assign (ta, e, &err);
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
}
MAKE_exp_postinc (tb, a, b, e, e);
return (e);
}
/* ... or pointer ... */
if (IS_TYPE_PTR (ca)) {
/* Pointer must be to complete object type */
EXP b;
OFFSET off;
TYPE t = check_pointer (ta, &err);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_post_incr_incompl (op));
report (crt_loc, err);
}
if (IS_type_top_etc (t)) t = type_char;
/* Create the identities */
MAKE_exp_dummy (ta, a, LINK_NONE, NULL_off, 0, a);
b = convert_lvalue (a);
ta = DEREF_type (exp_type (b));
MAKE_exp_dummy (ta, b, LINK_NONE, NULL_off, 0, b);
/* Form the result */
MAKE_off_type (t, off);
if (op == lex_minus_Hminus) MAKE_off_negate (off, off);
e = make_add_ptr (ta, b, off);
MAKE_exp_postinc (ta, a, b, e, e);
return (e);
}
/* ... and nothing else */
error_lab : {
if (!IS_TYPE_ERROR (ca)) {
report (crt_loc, ERR_expr_post_incr_op (op, ta));
}
}
e = make_error_exp (0);
return (e);
}
/*
* CREATE A PRE-INCREMENT EXPRESSION
*
* This routine creates a pre-increment or assignment expression for
* the expression a of type t given by the operation b. If a is a
* bitfield then off gives the bitfield offset. The result is an
* lvalue in C++, but an rvalue in C. There is a slight problem in the
* latter case when t is a bitfield: the value is not b, but
* convert_bitfield (b). This conversion is left implicit, and is
* only made explicit in the TDF output routines.
*/
static EXP
make_preinc_exp(TYPE t, EXP a, EXP b, OFFSET off, int op)
{
EXP e;
#if LANGUAGE_C
t = rvalue_type (t);
#endif
if (IS_NULL_off (off)) {
/* Simple case */
if (op == lex_assign) {
MAKE_exp_assign (t, a, b, e);
} else {
MAKE_exp_preinc (t, a, b, op, e);
}
} else {
/* Bitfield case */
#if LANGUAGE_C
MAKE_exp_preinc (t, a, b, op, e);
t = promote_type (t);
#else
TYPE p;
TYPE s = find_bitfield_type (t);
MAKE_type_ptr (cv_none, s, p);
s = lvalue_type (s);
MAKE_exp_preinc (s, a, b, op, e);
MAKE_exp_address (p, e, e);
MAKE_exp_add_ptr (p, e, off, 0, e);
MAKE_exp_indir (t, e, e);
#endif
}
#if LANGUAGE_C
MAKE_exp_contents (t, e, e);
#endif
return (e);
}
/*
* CONSTRUCT A PREFIX EXPRESSION
*
* This routine constructs the expressions '++a' and '--a'. The result is
* an lvalue in C++ but an rvalue in C.
*/
EXP
make_prefix_exp(int op, EXP a)
{
EXP e;
TYPE ta;
ERROR err;
unsigned ca;
int is_bool;
/* An assignment is a side effect */
no_side_effects++;
/* Allow for reference conversions */
a = convert_reference (a, REF_NORMAL);
ta = DEREF_type (exp_type (a));
ca = type_category (&ta);
/* Check for overloading */
#if LANGUAGE_CPP
if (IS_TYPE_OVERLOAD (ca)) {
if (overload_depth == 0) {
/* Overloads as 'operator op (a)' */
e = unary_overload (op, a);
return (e);
}
if (IS_TYPE_CLASS (ca)) goto error_lab;
}
#else
if (IS_TYPE_CLASS (ca)) goto error_lab;
#endif
/* Operand should be a modifiable lvalue */
err = check_modifiable (ta, a);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_pre_incr_mod (op));
report (crt_loc, err);
err = NULL_err;
}
/* Operand can be arithmetic ... */
if (IS_TYPE_ARITH (ca)) {
EXP c;
TYPE t;
OFFSET off = NULL_off;
is_bool = check_int_type (ta, btype_bool);
if (is_bool && op == lex_plus_Hplus) {
/* bool b; ++b results in b being true. */
report (crt_loc, ERR_expr_pre_incr_bool_inc (op, ta));
c = make_bool_exp (BOOL_TRUE, exp_int_lit_tag);
e = make_preinc_exp (ta, a, c, NULL_off, lex_assign);
return (e);
} else if (is_bool) {
report (crt_loc, ERR_expr_pre_incr_bool_dec (op, ta));
}
/* Allow for bitfields */
if (IS_TYPE_BITF (ca)) off = decons_bitf_exp (&a);
/* Form the result */
MAKE_exp_dummy (ta, a, LINK_NONE, off, 0, a);
e = convert_lvalue (a);
t = DEREF_type (exp_type (e));
t = promote_type (t);
e = convert_promote (t, e);
c = make_unit_exp (t);
if (op == lex_plus_Hplus) {
MAKE_exp_plus (t, e, c, e);
} else {
MAKE_exp_minus (t, e, c, e);
}
e = convert_assign (ta, e, &err);
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
e = make_preinc_exp (ta, a, e, off, op);
return (e);
}
/* ... or pointer ... */
if (IS_TYPE_PTR (ca)) {
/* Pointer must be to complete object type */
OFFSET off;
TYPE t = check_pointer (ta, &err);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_pre_incr_incompl (op));
report (crt_loc, err);
}
if (IS_type_top_etc (t)) t = type_char;
/* Form the result */
MAKE_exp_dummy (ta, a, LINK_NONE, NULL_off, 0, a);
e = convert_lvalue (a);
if (!IS_type_ptr (ta)) ta = DEREF_type (exp_type (e));
MAKE_off_type (t, off);
if (op == lex_minus_Hminus) MAKE_off_negate (off, off);
e = make_add_ptr (ta, e, off);
e = make_preinc_exp (ta, a, e, NULL_off, op);
return (e);
}
/* ... and nothing else */
error_lab : {
if (!IS_TYPE_ERROR (ca)) {
report (crt_loc, ERR_expr_pre_incr_op (op, ta));
}
e = make_error_exp (LANGUAGE_CPP);
return (e);
}
}
/*
* CONSTRUCT AN ASSIGNMENT EXPRESSION
*
* This routine constructs the expression 'a = b'. If c is true then
* assignment of classes is done directly rather than via an assignment
* operator. The result is an lvalue in C++ but an rvalue in C.
*/
EXP
make_assign_exp(EXP a, EXP b, int c)
{
EXP e;
ERROR err;
TYPE ta, tb;
unsigned ca, cb;
int to_class = 0;
int op = lex_assign;
OFFSET off = NULL_off;
/* An assignment is a side effect */
no_side_effects++;
/* Apply reference conversion on first operand */
a = convert_reference (a, REF_NORMAL);
ta = DEREF_type (exp_type (a));
ca = type_category (&ta);
/* Apply reference conversion on second operand */
b = convert_reference (b, REF_ASSIGN);
tb = DEREF_type (exp_type (b));
cb = type_category (&tb);
/* Check for template parameters */
#if LANGUAGE_CPP
if (IS_TYPE_TEMPL (ca) || IS_TYPE_TEMPL (cb)) {
if (overload_depth == 0) {
e = binary_overload (op, a, b);
return (e);
}
}
#endif
/* Check for overloading (classes only) */
if (IS_TYPE_CLASS (ca)) {
#if LANGUAGE_CPP
if (c == 0) {
if (overload_depth == 0) {
e = binary_overload (op, a, b);
return (e);
}
if (!IS_TYPE_ERROR (cb)) {
/* Find reason for failure */
err = check_incomplete (ta);
if (IS_NULL_err (err) && IS_type_compound (ta)) {
CLASS_TYPE ct;
IDENTIFIER id;
ct = DEREF_ctype (type_compound_defn (ta));
id = find_operator (ct, op);
if (!IS_NULL_id (id)) {
err = ERR_over_match_viable_none (id);
}
}
err = concat_error (err, ERR_expr_ass_op (op, ta, tb));
report (crt_loc, err);
}
e = make_error_exp (LANGUAGE_CPP);
return (e);
}
#else
UNUSED (c);
UNUSED (cb);
#endif
to_class = 1;
}
/* First operand should be a modifiable lvalue */
err = check_modifiable (ta, a);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_ass_mod (op));
report (crt_loc, err);
}
/* Do operand conversion */
err = NULL_err;
if (to_class) {
b = convert_none (b);
b = convert_class (ta, b, &err);
b = remove_temporary (b, a);
} else {
b = convert_assign (ta, b, &err);
}
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
/* Construct the result */
if (IS_type_bitfield (ta)) {
off = decons_bitf_exp (&a);
MAKE_exp_dummy (ta, a, LINK_NONE, off, 0, a);
}
e = make_preinc_exp (ta, a, b, off, op);
return (e);
}
/*
* CONSTRUCT A BECOMES EXPRESSION
*
* This routine constructs the expression 'a op b' where op is one of the
* assignment operators, '*=', '/=' etc. The result is an lvalue in
* C++, but an rvalue in C.
*/
EXP
make_become_exp(int op, EXP a, EXP b)
{
EXP e;
EXP d;
TYPE td;
ERROR err;
TYPE ta, tb;
unsigned tag;
unsigned ca, cb;
OFFSET off = NULL_off;
/* An assignment is a side effect */
no_side_effects++;
/* Apply reference conversion on first operand */
a = convert_reference (a, REF_NORMAL);
ta = DEREF_type (exp_type (a));
ca = type_category (&ta);
/* Apply reference conversion on second operand */
b = convert_reference (b, REF_NORMAL);
tb = DEREF_type (exp_type (b));
cb = type_category (&tb);
/* Allow for overloading */
#if LANGUAGE_CPP
if (IS_TYPE_OVERLOAD (ca) || IS_TYPE_OVERLOAD (cb)) {
if (overload_depth == 0) {
e = binary_overload (op, a, b);
return (e);
}
if (IS_TYPE_CLASS (ca)) goto error_lab;
}
#else
if (IS_TYPE_CLASS (ca)) goto error_lab;
#endif
/* First operand should be a modifiable lvalue */
err = check_modifiable (ta, a);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_ass_mod (op));
report (crt_loc, err);
err = NULL_err;
}
/* Allow for bitfields */
if (IS_TYPE_BITF (ca)) off = decons_bitf_exp (&a);
/* Introduce identity for assignment variable */
td = ta;
MAKE_exp_dummy (td, a, LINK_NONE, off, 0, d);
a = convert_lvalue (d);
ta = DEREF_type (exp_type (a));
ca = type_category (&ta);
/* Do lvalue conversions */
if (IS_TYPE_ADDRESS (cb)) {
b = convert_lvalue (b);
tb = DEREF_type (exp_type (b));
cb = type_category (&tb);
}
/* Weed out booleans immediately */
if (IS_TYPE_INT (ca) && check_int_type (ta, btype_bool)) {
report (crt_loc, ERR_expr_ass_op (op, ta, tb));
e = make_error_exp (LANGUAGE_CPP);
return (e);
}
/* Find the operation type */
switch (op) {
case lex_and_Heq_H1 : tag = exp_and_tag ; goto integral_lab;
case lex_div_Heq : tag = exp_div_tag ; goto arithmetic_lab;
case lex_lshift_Heq : tag = exp_lshift_tag ; goto shift_lab;
case lex_minus_Heq : tag = exp_minus_tag ; goto pointer_lab;
case lex_or_Heq_H1 : tag = exp_or_tag ; goto integral_lab;
case lex_plus_Heq : tag = exp_plus_tag ; goto pointer_lab;
case lex_rem_Heq : tag = exp_rem_tag ; goto integral_lab;
case lex_rshift_Heq : tag = exp_rshift_tag ; goto shift_lab;
case lex_star_Heq : tag = exp_mult_tag ; goto arithmetic_lab;
case lex_xor_Heq_H1 : tag = exp_xor_tag ; goto integral_lab;
default : goto error_lab;
}
integral_lab : {
/* Integral operations */
if (IS_TYPE_INT (ca) && IS_TYPE_INT (cb)) {
TYPE t = arith_type (ta, tb, a, b);
a = convert_arith (t, a, op, 1);
b = convert_arith (t, b, op, 2);
if (op == lex_rem_Heq) {
IGNORE check_div_exp (op, a, b);
}
MAKE_exp_plus_etc (tag, t, a, b, e);
e = convert_assign (td, e, &err);
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
e = make_preinc_exp (td, d, e, off, op);
return (e);
}
goto error_lab;
}
arithmetic_lab : {
/* Arithmetic operations */
if (IS_TYPE_ARITH (ca) && IS_TYPE_ARITH (cb)) {
TYPE t = arith_type (ta, tb, a, b);
a = convert_arith (t, a, op, 1);
b = convert_arith (t, b, op, 2);
if (op == lex_div_Heq) {
IGNORE check_div_exp (op, a, b);
}
MAKE_exp_plus_etc (tag, t, a, b, e);
e = convert_assign (td, e, &err);
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
e = make_preinc_exp (td, d, e, off, op);
return (e);
}
goto error_lab;
}
shift_lab : {
/* Shift operations */
if (IS_TYPE_INT (ca) && IS_TYPE_INT (cb)) {
TYPE pta = promote_type (ta);
TYPE ptb = promote_type (tb);
a = convert_promote (pta, a);
b = convert_promote (ptb, b);
IGNORE check_shift_exp (op, pta, a, b);
MAKE_exp_plus_etc (tag, pta, a, b, e);
e = convert_assign (td, e, &err);
if (!IS_NULL_err (err)) {
err = concat_warning (err, ERR_expr_ass_conv ());
report (crt_loc, err);
}
e = make_preinc_exp (td, d, e, off, op);
return (e);
}
goto error_lab;
}
pointer_lab : {
/* Pointer or arithmetic operations */
if (IS_TYPE_PTR (ca) && IS_TYPE_INT (cb)) {
OFFSET off1;
int neg = 0;
TYPE t = check_pointer (ta, &err);
if (!IS_NULL_err (err)) {
err = concat_error (err, ERR_expr_ass_incompl (op));
report (crt_loc, err);
}
if (op == lex_minus_Heq) neg = 1;
off1 = make_off_mult (t, b, neg);
e = make_add_ptr (ta, a, off1);
e = make_preinc_exp (td, d, e, NULL_off, op);
return (e);
}
goto arithmetic_lab;
}
error_lab : {
/* Bad operations */
if (!IS_TYPE_ERROR (ca) && !IS_TYPE_ERROR (cb)) {
report (crt_loc, ERR_expr_ass_op (op, ta, tb));
}
e = make_error_exp (LANGUAGE_CPP);
return (e);
}
}
syntax highlighted by Code2HTML, v. 0.9.1