2021-08-13 01:31:23 +03:00
|
|
|
[CConditions::] C Conditions.
|
|
|
|
|
|
|
|
Evaluating conditions.
|
|
|
|
|
2021-10-31 19:28:32 +02:00
|
|
|
@ This section implements the primitives which evaluate conditions. |!propertyvalue|
|
|
|
|
might seem a surprising inclusion in the list: as the name suggests, this finds
|
|
|
|
a property value. But although it is often used in a value context, it's also used
|
|
|
|
as a condition. For example, if kit code (written in Inform 6 notation) does this:
|
|
|
|
= (text as Inform 6)
|
|
|
|
if (obj has concealed) ...
|
|
|
|
=
|
|
|
|
then the condition amounts to an |inv !propertyvalue|. Now, since any value can
|
|
|
|
be used as a condition, this may still not seem to mean that |!propertyvalue|
|
|
|
|
belongs here; but consider that it is also legal to write --
|
|
|
|
= (text as Inform 6)
|
|
|
|
if (obj has concealed or scenery) ...
|
|
|
|
=
|
|
|
|
Here the |inv !propertyvalue| involves an |inv !alternative| in its children,
|
|
|
|
and handling that requires the mechanism below.
|
2021-08-13 01:31:23 +03:00
|
|
|
|
|
|
|
=
|
2021-09-25 20:21:49 +03:00
|
|
|
int CConditions::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
|
2021-08-13 01:31:23 +03:00
|
|
|
text_stream *OUT = CodeGen::current(gen);
|
|
|
|
switch (bip) {
|
2021-10-31 19:28:32 +02:00
|
|
|
case NOT_BIP:
|
|
|
|
WRITE("(!("); VNODE_1C; WRITE("))"); break;
|
|
|
|
case AND_BIP:
|
|
|
|
WRITE("(("); VNODE_1C; WRITE(") && ("); VNODE_2C; WRITE("))"); break;
|
|
|
|
case OR_BIP:
|
|
|
|
WRITE("(("); VNODE_1C; WRITE(") || ("); VNODE_2C; WRITE("))"); break;
|
2021-10-18 00:55:41 +03:00
|
|
|
case PROPERTYEXISTS_BIP:
|
2021-10-16 01:49:12 +03:00
|
|
|
C_GEN_DATA(objdata.value_ranges_needed) = TRUE;
|
|
|
|
C_GEN_DATA(objdata.value_property_holders_needed) = TRUE;
|
2021-10-31 12:38:25 +02:00
|
|
|
WRITE("(i7_provides_gprop(proc, "); VNODE_1C; WRITE(", ");
|
2021-11-08 12:16:46 +02:00
|
|
|
VNODE_2C; WRITE(", "); VNODE_3C; WRITE("))");
|
2021-10-31 19:28:32 +02:00
|
|
|
break;
|
|
|
|
case EQ_BIP: case NE_BIP: case GT_BIP: case GE_BIP: case LT_BIP: case LE_BIP:
|
|
|
|
case OFCLASS_BIP: case IN_BIP: case NOTIN_BIP:
|
|
|
|
CConditions::comparison_r(gen, bip, NULL,
|
|
|
|
InterTree::first_child(P), InterTree::second_child(P), 0);
|
|
|
|
break;
|
|
|
|
case PROPERTYVALUE_BIP:
|
|
|
|
CConditions::comparison_r(gen, bip, InterTree::first_child(P),
|
|
|
|
InterTree::second_child(P), InterTree::third_child(P), 0);
|
2021-10-31 12:38:25 +02:00
|
|
|
break;
|
2021-10-31 19:28:32 +02:00
|
|
|
case ALTERNATIVE_BIP:
|
|
|
|
internal_error("misplaced !alternative in Inter tree"); break;
|
|
|
|
default: return NOT_APPLICABLE;
|
2021-08-13 01:31:23 +03:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2021-10-31 19:28:32 +02:00
|
|
|
@ The following recursive mechanism exists because of the need to support
|
|
|
|
alternative choices in Inter conditions, as here:
|
|
|
|
= (text as Inter)
|
|
|
|
inv !if
|
|
|
|
inv !eq
|
|
|
|
val K_number x
|
|
|
|
inv !alternative
|
|
|
|
val K_number 4
|
|
|
|
val K_number 8
|
|
|
|
...
|
|
|
|
=
|
|
|
|
This is the equivalent of writing |if (x == 4 or 8) ...| in Inform 6, but C does
|
|
|
|
not have an |or| operator like that. We could with care sometimes compile this
|
|
|
|
as |if ((x == 4) || (x == 8))|, but if evaluating |x| has side-effects, or is
|
|
|
|
slow, this will cause problems. Instead we compile |if (t = x, ((t == 4) || (t == 8)))|
|
|
|
|
where |t| is temporary storage.
|
|
|
|
|
|
|
|
Note that |!ne| and |!notin| interpret |!alternative| in a de Morgan-like way,
|
|
|
|
so that we compile |if ((x != 4) && (x != 8))| rather than |if ((x != 4) || (x != 8))|.
|
|
|
|
The former is equivalent to negating |!eq| on the same choices, which is what we want;
|
|
|
|
the latter would be universally true, which is useless.
|
2021-08-13 01:31:23 +03:00
|
|
|
|
2021-10-31 19:28:32 +02:00
|
|
|
=
|
2021-08-13 01:31:23 +03:00
|
|
|
void CConditions::comparison_r(code_generation *gen,
|
2021-10-18 00:55:41 +03:00
|
|
|
inter_ti bip, inter_tree_node *K, inter_tree_node *X, inter_tree_node *Y, int depth) {
|
2022-03-14 00:08:41 +02:00
|
|
|
if (Inode::is(Y, INV_IST)) {
|
2022-03-13 13:28:33 +02:00
|
|
|
if (InvInstruction::method(Y) == PRIMITIVE_INVMETH) {
|
2022-03-13 01:44:46 +02:00
|
|
|
inter_symbol *prim = InvInstruction::primitive(Y);
|
2022-01-14 12:56:42 +02:00
|
|
|
inter_ti ybip = Primitives::to_BIP(gen->from, prim);
|
2021-08-13 01:31:23 +03:00
|
|
|
if (ybip == ALTERNATIVE_BIP) {
|
|
|
|
text_stream *OUT = CodeGen::current(gen);
|
2021-10-31 19:28:32 +02:00
|
|
|
if (depth == 0) {
|
|
|
|
WRITE("(proc->state.tmp[0] = "); Vanilla::node(gen, X); WRITE(", (");
|
|
|
|
}
|
2021-10-18 00:55:41 +03:00
|
|
|
CConditions::comparison_r(gen, bip, K, NULL, InterTree::first_child(Y), depth+1);
|
2021-10-15 01:53:44 +03:00
|
|
|
if ((bip == NE_BIP) || (bip == NOTIN_BIP)) WRITE(" && ");
|
2021-08-19 01:59:31 +03:00
|
|
|
else WRITE(" || ");
|
2021-10-18 00:55:41 +03:00
|
|
|
CConditions::comparison_r(gen, bip, K, NULL, InterTree::second_child(Y), depth+1);
|
2021-08-13 01:31:23 +03:00
|
|
|
if (depth == 0) { WRITE("))"); }
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
text_stream *OUT = CodeGen::current(gen);
|
|
|
|
int positive = TRUE;
|
2021-10-31 19:28:32 +02:00
|
|
|
text_stream *test_fn = NULL, *test_operator = NULL;
|
|
|
|
switch (bip) {
|
|
|
|
case OFCLASS_BIP: positive = TRUE; test_fn = I"i7_ofclass"; break;
|
|
|
|
case IN_BIP: positive = TRUE; test_fn = I"i7_in"; break;
|
|
|
|
case NOTIN_BIP: positive = FALSE; test_fn = I"i7_in"; break;
|
|
|
|
case EQ_BIP: test_operator = I"=="; break;
|
|
|
|
case NE_BIP: test_operator = I"!="; break;
|
|
|
|
case GT_BIP: test_operator = I">"; break;
|
|
|
|
case GE_BIP: test_operator = I">="; break;
|
|
|
|
case LT_BIP: test_operator = I"<"; break;
|
|
|
|
case LE_BIP: test_operator = I"<="; break;
|
|
|
|
case PROPERTYVALUE_BIP: break;
|
|
|
|
default: internal_error("unsupported condition"); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bip == PROPERTYVALUE_BIP) {
|
2021-11-08 12:16:46 +02:00
|
|
|
WRITE("(i7_read_gprop_value(proc, ", test_fn);
|
2021-10-31 19:28:32 +02:00
|
|
|
Vanilla::node(gen, K); WRITE(", ");
|
|
|
|
@<Compile first comparand@>;
|
|
|
|
WRITE(", ");
|
|
|
|
@<Compile second comparand@>;
|
|
|
|
WRITE("))");
|
|
|
|
} else if (Str::len(test_fn) > 0) {
|
2021-09-08 01:28:19 +03:00
|
|
|
WRITE("(%S(proc, ", test_fn);
|
2021-10-31 19:28:32 +02:00
|
|
|
@<Compile first comparand@>;
|
2021-08-13 01:31:23 +03:00
|
|
|
WRITE(", ");
|
2021-10-31 19:28:32 +02:00
|
|
|
@<Compile second comparand@>;
|
2021-08-13 01:31:23 +03:00
|
|
|
WRITE(")");
|
|
|
|
if (positive == FALSE) WRITE(" == 0");
|
|
|
|
WRITE(")");
|
|
|
|
} else {
|
2021-10-31 19:28:32 +02:00
|
|
|
WRITE("("); @<Compile first comparand@>;
|
|
|
|
WRITE(" %S ", test_operator);
|
|
|
|
@<Compile second comparand@>; WRITE(")");
|
2021-08-13 01:31:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 19:28:32 +02:00
|
|
|
@<Compile first comparand@> =
|
2021-10-30 15:04:16 +03:00
|
|
|
if (X) Vanilla::node(gen, X); else WRITE("proc->state.tmp[0]");
|
2021-08-13 01:31:23 +03:00
|
|
|
|
2021-10-31 19:28:32 +02:00
|
|
|
@<Compile second comparand@> =
|
2021-09-24 01:48:56 +03:00
|
|
|
Vanilla::node(gen, Y);
|