2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
2024-07-19 11:43:27 -04:00
|
|
|
* Copyright 2001, 2013 Fidelity Information Services, Inc *
|
2012-02-05 11:35:58 -05:00
|
|
|
* *
|
|
|
|
* This source code contains the intellectual property *
|
|
|
|
* of its copyright holder(s), and is made available *
|
|
|
|
* under a license. If you do not know the terms of *
|
|
|
|
* the license, please stop and do not read further. *
|
|
|
|
* *
|
|
|
|
****************************************************************/
|
|
|
|
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "opcode.h"
|
2024-07-19 11:43:27 -04:00
|
|
|
#include "mdq.h"
|
2012-02-05 11:35:58 -05:00
|
|
|
#include "toktyp.h"
|
|
|
|
#include "advancewindow.h"
|
|
|
|
#include "compile_pattern.h"
|
2024-07-19 11:43:27 -04:00
|
|
|
#include "fullbool.h"
|
|
|
|
#include "show_source_line.h"
|
|
|
|
|
|
|
|
GBLREF boolean_t run_time;
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
error_def(ERR_EXPR);
|
|
|
|
error_def(ERR_RHMISSING);
|
2024-07-19 11:43:27 -04:00
|
|
|
error_def(ERR_SIDEEFFECTEVAL);
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
LITREF octabstruct oc_tab[];
|
|
|
|
LITREF toktabtype tokentable[];
|
|
|
|
|
|
|
|
int eval_expr(oprtype *a)
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
boolean_t ind_pat, saw_local, saw_se, se_warn;
|
|
|
|
int op_count, se_handling;
|
|
|
|
opctype bin_opcode;
|
|
|
|
oprtype optyp_1, optyp_2, *optyp_ptr;
|
|
|
|
tbp *catbp, *tripbp;
|
|
|
|
triple *argtrip, *parm, *ref, *ref1, *t1, *t2;
|
|
|
|
unsigned short type;
|
2012-02-05 11:35:58 -05:00
|
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!expratom(&optyp_1))
|
2012-02-05 11:35:58 -05:00
|
|
|
{ /* If didn't already add an error of our own, do so now with catch all expression error */
|
2012-03-24 14:06:46 -04:00
|
|
|
if (OC_RTERROR != (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode)
|
2012-02-05 11:35:58 -05:00
|
|
|
stx_error(ERR_EXPR);
|
|
|
|
return EXPR_FAIL;
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
se_handling = TREF(side_effect_handling);
|
|
|
|
se_warn = (!run_time && (SE_WARN == se_handling));
|
|
|
|
while (bin_opcode = tokentable[TREF(window_token)].bo_type) /* NOTE assignment NOT condition */
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
type = tokentable[TREF(window_token)].opr_type;
|
2024-07-19 11:43:27 -04:00
|
|
|
if (oc_tab[bin_opcode].octype & OCT_BOOL)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
if (!TREF(shift_side_effects))
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
assert(FALSE == TREF(saw_side_effect));
|
|
|
|
for (ref = (TREF(curtchain))->exorder.bl; oc_tab[ref->opcode].octype & OCT_BOOL;
|
|
|
|
ref = ref->exorder.bl)
|
|
|
|
;
|
2012-02-05 11:35:58 -05:00
|
|
|
TREF(expr_start) = TREF(expr_start_orig) = ref;
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
switch (bin_opcode)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
case OC_NAND:
|
|
|
|
case OC_AND:
|
|
|
|
case OC_NOR:
|
|
|
|
case OC_OR:
|
|
|
|
TREF(shift_side_effects) = TRUE;
|
|
|
|
default:
|
|
|
|
break;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
coerce(&optyp_1, type);
|
|
|
|
if (OC_CAT == bin_opcode)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
ref1 = ref = maketriple(OC_CAT);
|
2024-07-19 11:43:27 -04:00
|
|
|
catbp = &ref->backptr; /* borrow backptr to track args */
|
|
|
|
saw_se = saw_local = FALSE;
|
2012-02-05 11:35:58 -05:00
|
|
|
for (op_count = 2; ; op_count++) /* op_count = first operand plus destination */
|
|
|
|
{
|
|
|
|
parm = newtriple(OC_PARAMETER);
|
|
|
|
ref1->operand[1] = put_tref(parm);
|
|
|
|
ref1 = parm;
|
2024-07-19 11:43:27 -04:00
|
|
|
ref1->operand[0] = optyp_1;
|
|
|
|
if (se_handling)
|
|
|
|
{ /* the following code deals with protecting lvn values from change by a following
|
|
|
|
* side effect and thereby produces a standard evaluation order. It is similar to code in
|
|
|
|
* expritem for function arguments, but has slightly different and easier circumstances
|
|
|
|
*/
|
|
|
|
assert(OLD_SE != TREF(side_effect_handling));
|
|
|
|
assert(0 < TREF(expr_depth));
|
|
|
|
t1 = optyp_1.oprval.tref;
|
|
|
|
t2 = (oc_tab[t1->opcode].octype & OCT_COERCE) ? t1->operand[0].oprval.tref
|
|
|
|
: t1; /* need to step back past coerce of side effects in order to detect them */
|
|
|
|
if (((OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) && (t1 == t2))
|
|
|
|
saw_local = TRUE; /* left operand is an lvn */
|
|
|
|
if (saw_local)
|
|
|
|
{
|
|
|
|
if ((TREF(side_effect_base))[TREF(expr_depth)])
|
|
|
|
saw_se = TRUE;
|
|
|
|
if (saw_se || (OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode))
|
|
|
|
{ /* chain stores args to manage later insert of temps to hold lvn */
|
|
|
|
tripbp = &ref1->backptr;
|
|
|
|
assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl));
|
|
|
|
tripbp->bpt = ref1;
|
|
|
|
dqins(catbp, que, tripbp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
if (TK_UNDERSCORE != TREF(window_token))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!saw_se) /* suppressed standard or lucked out on ordering */
|
|
|
|
saw_local = FALSE; /* just clear the backptrs - shut off other processing */
|
|
|
|
dqloop(catbp, que, tripbp)
|
|
|
|
{ /* work chained arguments which are in reverse order */
|
|
|
|
argtrip = tripbp->bpt;
|
|
|
|
assert(NULL != argtrip);
|
|
|
|
dqdel(tripbp, que);
|
|
|
|
tripbp->bpt = NULL;
|
|
|
|
if (!saw_local)
|
|
|
|
continue;
|
|
|
|
/* some need to insert temps */
|
|
|
|
for (optyp_ptr = &argtrip->operand[0]; INDR_REF == optyp_ptr->oprclass;
|
|
|
|
optyp_ptr = optyp_ptr->oprval.indr)
|
|
|
|
; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */
|
|
|
|
t1 = optyp_ptr->oprval.tref;
|
|
|
|
if ((OC_VAR == t1->opcode) || (OC_GETINDX == t1->opcode))
|
|
|
|
{ /* have an lvn that needs a temp because threat from some side effect */
|
|
|
|
argtrip = maketriple(OC_STOTEMP);
|
|
|
|
argtrip->operand[0] = put_tref(t1);
|
|
|
|
dqins(t1, exorder, argtrip); /* NOTE: violates infomation hiding */
|
|
|
|
optyp_ptr->oprval.tref = argtrip;
|
|
|
|
if (se_warn)
|
|
|
|
ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1);
|
|
|
|
}
|
|
|
|
} /* end of side effect processing */
|
|
|
|
assert((catbp == catbp->que.fl) && (catbp == catbp->que.bl) && (NULL == catbp->bpt));
|
2012-02-05 11:35:58 -05:00
|
|
|
assert(op_count > 1);
|
|
|
|
ref->operand[0] = put_ilit(op_count);
|
|
|
|
ins_triple(ref);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
advancewindow();
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!expratom(&optyp_1))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
stx_error(ERR_RHMISSING);
|
|
|
|
return EXPR_FAIL;
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
coerce(&optyp_1, type);
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
if ((TK_QUESTION == TREF(window_token)) || (TK_NQUESTION == TREF(window_token)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
ind_pat = FALSE;
|
2012-03-24 14:06:46 -04:00
|
|
|
if (TK_ATSIGN == TREF(director_token))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
ind_pat = TRUE;
|
|
|
|
advancewindow();
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!compile_pattern(&optyp_2, ind_pat))
|
2012-02-05 11:35:58 -05:00
|
|
|
return EXPR_FAIL;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
advancewindow();
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!expratom(&optyp_2))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
stx_error(ERR_RHMISSING);
|
|
|
|
return EXPR_FAIL;
|
|
|
|
}
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
coerce(&optyp_2, type);
|
|
|
|
ref1 = optyp_1.oprval.tref;
|
|
|
|
if (((OC_VAR == ref1->opcode) || (OC_GETINDX == ref1->opcode))
|
|
|
|
&& (TREF(side_effect_base))[TREF(expr_depth)])
|
|
|
|
{ /* this section is to protect lvns from changes by a following side effect extrinsic or function
|
|
|
|
* by inserting a temporary to capture the lvn evaluation before it's changed by a "later" or
|
|
|
|
* "to-the-right" side effect; a preexisting coerce or temporary might already to the job;
|
|
|
|
* indirects may already have been shifted to evaluate early
|
|
|
|
*/
|
|
|
|
assert(OLD_SE != TREF(side_effect_handling));
|
|
|
|
ref = maketriple(OC_STOTEMP);
|
|
|
|
ref->operand[0] = optyp_1;
|
|
|
|
optyp_1 = put_tref(ref);
|
|
|
|
dqins(ref1, exorder, ref); /* NOTE: another violation of information hiding */
|
|
|
|
if (se_warn)
|
|
|
|
ISSUE_SIDEEFFECTEVAL_WARNING(ref1->src.column + 1);
|
|
|
|
}
|
|
|
|
ref = newtriple(bin_opcode);
|
|
|
|
ref->operand[0] = optyp_1;
|
|
|
|
ref->operand[1] = optyp_2;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
optyp_1 = put_tref(ref);
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
*a = optyp_1;
|
2012-03-24 14:06:46 -04:00
|
|
|
return (OC_INDGLVN == (TREF(curtchain))->exorder.bl->opcode) ? EXPR_INDR : EXPR_GOOD;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|