X-Git-Url: https://jxself.org/git/?p=inform.git;a=blobdiff_plain;f=src%2Fdirects.c;fp=src%2Fdirects.c;h=388ac861bcae9ba46f13fbc033ab4a5b4824f03a;hp=15831728118b840102d401f7f67b7619c996a21e;hb=8e63120c630c94c598d4e2d6ba823dac59bce8fa;hpb=d11f2f726ed7feea617476d99cf7505ddd9a27ce diff --git a/src/directs.c b/src/directs.c index 1583172..388ac86 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.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 */ @@ -108,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. */ @@ -170,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); @@ -181,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); @@ -192,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); @@ -209,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"); @@ -228,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); @@ -258,9 +258,9 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); 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(); @@ -273,7 +273,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); } @@ -328,6 +328,8 @@ 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 (AO.marker != 0) error("A definite value must be given as a Dictionary flag"); @@ -405,17 +407,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: @@ -428,14 +441,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: @@ -508,7 +524,9 @@ 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; @@ -597,6 +615,10 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); get_next_token(); if (token_type != DQ_TT) return ebf_error_recover("filename in double-quotes", token_text); + if (strlen(token_text) >= PATHLEN-1) { + error_numbered("'Link' filename is too long; max length is", PATHLEN-1); + break; + } link_module(token_text); /* See "linker.c" */ break; @@ -620,8 +642,8 @@ 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) @@ -761,7 +783,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" */ @@ -812,10 +837,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. */ @@ -829,7 +854,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 @@ -891,8 +916,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; } @@ -908,15 +933,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, @@ -929,7 +956,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()); } @@ -966,14 +993,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] */ + /* tokens [on/off/NUM] */ + /* linker [on/off/NUM] */ + /* */ + /* The first four trace commands immediately display a compiler table. */ + /* The rest set or clear an ongoing trace. */ /* --------------------------------------------------------------------- */ case TRACE_CODE: @@ -982,62 +1014,105 @@ 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 LINKER_TK: + trace_level = &linker_trace_level; break; + case DICTIONARY_TK: + case SYMBOLS_TK: + case OBJECTS_TK: + case VERBS_TK: + trace_level = NULL; break; + case LINES_TK: + /* never implememented */ + 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(); + } + 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) { + 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; /* --------------------------------------------------------------------- */ @@ -1049,12 +1124,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; } @@ -1062,7 +1137,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; /* --------------------------------------------------------------------- */ @@ -1088,21 +1163,46 @@ the first constant definition"); } if (AO.marker != 0) - error("A definite value must be given as version number"); - else - if (glulx_mode) + { + 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; } 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" */