ack/lang/m2/comp/chk_expr.c

1108 lines
23 KiB
C
Raw Normal View History

1986-04-08 18:15:46 +00:00
/* E X P R E S S I O N C H E C K I N G */
1986-05-01 19:06:53 +00:00
#ifndef NORCSID
1986-04-08 18:15:46 +00:00
static char *RcsId = "$Header$";
1986-05-01 19:06:53 +00:00
#endif
1986-04-08 18:15:46 +00:00
/* Check expressions, and try to evaluate them as far as possible.
*/
1986-05-01 19:06:53 +00:00
#include "debug.h"
1986-04-08 18:15:46 +00:00
#include <em_arith.h>
#include <em_label.h>
#include <assert.h>
1986-04-09 18:14:49 +00:00
#include <alloc.h>
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
#include "Lpars.h"
1986-04-08 18:15:46 +00:00
#include "idf.h"
#include "type.h"
#include "def.h"
#include "LLlex.h"
#include "node.h"
#include "scope.h"
1986-04-09 18:14:49 +00:00
#include "const.h"
#include "standards.h"
1986-04-18 17:53:47 +00:00
1986-04-23 22:12:22 +00:00
extern char *symbol2str();
1986-04-08 18:15:46 +00:00
int
1986-04-10 01:08:49 +00:00
chk_expr(expp)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
/* Check the expression indicated by expp for semantic errors,
identify identifiers used in it, replace constants by
1986-04-18 17:53:47 +00:00
their value, and try to evaluate the expression.
1986-04-08 18:15:46 +00:00
*/
switch(expp->nd_class) {
case Oper:
1986-04-23 22:12:22 +00:00
if (expp->nd_symb == '[') {
1986-05-28 18:36:51 +00:00
return chk_designator(expp, DESIGNATOR|VARIABLE, D_NOREG|D_USED);
1986-04-23 22:12:22 +00:00
}
1986-04-10 01:08:49 +00:00
return chk_expr(expp->nd_left) &&
chk_expr(expp->nd_right) &&
chk_oper(expp);
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Uoper:
1986-04-23 22:12:22 +00:00
if (expp->nd_symb == '^') {
1986-05-28 18:36:51 +00:00
return chk_designator(expp, DESIGNATOR|VARIABLE, D_USED);
1986-04-23 22:12:22 +00:00
}
1986-04-10 01:08:49 +00:00
return chk_expr(expp->nd_right) &&
chk_uoper(expp);
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Value:
switch(expp->nd_symb) {
case REAL:
case STRING:
case INTEGER:
return 1;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
default:
1986-06-04 09:01:48 +00:00
crash("(chk_expr(Value))");
1986-04-08 18:15:46 +00:00
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Xset:
1986-04-10 01:08:49 +00:00
return chk_set(expp);
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Name:
1986-05-28 18:36:51 +00:00
return chk_designator(expp, VALUE, D_USED);
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Call:
1986-04-10 01:08:49 +00:00
return chk_call(expp);
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case Link:
1986-05-28 18:36:51 +00:00
return chk_designator(expp, DESIGNATOR|VALUE, D_USED|D_NOREG);
1986-04-22 22:36:16 +00:00
1986-04-08 23:34:10 +00:00
default:
1986-06-04 09:01:48 +00:00
crash("(chk_expr)");
1986-04-08 18:15:46 +00:00
}
/*NOTREACHED*/
}
int
1986-04-10 01:08:49 +00:00
chk_set(expp)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
1986-04-09 18:14:49 +00:00
/* Check the legality of a SET aggregate, and try to evaluate it
compile time. Unfortunately this is all rather complicated.
*/
1986-06-04 09:01:48 +00:00
register struct type *tp;
1986-04-08 23:34:10 +00:00
register struct node *nd;
1986-06-04 09:01:48 +00:00
register struct def *df;
1986-04-09 18:14:49 +00:00
arith *set;
1986-05-28 18:36:51 +00:00
unsigned size;
1986-04-08 23:34:10 +00:00
assert(expp->nd_symb == SET);
/* First determine the type of the set
*/
1986-04-22 22:36:16 +00:00
if (nd = expp->nd_left) {
1986-04-08 23:34:10 +00:00
/* A type was given. Check it out
*/
1986-05-28 18:36:51 +00:00
if (! chk_designator(nd, 0, D_USED)) return 0;
1986-04-23 22:12:22 +00:00
1986-04-22 22:36:16 +00:00
assert(nd->nd_class == Def);
df = nd->nd_def;
1986-04-18 17:53:47 +00:00
if (!(df->df_kind & (D_TYPE|D_ERROR)) ||
1986-04-10 01:08:49 +00:00
(df->df_type->tp_fund != T_SET)) {
1986-06-04 09:01:48 +00:00
node_error(expp, "specifier does not represent a set type");
1986-04-08 23:34:10 +00:00
return 0;
}
tp = df->df_type;
1986-04-22 22:36:16 +00:00
FreeNode(expp->nd_left);
expp->nd_left = 0;
1986-04-08 23:34:10 +00:00
}
else tp = bitset_type;
1986-05-28 18:36:51 +00:00
expp->nd_type = tp;
nd = expp->nd_right;
1986-04-08 23:34:10 +00:00
1986-04-09 18:14:49 +00:00
/* Now check the elements given, and try to compute a constant set.
1986-05-28 18:36:51 +00:00
First allocate room for the set, but only if it is'nt empty.
1986-04-08 23:34:10 +00:00
*/
1986-05-28 18:36:51 +00:00
if (! nd) {
/* The resulting set IS empty, so we just return
*/
expp->nd_class = Set;
expp->nd_set = 0;
return 1;
}
size = tp->tp_size * (sizeof(arith) / word_size);
set = (arith *) Malloc(size);
clear((char *) set, size);
1986-04-22 22:36:16 +00:00
/* Now check the elements, one by one
*/
1986-04-08 23:34:10 +00:00
while (nd) {
assert(nd->nd_class == Link && nd->nd_symb == ',');
1986-04-22 22:36:16 +00:00
1986-04-10 01:08:49 +00:00
if (!chk_el(nd->nd_left, tp->next, &set)) return 0;
1986-04-08 23:34:10 +00:00
nd = nd->nd_right;
}
1986-04-22 22:36:16 +00:00
1986-04-09 18:14:49 +00:00
if (set) {
1986-04-18 17:53:47 +00:00
/* Yes, it was a constant set, and we managed to compute it!
Notice that at the moment there is no such thing as
partial evaluation. Either we evaluate the set, or we
don't (at all). Improvement not neccesary. (???)
1986-04-09 18:14:49 +00:00
*/
expp->nd_class = Set;
expp->nd_set = set;
FreeNode(expp->nd_right);
1986-04-22 22:36:16 +00:00
expp->nd_right = 0;
1986-04-09 18:14:49 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-08 23:34:10 +00:00
return 1;
}
int
1986-04-10 01:08:49 +00:00
chk_el(expp, tp, set)
1986-04-09 18:14:49 +00:00
register struct node *expp;
1986-06-04 09:01:48 +00:00
register struct type *tp;
1986-04-09 18:14:49 +00:00
arith **set;
1986-04-08 23:34:10 +00:00
{
/* Check elements of a set. This routine may call itself
1986-04-09 18:14:49 +00:00
recursively.
Also try to compute the set!
1986-04-08 23:34:10 +00:00
*/
1986-04-22 22:36:16 +00:00
register struct node *left = expp->nd_left;
register struct node *right = expp->nd_right;
1986-06-04 09:01:48 +00:00
register int i;
1986-04-18 17:53:47 +00:00
1986-04-08 23:34:10 +00:00
if (expp->nd_class == Link && expp->nd_symb == UPTO) {
1986-04-09 18:14:49 +00:00
/* { ... , expr1 .. expr2, ... }
First check expr1 and expr2, and try to compute them.
*/
1986-04-22 22:36:16 +00:00
if (!chk_el(left, tp, set) || !chk_el(right, tp, set)) {
1986-04-08 23:34:10 +00:00
return 0;
}
1986-04-22 22:36:16 +00:00
if (left->nd_class == Value && right->nd_class == Value) {
1986-04-09 18:14:49 +00:00
/* We have a constant range. Put all elements in the
set
*/
1986-04-22 22:36:16 +00:00
if (left->nd_INT > right->nd_INT) {
1986-04-18 17:53:47 +00:00
node_error(expp, "lower bound exceeds upper bound in range");
1986-04-09 18:14:49 +00:00
return rem_set(set);
1986-04-08 23:34:10 +00:00
}
1986-04-22 22:36:16 +00:00
if (*set) {
for (i=left->nd_INT+1; i<right->nd_INT; i++) {
(*set)[i/wrd_bits] |= (1<<(i%wrd_bits));
}
1986-04-09 18:14:49 +00:00
}
}
else if (*set) {
1986-04-17 09:28:09 +00:00
free((char *) *set);
1986-04-09 18:14:49 +00:00
*set = 0;
1986-04-08 23:34:10 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-08 23:34:10 +00:00
return 1;
}
1986-04-09 18:14:49 +00:00
/* Here, a single element is checked
*/
1986-04-10 01:08:49 +00:00
if (!chk_expr(expp)) {
1986-04-09 18:14:49 +00:00
return rem_set(set);
}
1986-04-22 22:36:16 +00:00
1986-04-08 23:34:10 +00:00
if (!TstCompat(tp, expp->nd_type)) {
1986-04-18 17:53:47 +00:00
node_error(expp, "set element has incompatible type");
1986-04-09 18:14:49 +00:00
return rem_set(set);
1986-04-08 23:34:10 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-08 23:34:10 +00:00
if (expp->nd_class == Value) {
1986-04-22 22:36:16 +00:00
/* a constant element
*/
1986-04-18 17:53:47 +00:00
i = expp->nd_INT;
1986-04-22 22:36:16 +00:00
1986-04-10 01:08:49 +00:00
if ((tp->tp_fund != T_ENUMERATION &&
1986-04-18 17:53:47 +00:00
(i < tp->sub_lb || i > tp->sub_ub))
1986-04-08 23:34:10 +00:00
||
1986-04-10 01:08:49 +00:00
(tp->tp_fund == T_ENUMERATION &&
1986-04-18 17:53:47 +00:00
(i < 0 || i > tp->enm_ncst))
1986-04-08 23:34:10 +00:00
) {
1986-04-18 17:53:47 +00:00
node_error(expp, "set element out of range");
1986-04-09 18:14:49 +00:00
return rem_set(set);
1986-04-08 23:34:10 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-18 17:53:47 +00:00
if (*set) (*set)[i/wrd_bits] |= (1 << (i%wrd_bits));
1986-04-08 23:34:10 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-08 18:15:46 +00:00
return 1;
}
1986-04-09 18:14:49 +00:00
int
rem_set(set)
arith **set;
{
/* This routine is only used for error exits of chk_el.
It frees the set indicated by "set", and returns 0.
*/
if (*set) {
free((char *) *set);
*set = 0;
}
return 0;
}
1986-04-10 01:08:49 +00:00
struct node *
1986-05-23 09:46:31 +00:00
getarg(argp, bases, designator)
1986-05-30 18:48:00 +00:00
struct node **argp;
1986-04-10 01:08:49 +00:00
{
struct type *tp;
1986-05-30 18:48:00 +00:00
register struct node *arg = *argp;
1986-04-10 01:08:49 +00:00
1986-05-30 18:48:00 +00:00
if (!arg->nd_right) {
node_error(arg, "too few arguments supplied");
1986-04-10 01:08:49 +00:00
return 0;
}
1986-05-30 18:48:00 +00:00
arg = arg->nd_right;
if ((!designator && !chk_expr(arg->nd_left)) ||
(designator && !chk_designator(arg->nd_left, DESIGNATOR, D_REFERRED))) {
1986-05-23 09:46:31 +00:00
return 0;
}
1986-05-30 18:48:00 +00:00
tp = arg->nd_left->nd_type;
1986-04-10 01:08:49 +00:00
if (tp->tp_fund == T_SUBRANGE) tp = tp->next;
1986-04-18 17:53:47 +00:00
if (bases && !(tp->tp_fund & bases)) {
1986-05-30 18:48:00 +00:00
node_error(arg, "unexpected type");
1986-04-10 01:08:49 +00:00
return 0;
}
1986-05-30 18:48:00 +00:00
*argp = arg;
return arg->nd_left;
1986-04-10 01:08:49 +00:00
}
struct node *
getname(argp, kinds)
1986-05-30 18:48:00 +00:00
struct node **argp;
1986-04-10 01:08:49 +00:00
{
1986-05-30 18:48:00 +00:00
register struct node *arg = *argp;
if (!arg->nd_right) {
node_error(arg, "too few arguments supplied");
1986-04-10 01:08:49 +00:00
return 0;
}
1986-05-30 18:48:00 +00:00
arg = arg->nd_right;
if (! chk_designator(arg->nd_left, 0, D_REFERRED)) return 0;
1986-04-25 10:14:08 +00:00
1986-05-30 18:48:00 +00:00
assert(arg->nd_left->nd_class == Def);
1986-04-25 10:14:08 +00:00
1986-05-30 18:48:00 +00:00
if (!(arg->nd_left->nd_def->df_kind & kinds)) {
node_error(arg, "unexpected type");
1986-04-10 01:08:49 +00:00
return 0;
}
1986-04-25 10:14:08 +00:00
1986-05-30 18:48:00 +00:00
*argp = arg;
return arg->nd_left;
1986-04-10 01:08:49 +00:00
}
1986-04-08 18:15:46 +00:00
int
1986-04-10 01:08:49 +00:00
chk_call(expp)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
1986-04-11 11:57:19 +00:00
/* Check something that looks like a procedure or function call.
Of course this does not have to be a call at all.
it may also be a cast or a standard procedure call.
*/
1986-04-09 18:14:49 +00:00
register struct node *left;
1986-04-10 01:08:49 +00:00
register struct node *arg;
1986-04-09 18:14:49 +00:00
1986-04-18 17:53:47 +00:00
/* First, get the name of the function or procedure
*/
1986-04-09 18:14:49 +00:00
expp->nd_type = error_type;
left = expp->nd_left;
1986-05-28 18:36:51 +00:00
if (! chk_designator(left, 0, D_USED)) return 0;
1986-04-09 18:14:49 +00:00
1986-05-30 18:48:00 +00:00
if (IsCast(left)) {
1986-04-18 17:53:47 +00:00
/* It was a type cast. This is of course not portable.
1986-04-09 18:14:49 +00:00
*/
1986-05-30 18:48:00 +00:00
return chk_cast(expp, left);
1986-04-09 18:14:49 +00:00
}
1986-05-30 18:48:00 +00:00
if (IsProcCall(left)) {
1986-04-09 18:14:49 +00:00
/* A procedure call. it may also be a call to a
standard procedure
*/
1986-04-11 11:57:19 +00:00
if (left->nd_type == std_type) {
/* A standard procedure
*/
1986-05-30 18:48:00 +00:00
return chk_std(expp, left);
1986-04-09 18:14:49 +00:00
}
1986-04-18 17:53:47 +00:00
/* Here, we have found a real procedure call. The left hand
side may also represent a procedure variable.
1986-04-11 11:57:19 +00:00
*/
1986-04-18 17:53:47 +00:00
return chk_proccall(expp);
1986-04-09 18:14:49 +00:00
}
node_error(expp->nd_left, "procedure, type, or function expected");
return 0;
1986-04-08 18:15:46 +00:00
}
1986-04-18 17:53:47 +00:00
chk_proccall(expp)
1986-05-30 18:48:00 +00:00
register struct node *expp;
1986-04-18 17:53:47 +00:00
{
/* Check a procedure call
*/
1986-05-28 18:36:51 +00:00
register struct node *left;
1986-05-30 18:48:00 +00:00
struct node *arg;
1986-04-18 17:53:47 +00:00
register struct paramlist *param;
1986-05-28 18:36:51 +00:00
left = 0;
arg = expp->nd_right;
/* First, reverse the order in the argument list */
while (arg) {
expp->nd_right = arg;
arg = arg->nd_right;
expp->nd_right->nd_right = left;
left = expp->nd_right;
}
left = expp->nd_left;
1986-04-18 17:53:47 +00:00
arg = expp;
1986-05-30 18:48:00 +00:00
expp->nd_type = left->nd_type->next;
1986-04-25 10:14:08 +00:00
param = left->nd_type->prc_params;
1986-04-18 17:53:47 +00:00
while (param) {
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, 0, IsVarParam(param)))) return 0;
1986-06-04 09:01:48 +00:00
if (left->nd_symb == STRING) {
TryToString(left, TypeOfParam(param));
}
1986-05-30 18:48:00 +00:00
if (! TstParCompat(TypeOfParam(param),
left->nd_type,
IsVarParam(param),
left)) {
node_error(left, "type incompatibility in parameter");
1986-04-18 17:53:47 +00:00
return 0;
}
1986-05-30 18:48:00 +00:00
if (IsVarParam(param) && left->nd_class == Def) {
left->nd_def->df_flags |= D_NOREG;
1986-05-28 18:36:51 +00:00
}
1986-04-25 10:14:08 +00:00
1986-04-18 17:53:47 +00:00
param = param->next;
}
1986-04-25 10:14:08 +00:00
1986-04-18 17:53:47 +00:00
if (arg->nd_right) {
node_error(arg->nd_right, "too many parameters supplied");
return 0;
}
1986-04-25 10:14:08 +00:00
return 1;
}
static int
FlagCheck(expp, df, flag)
struct node *expp;
struct def *df;
{
/* See the routine "chk_designator" for an explanation of
"flag". Here, a definition "df" is checked against it.
*/
1986-04-28 18:06:58 +00:00
if (df->df_kind == D_ERROR) return 0;
1986-04-25 10:14:08 +00:00
if ((flag & VARIABLE) &&
!(df->df_kind & (D_FIELD|D_VARIABLE))) {
node_error(expp, "variable expected");
return 0;
}
if ((flag & HASSELECTORS) &&
( !(df->df_kind & (D_VARIABLE|D_FIELD|D_MODULE)) ||
df->df_type->tp_fund != T_RECORD)) {
node_error(expp, "illegal selection");
return 0;
}
if ((flag & VALUE) &&
( !(df->df_kind & (D_VARIABLE|D_FIELD|D_CONST|D_ENUM)))) {
node_error(expp, "value expected");
return 0;
}
1986-04-18 17:53:47 +00:00
return 1;
}
1986-04-23 22:12:22 +00:00
int
1986-05-28 18:36:51 +00:00
chk_designator(expp, flag, dflags)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
/* Find the name indicated by "expp", starting from the current
1986-04-25 10:14:08 +00:00
scope. "flag" indicates the kind of designator we expect:
It contains the flags VARIABLE, indicating that the result must
be something that can be assigned to.
It may also contain the flag VALUE, indicating that a
value is expected. In this case, VARIABLE may not be set.
It also contains the flag DESIGNATOR, indicating that '['
and '^' are allowed for this designator.
Also contained may be the flag HASSELECTORS, indicating that
the result must have selectors.
1986-05-28 18:36:51 +00:00
"dflags" contains some flags that must be set at the definition
found.
1986-04-08 18:15:46 +00:00
*/
register struct def *df;
1986-04-09 18:14:49 +00:00
register struct type *tp;
1986-04-17 09:28:09 +00:00
struct def *lookfor();
1986-04-08 18:15:46 +00:00
1986-04-09 18:14:49 +00:00
expp->nd_type = error_type;
1986-04-23 22:12:22 +00:00
1986-04-08 18:15:46 +00:00
if (expp->nd_class == Name) {
1986-04-28 18:06:58 +00:00
expp->nd_def = lookfor(expp, CurrVis, 1);
1986-04-09 18:14:49 +00:00
expp->nd_class = Def;
expp->nd_type = expp->nd_def->df_type;
1986-04-23 22:12:22 +00:00
if (expp->nd_type == error_type) return 0;
1986-04-08 18:15:46 +00:00
}
1986-04-23 22:12:22 +00:00
1986-04-09 18:14:49 +00:00
if (expp->nd_class == Link) {
assert(expp->nd_symb == '.');
1986-04-23 22:12:22 +00:00
1986-04-25 10:14:08 +00:00
if (! chk_designator(expp->nd_left,
1986-05-28 18:36:51 +00:00
flag|HASSELECTORS,
dflags|D_NOREG)) return 0;
1986-04-25 10:14:08 +00:00
1986-04-09 18:14:49 +00:00
tp = expp->nd_left->nd_type;
1986-04-25 10:14:08 +00:00
assert(tp->tp_fund == T_RECORD);
1986-05-30 18:48:00 +00:00
df = lookup(expp->nd_IDF, tp->rec_scope);
1986-04-23 22:12:22 +00:00
1986-04-08 18:15:46 +00:00
if (!df) {
1986-05-30 18:48:00 +00:00
id_not_declared(expp);
1986-04-23 22:12:22 +00:00
return 0;
1986-04-08 18:15:46 +00:00
}
1986-04-25 10:14:08 +00:00
else {
1986-05-30 18:48:00 +00:00
expp->nd_def = df;
1986-04-09 18:14:49 +00:00
expp->nd_type = df->df_type;
if (!(df->df_flags & (D_EXPORTED|D_QEXPORTED))) {
1986-05-30 18:48:00 +00:00
node_error(expp, "identifier \"%s\" not exported from qualifying module",
1986-04-08 18:15:46 +00:00
df->df_idf->id_text);
1986-04-23 22:12:22 +00:00
return 0;
1986-04-09 18:14:49 +00:00
}
1986-04-08 18:15:46 +00:00
}
1986-04-23 22:12:22 +00:00
1986-05-21 18:32:20 +00:00
if (expp->nd_left->nd_class == Def &&
expp->nd_left->nd_def->df_kind == D_MODULE) {
1986-04-09 18:14:49 +00:00
expp->nd_class = Def;
expp->nd_def = df;
FreeNode(expp->nd_left);
1986-05-30 18:48:00 +00:00
expp->nd_left = 0;
1986-04-09 18:14:49 +00:00
}
1986-04-25 10:14:08 +00:00
else {
1986-05-30 18:48:00 +00:00
return FlagCheck(expp, df, flag);
1986-04-25 10:14:08 +00:00
}
1986-04-09 18:14:49 +00:00
}
1986-04-23 22:12:22 +00:00
if (expp->nd_class == Def) {
df = expp->nd_def;
1986-04-25 10:14:08 +00:00
if (! FlagCheck(expp, df, flag)) return 0;
1986-04-23 22:12:22 +00:00
if (df->df_kind & (D_ENUM | D_CONST)) {
if (df->df_kind == D_ENUM) {
expp->nd_class = Value;
expp->nd_INT = df->enm_val;
expp->nd_symb = INTEGER;
}
else {
1986-05-23 19:25:21 +00:00
unsigned int ln;
1986-04-28 18:06:58 +00:00
1986-04-23 22:12:22 +00:00
assert(df->df_kind == D_CONST);
1986-04-28 18:06:58 +00:00
ln = expp->nd_lineno;
1986-04-23 22:12:22 +00:00
*expp = *(df->con_const);
1986-04-28 18:06:58 +00:00
expp->nd_lineno = ln;
1986-04-23 22:12:22 +00:00
}
}
1986-05-28 18:36:51 +00:00
df->df_flags |= dflags;
1986-04-23 22:12:22 +00:00
return 1;
}
1986-04-25 10:14:08 +00:00
if (! (flag & DESIGNATOR)) {
1986-04-23 22:12:22 +00:00
node_error(expp, "identifier expected");
return 0;
}
1986-04-09 18:14:49 +00:00
if (expp->nd_class == Oper) {
1986-04-23 22:12:22 +00:00
struct type *tpl, *tpr;
1986-04-09 18:14:49 +00:00
assert(expp->nd_symb == '[');
1986-04-08 18:15:46 +00:00
1986-04-23 22:12:22 +00:00
if (
1986-05-28 18:36:51 +00:00
!chk_designator(expp->nd_left, DESIGNATOR|VARIABLE, dflags|D_NOREG)
1986-04-23 22:12:22 +00:00
||
!chk_expr(expp->nd_right)
||
expp->nd_left->nd_type == error_type
) return 0;
tpr = expp->nd_right->nd_type;
tpl = expp->nd_left->nd_type;
1986-04-08 18:15:46 +00:00
1986-04-23 22:12:22 +00:00
if (tpl->tp_fund != T_ARRAY) {
node_error(expp,
"array index not belonging to an ARRAY");
return 0;
1986-04-08 18:15:46 +00:00
}
1986-04-23 22:12:22 +00:00
/* Type of the index must be assignment compatible with
the index type of the array (Def 8.1)
*/
if ((tpl->next && !TstAssCompat(tpl->next, tpr)) ||
(!tpl->next && !TstAssCompat(intorcard_type, tpr))) {
node_error(expp, "incompatible index type");
return 0;
1986-04-08 18:15:46 +00:00
}
1986-04-23 22:12:22 +00:00
expp->nd_type = tpl->arr_elem;
return 1;
1986-04-08 18:15:46 +00:00
}
1986-04-23 22:12:22 +00:00
if (expp->nd_class == Uoper) {
assert(expp->nd_symb == '^');
1986-05-28 18:36:51 +00:00
if (! chk_designator(expp->nd_right, DESIGNATOR|VARIABLE, dflags)) {
1986-04-25 10:14:08 +00:00
return 0;
}
1986-04-23 22:12:22 +00:00
if (expp->nd_right->nd_type->tp_fund != T_POINTER) {
node_error(expp, "illegal operand for unary operator \"%s\"",
symbol2str(expp->nd_symb));
return 0;
}
expp->nd_type = expp->nd_right->nd_type->next;
return 1;
}
node_error(expp, "designator expected");
return 0;
1986-04-08 18:15:46 +00:00
}
int
1986-04-10 01:08:49 +00:00
chk_oper(expp)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
1986-04-10 01:08:49 +00:00
/* Check a binary operation.
1986-04-08 18:15:46 +00:00
*/
1986-04-23 22:12:22 +00:00
register struct node *left = expp->nd_left;
register struct node *right = expp->nd_right;
struct type *tpl = left->nd_type;
struct type *tpr = right->nd_type;
1986-04-08 18:15:46 +00:00
int errval = 1;
if (tpl == intorcard_type) {
if (tpr == int_type || tpr == card_type) {
1986-04-23 22:12:22 +00:00
left->nd_type = tpl = tpr;
1986-04-08 18:15:46 +00:00
}
}
if (tpr == intorcard_type) {
if (tpl == int_type || tpl == card_type) {
1986-04-23 22:12:22 +00:00
right->nd_type = tpr = tpl;
1986-04-08 18:15:46 +00:00
}
}
1986-04-09 18:14:49 +00:00
expp->nd_type = error_type;
1986-04-08 18:15:46 +00:00
if (expp->nd_symb == IN) {
/* Handle this one specially */
1986-04-09 18:14:49 +00:00
expp->nd_type = bool_type;
1986-04-10 01:08:49 +00:00
if (tpr->tp_fund != T_SET) {
1986-04-08 18:15:46 +00:00
node_error(expp, "RHS of IN operator not a SET type");
return 0;
}
1986-04-23 22:12:22 +00:00
if (!TstAssCompat(tpl, tpr->next)) {
/* Assignment compatible ???
1986-04-28 18:06:58 +00:00
I don't know! Should we be allowed to check
1986-04-23 22:12:22 +00:00
if a CARDINAL is a member of a BITSET???
*/
1986-04-08 18:15:46 +00:00
node_error(expp, "IN operator: type of LHS not compatible with element type of RHS");
return 0;
}
1986-04-23 22:12:22 +00:00
if (left->nd_class == Value && right->nd_class == Set) {
1986-04-11 11:57:19 +00:00
cstset(expp);
}
1986-04-08 18:15:46 +00:00
return 1;
}
1986-04-10 01:08:49 +00:00
if (tpl->tp_fund == T_SUBRANGE) tpl = tpl->next;
1986-04-08 18:15:46 +00:00
expp->nd_type = tpl;
1986-04-23 22:12:22 +00:00
/* Operands must be compatible (distilled from Def 8.2)
*/
1986-04-08 18:15:46 +00:00
if (!TstCompat(tpl, tpr)) {
1986-04-23 22:12:22 +00:00
node_error(expp, "incompatible types for operator \"%s\"",
symbol2str(expp->nd_symb));
1986-04-08 18:15:46 +00:00
return 0;
}
1986-05-21 18:32:20 +00:00
1986-04-08 18:15:46 +00:00
switch(expp->nd_symb) {
case '+':
case '-':
case '*':
switch(tpl->tp_fund) {
1986-04-28 18:06:58 +00:00
case T_POINTER:
1986-05-14 09:03:51 +00:00
if (! chk_address(tpl, tpr)) break;
1986-04-28 18:06:58 +00:00
/* Fall through */
1986-04-10 01:08:49 +00:00
case T_INTEGER:
case T_CARDINAL:
1986-04-11 11:57:19 +00:00
case T_INTORCARD:
1986-04-23 22:12:22 +00:00
if (left->nd_class==Value && right->nd_class==Value) {
1986-04-08 18:15:46 +00:00
cstbin(expp);
}
return 1;
1986-04-18 17:53:47 +00:00
1986-04-11 11:57:19 +00:00
case T_SET:
1986-04-23 22:12:22 +00:00
if (left->nd_class == Set && right->nd_class == Set) {
1986-04-11 11:57:19 +00:00
cstset(expp);
}
/* Fall through */
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
case T_REAL:
1986-04-08 18:15:46 +00:00
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case '/':
switch(tpl->tp_fund) {
1986-04-10 01:08:49 +00:00
case T_SET:
1986-04-23 22:12:22 +00:00
if (left->nd_class == Set && right->nd_class == Set) {
1986-04-11 11:57:19 +00:00
cstset(expp);
1986-04-08 18:15:46 +00:00
}
1986-04-11 11:57:19 +00:00
/* Fall through */
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
case T_REAL:
1986-04-08 18:15:46 +00:00
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case DIV:
case MOD:
1986-05-14 09:03:51 +00:00
switch(tpl->tp_fund) {
case T_POINTER:
if (! chk_address(tpl, tpr)) break;
/* Fall through */
case T_INTEGER:
case T_CARDINAL:
case T_INTORCARD:
1986-04-23 22:12:22 +00:00
if (left->nd_class==Value && right->nd_class==Value) {
1986-04-08 18:15:46 +00:00
cstbin(expp);
}
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case OR:
case AND:
1986-04-22 22:36:16 +00:00
case '&':
1986-04-08 18:15:46 +00:00
if (tpl == bool_type) {
1986-04-23 22:12:22 +00:00
if (left->nd_class==Value && right->nd_class==Value) {
1986-04-08 18:15:46 +00:00
cstbin(expp);
}
return 1;
}
errval = 3;
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case '=':
case '#':
case GREATEREQUAL:
case LESSEQUAL:
case '<':
case '>':
1986-04-22 22:36:16 +00:00
expp->nd_type = bool_type;
1986-04-08 18:15:46 +00:00
switch(tpl->tp_fund) {
1986-04-10 01:08:49 +00:00
case T_SET:
1986-04-08 18:15:46 +00:00
if (expp->nd_symb == '<' || expp->nd_symb == '>') {
break;
}
1986-04-23 22:12:22 +00:00
if (left->nd_class == Set && right->nd_class == Set) {
1986-04-11 11:57:19 +00:00
cstset(expp);
1986-04-10 01:08:49 +00:00
}
return 1;
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
case T_INTEGER:
case T_CARDINAL:
case T_ENUMERATION: /* includes boolean */
case T_CHAR:
1986-04-11 11:57:19 +00:00
case T_INTORCARD:
1986-04-23 22:12:22 +00:00
if (left->nd_class==Value && right->nd_class==Value) {
1986-04-08 18:15:46 +00:00
cstbin(expp);
}
return 1;
1986-04-18 17:53:47 +00:00
1986-06-04 09:01:48 +00:00
case T_HIDDEN:
1986-04-10 01:08:49 +00:00
case T_POINTER:
1986-05-14 09:03:51 +00:00
if (chk_address(tpl, tpr) ||
expp->nd_symb == '=' ||
1986-04-22 22:36:16 +00:00
expp->nd_symb == '#') return 1;
break;
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
case T_REAL:
1986-04-08 18:15:46 +00:00
return 1;
}
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
default:
assert(0);
}
switch(errval) {
case 1:
1986-04-18 17:53:47 +00:00
node_error(expp,"operator \"%s\": illegal operand type(s)", symbol2str(expp->nd_symb));
1986-04-08 18:15:46 +00:00
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case 3:
node_error(expp, "BOOLEAN type(s) expected");
break;
1986-04-18 17:53:47 +00:00
1986-04-10 01:08:49 +00:00
default:
assert(0);
1986-04-08 18:15:46 +00:00
}
return 0;
}
1986-05-14 09:03:51 +00:00
int
chk_address(tpl, tpr)
register struct type *tpl, *tpr;
{
if (tpl == address_type) {
return tpr == address_type || tpr->tp_fund != T_POINTER;
}
if (tpr == address_type) {
return tpl->tp_fund != T_POINTER;
}
return 0;
}
1986-04-08 18:15:46 +00:00
int
1986-04-10 01:08:49 +00:00
chk_uoper(expp)
1986-04-08 18:15:46 +00:00
register struct node *expp;
{
1986-04-10 01:08:49 +00:00
/* Check an unary operation.
1986-04-08 18:15:46 +00:00
*/
1986-04-28 18:06:58 +00:00
register struct node *right = expp->nd_right;
register struct type *tpr = right->nd_type;
1986-04-08 18:15:46 +00:00
1986-04-10 01:08:49 +00:00
if (tpr->tp_fund == T_SUBRANGE) tpr = tpr->next;
1986-04-08 18:15:46 +00:00
expp->nd_type = tpr;
switch(expp->nd_symb) {
case '+':
1986-04-11 11:57:19 +00:00
if (tpr->tp_fund & T_NUMERIC) {
1986-04-28 18:06:58 +00:00
expp->nd_token = right->nd_token;
1986-05-28 18:36:51 +00:00
expp->nd_class = right->nd_class;
1986-04-28 18:06:58 +00:00
FreeNode(right);
1986-04-08 18:15:46 +00:00
expp->nd_right = 0;
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case '-':
1986-04-11 11:57:19 +00:00
if (tpr->tp_fund & T_INTORCARD) {
1986-05-14 09:03:51 +00:00
if (tpr == intorcard_type) {
expp->nd_type = int_type;
}
1986-04-28 18:06:58 +00:00
if (right->nd_class == Value) {
1986-04-08 18:15:46 +00:00
cstunary(expp);
}
return 1;
1986-04-11 11:57:19 +00:00
}
else if (tpr->tp_fund == T_REAL) {
1986-06-04 09:01:48 +00:00
expp->nd_type = tpr;
1986-04-28 18:06:58 +00:00
if (right->nd_class == Value) {
1986-06-04 09:01:48 +00:00
if (*(right->nd_REL) == '-') (right->nd_REL)++;
else (right->nd_REL)--;
1986-05-28 18:36:51 +00:00
expp->nd_class = Value;
1986-06-04 09:01:48 +00:00
expp->nd_symb = REAL;
expp->nd_REL = right->nd_REL;
1986-04-28 18:06:58 +00:00
FreeNode(right);
1986-04-08 18:15:46 +00:00
expp->nd_right = 0;
}
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
case NOT:
1986-04-22 22:36:16 +00:00
case '~':
1986-04-08 18:15:46 +00:00
if (tpr == bool_type) {
1986-04-28 18:06:58 +00:00
if (right->nd_class == Value) {
1986-04-08 18:15:46 +00:00
cstunary(expp);
}
return 1;
}
break;
1986-04-18 17:53:47 +00:00
1986-04-08 18:15:46 +00:00
default:
assert(0);
}
1986-04-11 11:57:19 +00:00
node_error(expp, "illegal operand for unary operator \"%s\"",
1986-04-08 18:15:46 +00:00
symbol2str(expp->nd_symb));
return 0;
}
1986-04-23 22:12:22 +00:00
struct node *
1986-05-30 18:48:00 +00:00
getvariable(argp)
struct node **argp;
1986-04-23 22:12:22 +00:00
{
1986-05-30 18:48:00 +00:00
register struct node *arg = *argp;
register struct def *df;
1986-04-28 18:06:58 +00:00
register struct node *left;
1986-04-23 22:12:22 +00:00
arg = arg->nd_right;
if (!arg) {
node_error(arg, "too few parameters supplied");
return 0;
}
1986-04-28 18:06:58 +00:00
left = arg->nd_left;
1986-05-28 18:36:51 +00:00
if (! chk_designator(left, DESIGNATOR, D_REFERRED)) return 0;
1986-04-28 18:06:58 +00:00
if (left->nd_class == Oper || left->nd_class == Uoper) {
1986-05-30 18:48:00 +00:00
*argp = arg;
return left;
1986-04-23 22:12:22 +00:00
}
1986-04-28 18:06:58 +00:00
df = 0;
1986-05-30 18:48:00 +00:00
if (left->nd_class == Link || left->nd_class == Def) {
df = left->nd_def;
}
1986-04-28 18:06:58 +00:00
if (!df || !(df->df_kind & (D_VARIABLE|D_FIELD))) {
1986-04-23 22:12:22 +00:00
node_error(arg, "variable expected");
return 0;
}
1986-05-30 18:48:00 +00:00
*argp = arg;
return left;
1986-04-23 22:12:22 +00:00
}
int
1986-05-30 18:48:00 +00:00
chk_std(expp, left)
register struct node *expp, *left;
1986-04-23 22:12:22 +00:00
{
/* Check a call of a standard procedure or function
*/
1986-05-30 18:48:00 +00:00
struct node *arg = expp;
int std;
1986-04-23 22:12:22 +00:00
assert(left->nd_class == Def);
1986-05-30 18:48:00 +00:00
std = left->nd_def->df_value.df_stdname;
DO_DEBUG(3,debug("standard name \"%s\", %d",left->nd_def->df_idf->id_text,std));
1986-04-23 22:12:22 +00:00
1986-05-30 18:48:00 +00:00
switch(std) {
1986-04-23 22:12:22 +00:00
case S_ABS:
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_NUMERIC, 0))) return 0;
1986-04-23 22:12:22 +00:00
expp->nd_type = left->nd_type;
1986-06-04 09:01:48 +00:00
if (left->nd_class == Value &&
expp->nd_type->tp_fund != T_REAL) {
cstcall(expp, S_ABS);
}
1986-04-23 22:12:22 +00:00
break;
case S_CAP:
expp->nd_type = char_type;
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_CHAR, 0))) return 0;
1986-04-23 22:12:22 +00:00
if (left->nd_class == Value) cstcall(expp, S_CAP);
break;
case S_CHR:
expp->nd_type = char_type;
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_INTORCARD, 0))) return 0;
1986-04-23 22:12:22 +00:00
if (left->nd_class == Value) cstcall(expp, S_CHR);
break;
case S_FLOAT:
expp->nd_type = real_type;
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_INTORCARD, 0))) return 0;
1986-04-23 22:12:22 +00:00
break;
case S_HIGH:
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_ARRAY, 0))) return 0;
expp->nd_type = left->nd_type->next;
1986-04-23 22:12:22 +00:00
if (!expp->nd_type) {
/* A dynamic array has no explicit index type
*/
expp->nd_type = intorcard_type;
}
else cstcall(expp, S_MAX);
break;
case S_MAX:
case S_MIN:
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_DISCRETE, 0))) return 0;
expp->nd_type = left->nd_type;
cstcall(expp,std);
1986-04-23 22:12:22 +00:00
break;
case S_ODD:
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_INTORCARD, 0))) return 0;
1986-04-23 22:12:22 +00:00
expp->nd_type = bool_type;
1986-05-30 18:48:00 +00:00
if (left->nd_class == Value) cstcall(expp, S_ODD);
1986-04-23 22:12:22 +00:00
break;
case S_ORD:
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_DISCRETE, 0))) return 0;
if (left->nd_type->tp_size > word_size) {
node_error(left, "illegal type in argument of ORD");
return 0;
}
1986-04-23 22:12:22 +00:00
expp->nd_type = card_type;
1986-05-30 18:48:00 +00:00
if (left->nd_class == Value) cstcall(expp, S_ORD);
1986-04-23 22:12:22 +00:00
break;
case S_TSIZE: /* ??? */
case S_SIZE:
expp->nd_type = intorcard_type;
1986-05-30 18:48:00 +00:00
if (! getname(&arg, D_FIELD|D_VARIABLE|D_ISTYPE)) return 0;
1986-04-23 22:12:22 +00:00
cstcall(expp, S_SIZE);
break;
case S_TRUNC:
expp->nd_type = card_type;
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_REAL, 0))) return 0;
1986-04-23 22:12:22 +00:00
break;
case S_VAL:
{
struct type *tp;
1986-05-30 18:48:00 +00:00
if (!(left = getname(&arg, D_ISTYPE))) return 0;
tp = left->nd_def->df_type;
1986-04-23 22:12:22 +00:00
if (tp->tp_fund == T_SUBRANGE) tp = tp->next;
if (!(tp->tp_fund & T_DISCRETE)) {
node_error(arg, "unexpected type");
return 0;
}
1986-05-30 18:48:00 +00:00
expp->nd_type = left->nd_def->df_type;
1986-04-23 22:12:22 +00:00
expp->nd_right = arg->nd_right;
arg->nd_right = 0;
FreeNode(arg);
1986-05-30 18:48:00 +00:00
arg = expp;
if (!(left = getarg(&arg, T_INTORCARD, 0))) return 0;
if (left->nd_class == Value) cstcall(expp, S_VAL);
1986-04-23 22:12:22 +00:00
break;
}
case S_ADR:
expp->nd_type = address_type;
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, 0, 1))) return 0;
1986-04-23 22:12:22 +00:00
break;
case S_DEC:
case S_INC:
expp->nd_type = 0;
1986-05-30 18:48:00 +00:00
if (! (left = getvariable(&arg))) return 0;
if (! (left->nd_type->tp_fund & T_DISCRETE)) {
node_error(left, "illegal type in argument of INC or DEC");
return 0;
}
1986-04-23 22:12:22 +00:00
if (arg->nd_right) {
1986-05-30 18:48:00 +00:00
if (! getarg(&arg, T_INTORCARD, 0)) return 0;
1986-04-23 22:12:22 +00:00
}
break;
case S_HALT:
expp->nd_type = 0;
break;
case S_EXCL:
case S_INCL:
{
struct type *tp;
expp->nd_type = 0;
1986-05-30 18:48:00 +00:00
if (!(left = getvariable(&arg))) return 0;
tp = left->nd_type;
1986-04-23 22:12:22 +00:00
if (tp->tp_fund != T_SET) {
node_error(arg, "EXCL and INCL expect a SET parameter");
return 0;
}
1986-05-30 18:48:00 +00:00
if (!(left = getarg(&arg, T_DISCRETE, 0))) return 0;
if (!TstAssCompat(tp->next, left->nd_type)) {
1986-04-28 18:06:58 +00:00
/* What type of compatibility do we want here?
apparently assignment compatibility! ??? ???
*/
1986-04-23 22:12:22 +00:00
node_error(arg, "unexpected type");
return 0;
}
break;
}
default:
1986-05-30 18:48:00 +00:00
crash("(chk_std)");
1986-04-23 22:12:22 +00:00
}
if (arg->nd_right) {
node_error(arg->nd_right, "too many parameters supplied");
return 0;
}
return 1;
}
1986-05-30 18:48:00 +00:00
chk_cast(expp, left)
register struct node *expp, *left;
{
/* Check a cast and perform it if the argument is constant.
If the sizes don't match, only complain if at least one of them
has a size larger than the word size.
If both sizes are equal to or smaller than the word size, there
is no problem as such values take a word on the EM stack
anyway.
*/
register struct node *arg = expp->nd_right;
if ((! arg) || arg->nd_right) {
node_error(expp, "only one parameter expected in type cast");
return 0;
}
arg = arg->nd_left;
if (! chk_expr(arg)) return 0;
if (arg->nd_type->tp_size != left->nd_type->tp_size &&
(arg->nd_type->tp_size > word_size ||
left->nd_type->tp_size > word_size)) {
node_error(expp, "unequal sizes in type cast");
}
if (arg->nd_class == Value) {
struct type *tp = left->nd_type;
FreeNode(left);
expp->nd_right->nd_left = 0;
FreeNode(expp->nd_right);
expp->nd_left = expp->nd_right = 0;
*expp = *arg;
expp->nd_type = tp;
}
else expp->nd_type = left->nd_type;
return 1;
}
1986-06-04 09:01:48 +00:00
TryToString(nd, tp)
struct node *nd;
struct type *tp;
{
/* Try a coercion from character constant to string */
if (tp->tp_fund == T_ARRAY && nd->nd_type == char_type) {
int ch = nd->nd_INT;
nd->nd_type = standard_type(T_STRING, 1, (arith) 2);
nd->nd_token.tk_data.tk_str =
(struct string *) Malloc(sizeof(struct string));
nd->nd_STR = Salloc("X", 2);
*(nd->nd_STR) = ch;
nd->nd_SLE = 1;
}
}