1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-01 06:24:58 +03:00

Tidied up conditions and program control

This commit is contained in:
Graham Nelson 2021-10-31 17:28:32 +00:00
parent b246e007fc
commit 3201cd9d77
6 changed files with 184 additions and 142 deletions

View file

@ -392,11 +392,11 @@ void i7_opcode_restart(i7process_t *proc) {
printf("(RESTART is not implemented on this C program.)\n");
}
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t y) {
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t *y) {
printf("(RESTORE is not implemented on this C program.)\n");
}
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t y) {
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t *y) {
printf("(SAVE is not implemented on this C program.)\n");
}
void i7_opcode_streamnum(i7process_t *proc, i7word_t x) {

View file

@ -117,8 +117,8 @@ void i7_opcode_saveundo(i7process_t *proc, i7word_t *x);
void i7_opcode_hasundo(i7process_t *proc, i7word_t *x);
void i7_opcode_discardundo(i7process_t *proc);
void i7_opcode_restart(i7process_t *proc);
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t y);
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t y);
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t *y);
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t *y);
void i7_opcode_streamnum(i7process_t *proc, i7word_t x);
void i7_opcode_streamchar(i7process_t *proc, i7word_t x);
void i7_opcode_streamunichar(i7process_t *proc, i7word_t x);

View file

@ -197,10 +197,10 @@ C_supported_opcode *CAssembly::find_opcode(code_generation *gen, text_stream *na
CAssembly::new_opcode(gen, I"@quit", -1, -1, -1);
CAssembly::new_opcode(gen, I"@random", 2, -1, -1);
CAssembly::new_opcode(gen, I"@restart", -1, -1, -1);
CAssembly::new_opcode(gen, I"@restore", -1, -1, -1);
CAssembly::new_opcode(gen, I"@restore", 2, -1, -1);
CAssembly::new_opcode(gen, I"@restoreundo", 1, -1, -1);
CAssembly::new_opcode(gen, I"@return", -1, -1, -1);
CAssembly::new_opcode(gen, I"@save", -1, -1, -1);
CAssembly::new_opcode(gen, I"@save", 2, -1, -1);
CAssembly::new_opcode(gen, I"@saveundo", 1, -1, -1);
CAssembly::new_opcode(gen, I"@setiosys", -1, -1, -1);
CAssembly::new_opcode(gen, I"@setrandom", -1, -1, -1);
@ -553,8 +553,8 @@ but not so simple to restart execution as if from a clean process start.
= (text to inform7_clib.h)
void i7_opcode_restart(i7process_t *proc);
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t y);
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t y);
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t *y);
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t *y);
=
= (text to inform7_clib.c)
@ -562,11 +562,11 @@ void i7_opcode_restart(i7process_t *proc) {
printf("(RESTART is not implemented on this C program.)\n");
}
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t y) {
void i7_opcode_restore(i7process_t *proc, i7word_t x, i7word_t *y) {
printf("(RESTORE is not implemented on this C program.)\n");
}
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t y) {
void i7_opcode_save(i7process_t *proc, i7word_t x, i7word_t *y) {
printf("(SAVE is not implemented on this C program.)\n");
}
=

View file

@ -2,41 +2,79 @@
Evaluating conditions.
@
@ 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.
=
int CConditions::invoke_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
text_stream *OUT = CodeGen::current(gen);
switch (bip) {
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;
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;
case PROPERTYEXISTS_BIP:
C_GEN_DATA(objdata.value_ranges_needed) = TRUE;
C_GEN_DATA(objdata.value_property_holders_needed) = TRUE;
WRITE("(i7_provides_gprop(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C;
WRITE(", i7_mgl_OBJECT_TY, i7_mgl_value_ranges, i7_mgl_value_property_holders, i7_mgl_A_door_to, i7_mgl_COL_HSIZE))");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", ");
WRITE("i7_mgl_OBJECT_TY, i7_mgl_value_ranges, i7_mgl_value_property_holders, ");
WRITE("i7_mgl_A_door_to, i7_mgl_COL_HSIZE))");
break;
case EQ_BIP: @<Generate comparison@>; break;
case NE_BIP: @<Generate comparison@>; break;
case GT_BIP: @<Generate comparison@>; break;
case GE_BIP: @<Generate comparison@>; break;
case LT_BIP: @<Generate comparison@>; break;
case LE_BIP: @<Generate comparison@>; break;
case OFCLASS_BIP: @<Generate comparison@>; break;
case IN_BIP: @<Generate comparison@>; break;
case NOTIN_BIP: @<Generate comparison@>; break;
case ALTERNATIVE_BIP: internal_error("loose ALTERNATIVE_BIP primitive node"); break;
default: return NOT_APPLICABLE;
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);
break;
case ALTERNATIVE_BIP:
internal_error("misplaced !alternative in Inter tree"); break;
default: return NOT_APPLICABLE;
}
return FALSE;
}
@<Generate comparison@> =
CConditions::comparison_r(gen, bip, NULL, InterTree::first_child(P), InterTree::second_child(P), 0);
@ 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.
=
void CConditions::comparison_r(code_generation *gen,
inter_ti bip, inter_tree_node *K, inter_tree_node *X, inter_tree_node *Y, int depth) {
if (Y->W.data[ID_IFLD] == INV_IST) {
@ -45,7 +83,9 @@ void CConditions::comparison_r(code_generation *gen,
inter_ti ybip = Primitives::to_bip(gen->from, prim);
if (ybip == ALTERNATIVE_BIP) {
text_stream *OUT = CodeGen::current(gen);
if (depth == 0) { WRITE("(proc->state.tmp[0] = "); Vanilla::node(gen, X); WRITE(", ("); }
if (depth == 0) {
WRITE("(proc->state.tmp[0] = "); Vanilla::node(gen, X); WRITE(", (");
}
CConditions::comparison_r(gen, bip, K, NULL, InterTree::first_child(Y), depth+1);
if ((bip == NE_BIP) || (bip == NOTIN_BIP)) WRITE(" && ");
else WRITE(" || ");
@ -57,38 +97,47 @@ void CConditions::comparison_r(code_generation *gen,
}
text_stream *OUT = CodeGen::current(gen);
int positive = TRUE;
text_stream *test_fn = CObjectModel::test_with_function(bip, &positive);
if (Str::len(test_fn) > 0) {
WRITE("(%S(proc, ", test_fn);
if (bip == PROPERTYVALUE_BIP) {
Vanilla::node(gen, K);
WRITE(", ");
}
@<Compile first compared@>;
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) {
WRITE("(i7_read_gprop(proc, ", test_fn);
Vanilla::node(gen, K); WRITE(", ");
@<Compile first comparand@>;
WRITE(", ");
@<Compile second compared@>;
if (bip == PROPERTYVALUE_BIP) {
WRITE(", i7_mgl_OBJECT_TY, i7_mgl_value_ranges, i7_mgl_value_property_holders, i7_mgl_A_door_to, i7_mgl_COL_HSIZE");
}
@<Compile second comparand@>;
WRITE(", i7_mgl_OBJECT_TY, i7_mgl_value_ranges, i7_mgl_value_property_holders, ");
WRITE("i7_mgl_A_door_to, i7_mgl_COL_HSIZE");
WRITE("))");
} else if (Str::len(test_fn) > 0) {
WRITE("(%S(proc, ", test_fn);
@<Compile first comparand@>;
WRITE(", ");
@<Compile second comparand@>;
WRITE(")");
if (positive == FALSE) WRITE(" == 0");
WRITE(")");
} else {
WRITE("("); @<Compile first compared@>;
switch (bip) {
case EQ_BIP: WRITE(" == "); break;
case NE_BIP: WRITE(" != "); break;
case GT_BIP: WRITE(" > "); break;
case GE_BIP: WRITE(" >= "); break;
case LT_BIP: WRITE(" < "); break;
case LE_BIP: WRITE(" <= "); break;
}
@<Compile second compared@>; WRITE(")");
WRITE("("); @<Compile first comparand@>;
WRITE(" %S ", test_operator);
@<Compile second comparand@>; WRITE(")");
}
}
@<Compile first compared@> =
@<Compile first comparand@> =
if (X) Vanilla::node(gen, X); else WRITE("proc->state.tmp[0]");
@<Compile second compared@> =
@<Compile second comparand@> =
Vanilla::node(gen, Y);

View file

@ -736,8 +736,6 @@ int CObjectModel::invoke_primitive(code_generation *gen, inter_ti bip, inter_tre
switch (bip) {
case PROPERTYARRAY_BIP: WRITE("i7_prop_addr(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(", "); VNODE_3C; WRITE(")"); break;
case PROPERTYLENGTH_BIP: WRITE("i7_prop_len(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(", "); VNODE_3C; WRITE(")"); break;
case PROPERTYVALUE_BIP: CConditions::comparison_r(gen, bip, InterTree::first_child(P), InterTree::second_child(P), InterTree::third_child(P), 0);
break;
case MESSAGE0_BIP: WRITE("i7_mcall_0(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(")"); break;
case MESSAGE1_BIP: WRITE("i7_mcall_1(proc, "); VNODE_1C; WRITE(", "); VNODE_2C; WRITE(", ");
VNODE_3C; WRITE(")"); break;
@ -839,19 +837,6 @@ i7word_t i7_prop_addr(i7process_t *proc, i7word_t K, i7word_t obj, i7word_t pr_a
}
=
@h Special object-related conditions.
=
text_stream *CObjectModel::test_with_function(inter_ti bip, int *positive) {
switch (bip) {
case OFCLASS_BIP: *positive = TRUE; return I"i7_ofclass"; break;
case PROPERTYVALUE_BIP: *positive = TRUE; return I"i7_read_gprop"; break;
case IN_BIP: *positive = TRUE; return I"i7_in"; break;
case NOTIN_BIP: *positive = FALSE; return I"i7_in"; break;
}
*positive = NOT_APPLICABLE; return NULL;
}
@
= (text to inform7_clib.h)

View file

@ -2,7 +2,9 @@
Generating C code to effect loops, branches and the like.
@
@ This is as good a place as any to provide the general function for compiling
invocations of primitives. There are a lot of primitives, so the actual work is
distributed throughout this chapter.
=
void CProgramControl::initialise(code_generator *cgt) {
@ -28,88 +30,66 @@ void CProgramControl::invoke_primitive(code_generator *cgt, code_generation *gen
}
}
int CProgramControl::compile_control_primitive(code_generation *gen, inter_ti bip, inter_tree_node *P) {
@ And the rest of this section implements the primitives to do with execution
control: branches, loops and so on.
=
int CProgramControl::compile_control_primitive(code_generation *gen, inter_ti bip,
inter_tree_node *P) {
int suppress_terminal_semicolon = FALSE;
text_stream *OUT = CodeGen::current(gen);
inter_tree *I = gen->from;
switch (bip) {
case PUSH_BIP: WRITE("i7_push(proc, "); VNODE_1C; WRITE(")"); break;
case PULL_BIP: VNODE_1C; WRITE(" = i7_pull(proc)"); break;
case BREAK_BIP: WRITE("break"); break;
case CONTINUE_BIP: WRITE("continue"); break;
case RETURN_BIP: @<Generate primitive for return@>; break;
case JUMP_BIP: WRITE("goto "); VNODE_1C; break;
case QUIT_BIP: WRITE("exit(0)"); break;
case RESTORE_BIP: break; /* we won't support this in C */
case PUSH_BIP: WRITE("i7_push(proc, "); VNODE_1C; WRITE(")"); break;
case PULL_BIP: VNODE_1C; WRITE(" = i7_pull(proc)"); break;
case IF_BIP: @<Generate primitive for if@>; break;
case IFDEBUG_BIP: @<Generate primitive for ifdebug@>; break;
case IFSTRICT_BIP: @<Generate primitive for ifstrict@>; break;
case IFELSE_BIP: @<Generate primitive for ifelse@>; break;
case BREAK_BIP: WRITE("break"); break;
case CONTINUE_BIP: WRITE("continue"); break;
case JUMP_BIP: WRITE("goto "); VNODE_1C; break;
case QUIT_BIP: WRITE("i7_benign_exit(proc)"); break;
case RESTORE_BIP: WRITE("i7_opcode_restore(proc, 0, NULL)"); break;
case RETURN_BIP: WRITE("return (i7word_t) "); VNODE_1C; break;
case WHILE_BIP: @<Generate primitive for while@>; break;
case DO_BIP: @<Generate primitive for do@>; break;
case FOR_BIP: @<Generate primitive for for@>; break;
case OBJECTLOOP_BIP: @<Generate primitive for objectloop@>; break;
case OBJECTLOOPX_BIP: @<Generate primitive for objectloopx@>; break;
case LOOP_BIP: @<Generate primitive for loop@>; break;
case SWITCH_BIP: @<Generate primitive for switch@>; break;
case CASE_BIP: @<Generate primitive for case@>; break;
case DEFAULT_BIP: @<Generate primitive for default@>; break;
case INDIRECT0_BIP: case INDIRECT0V_BIP:
WRITE("i7_call_0(proc, "); VNODE_1C; WRITE(")"); break;
WRITE("i7_call_0(proc, "); VNODE_1C; WRITE(")"); break;
case INDIRECT1_BIP: case INDIRECT1V_BIP:
WRITE("i7_call_1(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(")"); break;
WRITE("i7_call_1(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(")"); break;
case INDIRECT2_BIP: case INDIRECT2V_BIP:
WRITE("i7_call_2(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(")"); break;
WRITE("i7_call_2(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(")"); break;
case INDIRECT3_BIP: case INDIRECT3V_BIP:
WRITE("i7_call_3(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(")"); break;
WRITE("i7_call_3(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(")"); break;
case INDIRECT4_BIP: case INDIRECT4V_BIP:
WRITE("i7_call_4(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(", ");
VNODE_5C; WRITE(")"); break;
WRITE("i7_call_4(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(", ");
VNODE_5C; WRITE(")"); break;
case INDIRECT5_BIP: case INDIRECT5V_BIP:
WRITE("i7_call_5(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(", ");
VNODE_5C; WRITE(", "); VNODE_6C; WRITE(")"); break;
case EXTERNALCALL_BIP: {
inter_tree_node *N = InterTree::first_child(P);
if ((N) && (N->W.data[ID_IFLD] == VAL_IST) && (N->W.data[VAL1_VAL_IFLD] == LITERAL_TEXT_IVAL)) {
text_stream *glob_text = Inter::Warehouse::get_text(InterTree::warehouse(I), N->W.data[VAL1_VAL_IFLD + 1]);
WRITE("%S(proc, ", CFunctionModel::external_function(gen, glob_text)); VNODE_2C; WRITE(")");
} else {
internal_error("unimplemented form of !externalcall");
}
break;
}
case IF_BIP: @<Generate primitive for if@>; break;
case IFDEBUG_BIP: @<Generate primitive for ifdebug@>; break;
case IFSTRICT_BIP: @<Generate primitive for ifstrict@>; break;
case IFELSE_BIP: @<Generate primitive for ifelse@>; break;
case WHILE_BIP: @<Generate primitive for while@>; break;
case DO_BIP: @<Generate primitive for do@>; break;
case FOR_BIP: @<Generate primitive for for@>; break;
case OBJECTLOOP_BIP: @<Generate primitive for objectloop@>; break;
case OBJECTLOOPX_BIP: @<Generate primitive for objectloopx@>; break;
case LOOP_BIP: @<Generate primitive for loop@>; break;
case SWITCH_BIP: @<Generate primitive for switch@>; break;
case CASE_BIP: @<Generate primitive for case@>; break;
case ALTERNATIVECASE_BIP: VNODE_1C; WRITE(", "); VNODE_2C; break;
case DEFAULT_BIP: @<Generate primitive for default@>; break;
WRITE("i7_call_5(proc, "); VNODE_1C; WRITE(", ");
VNODE_2C; WRITE(", "); VNODE_3C; WRITE(", "); VNODE_4C; WRITE(", ");
VNODE_5C; WRITE(", "); VNODE_6C; WRITE(")"); break;
case EXTERNALCALL_BIP:
@<Generate primitive for externalcall@>; break;
case ALTERNATIVECASE_BIP: internal_error("misplaced !alternativecase"); break;
default: internal_error("unimplemented prim");
}
return suppress_terminal_semicolon;
}
@<Generate primitive for return@> =
int rboolean = NOT_APPLICABLE;
inter_tree_node *V = InterTree::first_child(P);
if (V->W.data[ID_IFLD] == VAL_IST) {
inter_ti val1 = V->W.data[VAL1_VAL_IFLD];
inter_ti val2 = V->W.data[VAL2_VAL_IFLD];
if (val1 == LITERAL_IVAL) {
if (val2 == 0) rboolean = FALSE;
if (val2 == 1) rboolean = TRUE;
}
}
switch (rboolean) {
case FALSE: WRITE("return 0"); break;
case TRUE: WRITE("return 1"); break;
case NOT_APPLICABLE: WRITE("return (i7word_t) "); Vanilla::node(gen, V); break;
}
@<Generate primitive for if@> =
WRITE("if ("); VNODE_1C; WRITE(") {\n"); INDENT; VNODE_2C;
OUTDENT; WRITE("}\n");
@ -138,7 +118,9 @@ int CProgramControl::compile_control_primitive(code_generation *gen, inter_ti bi
@<Generate primitive for for@> =
WRITE("for (");
inter_tree_node *INIT = InterTree::first_child(P);
if (!((INIT->W.data[ID_IFLD] == VAL_IST) && (INIT->W.data[VAL1_VAL_IFLD] == LITERAL_IVAL) && (INIT->W.data[VAL2_VAL_IFLD] == 1))) VNODE_1C;
if (!((INIT->W.data[ID_IFLD] == VAL_IST) &&
(INIT->W.data[VAL1_VAL_IFLD] == LITERAL_IVAL) &&
(INIT->W.data[VAL2_VAL_IFLD] == 1))) VNODE_1C;
WRITE(";"); VNODE_2C;
WRITE(";");
inter_tree_node *U = InterTree::third_child(P);
@ -151,7 +133,8 @@ int CProgramControl::compile_control_primitive(code_generation *gen, inter_ti bi
@<Generate primitive for objectloop@> =
int in_flag = FALSE;
inter_tree_node *U = InterTree::third_child(P);
if ((U->W.data[ID_IFLD] == INV_IST) && (U->W.data[METHOD_INV_IFLD] == INVOKED_PRIMITIVE)) {
if ((U->W.data[ID_IFLD] == INV_IST) &&
(U->W.data[METHOD_INV_IFLD] == INVOKED_PRIMITIVE)) {
inter_symbol *prim = Inter::Inv::invokee(U);
if ((prim) && (Primitives::to_bip(I, prim) == IN_BIP)) in_flag = TRUE;
}
@ -188,15 +171,24 @@ int CProgramControl::compile_control_primitive(code_generation *gen, inter_ti bi
WRITE(") {\n"); INDENT; VNODE_2C; OUTDENT; WRITE("}\n");
suppress_terminal_semicolon = TRUE;
@ Inter permits multiple match values to be supplied for a single case in a
|!switch| primitive: but C does not allow this for its keyword |case|, so we
have to recurse downwards through the possibilities and preface each one by
|case:|. For example,
= (text as Inter)
inv !switch
inv !alternativecase
val K_number 3
val K_number 7
...
=
becomes |case 3: case 7:|.
@<Generate primitive for case@> =
CProgramControl::caser(gen, InterTree::first_child(P));
INDENT; VNODE_2C; WRITE(";\n"); WRITE("break;\n"); OUTDENT;
suppress_terminal_semicolon = TRUE;
@<Generate primitive for default@> =
WRITE("default:\n"); INDENT; VNODE_1C; WRITE(";\n"); WRITE("break;\n"); OUTDENT;
suppress_terminal_semicolon = TRUE;
@ =
void CProgramControl::caser(code_generation *gen, inter_tree_node *X) {
if (X->W.data[ID_IFLD] == INV_IST) {
@ -215,3 +207,19 @@ void CProgramControl::caser(code_generation *gen, inter_tree_node *X) {
Vanilla::node(gen, X);
WRITE(": ");
}
@<Generate primitive for default@> =
WRITE("default:\n"); INDENT; VNODE_1C; WRITE(";\n"); WRITE("break;\n"); OUTDENT;
suppress_terminal_semicolon = TRUE;
@<Generate primitive for externalcall@> =
inter_tree_node *N = InterTree::first_child(P);
if ((N) && (N->W.data[ID_IFLD] == VAL_IST) &&
(N->W.data[VAL1_VAL_IFLD] == LITERAL_TEXT_IVAL)) {
text_stream *glob_text = Inter::Warehouse::get_text(
InterTree::warehouse(I), N->W.data[VAL1_VAL_IFLD + 1]);
WRITE("%S(proc, ", CFunctionModel::external_function(gen, glob_text));
VNODE_2C; WRITE(")");
} else {
internal_error("unimplemented form of !externalcall");
}