X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Fstates.c;h=56572acf7eeb6e396106d79c5b1512e91d771dac;hb=ee3b3a0cb830792c0569230872a0af20eab8bb7b;hp=8feb6a765148e61c1c0c4f8c9021a3994f7146e7;hpb=8760c1ba6442153afe76bcac742e086f90c59fe8;p=inform.git diff --git a/src/states.c b/src/states.c index 8feb6a7..56572ac 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 - 2020 */ +/* Part of Inform 6.41 */ +/* 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); @@ -308,7 +308,7 @@ static void parse_print_z(int finally_return) if (strlen(token_text) > 32) { INITAOT(&AO, LONG_CONSTANT_OT); AO.marker = STRING_MV; - AO.value = compile_string(token_text, FALSE, FALSE); + AO.value = compile_string(token_text, STRCTX_GAME); assemblez_1(print_paddr_zc, AO); if (finally_return) { get_next_token(); @@ -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: @@ -537,7 +539,7 @@ static void parse_print_g(int finally_return) so this always goes into the string area. */ { INITAOT(&AO, CONSTANT_OT); AO.marker = STRING_MV; - AO.value = compile_string(token_text, FALSE, FALSE); + AO.value = compile_string(token_text, STRCTX_GAME); assembleg_1(streamstr_gc, AO); if (finally_return) { get_next_token(); @@ -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; /* -------------------------------------------------------------------- */ @@ -974,6 +994,10 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); /* Initialisation code */ + AO.type = OMITTED_OT; + spare_debug_location1 = statement_debug_location; + AO2.type = OMITTED_OT; flag = 0; + spare_debug_location2 = statement_debug_location; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); @@ -993,10 +1017,9 @@ 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; } - AO.type = OMITTED_OT; goto ParseUpdate; } put_token_back(); @@ -1004,7 +1027,6 @@ static void parse_statement_z(int break_label, int continue_label) } get_next_token(); - AO.type = OMITTED_OT; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); spare_debug_location1 = get_token_location(); @@ -1014,7 +1036,6 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); ParseUpdate: - AO2.type = OMITTED_OT; flag = 0; if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP))) { put_token_back(); spare_debug_location2 = get_token_location(); @@ -1079,16 +1100,10 @@ static void parse_statement_z(int break_label, int continue_label) statement_debug_location = spare_debug_location2; if (flag > 0) { INITAOTV(&AO3, SHORT_CONSTANT_OT, flag); - if (module_switch - && (flag>=MAX_LOCAL_VARIABLES) && (flag=MAX_LOCAL_VARIABLES) - && (flag= 5) @@ -1158,8 +1171,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); @@ -1177,8 +1191,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(); @@ -1191,6 +1214,14 @@ static void parse_statement_z(int break_label, int continue_label) statements.enabled = TRUE; get_next_token(); + + /* An #if directive around the ELSE clause is legal. */ + while ((token_type == SEP_TT) && (token_value == HASH_SEP)) + { parse_directive(TRUE); + statements.enabled = TRUE; + get_next_token(); + } + if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE)) { flag = TRUE; if (ln >= 0) @@ -1203,13 +1234,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; /* -------------------------------------------------------------------- */ @@ -1262,6 +1326,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), @@ -1294,15 +1360,12 @@ 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; } - if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES) - && (AO.value < LOWEST_SYSTEM_VAR_NUMBER)) - AO.marker = VARIABLE_MV; misc_keywords.enabled = TRUE; get_next_token(); flag = TRUE; misc_keywords.enabled = FALSE; @@ -1481,6 +1544,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), @@ -1589,10 +1653,19 @@ static void parse_statement_z(int break_label, int continue_label) assemblez_2_to(loadw_zc, AO, AO2, AO3); 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 >= 96 || AO2.value >= MAX_DYNAMIC_STRINGS) { + error_max_dynamic_strings(AO2.value); + AO2.value = 0; + } + } get_next_token(); if (token_type == DQ_TT) { INITAOT(&AO4, LONG_CONSTANT_OT); - AO4.value = compile_string(token_text, TRUE, TRUE); + /* This string must be in low memory so that the + dynamic string table can refer to it. */ + AO4.value = compile_string(token_text, STRCTX_LOWSTRING); } else { put_token_back(); @@ -1653,7 +1726,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; /* -------------------------------------------------------------------- */ @@ -1671,7 +1744,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; /* -------------------------------------------------------------------- */ @@ -1696,57 +1769,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; @@ -1860,7 +1888,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(); @@ -1868,7 +1896,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; /* -------------------------------------------------------------------- */ @@ -1915,6 +1943,10 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); /* Initialisation code */ + AO.type = OMITTED_OT; + spare_debug_location1 = statement_debug_location; + AO2.type = OMITTED_OT; flag = 0; + spare_debug_location2 = statement_debug_location; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); @@ -1934,10 +1966,9 @@ 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; } - AO.type = OMITTED_OT; goto ParseUpdate; } put_token_back(); @@ -1945,7 +1976,6 @@ static void parse_statement_g(int break_label, int continue_label) } get_next_token(); - AO.type = OMITTED_OT; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); spare_debug_location1 = get_token_location(); @@ -1955,7 +1985,6 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); ParseUpdate: - AO2.type = OMITTED_OT; flag = 0; if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP))) { put_token_back(); spare_debug_location2 = get_token_location(); @@ -2050,7 +2079,7 @@ static void parse_statement_g(int break_label, int continue_label) } } - assemble_label_no(ln3); + assemble_forward_label_no(ln3); return; /* -------------------------------------------------------------------- */ @@ -2060,6 +2089,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 @@ -2077,15 +2107,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)) { @@ -2132,8 +2159,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); @@ -2151,8 +2179,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(); @@ -2165,6 +2202,14 @@ static void parse_statement_g(int break_label, int continue_label) statements.enabled = TRUE; get_next_token(); + + /* An #if directive around the ELSE clause is legal. */ + while ((token_type == SEP_TT) && (token_value == HASH_SEP)) + { parse_directive(TRUE); + statements.enabled = TRUE; + get_next_token(); + } + if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE)) { flag = TRUE; if (ln >= 0) @@ -2177,11 +2222,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; @@ -2262,6 +2340,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); @@ -2291,8 +2371,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); @@ -2394,7 +2474,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); @@ -2444,6 +2524,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); @@ -2513,10 +2594,19 @@ static void parse_statement_g(int break_label, int continue_label) case STRING_CODE: 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) { + error_max_dynamic_strings(AO2.value); + } + } get_next_token(); if (token_type == DQ_TT) { INITAOT(&AO4, CONSTANT_OT); - AO4.value = compile_string(token_text, TRUE, TRUE); + /* This is not actually placed in low memory; Glulx + has no such concept. We use the LOWSTRING flag + for compatibility with older compiler behavior. */ + AO4.value = compile_string(token_text, STRCTX_LOWSTRING); AO4.marker = STRING_MV; } else @@ -2592,7 +2682,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; /* -------------------------------------------------------------------- */ @@ -2610,7 +2700,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; /* -------------------------------------------------------------------- */ @@ -2644,10 +2734,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; } /* ========================================================================= */