1989-09-25 14:28:10 +00:00
|
|
|
/*
|
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
|
|
|
/* $Header$ */
|
|
|
|
/* SEMANTIC ANALYSIS (CHAPTER 3.3) -- MONADIC OPERATORS */
|
|
|
|
|
|
|
|
#include "botch_free.h"
|
1990-01-10 17:33:35 +00:00
|
|
|
#include "debug.h"
|
1989-09-25 14:28:10 +00:00
|
|
|
#include <alloc.h>
|
|
|
|
#include "nobitfield.h"
|
|
|
|
#include "Lpars.h"
|
|
|
|
#include <flt_arith.h>
|
|
|
|
#include "arith.h"
|
|
|
|
#include "type.h"
|
|
|
|
#include "label.h"
|
|
|
|
#include "expr.h"
|
|
|
|
#include "idf.h"
|
|
|
|
#include "def.h"
|
1989-12-13 12:53:22 +00:00
|
|
|
#include "sizes.h"
|
1989-09-25 14:28:10 +00:00
|
|
|
|
|
|
|
extern char options[];
|
|
|
|
extern arith full_mask[/*MAXSIZE*/]; /* cstoper.c */
|
|
|
|
char *symbol2str();
|
|
|
|
|
|
|
|
ch3mon(oper, expp)
|
|
|
|
register struct expr **expp;
|
|
|
|
{
|
|
|
|
/* The monadic prefix operator oper is applied to *expp.
|
|
|
|
*/
|
|
|
|
register struct expr *expr;
|
|
|
|
|
1989-11-27 11:37:11 +00:00
|
|
|
if (oper != PLUSPLUS && oper != MINMIN)
|
|
|
|
any2opnd(expp, oper);
|
1989-11-22 13:58:36 +00:00
|
|
|
|
1989-09-25 14:28:10 +00:00
|
|
|
switch (oper) {
|
|
|
|
case '*': /* 3.3.3.2 */
|
|
|
|
/* no FIELD type allowed */
|
|
|
|
if ((*expp)->ex_type->tp_fund != POINTER) {
|
1990-09-14 16:39:11 +00:00
|
|
|
if ((*expp)->ex_type != error_type) {
|
1989-09-25 14:28:10 +00:00
|
|
|
expr_error(*expp,
|
|
|
|
"* applied to non-pointer (%s)",
|
|
|
|
symbol2str((*expp)->ex_type->tp_fund));
|
1990-09-14 16:39:11 +00:00
|
|
|
}
|
1989-09-25 14:28:10 +00:00
|
|
|
} else {
|
|
|
|
expr = *expp;
|
1990-04-06 15:37:16 +00:00
|
|
|
|
|
|
|
if (is_ld_cst(expr))
|
1989-09-25 14:28:10 +00:00
|
|
|
/* dereference in administration only */
|
|
|
|
expr->ex_type = expr->ex_type->tp_up;
|
|
|
|
else /* runtime code */
|
|
|
|
*expp = new_oper(expr->ex_type->tp_up, NILEXPR,
|
|
|
|
'*', expr);
|
|
|
|
(*expp)->ex_lvalue = (
|
|
|
|
(*expp)->ex_type->tp_fund != ARRAY &&
|
|
|
|
(*expp)->ex_type->tp_fund != FUNCTION
|
|
|
|
);
|
|
|
|
if ((*expp)->ex_type->tp_typequal & TQ_CONST)
|
|
|
|
(*expp)->ex_flags |= EX_READONLY;
|
|
|
|
if ((*expp)->ex_type->tp_typequal & TQ_VOLATILE)
|
|
|
|
(*expp)->ex_flags |= EX_VOLATILE;
|
|
|
|
(*expp)->ex_flags &= ~EX_ILVALUE;
|
|
|
|
}
|
|
|
|
break;
|
1989-11-22 16:41:09 +00:00
|
|
|
case ADDRESSOF:
|
1989-09-25 14:28:10 +00:00
|
|
|
if ((*expp)->ex_type->tp_fund == ARRAY) {
|
1989-11-22 13:58:36 +00:00
|
|
|
(*expp)->ex_type = pointer_to((*expp)->ex_type, 0);
|
1989-09-25 14:28:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
if ((*expp)->ex_type->tp_fund == FUNCTION) {
|
1989-11-22 13:58:36 +00:00
|
|
|
(*expp)->ex_type = pointer_to((*expp)->ex_type, 0);
|
1989-09-25 14:28:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#ifndef NOBITFIELD
|
|
|
|
if ((*expp)->ex_type->tp_fund == FIELD)
|
|
|
|
expr_error(*expp, "& applied to field variable");
|
|
|
|
else
|
|
|
|
#endif NOBITFIELD
|
|
|
|
if (!(*expp)->ex_lvalue)
|
|
|
|
expr_error(*expp, "& applied to non-lvalue");
|
|
|
|
else if ((*expp)->ex_flags & EX_ILVALUE)
|
|
|
|
expr_error(*expp, "& applied to illegal lvalue");
|
|
|
|
else {
|
|
|
|
/* assume that enums are already filtered out */
|
|
|
|
if (ISNAME(*expp)) {
|
|
|
|
register struct def *def =
|
|
|
|
(*expp)->VL_IDF->id_def;
|
|
|
|
|
|
|
|
/* &<var> indicates that <var>
|
|
|
|
cannot be used as register
|
|
|
|
anymore
|
|
|
|
*/
|
|
|
|
if (def->df_sc == REGISTER) {
|
|
|
|
expr_error(*expp,
|
|
|
|
"& on register variable not allowed");
|
1989-11-22 16:41:09 +00:00
|
|
|
break; /* break case ADDRESSOF */
|
1989-09-25 14:28:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
(*expp)->ex_type = pointer_to((*expp)->ex_type,
|
|
|
|
(*expp)->ex_type->tp_typequal);
|
|
|
|
(*expp)->ex_lvalue = 0;
|
1989-09-29 16:20:38 +00:00
|
|
|
(*expp)->ex_flags &= ~(EX_READONLY | EX_VOLATILE);
|
1989-09-25 14:28:10 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
{
|
|
|
|
int fund = (*expp)->ex_type->tp_fund;
|
|
|
|
|
|
|
|
if (fund == FLOAT || fund == DOUBLE || fund == LNGDBL) {
|
|
|
|
expr_error( *expp,
|
|
|
|
"~ not allowed on %s operands",
|
|
|
|
symbol2str(fund));
|
|
|
|
erroneous2int(expp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
}
|
|
|
|
case '-':
|
|
|
|
any2arith(expp, oper);
|
|
|
|
if (is_cp_cst(*expp)) {
|
|
|
|
arith o1 = (*expp)->VL_VALUE;
|
|
|
|
|
|
|
|
(*expp)->VL_VALUE = (oper == '-') ? -o1 :
|
|
|
|
((*expp)->ex_type->tp_unsigned ?
|
1989-10-20 11:58:37 +00:00
|
|
|
(~o1) & full_mask[(int)(*expp)->ex_type->tp_size] :
|
1989-09-25 14:28:10 +00:00
|
|
|
~o1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (is_fp_cst(*expp))
|
|
|
|
switch_sign_fp(*expp);
|
|
|
|
else
|
|
|
|
*expp = new_oper((*expp)->ex_type,
|
|
|
|
NILEXPR, oper, *expp);
|
|
|
|
break;
|
|
|
|
case '!':
|
|
|
|
opnd2test(expp, '!');
|
|
|
|
if (is_cp_cst(*expp)) {
|
|
|
|
(*expp)->VL_VALUE = !((*expp)->VL_VALUE);
|
|
|
|
(*expp)->ex_type = int_type; /* a cast ???(EB) */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*expp = new_oper(int_type, NILEXPR, oper, *expp);
|
|
|
|
(*expp)->ex_flags |= EX_LOGICAL;
|
|
|
|
break;
|
|
|
|
case PLUSPLUS:
|
|
|
|
case MINMIN:
|
|
|
|
ch3incr(expp, oper);
|
|
|
|
break;
|
|
|
|
case SIZEOF:
|
|
|
|
if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
|
|
|
|
expr_warning(*expp, "sizeof formal array %s is sizeof pointer!",
|
|
|
|
(*expp)->VL_IDF->id_text);
|
|
|
|
expr = intexpr((*expp)->ex_class == String ?
|
|
|
|
(arith)((*expp)->SG_LEN) :
|
1989-11-22 13:58:36 +00:00
|
|
|
size_of_type((*expp)->ex_type,
|
|
|
|
symbol2str((*expp)->ex_type->tp_fund))
|
1990-04-23 13:33:07 +00:00
|
|
|
, UNSIGNED);
|
1989-09-25 14:28:10 +00:00
|
|
|
expr->ex_flags |= EX_SIZEOF;
|
|
|
|
free_expression(*expp);
|
|
|
|
*expp = expr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|