X-Git-Url: https://jxself.org/git/?p=inform.git;a=blobdiff_plain;f=src%2Fstates.c;fp=src%2Fstates.c;h=ea495505cf70bdef2b8f4bce014f0a4b1ff24dfd;hp=b569fb26cd933e66974fd551aaa5b7e4460b8766;hb=8e63120c630c94c598d4e2d6ba823dac59bce8fa;hpb=d11f2f726ed7feea617476d99cf7505ddd9a27ce diff --git a/src/states.c b/src/states.c index b569fb2..ea49550 100644 --- a/src/states.c +++ b/src/states.c @@ -1,8 +1,8 @@ /* ------------------------------------------------------------------------- */ /* "states" : Statement translator */ /* */ -/* Part of Inform 6.35 */ -/* copyright (c) Graham Nelson 1993 - 2021 */ +/* Part of Inform 6.40 */ +/* copyright (c) Graham Nelson 1993 - 2022 */ /* */ /* Inform is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -15,7 +15,7 @@ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ -/* along with Inform. If not, see https://gnu.org/licenses/ * +/* along with Inform. If not, see https://gnu.org/licenses/ */ /* */ /* ------------------------------------------------------------------------- */ @@ -259,17 +259,17 @@ extern int parse_label(void) get_next_token(); if ((token_type == SYMBOL_TT) && - (stypes[token_value] == LABEL_T)) - { sflags[token_value] |= USED_SFLAG; - return(svals[token_value]); + (symbols[token_value].type == LABEL_T)) + { symbols[token_value].flags |= USED_SFLAG; + return(symbols[token_value].value); } - if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG)) + if ((token_type == SYMBOL_TT) && (symbols[token_value].flags & UNKNOWN_SFLAG)) { assign_symbol(token_value, next_label, LABEL_T); define_symbol_label(token_value); next_label++; - sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG; - return(svals[token_value]); + symbols[token_value].flags |= CHANGE_SFLAG + USED_SFLAG; + return(symbols[token_value].value); } ebf_error("label name", token_text); @@ -429,19 +429,21 @@ static void parse_print_z(int finally_return) break; case SYMBOL_TT: - if (sflags[token_value] & UNKNOWN_SFLAG) + if (symbols[token_value].flags & UNKNOWN_SFLAG) { INITAOT(&AO, LONG_CONSTANT_OT); AO.value = token_value; AO.marker = SYMBOL_MV; + AO.symindex = token_value; } else { INITAOT(&AO, LONG_CONSTANT_OT); - AO.value = svals[token_value]; + AO.value = symbols[token_value].value; AO.marker = IROUTINE_MV; - if (stypes[token_value] != ROUTINE_T) + AO.symindex = token_value; + if (symbols[token_value].type != ROUTINE_T) ebf_error("printing routine name", token_text); } - sflags[token_value] |= USED_SFLAG; + symbols[token_value].flags |= USED_SFLAG; PrintByRoutine: @@ -664,19 +666,21 @@ static void parse_print_g(int finally_return) break; case SYMBOL_TT: - if (sflags[token_value] & UNKNOWN_SFLAG) + if (symbols[token_value].flags & UNKNOWN_SFLAG) { INITAOT(&AO, CONSTANT_OT); AO.value = token_value; AO.marker = SYMBOL_MV; + AO.symindex = token_value; } else { INITAOT(&AO, CONSTANT_OT); - AO.value = svals[token_value]; + AO.value = symbols[token_value].value; AO.marker = IROUTINE_MV; - if (stypes[token_value] != ROUTINE_T) + AO.symindex = token_value; + if (symbols[token_value].type != ROUTINE_T) ebf_error("printing routine name", token_text); } - sflags[token_value] |= USED_SFLAG; + symbols[token_value].flags |= USED_SFLAG; PrintByRoutine: @@ -734,57 +738,73 @@ static void parse_print_g(int finally_return) } } -static void parse_statement_z(int break_label, int continue_label) -{ int ln, ln2, ln3, ln4, flag; - assembly_operand AO, AO2, AO3, AO4; - debug_location spare_debug_location1, spare_debug_location2; - - ASSERT_ZCODE(); - - if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP)) +/* Parse any number of ".Label;" lines before a statement. + Returns whether a statement can in fact follow. */ +static int parse_named_label_statements() +{ + while ((token_type == SEP_TT) && (token_value == PROPERTY_SEP)) { /* That is, a full stop, signifying a label */ get_next_token(); - if (token_type == SYMBOL_TT) + if (token_type != SYMBOL_TT) { - if (sflags[token_value] & UNKNOWN_SFLAG) - { assign_symbol(token_value, next_label, LABEL_T); - sflags[token_value] |= USED_SFLAG; - assemble_label_no(next_label); - define_symbol_label(token_value); - next_label++; + ebf_error("label name", token_text); + return TRUE; + } + + if (symbols[token_value].flags & UNKNOWN_SFLAG) + { assign_symbol(token_value, next_label, LABEL_T); + symbols[token_value].flags |= USED_SFLAG; + assemble_label_no(next_label); + define_symbol_label(token_value); + next_label++; + } + else + { if (symbols[token_value].type != LABEL_T) { + ebf_error("label name", token_text); + return TRUE; } - else - { if (stypes[token_value] != LABEL_T) goto LabelError; - if (sflags[token_value] & CHANGE_SFLAG) - { sflags[token_value] &= (~(CHANGE_SFLAG)); - assemble_label_no(svals[token_value]); - define_symbol_label(token_value); - } - else error_named("Duplicate definition of label:", token_text); + if (symbols[token_value].flags & CHANGE_SFLAG) + { symbols[token_value].flags &= (~(CHANGE_SFLAG)); + assemble_label_no(symbols[token_value].value); + define_symbol_label(token_value); } + else error_named("Duplicate definition of label:", token_text); + } - get_next_token(); - if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP)) - { ebf_error("';'", token_text); - put_token_back(); return; - } + get_next_token(); + if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP)) + { ebf_error("';'", token_text); + put_token_back(); return FALSE; + } - /* Interesting point of Inform grammar: a statement can only - consist solely of a label when it is immediately followed - by a "}". */ + /* Interesting point of Inform grammar: a statement can only + consist solely of a label when it is immediately followed + by a "}". */ - get_next_token(); - if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP)) - { put_token_back(); return; - } - statement_debug_location = get_token_location(); - parse_statement(break_label, continue_label); - return; + get_next_token(); + if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP)) + { put_token_back(); return FALSE; } - LabelError: ebf_error("label name", token_text); + /* The following line prevents labels from influencing the positions + of sequence points. */ + statement_debug_location = get_token_location(); + + /* Another label might follow */ } + /* On with the statement */ + return TRUE; +} + +static void parse_statement_z(int break_label, int continue_label) +{ int ln, ln2, ln3, ln4, flag; + int pre_unreach, labelexists; + assembly_operand AO, AO2, AO3, AO4; + debug_location spare_debug_location1, spare_debug_location2; + + ASSERT_ZCODE(); + if ((token_type == SEP_TT) && (token_value == HASH_SEP)) { parse_directive(TRUE); parse_statement(break_label, continue_label); return; @@ -901,7 +921,7 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); if ((token_type == STATEMENT_TT) && (token_value == UNTIL_CODE)) - { assemble_label_no(ln2); + { assemble_forward_label_no(ln2); match_open_bracket(); AO = parse_expression(CONDITION_CONTEXT); match_close_bracket(); @@ -909,7 +929,7 @@ static void parse_statement_z(int break_label, int continue_label) } else error("'do' without matching 'until'"); - assemble_label_no(ln3); + assemble_forward_label_no(ln3); break; /* -------------------------------------------------------------------- */ @@ -997,7 +1017,7 @@ static void parse_statement_z(int break_label, int continue_label) sequence_point_follows = FALSE; if (!execution_never_reaches_here) assemblez_jump(ln); - assemble_label_no(ln2); + assemble_forward_label_no(ln2); return; } goto ParseUpdate; @@ -1106,7 +1126,7 @@ static void parse_statement_z(int break_label, int continue_label) } } - assemble_label_no(ln3); + assemble_forward_label_no(ln3); return; /* -------------------------------------------------------------------- */ @@ -1116,6 +1136,7 @@ static void parse_statement_z(int break_label, int continue_label) case GIVE_CODE: AO = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"give\" statement"); if ((AO.type == VARIABLE_OT) && (AO.value == 0)) { INITAOTV(&AO, SHORT_CONSTANT_OT, 252); if (version_number != 6) assemblez_1(pull_zc, AO); @@ -1130,15 +1151,12 @@ static void parse_statement_z(int break_label, int continue_label) if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP)) ln = clear_attr_zc; else - { if ((token_type == SYMBOL_TT) - && (stypes[token_value] != ATTRIBUTE_T)) - warning_named("This is not a declared Attribute:", - token_text); - ln = set_attr_zc; + { ln = set_attr_zc; put_token_back(); } AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO2, ATTRIBUTE_T, 0, "\"give\" statement"); if (runtime_error_checking_switch) { ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR; if (version_number >= 5) @@ -1159,8 +1177,9 @@ static void parse_statement_z(int break_label, int continue_label) /* -------------------------------------------------------------------- */ case IF_CODE: - flag = FALSE; + flag = FALSE; /* set if there's an "else" */ ln2 = 0; + pre_unreach = execution_never_reaches_here; match_open_bracket(); AO = parse_expression(CONDITION_CONTEXT); @@ -1178,8 +1197,17 @@ static void parse_statement_z(int break_label, int continue_label) ln = next_label++; } + /* The condition */ code_generate(AO, CONDITION_CONTEXT, ln); + if (!pre_unreach && ln >= 0 && execution_never_reaches_here) { + /* If the condition never falls through to here, then + it was an "if (0)" test. Our convention is to skip + the "not reached" warnings for this case. */ + execution_never_reaches_here |= EXECSTATE_NOWARN; + } + + /* The "if" block */ if (ln >= 0) parse_code_block(break_label, continue_label, 0); else { get_next_token(); @@ -1212,13 +1240,46 @@ static void parse_statement_z(int break_label, int continue_label) } else put_token_back(); - if (ln >= 0) assemble_label_no(ln); + /* The "else" label (or end of statement, if there is no "else") */ + labelexists = FALSE; + if (ln >= 0) labelexists = assemble_forward_label_no(ln); if (flag) - { parse_code_block(break_label, continue_label, 0); - if (ln >= 0) assemble_label_no(ln2); - } + { + /* If labelexists is false, then we started with + "if (1)". In this case, we don't want a "not + reached" warning on the "else" block. We + temporarily disable the NOWARN flag, and restore it + afterwards. */ + int saved_unreach = 0; + if (execution_never_reaches_here && !labelexists) { + saved_unreach = execution_never_reaches_here; + execution_never_reaches_here |= EXECSTATE_NOWARN; + } + + /* The "else" block */ + parse_code_block(break_label, continue_label, 0); + if (execution_never_reaches_here && !labelexists) { + if (saved_unreach & EXECSTATE_NOWARN) + execution_never_reaches_here |= EXECSTATE_NOWARN; + else + execution_never_reaches_here &= ~EXECSTATE_NOWARN; + } + + /* The post-"else" label */ + if (ln >= 0) assemble_forward_label_no(ln2); + } + else + { + /* There was no "else". If we're unreachable, then the + statement returned unconditionally, which means + "if (1) return". Skip warnings. */ + if (!pre_unreach && execution_never_reaches_here) { + execution_never_reaches_here |= EXECSTATE_NOWARN; + } + } + return; /* -------------------------------------------------------------------- */ @@ -1271,6 +1332,8 @@ static void parse_statement_z(int break_label, int continue_label) AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); AO = code_generate(AO, QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"move\" statement"); + check_warn_symbol_type(&AO2, OBJECT_T, CLASS_T, "\"move\" statement"); if ((runtime_error_checking_switch) && (veneer_mode == FALSE)) { if (version_number >= 5) assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR), @@ -1303,8 +1366,8 @@ static void parse_statement_z(int break_label, int continue_label) AO.value = token_value; else if ((token_type == SYMBOL_TT) && - (stypes[token_value] == GLOBAL_VARIABLE_T)) - AO.value = svals[token_value]; + (symbols[token_value].type == GLOBAL_VARIABLE_T)) + AO.value = symbols[token_value].value; else { ebf_error("'objectloop' variable", token_text); panic_mode_error_recovery(); break; @@ -1490,6 +1553,7 @@ static void parse_statement_z(int break_label, int continue_label) case REMOVE_CODE: AO = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"remove\" statement"); if ((runtime_error_checking_switch) && (veneer_mode == FALSE)) { if (version_number >= 5) assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR), @@ -1599,13 +1663,11 @@ static void parse_statement_z(int break_label, int continue_label) AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); if (is_constant_ot(AO2.type) && AO2.marker == 0) { - if (AO2.value >= 96) - { error("Z-machine dynamic strings are limited to 96"); + /* Compile-time check */ + if (AO2.value < 0 || AO2.value >= 96 || AO2.value >= MAX_DYNAMIC_STRINGS) { + error_max_dynamic_strings(AO2.value); AO2.value = 0; } - if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) { - memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS); - } } get_next_token(); if (token_type == DQ_TT) @@ -1673,7 +1735,7 @@ static void parse_statement_z(int break_label, int continue_label) assemblez_store(AO2, AO); parse_code_block(ln = next_label++, continue_label, 1); - assemble_label_no(ln); + assemble_forward_label_no(ln); return; /* -------------------------------------------------------------------- */ @@ -1691,7 +1753,7 @@ static void parse_statement_z(int break_label, int continue_label) parse_code_block(ln2, ln, 0); sequence_point_follows = FALSE; assemblez_jump(ln); - assemble_label_no(ln2); + assemble_forward_label_no(ln2); return; /* -------------------------------------------------------------------- */ @@ -1716,57 +1778,12 @@ static void parse_statement_z(int break_label, int continue_label) static void parse_statement_g(int break_label, int continue_label) { int ln, ln2, ln3, ln4, flag, onstack; + int pre_unreach, labelexists; assembly_operand AO, AO2, AO3, AO4; debug_location spare_debug_location1, spare_debug_location2; ASSERT_GLULX(); - if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP)) - { /* That is, a full stop, signifying a label */ - - get_next_token(); - if (token_type == SYMBOL_TT) - { - if (sflags[token_value] & UNKNOWN_SFLAG) - { assign_symbol(token_value, next_label, LABEL_T); - sflags[token_value] |= USED_SFLAG; - assemble_label_no(next_label); - define_symbol_label(token_value); - next_label++; - } - else - { if (stypes[token_value] != LABEL_T) goto LabelError; - if (sflags[token_value] & CHANGE_SFLAG) - { sflags[token_value] &= (~(CHANGE_SFLAG)); - assemble_label_no(svals[token_value]); - define_symbol_label(token_value); - } - else error_named("Duplicate definition of label:", token_text); - } - - get_next_token(); - if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP)) - { ebf_error("';'", token_text); - put_token_back(); return; - } - - /* Interesting point of Inform grammar: a statement can only - consist solely of a label when it is immediately followed - by a "}". */ - - get_next_token(); - if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP)) - { put_token_back(); return; - } - /* The following line prevents labels from influencing the positions - of sequence points. */ - statement_debug_location = get_token_location(); - parse_statement(break_label, continue_label); - return; - } - LabelError: ebf_error("label name", token_text); - } - if ((token_type == SEP_TT) && (token_value == HASH_SEP)) { parse_directive(TRUE); parse_statement(break_label, continue_label); return; @@ -1880,7 +1897,7 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); if ((token_type == STATEMENT_TT) && (token_value == UNTIL_CODE)) - { assemble_label_no(ln2); + { assemble_forward_label_no(ln2); match_open_bracket(); AO = parse_expression(CONDITION_CONTEXT); match_close_bracket(); @@ -1888,7 +1905,7 @@ static void parse_statement_g(int break_label, int continue_label) } else error("'do' without matching 'until'"); - assemble_label_no(ln3); + assemble_forward_label_no(ln3); break; /* -------------------------------------------------------------------- */ @@ -1958,7 +1975,7 @@ static void parse_statement_g(int break_label, int continue_label) sequence_point_follows = FALSE; if (!execution_never_reaches_here) assembleg_jump(ln); - assemble_label_no(ln2); + assemble_forward_label_no(ln2); return; } goto ParseUpdate; @@ -2071,7 +2088,7 @@ static void parse_statement_g(int break_label, int continue_label) } } - assemble_label_no(ln3); + assemble_forward_label_no(ln3); return; /* -------------------------------------------------------------------- */ @@ -2081,6 +2098,7 @@ static void parse_statement_g(int break_label, int continue_label) case GIVE_CODE: AO = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"give\" statement"); if ((AO.type == LOCALVAR_OT) && (AO.value == 0)) onstack = TRUE; else @@ -2098,15 +2116,12 @@ static void parse_statement_g(int break_label, int continue_label) if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP)) ln = 0; else - { if ((token_type == SYMBOL_TT) - && (stypes[token_value] != ATTRIBUTE_T)) - warning_named("This is not a declared Attribute:", - token_text); - ln = 1; + { ln = 1; put_token_back(); } AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO2, ATTRIBUTE_T, 0, "\"give\" statement"); if (runtime_error_checking_switch && (!veneer_mode)) { ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR); if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) { @@ -2153,8 +2168,9 @@ static void parse_statement_g(int break_label, int continue_label) /* -------------------------------------------------------------------- */ case IF_CODE: - flag = FALSE; + flag = FALSE; /* set if there's an "else" */ ln2 = 0; + pre_unreach = execution_never_reaches_here; match_open_bracket(); AO = parse_expression(CONDITION_CONTEXT); @@ -2172,8 +2188,17 @@ static void parse_statement_g(int break_label, int continue_label) ln = next_label++; } + /* The condition */ code_generate(AO, CONDITION_CONTEXT, ln); + if (!pre_unreach && ln >= 0 && execution_never_reaches_here) { + /* If the condition never falls through to here, then + it was an "if (0)" test. Our convention is to skip + the "not reached" warnings for this case. */ + execution_never_reaches_here |= EXECSTATE_NOWARN; + } + + /* The "if" block */ if (ln >= 0) parse_code_block(break_label, continue_label, 0); else { get_next_token(); @@ -2206,11 +2231,44 @@ static void parse_statement_g(int break_label, int continue_label) } else put_token_back(); - if (ln >= 0) assemble_label_no(ln); + /* The "else" label (or end of statement, if there is no "else") */ + labelexists = FALSE; + if (ln >= 0) labelexists = assemble_forward_label_no(ln); if (flag) - { parse_code_block(break_label, continue_label, 0); - if (ln >= 0) assemble_label_no(ln2); + { + /* If labelexists is false, then we started with + "if (1)". In this case, we don't want a "not + reached" warning on the "else" block. We + temporarily disable the NOWARN flag, and restore it + afterwards. */ + int saved_unreach = 0; + if (execution_never_reaches_here && !labelexists) { + saved_unreach = execution_never_reaches_here; + execution_never_reaches_here |= EXECSTATE_NOWARN; + } + + /* The "else" block */ + parse_code_block(break_label, continue_label, 0); + + if (execution_never_reaches_here && !labelexists) { + if (saved_unreach & EXECSTATE_NOWARN) + execution_never_reaches_here |= EXECSTATE_NOWARN; + else + execution_never_reaches_here &= ~EXECSTATE_NOWARN; + } + + /* The post-"else" label */ + if (ln >= 0) assemble_forward_label_no(ln2); + } + else + { + /* There was no "else". If we're unreachable, then the + statement returned unconditionally, which means + "if (1) return". Skip warnings. */ + if (!pre_unreach && execution_never_reaches_here) { + execution_never_reaches_here |= EXECSTATE_NOWARN; + } } return; @@ -2291,6 +2349,8 @@ static void parse_statement_g(int break_label, int continue_label) AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); AO = code_generate(AO, QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"move\" statement"); + check_warn_symbol_type(&AO2, OBJECT_T, CLASS_T, "\"move\" statement"); if ((runtime_error_checking_switch) && (veneer_mode == FALSE)) assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2, zero_operand); @@ -2320,8 +2380,8 @@ static void parse_statement_g(int break_label, int continue_label) INITAOTV(&AO, LOCALVAR_OT, token_value); } else if ((token_type == SYMBOL_TT) && - (stypes[token_value] == GLOBAL_VARIABLE_T)) { - INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]); + (symbols[token_value].type == GLOBAL_VARIABLE_T)) { + INITAOTV(&AO, GLOBALVAR_OT, symbols[token_value].value); } else { ebf_error("'objectloop' variable", token_text); @@ -2423,7 +2483,7 @@ static void parse_statement_g(int break_label, int continue_label) sequence_point_follows = TRUE; ln = symbol_index("Class", -1); INITAOT(&AO2, CONSTANT_OT); - AO2.value = svals[ln]; + AO2.value = symbols[ln].value; AO2.marker = OBJECT_MV; assembleg_store(AO, AO2); @@ -2473,6 +2533,7 @@ static void parse_statement_g(int break_label, int continue_label) case REMOVE_CODE: AO = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); + check_warn_symbol_type(&AO, OBJECT_T, 0, "\"remove\" statement"); if ((runtime_error_checking_switch) && (veneer_mode == FALSE)) assembleg_call_1(veneer_routine(RT__ChR_VR), AO, zero_operand); @@ -2543,8 +2604,9 @@ static void parse_statement_g(int break_label, int continue_label) AO2 = code_generate(parse_expression(QUANTITY_CONTEXT), QUANTITY_CONTEXT, -1); if (is_constant_ot(AO2.type) && AO2.marker == 0) { + /* Compile-time check */ if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) { - memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS); + error_max_dynamic_strings(AO2.value); } } get_next_token(); @@ -2629,7 +2691,7 @@ static void parse_statement_g(int break_label, int continue_label) assembleg_store(temp_var1, AO); parse_code_block(ln = next_label++, continue_label, 1); - assemble_label_no(ln); + assemble_forward_label_no(ln); return; /* -------------------------------------------------------------------- */ @@ -2647,7 +2709,7 @@ static void parse_statement_g(int break_label, int continue_label) parse_code_block(ln2, ln, 0); sequence_point_follows = FALSE; assembleg_jump(ln); - assemble_label_no(ln2); + assemble_forward_label_no(ln2); return; /* -------------------------------------------------------------------- */ @@ -2681,10 +2743,26 @@ static void parse_statement_g(int break_label, int continue_label) extern void parse_statement(int break_label, int continue_label) { - if (!glulx_mode) - parse_statement_z(break_label, continue_label); - else - parse_statement_g(break_label, continue_label); + int res; + int saved_entire_flag; + + res = parse_named_label_statements(); + if (!res) + return; + + saved_entire_flag = (execution_never_reaches_here & EXECSTATE_ENTIRE); + if (execution_never_reaches_here) + execution_never_reaches_here |= EXECSTATE_ENTIRE; + + if (!glulx_mode) + parse_statement_z(break_label, continue_label); + else + parse_statement_g(break_label, continue_label); + + if (saved_entire_flag) + execution_never_reaches_here |= EXECSTATE_ENTIRE; + else + execution_never_reaches_here &= ~EXECSTATE_ENTIRE; } /* ========================================================================= */