2020-03-04 21:34:23 +02:00
|
|
|
[ControlStructures::] Control Structures.
|
|
|
|
|
|
|
|
To specify the syntax of control structures such as repeat, if and otherwise.
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
@ Certain phrases are "control structures": otherwise, if, repeat, while and
|
|
|
|
so on. These have different expectations in terms of the layout of surrounding
|
2020-03-04 21:34:23 +02:00
|
|
|
phrases in rule or phrase definitions, and the following structure defines
|
|
|
|
the relevant behaviour. (The contents are static.)
|
|
|
|
|
|
|
|
=
|
|
|
|
typedef struct control_structure_phrase {
|
|
|
|
struct control_structure_phrase *subordinate_to;
|
2020-05-07 18:44:07 +03:00
|
|
|
struct text_stream *mnemonic;
|
2020-03-04 21:34:23 +02:00
|
|
|
int indent_subblocks;
|
|
|
|
int body_empty_except_for_subordinates;
|
|
|
|
int used_at_stage;
|
|
|
|
int is_a_loop;
|
|
|
|
int requires_new_syntax;
|
|
|
|
int allow_run_on;
|
2023-09-05 10:36:51 +03:00
|
|
|
inchar32_t *keyword;
|
2020-05-09 15:07:39 +03:00
|
|
|
CLASS_DEFINITION
|
2020-03-04 21:34:23 +02:00
|
|
|
} control_structure_phrase;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
@ =
|
|
|
|
control_structure_phrase *ControlStructures::new(text_stream *mnemonic) {
|
2020-03-04 21:34:23 +02:00
|
|
|
control_structure_phrase *csp = CREATE(control_structure_phrase);
|
2020-05-07 18:44:07 +03:00
|
|
|
csp->mnemonic = Str::duplicate(mnemonic);
|
2020-03-04 21:34:23 +02:00
|
|
|
csp->subordinate_to = NULL;
|
|
|
|
csp->indent_subblocks = FALSE;
|
|
|
|
csp->body_empty_except_for_subordinates = FALSE;
|
|
|
|
csp->used_at_stage = -1;
|
|
|
|
csp->requires_new_syntax = FALSE;
|
|
|
|
csp->allow_run_on = FALSE;
|
2023-09-05 10:36:51 +03:00
|
|
|
csp->keyword = U"<none>";
|
2020-03-04 21:34:23 +02:00
|
|
|
csp->is_a_loop = FALSE;
|
|
|
|
return csp;
|
|
|
|
}
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
@ Some cryptic mnemonics for logging the invocation tree:
|
|
|
|
|
|
|
|
=
|
2020-08-07 12:39:22 +03:00
|
|
|
void ControlStructures::log(text_stream *OUT, control_structure_phrase *csp) {
|
|
|
|
if (csp == NULL) WRITE("---");
|
|
|
|
else WRITE("%S", csp->mnemonic);
|
2020-05-07 18:44:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@ The following set is built in to the Inform language; Basic Inform and such
|
|
|
|
extensions cannot extend it.
|
|
|
|
|
|
|
|
=
|
|
|
|
control_structure_phrase *switch_CSP = NULL, *if_CSP = NULL, *repeat_CSP = NULL,
|
|
|
|
*while_CSP = NULL, *otherwise_CSP = NULL, *abbreviated_otherwise_CSP = NULL,
|
|
|
|
*otherwise_if_CSP = NULL, *default_case_CSP = NULL, *case_CSP = NULL,
|
|
|
|
*say_CSP = NULL, *now_CSP = NULL, *instead_CSP = NULL;
|
|
|
|
|
|
|
|
@ And this is where they are all created:
|
|
|
|
|
|
|
|
=
|
2020-03-04 21:34:23 +02:00
|
|
|
void ControlStructures::create_standard(void) {
|
2020-05-07 18:44:07 +03:00
|
|
|
switch_CSP = ControlStructures::new(I"SWI");
|
2020-03-04 21:34:23 +02:00
|
|
|
switch_CSP->body_empty_except_for_subordinates = TRUE;
|
|
|
|
switch_CSP->indent_subblocks = TRUE;
|
|
|
|
switch_CSP->requires_new_syntax = TRUE;
|
2023-09-05 10:36:51 +03:00
|
|
|
switch_CSP->keyword = U"if";
|
2020-03-04 21:34:23 +02:00
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
if_CSP = ControlStructures::new(I"IF");
|
2023-09-05 10:36:51 +03:00
|
|
|
if_CSP->keyword = U"if";
|
2020-03-04 21:34:23 +02:00
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
repeat_CSP = ControlStructures::new(I"RPT");
|
2023-09-05 10:36:51 +03:00
|
|
|
repeat_CSP->keyword = U"repeat";
|
2020-03-04 21:34:23 +02:00
|
|
|
repeat_CSP->is_a_loop = TRUE;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
while_CSP = ControlStructures::new(I"WHI");
|
2023-09-05 10:36:51 +03:00
|
|
|
while_CSP->keyword = U"while";
|
2020-03-04 21:34:23 +02:00
|
|
|
while_CSP->is_a_loop = TRUE;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
otherwise_CSP = ControlStructures::new(I"O");
|
2020-03-04 21:34:23 +02:00
|
|
|
otherwise_CSP->subordinate_to = if_CSP;
|
|
|
|
otherwise_CSP->used_at_stage = 1;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
abbreviated_otherwise_CSP = ControlStructures::new(I"AO");
|
2020-03-04 21:34:23 +02:00
|
|
|
abbreviated_otherwise_CSP->subordinate_to = if_CSP;
|
|
|
|
abbreviated_otherwise_CSP->used_at_stage = 1;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
otherwise_if_CSP = ControlStructures::new(I"OIF");
|
2020-03-04 21:34:23 +02:00
|
|
|
otherwise_if_CSP->subordinate_to = if_CSP;
|
|
|
|
otherwise_if_CSP->used_at_stage = 0;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
case_CSP = ControlStructures::new(I"CAS");
|
2020-03-04 21:34:23 +02:00
|
|
|
case_CSP->subordinate_to = switch_CSP;
|
|
|
|
case_CSP->used_at_stage = 1;
|
|
|
|
case_CSP->requires_new_syntax = TRUE;
|
|
|
|
case_CSP->allow_run_on = TRUE;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
default_case_CSP = ControlStructures::new(I"DEF");
|
2020-03-04 21:34:23 +02:00
|
|
|
default_case_CSP->subordinate_to = switch_CSP;
|
|
|
|
default_case_CSP->used_at_stage = 2;
|
|
|
|
default_case_CSP->requires_new_syntax = TRUE;
|
|
|
|
default_case_CSP->allow_run_on = TRUE;
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
say_CSP = ControlStructures::new(I"SAY");
|
2020-03-04 21:34:23 +02:00
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
now_CSP = ControlStructures::new(I"NOW");
|
2020-03-04 21:34:23 +02:00
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
instead_CSP = ControlStructures::new(I"INS");
|
2020-03-04 21:34:23 +02:00
|
|
|
}
|
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
@ Control structures such as "if" act as a sort of super-punctuation inside
|
|
|
|
rule and phrase definitions, and in particular they affect the actual
|
|
|
|
punctuation of the sentences there (consider the rules about colons versus
|
|
|
|
semicolons). So, though it's still early in Inform's run, we need to seek
|
|
|
|
them out.
|
|
|
|
|
|
|
|
Here we parse the text of a command phrase which, if any, of the control
|
|
|
|
structures it might be. Note that <s-command> has a grammar partially
|
|
|
|
overlapping with this, and they need to match.
|
|
|
|
|
|
|
|
@d NO_SIGF 0
|
|
|
|
@d SAY_SIGF 1
|
|
|
|
@d NOW_SIGF 2
|
|
|
|
|
|
|
|
=
|
|
|
|
<control-structure-phrase> ::=
|
2020-07-28 14:29:51 +03:00
|
|
|
if ... is begin | ==> { -, switch_CSP }
|
|
|
|
if ... is | ==> { -, switch_CSP }
|
|
|
|
if/unless ... | ==> { -, if_CSP }
|
|
|
|
repeat ... | ==> { -, repeat_CSP }
|
|
|
|
while ... | ==> { -, while_CSP }
|
|
|
|
else/otherwise | ==> { -, otherwise_CSP }
|
|
|
|
else/otherwise if/unless ... | ==> { -, otherwise_if_CSP }
|
|
|
|
else/otherwise ... | ==> { -, abbreviated_otherwise_CSP }
|
|
|
|
-- otherwise | ==> { -, default_case_CSP }
|
|
|
|
-- ... ==> { -, case_CSP }
|
2020-05-07 18:44:07 +03:00
|
|
|
|
|
|
|
<end-control-structure-phrase> ::=
|
2020-07-28 14:29:51 +03:00
|
|
|
end if/unless | ==> { -, if_CSP }
|
|
|
|
end while | ==> { -, while_CSP }
|
|
|
|
end repeat ==> { -, repeat_CSP }
|
2020-05-07 18:44:07 +03:00
|
|
|
|
|
|
|
<other-significant-phrase> ::=
|
2020-07-28 12:43:16 +03:00
|
|
|
say ... | ==> { SAY_SIGF, - }
|
|
|
|
now ... ==> { NOW_SIGF, - }
|
2020-03-04 21:34:23 +02:00
|
|
|
|
2020-05-07 18:44:07 +03:00
|
|
|
@ This is used to see if an "if" is being used with the comma notation:
|
|
|
|
|
|
|
|
=
|
|
|
|
<phrase-with-comma-notation> ::=
|
|
|
|
...... , ......
|
|
|
|
|
|
|
|
@ This is used to see if an "if" is being used with the comma notation:
|
|
|
|
|
|
|
|
=
|
|
|
|
<instead-keyword> ::=
|
|
|
|
instead ... |
|
|
|
|
... instead
|
|
|
|
|
|
|
|
@ Finally, this is used to see if a control structure opens a block:
|
|
|
|
|
|
|
|
=
|
|
|
|
<phrase-beginning-block> ::=
|
|
|
|
... begin
|
|
|
|
|
|
|
|
@ And some miscellaneous provisions:
|
|
|
|
|
|
|
|
=
|
2020-03-04 21:34:23 +02:00
|
|
|
int ControlStructures::comma_possible(control_structure_phrase *csp) {
|
|
|
|
if ((csp == if_CSP) || (csp == switch_CSP) || (csp == otherwise_if_CSP))
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ControlStructures::is_a_loop(control_structure_phrase *csp) {
|
|
|
|
if (csp) return csp->is_a_loop;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ControlStructures::opens_block(control_structure_phrase *csp) {
|
|
|
|
if ((csp) && (csp->subordinate_to == NULL) &&
|
|
|
|
(csp != say_CSP) && (csp != now_CSP) && (csp != instead_CSP)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ControlStructures::permits_break(control_structure_phrase *csp) {
|
|
|
|
if ((csp == repeat_CSP) || (csp == while_CSP)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-09-05 10:36:51 +03:00
|
|
|
inchar32_t *ControlStructures::incipit(control_structure_phrase *csp) {
|
2020-03-04 21:34:23 +02:00
|
|
|
if (csp) return csp->keyword;
|
2023-09-05 10:36:51 +03:00
|
|
|
return U"<none>";
|
2020-03-04 21:34:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
control_structure_phrase *ControlStructures::detect(wording W) {
|
|
|
|
if (<control-structure-phrase>(W)) {
|
|
|
|
if (<<rp>> == abbreviated_otherwise_CSP) return NULL;
|
|
|
|
return <<rp>>;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ControlStructures::abbreviated_otherwise(wording W) {
|
|
|
|
if (<control-structure-phrase>(W)) {
|
|
|
|
if (<<rp>> == abbreviated_otherwise_CSP) return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
control_structure_phrase *ControlStructures::detect_end(wording W) {
|
|
|
|
if (<end-control-structure-phrase>(W)) return <<rp>>;
|
|
|
|
return NULL;
|
|
|
|
}
|