📄 expr.c
字号:
/*
* C compiler
* ==========
*
* Copyright 1989, 1990, 1991 Christoph van Wuellen.
* Credits to Matthew Brandt.
* All commercial rights reserved.
*
* This compiler may be redistributed as long there is no
* commercial interest. The compiler must not be redistributed
* without its full sources. This notice must stay intact.
*
* History:
*
* 1989 starting an 68000 C compiler, starting with material
* originally by M. Brandt
* 1990 68000 C compiler further bug fixes
* started i386 port (December)
* 1991 i386 port finished (January)
* further corrections in the front end and in the 68000
* code generator.
* The next port will be a SPARC port
*/
/******************************************************************************
*
* expression evaluation
*
* this set of routines builds a parse tree for an expression. no code is
* generated for the expressions during the build, this is the job of the
* codegen module. for most purposes expression() is the routine to call. it
* will allow all of the C operators. for the case where the comma operator
* is not valid (function parameters for instance) call exprnc().
*
* each of the routines returns a pointer to a describing type structure. each
* routine also takes one parameter which is a pointer to an expression node
* by reference (address of pointer). the completed expression is returned in
* this pointer. all routines return either a pointer to a valid type or NULL
* if the hierarchy of the next operator is too low or the next symbol is not
* part of an expression.
*
*****************************************************************************/
#include "chdr.h"
#include "expr.h"
#include "cglbdec.h"
#include "proto.h"
/********************************************************* Macro Definitions */
#define NIL_STREE ((STREE *)0)
#ifdef SYNTAX_CORRECT
#define check_scalar(x)
#define check_integral(x)
#define check_arithmetic(x)
#define check_zero(x)
#define check_shift(x1,x2)
#define check_discard(x)
#define check_unsigned(x1,x2,x3)
#define check_relational(x1,x2)
#define check_modifiable_lvalue(x)
#define check_sizeof(x1,x2)
#define set_used(x)
#define check_set(x)
#define check_equality(x1,x2)
#endif /* SYNTAX_CORRECT */
/********************************************************** Type Definitions */
typedef struct _stree STREE;
struct _stree
{
LABEL label;
const CHAR *sptr;
size_t len;
STREE *less;
STREE *more;
};
enum fpos
{
format_start, format_precision, format_optional
};
/********************************************************** Static Variables */
static STREE *strtree = NIL_STREE; /* Tree for string constants */
static BOOL sizeof_flag = FALSE;
static BOOL address_flag = FALSE;
#ifdef SEQUENCE
static SEQNUM sequence_number = (SEQNUM) 1;
#else /* SEQUENCE */
#define check_sequence(ep,mnum)
#define check_sequence_modified(ep)
#define check_sequence_accessed(ep)
#endif /* SEQUENCE */
/*********************************************** Static Function Definitions */
#ifndef SYNTAX_CORRECT
static void check_object P_ ((const EXPR *));
static void check_scalar P_ ((const EXPR *));
static void check_integral P_ ((const EXPR *));
static void check_arithmetic P_ ((const EXPR *));
static void check_modifiable_lvalue P_ ((const EXPR *));
#ifdef FORMAT_CHECK
static void check_parameter
P_ ((const CHAR *, int, const TYP *, const TYP *));
static void check_pointer_parameter
P_ ((const CHAR *, int, const TYP *, const TYP *));
static void check_array_parameter P_ ((const CHAR *, int, const TYP *));
static const CHAR *check_printf
P_ ((const CHAR *, int, const CHAR *, enum fpos *, const TYP *));
static const CHAR *check_scanf
P_ ((const CHAR *, int, const CHAR *, enum fpos *, const TYP *));
static const CHAR *findstr P_ ((const STREE *, LABEL));
#endif /* FORMAT_CHECK */
#endif /* SYNTAX_CORRECT */
static BOOL is_null_pointer P_ ((const EXPR *));
static EXPR *condition P_ ((EXPR *));
static EXPR *integral_promotion P_ ((EXPR *));
static EXPR *mk_enode P_ ((EXPRTYPE, TYP *));
static EXPR *mk_size P_ ((SIZE, TYP *));
static EXPR *deref P_ ((EXPR *, TYP *));
static EXPR *cond_deref P_ ((EXPR *, TYP *));
static EXPR *nameref P_ ((void));
static EXPR *addops P_ ((void));
static EXPR *andop P_ ((void));
static EXPR *asnop P_ ((void));
static EXPR *binlog P_ ((EXPR *(*)(void), EXPRTYPE, TOKEN));
static EXPR *binop P_ ((EXPR *(*)(void), EXPRTYPE, TOKEN, const char *));
static EXPR *bitandop P_ ((void));
static EXPR *bitorop P_ ((void));
static EXPR *bitxor P_ ((void));
static EXPR *commaop P_ ((void));
static EXPR *conditional P_ ((void));
static EXPR *equalops P_ ((void));
static EXPR *multops P_ ((void));
static EXPR *orop P_ ((void));
static EXPR *parmlist P_ ((const EXPR *, const BLOCK *));
static EXPR *primary P_ ((void));
static EXPR *relation P_ ((void));
static EXPR *shiftop P_ ((void));
static EXPR *unary P_ ((void));
static EXPR *explicit_castop P_ ((EXPR *, TYP *));
static TYP *arithmetic_conversion P_ ((EXPR **, EXPR **));
static TYP *arithmetic_conversion2 P_ ((EXPR **, EXPR **));
#ifdef FLOAT_SUPPORT
#ifndef TMS320C30
static EXPR *mk_fcon P_ ((const RVAL *, TYP *));
#endif /* TMS320C30 */
#endif /* FLOAT_SUPPORT */
/*****************************************************************************/
/*
* returns true if the expression is a constant integral expression node,
* otherwise returns false.
*/
static BOOL is_constexpr P1 (const EXPR *, ep)
{
return (is_icon (ep));
}
/*
* returns true if the expression is a constant which can be represented
* within the range of the type, otherwise it returns false.
*/
BOOL is_constant_in_range P2 (const EXPR *, ep, const TYP *, tp)
{
return (is_constexpr (ep)
&& is_constant_in_type_range (ep->v.i, ep->etp, tp));
}
/*
* returns true if the expression is a null pointer constant, otherwise
* returns false.
*/
static BOOL is_null_pointer P1 (const EXPR *, ep)
{
return (is_constexpr (ep) && ep->v.i == 0L);
}
#ifndef SYNTAX_CORRECT
static BOOL is_negative P1 (const EXPR *, ep)
{
return (is_constexpr (ep) && ep->v.i < 0L);
}
static BOOL is_negative_or_zero P1 (const EXPR *, ep)
{
return (is_constexpr (ep) && ep->v.i <= 0L);
}
#endif /* SYNTAX_CORRECT */
/*
* returns true if ep is an expression suitable as an lvalue
*/
BOOL is_lvalue P1 (const EXPR *, ep)
{
switch (ep->nodetype) {
case en_ref:
/*
* a function returning a structure (which cannot be used as an
* lvalue) will create an en_deref node
*/
return (ep->v.p[0]->nodetype != en_add ||
ep->v.p[0]->v.p[0]->nodetype != en_deref);
case en_fieldref:
return (ep->v.p[0]->nodetype != en_add ||
ep->v.p[0]->v.p[0]->nodetype != en_deref);
default:
break;
}
return FALSE;
}
#ifdef SEQUENCE
static void check_sequence P2 (const EXPR *, ep, MSGNUM, mnum)
{
SYM *sp;
switch (ep->nodetype) {
case en_ref:
check_sequence (ep->v.p[0], mnum);
break;
case en_sym:
sp = ep->v.sp;
if (sp->sequence == sequence_number) {
/* already modified at this sequence point */
message (mnum, nameof (sp));
}
#ifndef SYNTAX_CORRECT
if (mnum == WARN_MODIFIED) {
sp->sequence = sequence_number;
}
#endif /* SYNTAX_CORRECT */
break;
default:
break;
}
}
static void check_sequence_modified P1 (const EXPR *, ep)
{
#ifndef SYNTAX_CORRECT
check_sequence (ep, WARN_MODIFIED);
#endif /* SYNTAX_CORRECT */
}
static void check_sequence_accessed P1 (const EXPR *, ep)
{
#ifndef SYNTAX_CORRECT
check_sequence (ep, WARN_ACCESS);
#endif /* SYNTAX_CORRECT */
}
/*
* a sequence-point has been encountered
*/
void sequence_point P0 (void)
{
sequence_number++;
}
#endif
static void check_object P1 (const EXPR *, ep)
{
#ifndef SYNTAX_CORRECT
if (!is_object_type (referenced_type (ep->etp))) {
message (ERR_OBJECT);
}
#endif /* SYNTAX_CORRECT */
}
#ifndef SYNTAX_CORRECT
static void check_scalar P1 (const EXPR *, ep)
{
if (!is_scalar_type (ep->etp)) {
message (ERR_SCALAR);
}
}
static void check_integral P1 (const EXPR *, ep)
{
if (!is_integral_type (ep->etp)) {
message (ERR_INTEGER);
}
}
static void check_arithmetic P1 (const EXPR *, ep)
{
if (!is_arithmetic_type (ep->etp)) {
message (ERR_ARITHMETIC);
}
}
static void check_zero P1 (const EXPR *, ep)
{
if (!is_constexpr (ep)) {
return;
}
if (is_integral_type (ep->etp) && (ep->v.i == 0L)) {
message (WARN_ZERO);
}
#ifdef FLOAT_SUPPORT
#ifndef FLOAT_BOOTSTRAP
else if (is_real_floating_type (ep->etp)
&& FEQ (((const EXPR *) ep)->v.f, F_zero)) {
message (WARN_ZERO);
}
#endif /* FLOAT_BOOTSTRAP */
#endif /* FLOAT_SUPPORT */
}
static void check_shift P2 (const EXPR *, ep, const TYP *, tp)
{
if (!is_constexpr (ep) || !is_integral_type (ep->etp)) {
return;
}
if ((ep->v.i < (IVAL) 0L) ||
(ep->v.i >= (IVAL) (tp->size * bits_in_sizeunit))) {
message (WARN_SHIFT, ep->v.i, nameoftype (tp));
}
}
void check_discard P1 (const EXPR *, ep)
{
if (ep == NIL_EXPR) {
return;
}
switch (ep->nodetype) {
case en_fcall:
case en_call:
case en_usercall:
if (!is_void (ep->etp)) {
message (WARN_IGNORE,
ep->v.p[0]->nodetype == en_nacon ?
(const char *) ep->v.p[0]->v.str : "");
}
break;
case en_assign:
case en_asadd:
case en_assub:
case en_asmul:
case en_asmul2:
case en_asdiv:
case en_asdiv2:
case en_asmod:
case en_asrsh:
case en_asxor:
case en_aslsh:
case en_asand:
case en_asor:
case en_ainc:
case en_adec:
break;
case en_comma:
check_discard (ep->v.p[1]);
break;
default:
if (!is_void (ep->etp)) {
message (WARN_DISCARD);
}
break;
}
}
static void check_unsigned P3 (const EXPR *, ep1, const EXPR *, ep2, BOOL,
check_for_zero)
{
if (is_signed_type (ep2->etp)) {
if (is_unsigned_type (ep1->etp)) {
if (check_for_zero ? is_negative_or_zero (ep2) :
is_negative (ep2)) {
message (WARN_UNSIGNED, nameoftype (ep1->etp));
}
} else if (is_char (ep1->etp)) {
if (check_for_zero ? is_negative_or_zero (ep2) :
is_negative (ep2)) {
message (WARN_CHAR);
}
}
}
}
static void check_relational P2 (const EXPR *, ep1, const EXPR *, ep2)
{
check_unsigned (ep1, ep2, TRUE);
check_unsigned (ep2, ep1, TRUE);
}
static void check_equality P2 (const EXPR *, ep1, const EXPR *, ep2)
{
check_unsigned (ep1, ep2, FALSE);
check_unsigned (ep2, ep1, FALSE);
}
/*
* A modifiable lvalue is an lvalue that does not have array
* type, does not have an incomplete type, does not have a
* const-qualified type, and if it is a structure or union,
* does not have any member (including, recursively, any member
* of all contained structures or unions) with const-qualified
* type.
*/
static void check_modifiable_lvalue P1 (const EXPR *, ep)
{
if (!is_lvalue (ep)) {
message (ERR_LVALUE);
}
if (is_const_qualified (ep->etp)) {
message (ERR_CONST);
}
}
/*
* Check that the sizeof hasn't been applied to a bitfield, void
* or a function.
*/
static void check_sizeof P2 (const EXPR *, ep, SIZE, size)
{
if (size == UNKNOWN_SIZE ||
(ep != NIL_EXPR &&
((ep->nodetype == en_fieldref) ||
((lang_option >= LANG_C90)
&& (is_sym (ep) && is_function_type (ep->etp)))))) {
message (ERR_ILLSIZEOF);
}
if (size == 0L) {
message (WARN_SIZEOF0);
}
/* a ">>" is undefined if the RHS equals number of bits of LHS! */
if (((USIZE) size >> ((USIZE) tp_size->size * 4L)) >>
((USIZE) tp_size->size * 4L) != Ox0UL) {
message (WARN_SIZEOFBIG, size);
}
}
/*
* If the expression is a symbol then mark the symbol as set
*/
static void set_used P1 (const EXPR *, ep)
{
switch (ep->nodetype) {
case en_ref:
set_used (ep->v.p[0]);
break;
case en_sym:
symbol_set (ep->v.sp);
break;
default:
break;
}
}
/*
* Check to see if the symbol has been set before it is about
* to be used.
*/
static void check_set P1 (const EXPR *, ep)
{
SYM *sp;
switch (ep->nodetype) {
case en_ref:
check_set (ep->v.p[0]);
break;
case en_sym:
sp = ep->v.sp;
switch (storageof (sp)) {
case sc_auto:
case sc_register:
if (!is_symbol_set (sp)) {
message (WARN_NOTSET, nameof (sp));
symbol_set (sp);
}
break;
default:
break;
}
break;
default:
break;
}
}
#endif /* SYNTAX_CORRECT */
#ifdef FORMAT_CHECK
/*
* Search the tree looking for the string associated with the supplied label
*/
static const CHAR *findstr P2 (const STREE *, tree, LABEL, lab)
{
const CHAR *str;
if (tree == (STREE *) 0) {
return (CHAR *) 0;
}
if (tree->label == lab) {
return tree->sptr;
}
str = findstr (tree->less, lab);
return str ? str : findstr (tree->more, lab);
}
static const CHAR *get_stringlit P1 (LABEL, lab)
{
return findstr (strtree, lab);
}
#endif /* FORMAT_CHECK */
/*
* mk_ s a string literal and return it's label number.
*
* Strict K&R requires that all strings even when
* written identically are distinct. This
* behaviour is enforced if the 'lang_option' flag
* is set to LANG_KANDR.
*/
static EXPR *mk_stringlit P2 (const CHAR *, s, size_t, len)
{
STREE *p, *q = NIL_STREE;
STRING *lp;
int local_global = global_flag;
int result = 0;
if (lang_option >= LANG_C90) {
/*
* Not in traditional mode, so shared strings allowed.
* Search our tree of existing strings to see if
* an identical one has already been generated.
* (this is allowed by ANSI).
* If so we can merely return its label.
*/
for (q = p = strtree; p; p = (result < 0) ? p->less : p->more) {
ptrdiff_t diff = (ptrdiff_t) (p->len - len);
if (diff >= 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -