⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expr.c

📁 一款拥有一定历史的C语言编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -