X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=src%2Finform.c;h=25da037e5b535b985a188d2365fa44e5509815d8;hb=HEAD;hp=b3396a3662c9097ca2057ad79463646dcb8c34eb;hpb=46cb3ffad9e3ed318a9109ff96421882f6642b2b;p=inform.git diff --git a/src/inform.c b/src/inform.c index b3396a3..25da037 100644 --- a/src/inform.c +++ b/src/inform.c @@ -2,9 +2,8 @@ /* "inform" : The top level of Inform: switches, pathnames, filenaming */ /* conventions, ICL (Inform Command Line) files, main */ /* */ -/* Copyright (c) Graham Nelson 1993 - 2020 */ -/* */ -/* This file is part of Inform. */ +/* Part of Inform 6.42 */ +/* copyright (c) Graham Nelson 1993 - 2024 */ /* */ /* Inform is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -48,7 +47,9 @@ int version_number, /* 3 to 8 (Z-code) */ int32 scale_factor, /* packed address multiplier */ length_scale_factor; /* length-in-header multiplier */ -int32 requested_glulx_version; +int32 requested_glulx_version; /* version requested via -v switch */ +int32 final_glulx_version; /* requested version combined with game + feature requirements */ extern void select_version(int vn) { version_number = vn; @@ -124,6 +125,8 @@ static void select_target(int targ) WORDSIZE = 2; MAXINTWORD = 0x7FFF; + MAX_LOCAL_VARIABLES = 16; /* including "sp" */ + if (INDIV_PROP_START != 64) { INDIV_PROP_START = 64; fatalerror("You cannot change INDIV_PROP_START in Z-code"); @@ -140,18 +143,6 @@ static void select_target(int targ) NUM_ATTR_BYTES = 6; fatalerror("You cannot change NUM_ATTR_BYTES in Z-code"); } - if (MAX_LOCAL_VARIABLES != 16) { - MAX_LOCAL_VARIABLES = 16; - fatalerror("You cannot change MAX_LOCAL_VARIABLES in Z-code"); - } - if (MAX_GLOBAL_VARIABLES != 240) { - MAX_GLOBAL_VARIABLES = 240; - fatalerror("You cannot change MAX_GLOBAL_VARIABLES in Z-code"); - } - if (MAX_VERBS > 255) { - MAX_VERBS = 255; - fatalerror("MAX_VERBS can only go above 255 when Glulx is used"); - } } else { /* Glulx */ @@ -159,39 +150,35 @@ static void select_target(int targ) MAXINTWORD = 0x7FFFFFFF; scale_factor = 0; /* It should never even get used in Glulx */ + /* This could really be 120, since the practical limit is the size + of local_variables.keywords. But historically it's been 119. */ + MAX_LOCAL_VARIABLES = 119; /* including "sp" */ + if (INDIV_PROP_START < 256) { INDIV_PROP_START = 256; - warning_numbered("INDIV_PROP_START should be at least 256 in Glulx. Setting to", INDIV_PROP_START); + warning_fmt("INDIV_PROP_START should be at least 256 in Glulx; setting to %d", INDIV_PROP_START); } if (NUM_ATTR_BYTES % 4 != 3) { NUM_ATTR_BYTES += (3 - (NUM_ATTR_BYTES % 4)); - warning_numbered("NUM_ATTR_BYTES must be a multiple of four, plus three. Increasing to", NUM_ATTR_BYTES); + warning_fmt("NUM_ATTR_BYTES must be a multiple of four, plus three; increasing to %d", NUM_ATTR_BYTES); } if (DICT_CHAR_SIZE != 1 && DICT_CHAR_SIZE != 4) { DICT_CHAR_SIZE = 4; - warning_numbered("DICT_CHAR_SIZE must be either 1 or 4. Setting to", DICT_CHAR_SIZE); + warning_fmt("DICT_CHAR_SIZE must be either 1 or 4; setting to %d", DICT_CHAR_SIZE); } } - if (MAX_LOCAL_VARIABLES >= 120) { - MAX_LOCAL_VARIABLES = 119; - warning("MAX_LOCAL_VARIABLES cannot exceed 119; resetting to 119"); - /* This is because the keyword table in the lexer only has 120 - entries. */ - } - if (DICT_WORD_SIZE > MAX_DICT_WORD_SIZE) { - DICT_WORD_SIZE = MAX_DICT_WORD_SIZE; - warning_numbered( - "DICT_WORD_SIZE cannot exceed MAX_DICT_WORD_SIZE; resetting", - MAX_DICT_WORD_SIZE); - /* MAX_DICT_WORD_SIZE can be increased in header.h without fear. */ + if (MAX_LOCAL_VARIABLES > MAX_KEYWORD_GROUP_SIZE) { + compiler_error("MAX_LOCAL_VARIABLES cannot exceed MAX_KEYWORD_GROUP_SIZE"); + MAX_LOCAL_VARIABLES = MAX_KEYWORD_GROUP_SIZE; } + if (NUM_ATTR_BYTES > MAX_NUM_ATTR_BYTES) { NUM_ATTR_BYTES = MAX_NUM_ATTR_BYTES; - warning_numbered( - "NUM_ATTR_BYTES cannot exceed MAX_NUM_ATTR_BYTES; resetting", + warning_fmt( + "NUM_ATTR_BYTES cannot exceed MAX_NUM_ATTR_BYTES; resetting to %d", MAX_NUM_ATTR_BYTES); /* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */ } @@ -201,10 +188,8 @@ static void select_target(int targ) if (!targ) { /* Z-machine */ DICT_WORD_BYTES = DICT_WORD_SIZE; - /* The Z-code generator doesn't use the following variables, although - it would be a little cleaner if it did. */ OBJECT_BYTE_LENGTH = 0; - DICT_ENTRY_BYTE_LENGTH = (version_number==3)?7:9; + DICT_ENTRY_BYTE_LENGTH = ((version_number==3)?7:9) - (ZCODE_LESS_DICT_DATA?1:0); DICT_ENTRY_FLAG_POS = 0; } else { @@ -220,49 +205,65 @@ static void select_target(int targ) DICT_ENTRY_FLAG_POS = (4+DICT_WORD_BYTES); } } + + if (!targ) { + /* Z-machine */ + /* The Z-machine's 96 abbreviations are used for these two purposes. + Make sure they are set consistently. If exactly one has been + set non-default, set the other to match. */ + if (MAX_DYNAMIC_STRINGS == 32 && MAX_ABBREVS != 64) { + MAX_DYNAMIC_STRINGS = 96 - MAX_ABBREVS; + } + if (MAX_ABBREVS == 64 && MAX_DYNAMIC_STRINGS != 32) { + MAX_ABBREVS = 96 - MAX_DYNAMIC_STRINGS; + } + if (MAX_ABBREVS + MAX_DYNAMIC_STRINGS != 96 + || MAX_ABBREVS < 0 + || MAX_DYNAMIC_STRINGS < 0) { + warning("MAX_ABBREVS plus MAX_DYNAMIC_STRINGS must be 96 in Z-code; resetting both"); + MAX_DYNAMIC_STRINGS = 32; + MAX_ABBREVS = 64; + } + } } /* ------------------------------------------------------------------------- */ /* Tracery: output control variables */ +/* (These are initially set to foo_trace_setting, but the Trace directive */ +/* can change them on the fly) */ /* ------------------------------------------------------------------------- */ int asm_trace_level, /* trace assembly: 0 for off, 1 for assembly - only, 2 for full assembly tracing with hex dumps */ - line_trace_level, /* line tracing: 0 off, 1 on */ - expr_trace_level, /* expression tracing: 0 off, 1 full, 2 brief */ - linker_trace_level, /* set by -y: 0 to 4 levels of tracing */ - tokens_trace_level; /* lexer output tracing: 0 off, 1 on */ + only, 2 for full assembly tracing with hex dumps, + 3 for branch shortening info, 4 for verbose + branch info */ + expr_trace_level, /* expression tracing: 0 off, 1 on, 2/3 more */ + tokens_trace_level; /* lexer output tracing: 0 off, 1 on, 2/3 more */ /* ------------------------------------------------------------------------- */ /* On/off switch variables (by default all FALSE); other switch settings */ +/* (Some of these have become numerical settings now) */ /* ------------------------------------------------------------------------- */ -int bothpasses_switch, /* -b */ - concise_switch, /* -c */ +int concise_switch, /* -c */ economy_switch, /* -e */ - frequencies_switch, /* -f */ + frequencies_setting, /* $!FREQ, -f */ ignore_switches_switch, /* -i */ - listobjects_switch, /* -j */ debugfile_switch, /* -k */ - listing_switch, /* -l */ - memout_switch, /* -m */ - printprops_switch, /* -n */ - offsets_switch, /* -o */ - percentages_switch, /* -p */ + memout_switch, /* $!MEM */ + printprops_switch, /* $!PROPS */ + printactions_switch, /* $!ACTIONS */ obsolete_switch, /* -q */ transcript_switch, /* -r */ - statistics_switch, /* -s */ + statistics_switch, /* $!STATS, -s */ optimise_switch, /* -u */ version_set_switch, /* -v */ nowarnings_switch, /* -w */ hash_switch, /* -x */ - memory_map_switch, /* -z */ + memory_map_setting, /* $!MAP, -z */ oddeven_packing_switch, /* -B */ define_DEBUG_switch, /* -D */ - temporary_files_switch, /* -F */ - module_switch, /* -M */ runtime_error_checking_switch, /* -S */ - define_USE_MODULES_switch, /* -U */ define_INFIX_switch; /* -X */ #ifdef ARC_THROWBACK int throwback_switch; /* -T */ @@ -274,55 +275,63 @@ int compression_switch; /* set by -H */ int character_set_setting, /* set by -C0 through -C9 */ character_set_unicode, /* set by -Cu */ error_format, /* set by -E */ - asm_trace_setting, /* set by -a and -t: value of - asm_trace_level to use when tracing */ + asm_trace_setting, /* $!ASM, -a: initial value of + asm_trace_level */ + bpatch_trace_setting, /* $!BPATCH */ + symdef_trace_setting, /* $!SYMDEF */ + expr_trace_setting, /* $!EXPR: initial value of + expr_trace_level */ + tokens_trace_setting, /* $!TOKENS: initial value of + tokens_trace_level */ + optabbrevs_trace_setting, /* $!FINDABBREVS */ double_space_setting, /* set by -d: 0, 1 or 2 */ - trace_fns_setting, /* set by -g: 0, 1 or 2 */ - linker_trace_setting, /* set by -y: ditto for linker_... */ + trace_fns_setting, /* $!RUNTIME, -g: 0, 1, 2, or 3 */ + files_trace_setting, /* $!FILES */ + list_verbs_setting, /* $!VERBS */ + list_dict_setting, /* $!DICT */ + list_objects_setting, /* $!OBJECTS */ + list_symbols_setting, /* $!SYMBOLS */ store_the_text; /* when set, record game text to a chunk - of memory (used by both -r & -k) */ + of memory (used by -u) */ static int r_e_c_s_set; /* has -S been explicitly set? */ int glulx_mode; /* -G */ static void reset_switch_settings(void) -{ asm_trace_setting=0; - linker_trace_level=0; - tokens_trace_level=0; +{ asm_trace_setting = 0; + tokens_trace_setting = 0; + expr_trace_setting = 0; + bpatch_trace_setting = 0; + symdef_trace_setting = 0; + list_verbs_setting = 0; + list_dict_setting = 0; + list_objects_setting = 0; + list_symbols_setting = 0; store_the_text = FALSE; - bothpasses_switch = FALSE; concise_switch = FALSE; double_space_setting = 0; economy_switch = FALSE; - frequencies_switch = FALSE; + files_trace_setting = 0; + frequencies_setting = 0; trace_fns_setting = 0; ignore_switches_switch = FALSE; - listobjects_switch = FALSE; debugfile_switch = FALSE; - listing_switch = FALSE; - memout_switch = FALSE; - printprops_switch = FALSE; - offsets_switch = FALSE; - percentages_switch = FALSE; + memout_switch = 0; + printprops_switch = 0; + printactions_switch = 0; obsolete_switch = FALSE; transcript_switch = FALSE; statistics_switch = FALSE; optimise_switch = FALSE; + optabbrevs_trace_setting = 0; version_set_switch = FALSE; nowarnings_switch = FALSE; hash_switch = FALSE; - memory_map_switch = FALSE; + memory_map_setting = 0; oddeven_packing_switch = FALSE; define_DEBUG_switch = FALSE; -#ifdef USE_TEMPORARY_FILES - temporary_files_switch = TRUE; -#else - temporary_files_switch = FALSE; -#endif - define_USE_MODULES_switch = FALSE; - module_switch = FALSE; #ifdef ARC_THROWBACK throwback_switch = FALSE; #endif @@ -340,6 +349,12 @@ static void reset_switch_settings(void) compression_switch = TRUE; glulx_mode = FALSE; requested_glulx_version = 0; + final_glulx_version = 0; + + /* These aren't switches, but for clarity we reset them too. */ + asm_trace_level = 0; + expr_trace_level = 0; + tokens_trace_level = 0; } /* ------------------------------------------------------------------------- */ @@ -370,7 +385,6 @@ static void init_vars(void) init_expressp_vars(); init_files_vars(); init_lexer_vars(); - init_linker_vars(); init_memory_vars(); init_objects_vars(); init_states_vars(); @@ -395,13 +409,11 @@ static void begin_pass(void) files_begin_pass(); endofpass_flag = FALSE; - line_trace_level = 0; expr_trace_level = 0; + expr_trace_level = expr_trace_setting; asm_trace_level = asm_trace_setting; - linker_trace_level = linker_trace_setting; - if (listing_switch) line_trace_level=1; + tokens_trace_level = tokens_trace_setting; lexer_begin_pass(); - linker_begin_pass(); memory_begin_pass(); objects_begin_pass(); states_begin_pass(); @@ -412,24 +424,21 @@ static void begin_pass(void) veneer_begin_pass(); verbs_begin_pass(); - if (!module_switch) - { - /* Compile a Main__ routine (see "veneer.c") */ - - compile_initial_routine(); - - /* Make the four metaclasses: Class must be object number 1, so - it must come first */ - - veneer_mode = TRUE; - - make_class("Class"); - make_class("Object"); - make_class("Routine"); - make_class("String"); - - veneer_mode = FALSE; - } + /* Compile a Main__ routine (see "veneer.c") */ + + compile_initial_routine(); + + /* Make the four metaclasses: Class must be object number 1, so + it must come first */ + + veneer_mode = TRUE; + + make_class("Class"); + make_class("Object"); + make_class("Routine"); + make_class("String"); + + veneer_mode = FALSE; } extern void allocate_arrays(void) @@ -445,7 +454,6 @@ extern void allocate_arrays(void) files_allocate_arrays(); lexer_allocate_arrays(); - linker_allocate_arrays(); memory_allocate_arrays(); objects_allocate_arrays(); states_allocate_arrays(); @@ -474,7 +482,6 @@ extern void free_arrays(void) files_free_arrays(); lexer_free_arrays(); - linker_free_arrays(); memory_free_arrays(); objects_free_arrays(); states_free_arrays(); @@ -493,8 +500,6 @@ extern void free_arrays(void) static char Source_Path[PATHLEN]; static char Include_Path[PATHLEN]; static char Code_Path[PATHLEN]; -static char Module_Path[PATHLEN]; -static char Temporary_Path[PATHLEN]; static char current_source_path[PATHLEN]; char Debugging_Name[PATHLEN]; char Transcript_Name[PATHLEN]; @@ -504,7 +509,7 @@ static char ICL_Path[PATHLEN]; /* Set one of the above Path buffers to the given location, or list of locations. (A list is comma-separated, and only accepted for Source_Path, - Include_Path, ICL_Path, Module_Path.) + Include_Path, ICL_Path.) */ static void set_path_value(char *path, char *value) { int i, j; @@ -519,10 +524,10 @@ static void set_path_value(char *path, char *value) if ((value[j] == FN_ALT) || (value[j] == 0)) { if ((value[j] == FN_ALT) && (path != Source_Path) && (path != Include_Path) - && (path != ICL_Path) && (path != Module_Path)) + && (path != ICL_Path)) { printf("The character '%c' is used to divide entries in a list \ -of possible locations, and can only be used in the Include_Path, Source_Path, \ -Module_Path or ICL_Path variables. Other paths are for output only.\n", FN_ALT); +of possible locations, and can only be used in the Include_Path, Source_Path \ +or ICL_Path variables. Other paths are for output only.\n", FN_ALT); exit(1); } if ((path != Debugging_Name) && (path != Transcript_Name) @@ -537,7 +542,7 @@ Module_Path or ICL_Path variables. Other paths are for output only.\n", FN_ALT); /* Prepend the given location or list of locations to one of the above Path buffers. This is only permitted for Source_Path, Include_Path, - ICL_Path, Module_Path. + ICL_Path. An empty field (in the comma-separated list) means the current directory. If the Path buffer is entirely empty, we assume that @@ -552,10 +557,10 @@ static void prepend_path_value(char *path, char *value) char new_path[PATHLEN]; if ((path != Source_Path) && (path != Include_Path) - && (path != ICL_Path) && (path != Module_Path)) + && (path != ICL_Path)) { printf("The character '+' is used to add to a list \ -of possible locations, and can only be used in the Include_Path, Source_Path, \ -Module_Path or ICL_Path variables. Other paths are for output only.\n"); +of possible locations, and can only be used in the Include_Path, Source_Path \ +or ICL_Path variables. Other paths are for output only.\n"); exit(1); } @@ -599,9 +604,7 @@ static void set_default_paths(void) set_path_value(Source_Path, Source_Directory); set_path_value(Include_Path, Include_Directory); set_path_value(Code_Path, Code_Directory); - set_path_value(Module_Path, Module_Directory); set_path_value(ICL_Path, ICL_Directory); - set_path_value(Temporary_Path, Temporary_Directory); set_path_value(Debugging_Name, Debugging_File); set_path_value(Transcript_Name, Transcript_File); set_path_value(Language_Name, Default_Language); @@ -641,9 +644,7 @@ static void set_path_command(char *command) if (strcmp(pathname, "source_path")==0) path_to_set=Source_Path; if (strcmp(pathname, "include_path")==0) path_to_set=Include_Path; if (strcmp(pathname, "code_path")==0) path_to_set=Code_Path; - if (strcmp(pathname, "module_path")==0) path_to_set=Module_Path; if (strcmp(pathname, "icl_path")==0) path_to_set=ICL_Path; - if (strcmp(pathname, "temporary_path")==0) path_to_set=Temporary_Path; if (strcmp(pathname, "debugging_name")==0) path_to_set=Debugging_Name; if (strcmp(pathname, "transcript_name")==0) path_to_set=Transcript_Name; if (strcmp(pathname, "language_name")==0) path_to_set=Language_Name; @@ -779,25 +780,6 @@ extern int translate_in_filename(int last_value, return last_value; } -extern int translate_link_filename(int last_value, - char *new_name, char *old_name) -{ char *prefix_path = NULL; - char *extension; - - if (contains_separator(old_name)==0) - if (Module_Path[0]!=0) - prefix_path = Module_Path; - -#ifdef FILE_EXTENSIONS - extension = check_extension(old_name, Module_Extension); -#else - extension = ""; -#endif - - return write_translated_name(new_name, old_name, - prefix_path, last_value, extension); -} - static int translate_icl_filename(int last_value, char *new_name, char *old_name) { char *prefix_path = NULL; @@ -840,27 +822,21 @@ extern void translate_out_filename(char *new_name, char *old_name) #endif prefix_path = NULL; - if (module_switch) - { extension = Module_Extension; - if (Module_Path[0]!=0) prefix_path = Module_Path; - } - else - { - if (!glulx_mode) { - switch(version_number) - { case 3: extension = Code_Extension; break; - case 4: extension = V4Code_Extension; break; - case 5: extension = V5Code_Extension; break; - case 6: extension = V6Code_Extension; break; - case 7: extension = V7Code_Extension; break; - case 8: extension = V8Code_Extension; break; - } - } - else { - extension = GlulxCode_Extension; + + if (!glulx_mode) { + switch(version_number) + { case 3: extension = Code_Extension; break; + case 4: extension = V4Code_Extension; break; + case 5: extension = V5Code_Extension; break; + case 6: extension = V6Code_Extension; break; + case 7: extension = V7Code_Extension; break; + case 8: extension = V8Code_Extension; break; } - if (Code_Path[0]!=0) prefix_path = Code_Path; } + else { + extension = GlulxCode_Extension; + } + if (Code_Path[0]!=0) prefix_path = Code_Path; #ifdef FILE_EXTENSIONS extension = check_extension(old_name, extension); @@ -877,9 +853,7 @@ static char *name_or_unset(char *p) static void help_on_filenames(void) { char old_name[PATHLEN]; char new_name[PATHLEN]; - int save_mm = module_switch, x; - - module_switch = FALSE; + int x; printf("Help information on filenames:\n\n"); @@ -894,8 +868,8 @@ If is given, however, the output filename is set to just \n\ (not altered in any way).\n\n"); printf( -"Filenames given in the game source (with commands like Include \"name\" and\n\ -Link \"name\") are also translated by the rules below.\n\n"); +"Filenames given in the game source (with commands like Include \"name\")\n\ +are also translated by the rules below.\n\n"); printf( "Rules of translation:\n\n\ @@ -929,11 +903,8 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ name_or_unset(Code_Path)); printf( -" Temporary file (out) temporary_path %s\n\ - ICL command file (in) icl_path %s\n\ - Module (in & out) module_path %s\n\n", - name_or_unset(Temporary_Path), - name_or_unset(ICL_Path), name_or_unset(Module_Path)); +" ICL command file (in) icl_path %s\n\n", + name_or_unset(ICL_Path)); printf( " If the path is unset, then the current working directory is used (so\n\ @@ -955,21 +926,17 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ " If two '+' signs are used (\"inform ++include_path=dir jigsaw\") then\n\ the path or paths are added to the existing list.\n\n"); printf( -" (Modules are written to the first alternative in the module_path list;\n\ - it is an error to give alternatives at all for purely output paths.)\n\n"); +" (It is an error to give alternatives at all for purely output paths.)\n\n"); #ifdef FILE_EXTENSIONS printf("3. The following file extensions are added:\n\n\ Source code: %s\n\ Include files: %s\n\ Story files: %s (Version 3), %s (v4), %s (v5, the default),\n\ - %s (v6), %s (v7), %s (v8), %s (Glulx)\n\ - Temporary files: .tmp\n\ - Modules: %s\n\n", + %s (v6), %s (v7), %s (v8), %s (Glulx)\n\n", Source_Extension, Include_Extension, Code_Extension, V4Code_Extension, V5Code_Extension, V6Code_Extension, - V7Code_Extension, V8Code_Extension, GlulxCode_Extension, - Module_Extension); + V7Code_Extension, V8Code_Extension, GlulxCode_Extension); printf("\ except that any extension you give (on the command line or in a filename\n\ used in a program) will override these. If you give the null extension\n\ @@ -993,19 +960,8 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ translate_out_filename(new_name, "rezrov"); printf(" and a story file is compiled to \"%s\".\n\n", new_name); - translate_in_filename(0, new_name, "frotz", 0, 1); - printf("2. \"inform -M frotz\"\n\ - the source code is read from \"%s\"\n", - new_name); - module_switch = TRUE; - convert_filename_flag = TRUE; - translate_out_filename(new_name, "frotz"); - printf(" and a module is compiled to \"%s\".\n\n", new_name); - - module_switch = FALSE; - sprintf(old_name, "demos%cplugh", FN_SEP); - printf("3. \"inform %s\"\n", old_name); + printf("2. \"inform %s\"\n", old_name); translate_in_filename(0, new_name, old_name, 0, 1); printf(" the source code is read from \"%s\"\n", new_name); sprintf(old_name, "demos%cplugh", FN_SEP); @@ -1013,7 +969,7 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ translate_out_filename(new_name, old_name); printf(" and a story file is compiled to \"%s\".\n\n", new_name); - printf("4. \"inform plover my_demo\"\n"); + printf("3. \"inform plover my_demo\"\n"); translate_in_filename(0, new_name, "plover", 0, 1); printf(" the source code is read from \"%s\"\n", new_name); convert_filename_flag = FALSE; @@ -1023,7 +979,7 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ strcpy(old_name, Source_Path); sprintf(new_name, "%cnew%cold%crecent%cold%cancient", FN_ALT, FN_ALT, FN_SEP, FN_ALT, FN_SEP); - printf("5. \"inform +source_path=%s zooge\"\n", new_name); + printf("4. \"inform +source_path=%s zooge\"\n", new_name); printf( " Note that four alternative paths are given, the first being the empty\n\ path-name (meaning: where you are now). Inform looks for the source code\n\ @@ -1036,33 +992,6 @@ Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\ printf(" \"%s\"\n", new_name); } while (x != 0); strcpy(Source_Path, old_name); - module_switch = save_mm; -} - -/* ------------------------------------------------------------------------- */ -/* Naming temporary files */ -/* (Arguably temporary files should be made using "tmpfile" in */ -/* the ANSI C library, but many supposed ANSI libraries lack it.) */ -/* ------------------------------------------------------------------------- */ - -extern void translate_temp_filename(int i) -{ char *p = NULL; - switch(i) - { case 1: p=Temp1_Name; break; - case 2: p=Temp2_Name; break; - case 3: p=Temp3_Name; break; - } - if (strlen(Temporary_Path)+strlen(Temporary_File)+6 >= PATHLEN) { - printf ("Temporary_Path is too long.\n"); - exit(1); - } - sprintf(p,"%s%s%d", Temporary_Path, Temporary_File, i); -#ifdef INCLUDE_TASK_ID - sprintf(p+strlen(p), "_proc%08lx", (long int) unique_task_id()); -#endif -#ifdef FILE_EXTENSIONS - sprintf(p+strlen(p), ".tmp"); -#endif } #ifdef ARCHIMEDES @@ -1071,12 +1000,10 @@ static char riscos_ft_buffer[4]; extern char *riscos_file_type(void) { if (riscos_file_type_format == 1) - { if (module_switch) return("data"); + { return("11A"); } - if (module_switch) return("075"); - sprintf(riscos_ft_buffer, "%03x", 0x60 + version_number); return(riscos_ft_buffer); } @@ -1101,26 +1028,23 @@ static void run_pass(void) compile_veneer(); lexer_endpass(); - if (module_switch) linker_endpass(); + issue_debug_symbol_warnings(); + close_all_source(); if (hash_switch && hash_printed_since_newline) printf("\n"); - if (temporary_files_switch) - { if (module_switch) flush_link_data(); - check_temp_files(); - } sort_dictionary(); if (track_unused_routines) locate_dead_functions(); + locate_dead_grammar_lines(); construct_storyfile(); } int output_has_occurred; -static void rennab(int32 time_taken) +static void rennab(float time_taken) { /* rennab = reverse of banner */ - int t = no_warnings + no_suppressed_warnings; if (memout_switch) print_memory_usage(); @@ -1147,7 +1071,16 @@ static void rennab(int32 time_taken) if (no_compiler_errors > 0) print_sorry_message(); if (statistics_switch) - printf("Completed in %ld seconds\n", (long int) time_taken); + { + /* Print the duration to a sensible number of decimal places. + (We aim for three significant figures.) */ + if (time_taken >= 10.0) + printf("Completed in %.1f seconds\n", time_taken); + else if (time_taken >= 1.0) + printf("Completed in %.2f seconds\n", time_taken); + else + printf("Completed in %.3f seconds\n", time_taken); + } } /* ------------------------------------------------------------------------- */ @@ -1157,7 +1090,9 @@ static void rennab(int32 time_taken) static int execute_icl_header(char *file1); static int compile(int number_of_files_specified, char *file1, char *file2) -{ int32 time_start; +{ + TIMEVALUE time_start, time_end; + float duration; if (execute_icl_header(file1)) return 1; @@ -1170,24 +1105,9 @@ disabling -X switch\n"); define_INFIX_switch = FALSE; } - if (module_switch && glulx_mode) { - printf("Modules are not available in Glulx: \ -disabling -M switch\n"); - module_switch = FALSE; - } - - if (define_INFIX_switch && module_switch) - { printf("Infix (-X) facilities are not available when compiling \ -modules: disabling -X switch\n"); - define_INFIX_switch = FALSE; - } - if (runtime_error_checking_switch && module_switch) - { printf("Strict checking (-S) facilities are not available when \ -compiling modules: disabling -S switch\n"); - runtime_error_checking_switch = FALSE; - } - - time_start=time(0); no_compilations++; + TIMEVALUE_NOW(&time_start); + + no_compilations++; strcpy(Source_Name, file1); convert_filename_flag = TRUE; strcpy(Code_Name, file1); @@ -1205,27 +1125,34 @@ compiling modules: disabling -S switch\n"); run_pass(); + if (no_errors==0) { output_file(); output_has_occurred = TRUE; } + else { output_has_occurred = FALSE; } + if (transcript_switch) { write_dictionary_to_transcript(); close_transcript_file(); } - if (no_errors==0) { output_file(); output_has_occurred = TRUE; } - else { output_has_occurred = FALSE; } - if (debugfile_switch) { end_debug_file(); } - if (temporary_files_switch && (no_errors>0)) remove_temp_files(); + if (optimise_switch) { + /* Pull out all_text so that it will not be freed. */ + extract_all_text(); + } free_arrays(); - rennab((int32) (time(0)-time_start)); - - if (optimise_switch) optimise_abbreviations(); + TIMEVALUE_NOW(&time_end); + duration = TIMEVALUE_DIFFERENCE(&time_start, &time_end); + + rennab(duration); - if (store_the_text) my_free(&all_text,"transcription text"); + if (optimise_switch) { + optimise_abbreviations(); + ao_free_arrays(); + } return (no_errors==0)?0:1; } @@ -1239,7 +1166,7 @@ static void cli_print_help(int help_level) printf( "\nThis program is a compiler of Infocom format (also called \"Z-machine\")\n\ story files, as well as \"Glulx\" story files:\n\ -Copyright (c) Graham Nelson 1993 - 2020.\n\n"); +Copyright (c) Graham Nelson 1993 - 2024.\n\n"); /* For people typing just "inform", a summary only: */ @@ -1265,18 +1192,16 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ ++dir add this directory to Include_Path\n\ +PATH=dir change the PATH to this directory\n\ ++PATH=dir add this directory to the PATH\n\n\ - $... one of the following memory commands:\n"); + $... one of the following configuration commands:\n"); printf( -" $list list current memory allocation settings\n\ - $huge make standard \"huge game\" settings %s\n\ - $large make standard \"large game\" settings %s\n\ - $small make standard \"small game\" settings %s\n\ +" $list list current settings\n\ $?SETTING explain briefly what SETTING is for\n\ - $SETTING=number change SETTING to given number\n\n", - (DEFAULT_MEMORY_SIZE==HUGE_SIZE)?"(default)":"", - (DEFAULT_MEMORY_SIZE==LARGE_SIZE)?"(default)":"", - (DEFAULT_MEMORY_SIZE==SMALL_SIZE)?"(default)":""); + $SETTING=number change SETTING to given number\n\ + $!TRACEOPT set trace option TRACEOPT\n\ + (or $!TRACEOPT=2, 3, etc for more tracing;\n\ + $! by itself to list all trace options)\n\ + $#SYMBOL=number define SYMBOL as a constant in the story\n\n"); printf( " (filename) read in a list of commands (in the format above)\n\ @@ -1284,16 +1209,19 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ printf("Alternate command-line formats for the above:\n\ --help (this page)\n\ - --path PATH=dir\n\ - --addpath PATH=dir\n\ - --list\n\ - --size huge, --size large, --size small\n\ - --helpopt SETTING\n\ - --opt SETTING=number\n\ - --config filename (setup file)\n\n"); + --path PATH=dir (set path)\n\ + --addpath PATH=dir (add to path)\n\ + --list (list current settings)\n\ + --helpopt SETTING (explain setting)\n\ + --opt SETTING=number (change setting)\n\ + --helptrace (list all trace options)\n\ + --trace TRACEOPT (set trace option)\n\ + --trace TRACEOPT=num (more tracing)\n\ + --define SYMBOL=number (define constant)\n\ + --config filename (read setup file)\n\n"); #ifndef PROMPT_INPUT - printf("For example: \"inform -dexs $huge curses\".\n\n"); + printf("For example: \"inform -dexs curses\".\n"); #endif return; @@ -1306,7 +1234,8 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ /* The -h2 (switches) help information: */ printf("Help on the full list of legal switch commands:\n\n\ - a trace assembly-language (without hex dumps; see -t)\n\ + a trace assembly-language\n\ + a2 trace assembly with hex dumps\n\ c more concise error messages\n\ d contract double spaces after full stops in text\n\ d2 contract double spaces after exclamation and question marks, too\n\ @@ -1314,37 +1243,33 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ printf("\ f frequencies mode: show how useful abbreviations are\n\ - g traces calls to functions (except in the library)\n\ - g2 traces calls to all functions\n\ - h print this information\n"); + g traces calls to all game functions\n\ + g2 traces calls to all game and library functions\n\ + g3 traces calls to all functions (including veneer)\n\ + h print general help information\n\ + h1 print help information on filenames and path options\n\ + h2 print help information on switches (this page)\n"); printf("\ i ignore default switches set within the file\n\ - j list objects as constructed\n\ - k output Infix debugging information to \"%s\" (and switch -D on)\n\ - l list every statement run through Inform\n\ - m say how much memory has been allocated\n\ - n print numbers of properties, attributes and actions\n", + k output debugging information to \"%s\"\n", Debugging_Name); printf("\ - o print offset addresses\n\ - p give percentage breakdown of story file\n\ q keep quiet about obsolete usages\n\ r record all the text to \"%s\"\n\ - s give statistics\n\ - t trace assembly-language (with full hex dumps; see -a)\n", + s give statistics\n", Transcript_Name); printf("\ u work out most useful abbreviations (very very slowly)\n\ - v3 compile to version-3 (\"Standard\") story file\n\ - v4 compile to version-4 (\"Plus\") story file\n\ - v5 compile to version-5 (\"Advanced\") story file: the default\n\ - v6 compile to version-6 (graphical) story file\n\ + v3 compile to version-3 (\"Standard\"/\"ZIP\") story file\n\ + v4 compile to version-4 (\"Plus\"/\"EZIP\") story file\n\ + v5 compile to version-5 (\"Advanced\"/\"XZIP\") story file: the default\n\ + v6 compile to version-6 (graphical/\"YZIP\") story file\n\ + v7 compile to version-7 (expanded \"Advanced\") story file\n\ v8 compile to version-8 (expanded \"Advanced\") story file\n\ w disable warning messages\n\ x print # for every 100 lines compiled\n\ - y trace linking system\n\ z print memory map of the virtual machine\n\n"); printf("\ @@ -1361,14 +1286,8 @@ printf(" E1 Microsoft-style error messages%s\n", (error_format==1)?" (current setting)":""); printf(" E2 Macintosh MPW-style error messages%s\n", (error_format==2)?" (current setting)":""); -#ifdef USE_TEMPORARY_FILES -printf(" F0 use extra memory rather than temporary files\n"); -#else -printf(" F1 use temporary files to reduce memory consumption\n"); -#endif printf(" G compile a Glulx game file\n"); printf(" H use Huffman encoding to compress Glulx strings\n"); -printf(" M compile as a Module for future linking\n"); #ifdef ARCHIMEDES printf("\ @@ -1379,7 +1298,6 @@ printf(" S compile strict error-checking at run-time (on by default)\n"); #ifdef ARC_THROWBACK printf(" T enable throwback of errors in the DDE\n"); #endif -printf(" U insert \"Constant USE_MODULES;\" automatically\n"); printf(" V print the version and date of this program\n"); printf(" Wn header extension table is at least n words (n = 3 to 99)\n"); printf(" X compile with INFIX debugging facilities present\n"); @@ -1406,8 +1324,14 @@ extern void switches(char *p, int cmode) } switch(p[i]) { - case 'a': asm_trace_setting = 1; break; - case 'b': bothpasses_switch = state; break; + case 'a': switch(p[i+1]) + { case '1': asm_trace_setting=1; s=2; break; + case '2': asm_trace_setting=2; s=2; break; + case '3': asm_trace_setting=3; s=2; break; + case '4': asm_trace_setting=4; s=2; break; + default: asm_trace_setting=1; break; + } + break; case 'c': concise_switch = state; break; case 'd': switch(p[i+1]) { case '1': double_space_setting=1; s=2; break; @@ -1416,10 +1340,11 @@ extern void switches(char *p, int cmode) } break; case 'e': economy_switch = state; break; - case 'f': frequencies_switch = state; break; + case 'f': frequencies_setting = (state?1:0); break; case 'g': switch(p[i+1]) { case '1': trace_fns_setting=1; s=2; break; case '2': trace_fns_setting=2; s=2; break; + case '3': trace_fns_setting=3; s=2; break; default: trace_fns_setting=1; break; } break; @@ -1431,26 +1356,17 @@ extern void switches(char *p, int cmode) } break; case 'i': ignore_switches_switch = state; break; - case 'j': listobjects_switch = state; break; case 'k': if (cmode == 0) error("The switch '-k' can't be set with 'Switches'"); else - { debugfile_switch = state; - if (state) define_DEBUG_switch = TRUE; - } + debugfile_switch = state; break; - case 'l': listing_switch = state; break; - case 'm': memout_switch = state; break; - case 'n': printprops_switch = state; break; - case 'o': offsets_switch = state; break; - case 'p': percentages_switch = state; break; case 'q': obsolete_switch = state; break; case 'r': if (cmode == 0) error("The switch '-r' can't be set with 'Switches'"); else transcript_switch = state; break; case 's': statistics_switch = state; break; - case 't': asm_trace_setting=2; break; case 'u': if (cmode == 0) { error("The switch '-u' can't be set with 'Switches'"); break; @@ -1475,8 +1391,7 @@ extern void switches(char *p, int cmode) break; case 'w': nowarnings_switch = state; break; case 'x': hash_switch = state; break; - case 'y': s=2; linker_trace_setting=p[i+1]-'0'; break; - case 'z': memory_map_switch = state; break; + case 'z': memory_map_setting = (state ? 1 : 0); break; case 'B': oddeven_packing_switch = state; break; case 'C': s=2; if (p[i+1] == 'u') { @@ -1504,20 +1419,6 @@ extern void switches(char *p, int cmode) default: error_format=1; break; } break; - case 'F': if (cmode == 0) { - error("The switch '-F' can't be set with 'Switches'"); - break; - } - switch(p[i+1]) - { case '0': s=2; temporary_files_switch = FALSE; break; - case '1': s=2; temporary_files_switch = TRUE; break; - default: temporary_files_switch = state; break; - } - break; - case 'M': module_switch = state; - if (state && (r_e_c_s_set == FALSE)) - runtime_error_checking_switch = FALSE; - break; #ifdef ARCHIMEDES case 'R': switch(p[i+1]) { case '0': s=2; riscos_file_type_format=0; break; @@ -1541,7 +1442,6 @@ extern void switches(char *p, int cmode) } break; case 'H': compression_switch = state; break; - case 'U': define_USE_MODULES_switch = state; break; case 'V': exit(0); break; case 'W': if ((p[i+1]>='0') && (p[i+1]<='9')) { s=2; ZCODE_HEADER_EXT_WORDS = p[i+1]-'0'; @@ -1559,22 +1459,15 @@ extern void switches(char *p, int cmode) } } - if (optimise_switch && (!store_the_text)) - { store_the_text=TRUE; -#ifdef PC_QUICKC - if (memout_switch) - printf("Allocation %ld bytes for transcription text\n", - (long) MAX_TRANSCRIPT_SIZE); - all_text = halloc(MAX_TRANSCRIPT_SIZE,1); - malloced_bytes += MAX_TRANSCRIPT_SIZE; - if (all_text==NULL) - fatalerror("Can't hallocate memory for transcription text. Darn."); -#else - all_text=my_malloc(MAX_TRANSCRIPT_SIZE,"transcription text"); -#endif + if (optimise_switch) + { + /* store_the_text is equivalent to optimise_switch; -u sets both. + We could simplify this. */ + store_the_text=TRUE; } } +/* Check whether the string looks like an ICL command. */ static int icl_command(char *p) { if ((p[0]=='+')||(p[0]=='-')||(p[0]=='$') || ((p[0]=='(')&&(p[strlen(p)-1]==')')) ) return TRUE; @@ -1643,6 +1536,16 @@ static int strcpyupper(char *to, char *from, int max) static void execute_icl_command(char *p); static int execute_dashdash_command(char *p, char *p2); +/* Open a file and see whether the initial lines match the "!% ..." format + used for ICL commands. Stop when we reach a line that doesn't. + + This does not do line break conversion. It just reads to the next + \n (and ignores \r as whitespace). Therefore it will work on Unix and + DOS source files, but fail to cope with Mac-Classic (\r) source files. + I am not going to worry about this, because files from the Mac-Classic + era shouldn't have "!%" lines; that convention was invented well after + Mac switched over to \n format. + */ static int execute_icl_header(char *argname) { FILE *command_file; @@ -1655,7 +1558,7 @@ static int execute_icl_header(char *argname) do { x = translate_in_filename(x, filename, argname, 0, 1); - command_file = fopen(filename,"r"); + command_file = fopen(filename,"rb"); } while ((command_file == NULL) && (x != 0)); if (!command_file) { /* Fail silently. The regular compiler will try to open the file @@ -1805,6 +1708,7 @@ static int execute_dashdash_command(char *p, char *p2) } else if (!strcmp(p, "size")) { consumed2 = TRUE; + /* We accept these arguments even though they've been withdrawn. */ if (!(p2 && (!strcmpcis(p2, "HUGE") || !strcmpcis(p2, "LARGE") || !strcmpcis(p2, "SMALL")))) { printf("--size must be followed by \"huge\", \"large\", or \"small\"\n"); return consumed2; @@ -1830,6 +1734,15 @@ static int execute_dashdash_command(char *p, char *p2) strcpy(cli_buff, "$?"); strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2); } + else if (!strcmp(p, "define")) { + consumed2 = TRUE; + if (!p2) { + printf("--define must be followed by \"symbol=number\"\n"); + return consumed2; + } + strcpy(cli_buff, "$#"); + strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2); + } else if (!strcmp(p, "path")) { consumed2 = TRUE; if (!p2 || !strchr(p2, '=')) { @@ -1854,6 +1767,17 @@ static int execute_dashdash_command(char *p, char *p2) } snprintf(cli_buff, CMD_BUF_SIZE, "(%s)", p2); } + else if (!strcmp(p, "trace")) { + consumed2 = TRUE; + if (!p2) { + printf("--trace must be followed by \"traceopt\" or \"traceopt=N\"\n"); + return consumed2; + } + snprintf(cli_buff, CMD_BUF_SIZE, "$!%s", p2); + } + else if (!strcmp(p, "helptrace")) { + strcpy(cli_buff, "$!"); + } else { printf("Option \"--%s\" unknown (try \"inform -h\")\n", p); return FALSE; @@ -1918,8 +1842,9 @@ static void read_command_line(int argc, char **argv) for (i=1, cli_files_specified=0; i