X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Fdirects.c;h=d8374c367a6e8863eae86cb5d2f5e59826c877fc;hb=ee3b3a0cb830792c0569230872a0af20eab8bb7b;hp=5df6b0b666f6a4249a0a29966205ec4194f48523;hpb=c881aa3386c00d7021ffabf2f66275d6c110c1c1;p=inform.git diff --git a/src/directs.c b/src/directs.c index 5df6b0b..d8374c3 100644 --- a/src/directs.c +++ b/src/directs.c @@ -1,8 +1,8 @@ /* ------------------------------------------------------------------------- */ /* "directs" : Directives (# commands) */ /* */ -/* Part of Inform 6.35 */ -/* copyright (c) Graham Nelson 1993 - 2021 */ +/* 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 */ @@ -34,7 +34,8 @@ brief_location routine_starts_line; /* Source code location where the current static int constant_made_yet; /* Have any constants been defined yet? */ -static int ifdef_stack[32], ifdef_sp; +#define MAX_IFDEF_STACK (32) +static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp; /* ------------------------------------------------------------------------- */ @@ -107,21 +108,21 @@ extern int parse_given_directive(int internal_flag) return FALSE; if (!glulx_mode && no_abbreviations==96) - { error("All 96 Z-machine abbreviations already declared"); + { error_max_abbreviations(no_abbreviations); + panic_mode_error_recovery(); return FALSE; + } + if (!glulx_mode && no_abbreviations==MAX_ABBREVS) + { error_max_abbreviations(no_abbreviations); + /* This is no longer a memoryerror(); MAX_ABBREVS is an authoring decision for Z-code games. */ panic_mode_error_recovery(); return FALSE; } - if (no_abbreviations==MAX_ABBREVS) - memoryerror("MAX_ABBREVS", MAX_ABBREVS); if (abbrevs_lookup_table_made) { error("All abbreviations must be declared together"); panic_mode_error_recovery(); return FALSE; } if (token_type != DQ_TT) - return ebf_error_recover("abbreviation string", token_text); - if (strlen(token_text)<2) - { error_named("It's not worth abbreviating", token_text); - continue; + { return ebf_error_recover("abbreviation string", token_text); } /* Abbreviation string with null must fit in a MAX_ABBREV_LENGTH array. */ @@ -133,10 +134,10 @@ extern int parse_given_directive(int internal_flag) } while (TRUE); /* --------------------------------------------------------------------- */ - /* Array arrayname array... */ + /* Array [static] */ /* --------------------------------------------------------------------- */ - case ARRAY_CODE: make_global(TRUE, FALSE); break; /* See "tables.c" */ + case ARRAY_CODE: make_array(); break; /* See "arrays.c" */ /* --------------------------------------------------------------------- */ /* Attribute newname [alias oldname] */ @@ -169,9 +170,9 @@ extern int parse_given_directive(int internal_flag) return ebf_error_recover("new constant name", token_text); } - if (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))) + if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))) { discard_token_location(beginning_debug_location); - return ebf_symbol_error_recover("new constant name", token_text, typename(stypes[i]), slines[i]); + return ebf_symbol_error_recover("new constant name", token_text, typename(symbols[i].type), symbols[i].line); } assign_symbol(i, 0, CONSTANT_T); @@ -180,7 +181,7 @@ extern int parse_given_directive(int internal_flag) get_next_token(); if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) - { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG)) + { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG)) { debug_file_printf(""); debug_file_printf("%s", constant_name); write_debug_symbol_optional_backpatch(i); @@ -191,7 +192,7 @@ extern int parse_given_directive(int internal_flag) } if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) - { if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG)) + { if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG)) { debug_file_printf(""); debug_file_printf("%s", constant_name); write_debug_symbol_optional_backpatch(i); @@ -208,7 +209,7 @@ extern int parse_given_directive(int internal_flag) if (AO.marker != 0) { assign_marked_symbol(i, AO.marker, AO.value, CONSTANT_T); - sflags[i] |= CHANGE_SFLAG; + symbols[i].flags |= CHANGE_SFLAG; if (i == grammar_version_symbol) error( "Grammar__Version must be given an explicit constant value"); @@ -227,7 +228,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); } } - if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG)) + if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG)) { debug_file_printf(""); debug_file_printf("%s", constant_name); write_debug_symbol_optional_backpatch(i); @@ -247,19 +248,14 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); /* --------------------------------------------------------------------- */ case DEFAULT_CODE: - if (module_switch) - { error("'Default' cannot be used in -M (Module) mode"); - panic_mode_error_recovery(); return FALSE; - } - get_next_token(); if (token_type != SYMBOL_TT) return ebf_error_recover("name", token_text); i = -1; - if (sflags[token_value] & UNKNOWN_SFLAG) + if (symbols[token_value].flags & UNKNOWN_SFLAG) { i = token_value; - sflags[i] |= DEFCON_SFLAG; + symbols[i].flags |= DEFCON_SFLAG; } get_next_token(); @@ -272,7 +268,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); { if (AO.marker != 0) { assign_marked_symbol(i, AO.marker, AO.value, CONSTANT_T); - sflags[i] |= CHANGE_SFLAG; + symbols[i].flags |= CHANGE_SFLAG; } else assign_symbol(i, AO.value, CONSTANT_T); } @@ -315,7 +311,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); assembly_operand AO; put_token_back(); AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as a Dictionary flag"); else val1 = AO.value; @@ -327,8 +323,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); else { assembly_operand AO; put_token_back(); + if (ZCODE_LESS_DICT_DATA && !glulx_mode) + warning("The third dictionary field will be ignored because ZCODE_LESS_DICT_DATA is set"); AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as a Dictionary flag"); else val3 = AO.value; @@ -375,10 +373,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); make_fake_action(); break; /* see "verbs.c" */ /* --------------------------------------------------------------------- */ - /* Global variable [= value / array...] */ + /* Global [ [=] ] */ /* --------------------------------------------------------------------- */ - case GLOBAL_CODE: make_global(FALSE, FALSE); break; /* See "tables.c" */ + case GLOBAL_CODE: make_global(); break; /* See "arrays.c" */ /* --------------------------------------------------------------------- */ /* If... */ @@ -404,17 +402,28 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (token_type != SYMBOL_TT) return ebf_error_recover("symbol name", token_text); + /* Special case: a symbol of the form "VN_nnnn" is considered + defined if the compiler version number is at least nnnn. + Compiler version numbers look like "1640" for Inform 6.40; + see RELEASE_NUMBER. + ("VN_nnnn" isn't a real symbol and can't be used in other + contexts.) */ if ((token_text[0] == 'V') && (token_text[1] == 'N') && (token_text[2] == '_') && (strlen(token_text)==7)) - { i = atoi(token_text+3); - if (VNUMBER < i) flag = (flag)?FALSE:TRUE; - goto HashIfCondition; + { + char *endstr; + i = strtol(token_text+3, &endstr, 10); + if (*endstr == '\0') { + /* All characters after the underscore were digits */ + if (VNUMBER < i) flag = (flag)?FALSE:TRUE; + goto HashIfCondition; + } } - if (sflags[token_value] & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE; - else sflags[token_value] |= USED_SFLAG; + if (symbols[token_value].flags & UNKNOWN_SFLAG) flag = (flag)?FALSE:TRUE; + else symbols[token_value].flags |= USED_SFLAG; goto HashIfCondition; case IFNOT_CODE: @@ -427,14 +436,17 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); { dont_enter_into_symbol_table = -2; n = 1; directives.enabled = TRUE; do - { get_next_token(); + { + release_token_texts(); + get_next_token(); if (token_type == EOF_TT) { error("End of file reached in code 'If...'d out"); directives.enabled = FALSE; return TRUE; } if (token_type == DIRECTIVE_TT) - { switch(token_value) + { + switch(token_value) { case ENDIF_CODE: n--; break; case IFV3_CODE: @@ -472,7 +484,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case IFTRUE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) { error("This condition can't be determined"); flag = 0; } @@ -483,7 +495,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case IFFALSE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) { error("This condition can't be determined"); flag = 1; } @@ -496,13 +508,20 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) return ebf_error_recover("semicolon after 'If...' condition", token_text); + if (ifdef_sp >= MAX_IFDEF_STACK) { + error("'If' directives nested too deeply"); + panic_mode_error_recovery(); return FALSE; + } + if (flag) { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; } else { dont_enter_into_symbol_table = -2; n = 1; directives.enabled = TRUE; do - { get_next_token(); + { + release_token_texts(); + get_next_token(); if (token_type == EOF_TT) { error("End of file reached in code 'If...'d out"); directives.enabled = FALSE; @@ -535,26 +554,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); /* --------------------------------------------------------------------- */ /* Import global [, ...] */ - /* */ - /* (Further imported goods may be allowed later.) */ /* --------------------------------------------------------------------- */ case IMPORT_CODE: - if (!module_switch) - { error("'Import' can only be used in -M (Module) mode"); - panic_mode_error_recovery(); return FALSE; - } - directives.enabled = TRUE; - do - { get_next_token(); - if ((token_type == DIRECTIVE_TT) && (token_value == GLOBAL_CODE)) - make_global(FALSE, TRUE); - else error_named("'Import' cannot import things of this type:", - token_text); - get_next_token(); - } while ((token_type == SEP_TT) && (token_value == COMMA_SEP)); - put_token_back(); - directives.enabled = FALSE; + error("The 'Import' directive is no longer supported."); break; /* --------------------------------------------------------------------- */ @@ -589,9 +592,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case LINK_CODE: get_next_token(); - if (token_type != DQ_TT) - return ebf_error_recover("filename in double-quotes", token_text); - link_module(token_text); /* See "linker.c" */ + error("The 'Link' directive is no longer supported."); break; /* --------------------------------------------------------------------- */ @@ -603,10 +604,6 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); /* --------------------------------------------------------------------- */ case LOWSTRING_CODE: - if (module_switch) - { error("'LowString' cannot be used in -M (Module) mode"); - panic_mode_error_recovery(); return FALSE; - } if (glulx_mode) { error("The LowString directive has no meaning in Glulx."); panic_mode_error_recovery(); return FALSE; @@ -614,14 +611,14 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); get_next_token(); i = token_value; if (token_type != SYMBOL_TT) return ebf_error_recover("new low string name", token_text); - if (!(sflags[i] & UNKNOWN_SFLAG)) - return ebf_symbol_error_recover("new low string name", token_text, typename(stypes[i]), slines[i]); + if (!(symbols[i].flags & UNKNOWN_SFLAG)) + return ebf_symbol_error_recover("new low string name", token_text, typename(symbols[i].type), symbols[i].line); get_next_token(); if (token_type != DQ_TT) return ebf_error_recover("literal string in double-quotes", token_text); - assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T); + assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T); break; /* --------------------------------------------------------------------- */ @@ -755,7 +752,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); break; /* --------------------------------------------------------------------- */ - /* Property [long] [additive] name [alias oldname] */ + /* Property [long] [additive] name */ + /* Property [long] [additive] name alias oldname */ + /* Property [long] [additive] name defaultvalue */ + /* Property [long] individual name */ /* --------------------------------------------------------------------- */ case PROPERTY_CODE: make_property(); break; /* See "objects.c" */ @@ -767,7 +767,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case RELEASE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as release number"); else release_number = AO.value; @@ -806,10 +806,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (token_type != SYMBOL_TT) return ebf_error_recover("name of routine to replace", token_text); - if (!(sflags[token_value] & UNKNOWN_SFLAG)) + if (!(symbols[token_value].flags & UNKNOWN_SFLAG)) return ebf_error_recover("name of routine not yet defined", token_text); - sflags[token_value] |= REPLACE_SFLAG; + symbols[token_value].flags |= REPLACE_SFLAG; /* If a second symbol is provided, it will refer to the original (replaced) definition of the routine. */ @@ -823,7 +823,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); { return FALSE; } - if (token_type != SYMBOL_TT || !(sflags[token_value] & UNKNOWN_SFLAG)) + if (token_type != SYMBOL_TT || !(symbols[token_value].flags & UNKNOWN_SFLAG)) return ebf_error_recover("semicolon ';' or new routine name", token_text); /* Define the original-form symbol as a zero constant. Its @@ -857,9 +857,6 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); /* --------------------------------------------------------------------- */ case STATUSLINE_CODE: - if (module_switch) - warning("This does not set the final game's statusline"); - directive_keywords.enabled = TRUE; get_next_token(); directive_keywords.enabled = FALSE; @@ -885,8 +882,8 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); i = token_value; flag = FALSE; - if (sflags[i] & UNKNOWN_SFLAG) - { sflags[i] |= STUB_SFLAG; + if (symbols[i].flags & UNKNOWN_SFLAG) + { symbols[i].flags |= STUB_SFLAG; flag = TRUE; } @@ -902,15 +899,17 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); { /* Give these parameter-receiving local variables names for the benefit of the debugging information file, - and for assembly tracing to look sensible. */ + and for assembly tracing to look sensible. + (We don't set local_variable.keywords because we're not + going to be parsing any code.) */ - local_variable_texts[0] = "dummy1"; - local_variable_texts[1] = "dummy2"; - local_variable_texts[2] = "dummy3"; - local_variable_texts[3] = "dummy4"; + strcpy(local_variable_names[0].text, "dummy1"); + strcpy(local_variable_names[1].text, "dummy2"); + strcpy(local_variable_names[2].text, "dummy3"); + strcpy(local_variable_names[3].text, "dummy4"); assign_symbol(i, - assemble_routine_header(k, FALSE, (char *) symbs[i], FALSE, i), + assemble_routine_header(k, FALSE, symbols[i].name, FALSE, i), ROUTINE_T); /* Ensure the return value of a stubbed routine is false, @@ -923,7 +922,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); /* Inhibit "local variable unused" warnings */ - for (i=1; i<=k; i++) variable_usage[i] = 1; + for (i=1; i<=k; i++) variables[i].usage = 1; sequence_point_follows = FALSE; assemble_routine_end(FALSE, get_token_locations()); } @@ -941,9 +940,18 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (token_type != DQ_TT) return ebf_error_recover("string of switches", token_text); if (!ignore_switches_switch) - { if (constant_made_yet) - error("A 'Switches' directive must must come before \ -the first constant definition"); + { + if (constant_made_yet) { + error("A 'Switches' directive must must come before the first constant definition"); + break; + } + if (no_routines > 1) + { + /* The built-in Main__ routine is number zero. */ + error("A 'Switches' directive must come before the first routine definition."); + break; + } + obsolete_warning("the Switches directive is deprecated and may produce incorrect results. Use command-line arguments or header comments."); switches(token_text, 0); /* see "inform.c" */ } break; @@ -960,14 +968,19 @@ the first constant definition"); declare_systemfile(); break; /* see "files.c" */ /* --------------------------------------------------------------------- */ - /* Trace dictionary */ - /* objects */ - /* symbols */ - /* verbs */ - /* [on/off] */ - /* assembly [on/off] */ - /* expressions [on/off] */ - /* lines [on/off] */ + /* Trace dictionary [on/NUM] */ + /* objects [on/NUM] */ + /* symbols [on/NUM] */ + /* verbs [on/NUM] */ + /* [on/off/NUM] {same as "assembly"} */ + /* assembly [on/off/NUM] */ + /* expressions [on/off/NUM] */ + /* lines [on/off/NUM] {not supported} */ + /* tokens [on/off/NUM] */ + /* linker [on/off/NUM] {not supported} */ + /* */ + /* The first four trace commands immediately display a compiler table. */ + /* The rest set or clear an ongoing trace. */ /* --------------------------------------------------------------------- */ case TRACE_CODE: @@ -976,62 +989,108 @@ the first constant definition"); get_next_token(); trace_keywords.enabled = FALSE; directives.enabled = TRUE; - if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) - { asm_trace_level = 1; return FALSE; } + + if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) { + /* "Trace;" */ + put_token_back(); + i = ASSEMBLY_TK; + trace_level = &asm_trace_level; + j = 1; + goto HandleTraceKeyword; + } + if (token_type == NUMBER_TT) { + /* "Trace NUM;" */ + i = ASSEMBLY_TK; + trace_level = &asm_trace_level; + j = token_value; + goto HandleTraceKeyword; + } + /* Anything else must be "Trace KEYWORD..." Remember that + 'on' and 'off' are trace keywords. */ + if (token_type != TRACE_KEYWORD_TT) return ebf_error_recover("debugging keyword", token_text); trace_keywords.enabled = TRUE; - i = token_value; j = 0; + /* Note that "Trace verbs" doesn't affect list_verbs_setting. + It shows the grammar at this point in the code. Setting + list_verbs_setting shows the grammar at the end of + compilation. + Same goes for "Trace dictionary" and list_dict_setting, etc. */ + + i = token_value; + switch(i) - { case DICTIONARY_TK: break; - case OBJECTS_TK: break; - case VERBS_TK: break; - default: - switch(token_value) - { case ASSEMBLY_TK: - trace_level = &asm_trace_level; break; - case EXPRESSIONS_TK: - trace_level = &expr_trace_level; break; - case LINES_TK: - trace_level = &line_trace_level; break; - case TOKENS_TK: - trace_level = &tokens_trace_level; break; - case LINKER_TK: - trace_level = &linker_trace_level; break; - case SYMBOLS_TK: - trace_level = NULL; break; - default: - put_token_back(); - trace_level = &asm_trace_level; break; - } - j = 1; - get_next_token(); - if ((token_type == SEP_TT) && - (token_value == SEMICOLON_SEP)) - { put_token_back(); break; - } - if (token_type == NUMBER_TT) - { j = token_value; break; } - if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK)) - { j = 1; break; } - if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK)) - { j = 0; break; } - put_token_back(); break; + { + case ASSEMBLY_TK: + trace_level = &asm_trace_level; break; + case EXPRESSIONS_TK: + trace_level = &expr_trace_level; break; + case TOKENS_TK: + trace_level = &tokens_trace_level; break; + case DICTIONARY_TK: + case SYMBOLS_TK: + case OBJECTS_TK: + case VERBS_TK: + /* show a table rather than changing any trace level */ + trace_level = NULL; break; + case LINES_TK: + /* never implememented */ + trace_level = NULL; break; + case LINKER_TK: + /* no longer implememented */ + trace_level = NULL; break; + default: + /* default to "Trace assembly" */ + put_token_back(); + trace_level = &asm_trace_level; break; + } + + j = 1; + get_next_token(); + if ((token_type == SEP_TT) && + (token_value == SEMICOLON_SEP)) + { put_token_back(); + } + else if (token_type == NUMBER_TT) + { j = token_value; + } + else if ((token_type == TRACE_KEYWORD_TT) && (token_value == ON_TK)) + { j = 1; + } + else if ((token_type == TRACE_KEYWORD_TT) && (token_value == OFF_TK)) + { j = 0; + } + else + { put_token_back(); } + trace_keywords.enabled = FALSE; + + HandleTraceKeyword: + + if (i == LINES_TK || i == LINKER_TK) { + warning_named("Trace option is not supported:", trace_keywords.keywords[i]); + break; + } + + if (trace_level == NULL && j == 0) { + warning_named("Trace directive to display table at 'off' level has no effect: table", trace_keywords.keywords[i]); + break; + } + switch(i) - { case DICTIONARY_TK: show_dictionary(); break; - case OBJECTS_TK: list_object_tree(); break; + { case DICTIONARY_TK: show_dictionary(j); break; + case OBJECTS_TK: list_object_tree(); break; case SYMBOLS_TK: list_symbols(j); break; - case VERBS_TK: list_verb_table(); break; + case VERBS_TK: list_verb_table(); break; default: - *trace_level = j; + if (trace_level) + *trace_level = j; break; } - trace_keywords.enabled = FALSE; break; /* --------------------------------------------------------------------- */ @@ -1043,12 +1102,12 @@ the first constant definition"); if (token_type != SYMBOL_TT) return ebf_error_recover("symbol name", token_text); - if (sflags[token_value] & UNKNOWN_SFLAG) + if (symbols[token_value].flags & UNKNOWN_SFLAG) { break; /* undef'ing an undefined constant is okay */ } - if (stypes[token_value] != CONSTANT_T) - { error_named("Cannot Undef a symbol which is not a defined constant:", (char *)symbs[token_value]); + if (symbols[token_value].type != CONSTANT_T) + { error_named("Cannot Undef a symbol which is not a defined constant:", symbols[token_value].name); break; } @@ -1056,7 +1115,7 @@ the first constant definition"); { write_debug_undef(token_value); } end_symbol_scope(token_value); - sflags[token_value] |= USED_SFLAG; + symbols[token_value].flags |= USED_SFLAG; break; /* --------------------------------------------------------------------- */ @@ -1081,22 +1140,48 @@ the first constant definition"); break; } - if (module_switch && (AO.marker != 0)) - error("A definite value must be given as version number"); - else - if (glulx_mode) + if (AO.marker != 0) + { + error("A definite value must be given as version number."); + break; + } + else if (no_routines > 1) + { + /* The built-in Main__ routine is number zero. */ + error("A 'Version' directive must come before the first routine definition."); + break; + } + else if (glulx_mode) { warning("The Version directive does not work in Glulx. Use \ -vX.Y.Z instead, as either a command-line argument or a header comment."); break; } else - { i = AO.value; + { + int debtok; + i = AO.value; if ((i<3) || (i>8)) { error("The version number must be in the range 3 to 8"); break; } + obsolete_warning("the Version directive is deprecated and may produce incorrect results. Use -vN instead, as either a command-line argument or a header comment."); select_version(i); + /* We must now do a small dance to reset the DICT_ENTRY_BYTES + constant, which was defined at startup based on the Z-code + version. + The calculation here is repeated from select_target(). */ + DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0); + debtok = symbol_index("DICT_ENTRY_BYTES", -1); + if (!(symbols[debtok].flags & UNKNOWN_SFLAG)) + { + if (!(symbols[debtok].flags & REDEFINABLE_SFLAG)) + { + warning("The DICT_ENTRY_BYTES symbol is not marked redefinable"); + } + /* Redefine the symbol... */ + assign_symbol(debtok, DICT_ENTRY_BYTE_LENGTH, CONSTANT_T); + } } } break; /* see "inform.c" */