V10/cmd/cyntax/cyn/f_expr.c
/*
* Sydney C Compiler.
*
* Copyright 1984, Bruce Ellis.
*
* Unauthorised possesion, sale or use prohibited.
*/
#include "defs.h"
#include "cnodes.h"
#include "types.h"
#include "flow.h"
extern xtset assops;
extern xtset constants;
extern xtset binary_ops;
extern xtset unary_ops;
#define CUT_LEFT 0x0001
#define CUT_UNION 0x0002
#define CUT_INTER 0x0004
#define MOD_LEFT 0x0008
#define MOD_UNION 0x0010
#define MOD_INTER 0x0020
#define REF_LR 0x0040
#define REF_UNION 0x0080
#define HIDE_UNION 0x0100
#define HIDE_CRIGHT 0x0200
#define HIDE_SEQ 0x0400
#define CMOD_UNION 0x0800
#define CMOD_CRIGHT 0x1000
#define CMOD_MOD 0x2000
#define EVAL_ORDER 0x4000
#define MOD_ORDER 0x8000
#define BIN_OP (CUT_UNION | MOD_UNION | REF_UNION | HIDE_UNION | CMOD_UNION | CMOD_MOD)
/*
* Flow set equations.
*/
static void
flow_calc(instr, s0, s1, d)
register int instr;
register flow_set *s0;
register flow_set *s1;
register flow_set *d;
{
/*
* To test for dependencies on order of evaluation
* check ref vs mod and cmod.
*/
if ((instr & EVAL_ORDER) != 0)
{
eval_check(s0->f_ref, s1->f_mod);
eval_check(s0->f_mod, s1->f_ref);
eval_check(s0->f_ref, s1->f_cmod);
eval_check(s0->f_cmod, s1->f_ref);
}
/*
* To test for dependencies on order of evaluation
* check ref vs mod and cmod.
*/
if ((instr & MOD_ORDER) != 0)
mod_check(s0, s1);
/*
* Hide sets. Fortunately the messy cases are rare.
*/
if ((instr & HIDE_UNION) != 0)
{
d->f_hide = flow_union(s0->f_hide, s1->f_hide);
if ((instr & HIDE_CRIGHT) != 0)
{
d->f_hide
=
flow_union
(
d->f_hide,
flow_diff
(
flow_inter
(
flow_union(copy_xlist(s0->f_mod), copy_xlist(s0->f_cmod)),
copy_xlist(s1->f_ref)
),
s1->f_mod
)
);
}
}
else if ((instr & HIDE_SEQ) != 0)
{
d->f_hide
=
flow_union
(
s1->f_hide,
flow_diff
(
flow_union
(
s0->f_hide,
flow_inter
(
flow_union(copy_xlist(s0->f_mod), copy_xlist(s0->f_cmod)),
copy_xlist(s1->f_ref)
)
),
s1->f_mod
)
);
}
/*
* ref set, either union or left to ride.
*/
if ((instr & REF_UNION) != 0)
d->f_ref = flow_union(s0->f_ref, s1->f_ref);
else if ((instr & REF_LR) != 0)
d->f_ref = flow_union(s0->f_ref, flow_diff(s1->f_ref, s0->f_mod));
/*
* Always CMOD_UNION, and then perhaps mod sets.
*/
d->f_cmod = flow_union(s0->f_cmod, s1->f_cmod);
if ((instr & CMOD_CRIGHT) != 0)
d->f_cmod = flow_union(d->f_cmod, copy_xlist(s1->f_mod));
else if ((instr & CMOD_MOD) != 0)
{
d->f_cmod = flow_union(d->f_cmod, copy_xlist(s0->f_mod));
d->f_cmod = flow_union(d->f_cmod, copy_xlist(s1->f_mod));
}
/*
* cut and mod sets are much neater. They
* are left to last becuase the values of the
* operands are used for other calculations.
*/
if ((instr & CUT_LEFT) != 0)
{
free_xlist(s1->f_cut);
d->f_cut = s0->f_cut;
}
else if ((instr & CUT_UNION) != 0)
d->f_cut = flow_union(s0->f_cut, s1->f_cut);
else if ((instr & CUT_INTER) != 0)
d->f_cut = flow_inter(s0->f_cut, s1->f_cut);
if ((instr & MOD_LEFT) != 0)
{
free_xlist(s1->f_mod);
d->f_mod = s0->f_mod;
}
else if ((instr & MOD_UNION) != 0)
d->f_mod = flow_union(s0->f_mod, s1->f_mod);
else if ((instr & MOD_INTER) != 0)
d->f_mod = flow_inter(s0->f_mod, s1->f_mod);
}
/*
* Calculate a flow set for an expression.
*/
void
expr_flow(x, res)
register xnode *x;
register flow_set *res;
{
register int instr;
flow_set left_op;
flow_set right_op;
res->f_cut = NULL;
res->f_mod = NULL;
res->f_ref = NULL;
res->f_hide = NULL;
res->f_cmod = NULL;
switch (x->x_what)
{
case xt_andand:
case xt_barbar:
instr = CUT_LEFT | MOD_LEFT | REF_LR | HIDE_UNION | HIDE_CRIGHT | CMOD_UNION | CMOD_CRIGHT;
expr_flow(x->x_right, &right_op);
expr_flow(x->x_left, &left_op);
break;
case xt_comma:
case xt_question:
instr = CUT_UNION | MOD_UNION | REF_LR | HIDE_SEQ | CMOD_UNION;
expr_flow(x->x_right, &right_op);
expr_flow(x->x_left, &left_op);
break;
case xt_colon:
instr = CUT_INTER | MOD_INTER | REF_UNION | HIDE_UNION | CMOD_UNION | CMOD_MOD;
expr_flow(x->x_right, &right_op);
expr_flow(x->x_left, &left_op);
break;
case xt_eq:
expr_flow(x->x_right, &right_op);
if (pure_var(x->x_left))
{
register ident *d;
instr = BIN_OP | MOD_ORDER;
d = x->x_left->x_left->x_value.d;
add_element(d, &eq_set);
make_set(&left_op.f_cut, d);
make_set(&left_op.f_mod, d);
left_op.f_ref = NULL;
left_op.f_hide = NULL;
left_op.f_cmod = NULL;
}
else
{
instr = BIN_OP | EVAL_ORDER;
expr_flow(x->x_left, &left_op);
}
break;
case xt_name:
if (is_pure(x->x_value.d))
make_set(&res->f_ref, x->x_value.d);
return;
case xt_ptrpredec:
case xt_ptrpreinc:
case xt_predec:
case xt_preinc:
if (pure_var(x->x_left))
{
register ident *d;
d = x->x_left->x_left->x_value.d;
res->f_cut = NULL;
make_set(&res->f_mod, d);
make_set(&res->f_ref, d);
make_set(&res->f_hide, d);
res->f_cmod = NULL;
}
else
expr_flow(x->x_left, res);
return;
case xt_ptrpostdec:
case xt_ptrpostinc:
case xt_postdec:
case xt_postinc:
if (pure_var(x->x_left))
{
register ident *d;
d = x->x_left->x_left->x_value.d;
res->f_cut = NULL;
make_set(&res->f_mod, d);
make_set(&res->f_ref, d);
res->f_hide = NULL;
res->f_cmod = NULL;
}
else
expr_flow(x->x_left, res);
return;
case xt_call:
expr_flow(x->x_left, res);
if (x->x_value.k != NULL)
{
register cnode *c;
for (c = x->x_value.k->c_head; c != NULL; c = c->c_next)
{
expr_flow(c->c_value.x, &left_op);
flow_calc(BIN_OP | EVAL_ORDER, res, &left_op, &right_op);
*res = right_op;
}
}
return;
case xt_dot:
if (x->x_left != NULL)
expr_flow(x->x_left, res);
return;
default:
if (in(assops, x->x_what))
{
expr_flow(x->x_right, &right_op);
if (pure_var(x->x_left))
{
register ident *d;
instr = BIN_OP | MOD_ORDER;
d = x->x_left->x_left->x_value.d;
left_op.f_cut = NULL;
make_set(&left_op.f_mod, d);
make_set(&left_op.f_ref, d);
left_op.f_hide = NULL;
left_op.f_cmod = NULL;
}
else
{
instr = BIN_OP;
expr_flow(x->x_left, &left_op);
}
}
else if (in(binary_ops, x->x_what))
{
instr = BIN_OP | EVAL_ORDER;
expr_flow(x->x_right, &right_op);
expr_flow(x->x_left, &left_op);
}
else if (in(constants, x->x_what))
return;
else if (in(unary_ops, x->x_what))
{
expr_flow(x->x_left, res);
return;
}
else
internal("expr_flow", "unkown xnode");
}
flow_calc(instr, &left_op, &right_op, res);
}