+++ /dev/null
-Format of Inform 6 Debugging Information Files
-
-Version 1.0
-
-0: Introduction
-
-This is a specification of the Version 1 format for the debugging information
-files emitted by the Inform 6 compiler. It replaces Version 0, which is
-documented in Section 12.5 of the Inform Technical Manual.
-
-1: Overview
-
-Debugging information files are written in XML and encoded in UTF-8. They
-therefore begin with the following declaration:
-
- <?xml version="1.0" encoding="UTF-8"?>
-
-Beyond the usual requirements for well-formed XML, the file adheres to the
-conventions that all numbers are written in decimal, all strings are
-case-sensitive, and all excerpts from binary files are Base64-encoded.
-
-2: The Top Level
-
-The root element is given by the tag <inform-story-file> with three attributes,
-the version of the debug file format being used, the name of the program that
-produced the file, and that program's version. For instance,
-
- <inform-story-file version="1.0" content-creator="Inform"
- content-creator-version="6.33">
- ...
- </inform-story-file>
-
-The elements from Sections 3--8 may appear in the ellipses.
-
-3: Story File Prefix
-
-The story file prefix contains a Base64 encoding of the story file's first bytes
-so that a debugging tool can easily check whether the story and the debug
-information file are mismatched. For example, the prefix for a Glulx story
-might appear as
-
- <story-file-prefix>
- R2x1bAADAQEACqEAAAwsAAAMLAAAAQAAAAAAPAAIo2Jc
- 6B2XSW5mbwABAAA2LjMyMC4zOAABMTIxMDE1wQAAMA==
- </story-file-prefix>
-
-The story file prefix is mandatory, but its length is unspecified. Version 6.33
-of the Inform compiler records 64 bytes, which seems sufficient.
-
-4: Story File Sections
-
-Story file sections partition the story file according to how the data will be
-used. For the Inform 6 compiler, this partitioning is the same as the one that
-the `z' flag prints.
-
-A record for a story file section gives a name for that section, its beginning
-address (inclusive), and its end address (exclusive):
-
- <story-file-section>
- <type>abbreviations table</type>
- <address>64</address>
- <end-address>128</end-address>
- </story-file-section>
-
-The names currently in use include those from Section 12.5 of the Inform
-Technical Manual:
-
- abbreviations table
- header extension (Z-code only)
- alphabets table (Z-code only)
- Unicode table (Z-code only)
- property defaults
- object tree
- common properties
- class numbers
- individual properties (Z-code only)
- global variables
- array space
- grammar table
- actions table
- parsing routines (Z-code only)
- adjectives table (Z-code only)
- dictionary
- code area
- strings area
-
-plus one addition for Z-code:
-
- abbreviations
-
-two additions for Glulx:
-
- memory layout id
- string decoding table
-
-and three additions for both targets:
-
- header
- identifier names
- zero padding
-
-Names may repeat; Glulx story files, for example, sometimes have two zero
-padding sections.
-
-A compiler that does not wish to subdivide the story file should emit one
-section for the entirety and give it the name
-
- story
-
-5: Source Files
-
-Source files are encoded as in the example below. Each file has a unique index,
-which is used by other elements when referring to source code locations; these
-indices count from zero. The file's path is recorded in two forms, first as it
-was given to the compiler via a command-line argument or include directive but
-without any path abbreviations like `>' (the form suitable for presentation to a
-human) and second after resolution to an absolute path (the form suitable for
-loading the file contents). All paths are written according to the conventions
-of the host OS. The language is, at present, either "Inform 6" or "Inform 7".
-More languages may added in the future.
-
- <source index="0">
- <given-path>example.inf</given-path>
- <resolved-path>/home/user/directory/example.inf</resolved-path>
- <language>Inform 6</language>
- </source>
-
-If the source file is known to appear in the story's Blorb, its chunk number
-will also be recorded:
-
- <source index="0">
- <given-path>example.inf</given-path>
- <resolved-path>/home/user/directory/example.inf</resolved-path>
- <language>Inform 6</language>
- <blorb-chunk-number>18</blorb-chunk-number>
- </source>
-
-6: Table Entries; Grammar Lines
-
-Table entries are data defined by particular parts of the source code, but
-without any corresponding identifiers. The <table-entry> element notes the
-entry's type, the address where it begins (inclusive), the address where it ends
-(exclusive), and the defining source code location(s), if any:
-
- <table-entry>
- <type>grammar line</type>
- <address>1004</address>
- <end-address>1030</end-address>
- <source-code-location>...</source-code-location>
- </table-entry>
-
-Version 6.33 of the Inform compiler only emits <table-entry> tags for grammar
-lines; these data are all located in the grammar table section.
-
-7: Named Values; Constants, Attributes, Properties, Actions, Fake Actions,
- Objects, Classes, Arrays, and Routines
-
-Records for named values store their identifier, their value, and the source
-code location(s) of their definition, if any. For instance,
-
- <constant>
- <identifier>MAX_SCORE</identifier>
- <value>40</value>
- <source-code-location>...</source-code-location>
- </constant>
-
-would represent a named constant. Attributes, properties, actions, fake
-actions, objects, arrays, and routines are also names for numbers, and differ
-only in their use; they are represented in the same format under the tags
-<attribute>, <property>, <action>, <fake-action>, <object>, <array>, and
-<routine>. (Moreover, unlike Version 0 of the debug information format, fake
-actions are not recorded as both fake actions and actions.)
-
-The records for constants include some extra entries for the system constants
-tabulated in Section 12.2 of the Inform Technical Manual, even though these are
-not created by Constant directives. Entries for #undefed constants are also
-included, but necessarily without values.
-
-Some records for objects will represent class objects. In that case, they will
-be given with the tag <class> rather than <object> and include an additional
-child to indicate their class number:
-
- <class>
- <identifier>lamp</identifier>
- <class-number>5</class-number>
- <value>1560</value>
- <source-code-location>...</source-code-location>
- </class>
-
-Records for arrays also have extra children, which record their size, their
-element size, and the intended semantics for their zeroth element:
-
- <array>
- <identifier>route</identifier>
- <value>1500</value>
- <byte-count>20</byte-count>
- <bytes-per-element>4</bytes-per-element>
- <zeroth-element-holds-length>true</zeroth-element-holds-length>
- <source-code-location>...</source-code-location>
- </array>
-
-And finally, <routine> records contain an <address> and a <byte-count> element,
-along with any number of the <local-variable> and <sequence-point> elements,
-which are described in Sections 9 and 10. The address is provided because the
-identifier's value may be packed.
-
-Sometimes what would otherwise be a named value is in fact anonymous; unnamed
-objects, embedded routines, some replaced routines, veneer properties, and the
-Infix attribute are all examples. In such a case, the <identifier> subelement
-will carry the XML attribute
-
- artificial
-
-to indicate that the compiler is providing a sensible name of its own, which
-could be presented to a human, but is not actually an identifier. For instance:
-
- <routine>
- <identifier artificial="true">lantern.time_left</identifier>
- <value>1820</value>
- <byte-count>80</byte-count>
- <source-code-location>...</source-code-location>
- ...
- </routine>
-
-Artificial identifiers may contain characters, like the full stop in
-``lantern.time_left'', that would not be legal in the source language.
-
-8: Global Variables
-
-Globals are similar to named values, except that they are not interpreted as a
-fixed value, but rather have an address where their value can be found. Their
-records therefore contain an <address> tag in place of the <value> tag, as in:
-
- <global-variable>
- <identifier>darkness_witnessed</identifier>
- <address>1520</address>
- <source-code-location>...</source-code-location>
- </global-variable>
-
-9: Local Variables
-
-The format for local variables mimics the format for global variables, except
-that a source code location is never included, and their memory locations are
-not given by address. For Z-code, locals are specified by index:
-
- <local-variable>
- <identifier>parameter</identifier>
- <index>1</index>
- </local-variable>
-
-whereas for Glulx they are specified by frame offset:
-
- <local-variable>
- <identifier>parameter</identifier>
- <frame-offset>4</frame-offset>
- </local-variable>
-
-If a local variable identifier is only in scope for part of a routine, it's
-scope will be encoded as a beginning instruction address (inclusive) and an
-ending instruction address (exclusive):
-
- <local-variable>
- <identifier>rulebook</identifier>
- <index>0</index>
- <scope-address>1628</scope-address>
- <end-scope-address>1678</end-scope-address>
- </local-variable>
-
-Identifiers with noncontiguous scopes are recorded as one <local-variable>
-element per contiguous region. It is possible for the same identifier to map to
-different variables, so long as the corresponding scopes are disjoint.
-
-10: Sequence Points
-
-Sequence points are stored as an instruction address and the corresponding
-single location in the source code:
-
- <sequence-point>
- <address>1628</address>
- <source-code-location>...</source-code-location>
- </sequence-point>
-
-The source code location will always be exactly one position with overlapping
-endpoints.
-
-Sequence points are defined as in Section 12.4 of the Inform Technical Manual,
-but with the further stipulation that labels do not influence their source code
-locations, as they did in Version 0 of the debug information format. For
-instance, in code like
-
- say__p = 1; ParaContent(); .L_Say59; .LSayX59;
- t_0 = 0;
-
-the sequence points are to be placed like this:
-
- <*> say__p = 1; <*> ParaContent(); .L_Say59; .LSayX59;
- <*> t_0 = 0;
-
-rather than like this:
-
- <*> say__p = 1; <*> ParaContent(); <*> .L_Say59; .LSayX59;
- t_0 = 0;
-
-11: Source Code Locations
-
-Most source code locations take the following format, which describes their
-file, the line and character number where they begin (inclusive), the line and
-character number where they end (exclusive), and the file positions (in bytes)
-corresponding to those endpoints:
-
- <source-code-location>
- <file-index>0</file-index>
- <line>1024</line>
- <character>4</character>
- <file-position>44153</file-position>
- <end-line>1025</end-line>
- <end-character>1</end-character>
- <end-file-position>44186</end-file-position>
- </source-code-location>
-
-Line numbers and character numbers begin at one, but file positions count from
-zero.
-
-In the special case where the endpoints coincide, as happens with sequence
-points, the end elements may be elided:
-
- <source-code-location>
- <file-index>0</file-index>
- <line>1024</line>
- <character>4</character>
- <file-position>44153</file-position>
- </source-code-location>
-
-At the other extreme, sometimes definitions span several source files or appear
-in two different languages. The former case is dealt with by including multiple
-code location elements and indexing them to indicate order:
-
- <!-- First Part of Inform 6 Definition -->
- <source-code-location index="0">
- <!-- Assuming file 0 was given with the language "Inform 6" -->
- <file-index>0</file-index>
- <line>1024</line>
- <character>4</character>
- <file-position>44153</file-position>
- <end-line>1025</end-line>
- <end-character>1</end-character>
- <end-file-position>44186</end-file-position>
- </source-code-location>
- <!-- Second Part of Inform 6 Definition -->
- <source-code-location index="1">
- <!-- Assuming file 1 was given with the language "Inform 6" -->
- <file-index>1</file-index>
- <line>1</line>
- <character>0</character>
- <file-position>0</file-position>
- <end-line>3</end-line>
- <end-character>1</end-character>
- <end-file-position>59</end-file-position>
- </source-code-location>
-
-The latter case is also handled with multiple elements. Note that indexing is
-only used to indicated order among locations in the same language.
-
- <!-- Inform 7 Definition -->
- <source-code-location>
- <!-- Assuming file 2 was given with the language "Inform 7" -->
- <file-index>2</file-index>
- <line>12</line>
- <character>0</character>
- <file-position>308</file-position>
- <end-line>12</end-line>
- <end-character>112</end-character>
- <end-file-position>420</end-file-position>
- </source-code-location>
- <!-- Inform 6 Definition -->
- <source-code-location>
- <!-- Assuming file 0 was given with the language "Inform 6" -->
- <file-index>0</file-index>
- <line>1024</line>
- <character>4</character>
- <file-position>44153</file-position>
- <end-line>1025</end-line>
- <end-character>1</end-character>
- <end-file-position>44186</end-file-position>
- </source-code-location>
-
---
-This file is part of Inform.
-
-Inform is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation, either version 3 of the License, or (at your
-option) any later version.
-
-Inform is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the 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/
\ No newline at end of file
/* likewise global variables, which are in some ways a */
/* simpler form of the same thing. */
/* */
-/* 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 */
/* ------------------------------------------------------------------------- */
/* Arrays defined below: */
/* */
-/* int dynamic_array_area[] Initial values for the bytes of */
+/* uchar dynamic_array_area[] Initial values for the bytes of */
/* the dynamic array area */
-/* int static_array_area[] Initial values for the bytes of */
+/* uchar static_array_area[] Initial values for the bytes of */
/* the static array area */
/* int32 global_initial_value[n] The initialised value of the nth */
-/* global variable (counting 0 - 239) */
+/* global variable (counting 0 - 239, */
+/* or higher for Glulx) */
/* */
/* The "dynamic array area" is the Z-machine area holding the current */
/* values of the global variables (in 240x2 = 480 bytes) followed by any */
-/* (dynamic) arrays which may be defined. Owing to a poor choice of name */
-/* some years ago, this is also called the "static data area", which is */
-/* why the memory setting for its maximum extent is "MAX_STATIC_DATA". */
+/* (dynamic) arrays which may be defined. */
/* */
-/* In Glulx, that 240 is changed to MAX_GLOBAL_VAR_NUMBER, and we take */
-/* correspondingly more space for the globals. This *really* ought to be */
-/* split into two segments. */
+/* In Glulx, we don't keep the global variables in dynamic_array_area. */
+/* Array data starts at the start. */
/* */
/* We can also store arrays (but not globals) into static memory (ROM). */
-/* The storage for these goes, unsurprisingly, into static_array_area -- */
-/* a separate allocation of MAX_STATIC_DATA bytes. */
+/* The storage for these goes, unsurprisingly, into static_array_area. */
/* ------------------------------------------------------------------------- */
-int *dynamic_array_area; /* See above */
-int32 *global_initial_value;
+uchar *dynamic_array_area; /* See above */
+memory_list dynamic_array_area_memlist;
+int dynamic_array_area_size; /* Size in bytes */
+
+int32 *global_initial_value; /* Allocated to no_globals */
+static memory_list global_initial_value_memlist;
int no_globals; /* Number of global variables used
by the programmer (Inform itself
/* In Glulx, Inform uses the bottom
ten. */
-int dynamic_array_area_size; /* Size in bytes */
-
-int *static_array_area;
+uchar *static_array_area;
+memory_list static_array_area_memlist;
int static_array_area_size;
int no_arrays;
-int32 *array_symbols;
-int *array_sizes, *array_types, *array_locs;
-/* array_sizes[N] gives the length of array N; array_types[N] is one of
- the constants BYTE_ARRAY, WORD_ARRAY, etc; array_locs[N] is true for
- static arrays, false for dynamic arrays. */
+arrayinfo *arrays;
+static memory_list arrays_memlist;
static int array_entry_size, /* 1 for byte array, 2 for word array */
array_base; /* Offset in dynamic array area of the
/* In Glulx, of course, that will be
4 instead of 2. */
+static memory_list current_array_name; /* The name of the global or array
+ currently being compiled. */
+
+/* Complete the array. Fill in the size field (if it has one) and
+ advance foo_array_area_size.
+*/
extern void finish_array(int32 i, int is_static)
{
- int *area;
+ uchar *area;
int area_size;
if (!is_static) {
+ ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+array_base+1*array_entry_size);
area = dynamic_array_area;
area_size = dynamic_array_area_size;
}
else {
+ ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+array_base+1*array_entry_size);
area = static_array_area;
area_size = static_array_area_size;
}
}
+/* Fill in array entry i (in either the static or dynamic area).
+ When this is called, foo_array_area_size is the end of the previous
+ array; we're writing after that.
+*/
extern void array_entry(int32 i, int is_static, assembly_operand VAL)
{
- int *area;
+ uchar *area;
int area_size;
if (!is_static) {
+ ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+(i+1)*array_entry_size);
area = dynamic_array_area;
area_size = dynamic_array_area_size;
}
else {
+ ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+(i+1)*array_entry_size);
area = static_array_area;
area_size = static_array_area_size;
}
if (!glulx_mode) {
/* Array entry i (initial entry has i=0) is set to Z-machine value j */
- if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
- memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
-
if (array_entry_size==1)
{ area[area_size+i] = (VAL.value)%256;
else {
/* Array entry i (initial entry has i=0) is set to value j */
- if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
- memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
-
if (array_entry_size==1)
{ area[area_size+i] = (VAL.value) & 0xFF;
if (VAL.marker != 0) {
if (!is_static) {
backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
- addr - 4*MAX_GLOBAL_VARIABLES);
+ addr);
}
else {
/* We can't use backpatch_zmachine() because that only applies to RAM. Instead we add an entry to staticarray_backpatch_table.
A backpatch entry is five bytes: *_MV followed by the array offset (in static array area). */
- write_byte_to_memory_block(&staticarray_backpatch_table,
- staticarray_backpatch_size++,
- VAL.marker);
- write_byte_to_memory_block(&staticarray_backpatch_table,
- staticarray_backpatch_size++, ((addr >> 24) & 0xFF));
- write_byte_to_memory_block(&staticarray_backpatch_table,
- staticarray_backpatch_size++, ((addr >> 16) & 0xFF));
- write_byte_to_memory_block(&staticarray_backpatch_table,
- staticarray_backpatch_size++, ((addr >> 8) & 0xFF));
- write_byte_to_memory_block(&staticarray_backpatch_table,
- staticarray_backpatch_size++, (addr & 0xFF));
+ if (bpatch_trace_setting >= 2)
+ printf("BP added: MV %d staticarray %04x\n", VAL.marker, addr);
+ ensure_memory_list_available(&staticarray_backpatch_table_memlist, staticarray_backpatch_size+5);
+ staticarray_backpatch_table[staticarray_backpatch_size++] = VAL.marker;
+ staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 24) & 0xFF);
+ staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 16) & 0xFF);
+ staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 8) & 0xFF);
+ staticarray_backpatch_table[staticarray_backpatch_size++] = (addr & 0xFF);
}
}
}
/* ------------------------------------------------------------------------- */
extern void set_variable_value(int i, int32 v)
-{ global_initial_value[i]=v;
+{
+ /* This can be called during module-load to create a new global,
+ so we call ensure. */
+ ensure_memory_list_available(&global_initial_value_memlist, i+1);
+ global_initial_value[i]=v;
}
/* There are four ways to initialise arrays: */
array_flag is always FALSE in that case. */
int32 i;
+ int name_length;
int array_type, data_type;
int is_static = FALSE;
assembly_operand AO;
int extraspace;
int32 global_symbol;
- const char *global_name;
debug_location_beginning beginning_debug_location =
get_token_location_beginning();
get_next_token();
i = token_value;
global_symbol = i;
- global_name = token_text;
+
+ name_length = strlen(token_text) + 1;
+ ensure_memory_list_available(¤t_array_name, name_length);
+ strncpy(current_array_name.data, token_text, name_length);
if (!glulx_mode) {
- if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T)
- && (svals[i] >= LOWEST_SYSTEM_VAR_NUMBER))
+ if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)
+ && (symbols[i].value >= LOWEST_SYSTEM_VAR_NUMBER))
goto RedefinitionOfSystemVar;
}
else {
- if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T))
+ if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T))
goto RedefinitionOfSystemVar;
}
panic_mode_error_recovery(); return;
}
- if (!(sflags[i] & UNKNOWN_SFLAG))
+ if (!(symbols[i].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
if (array_flag)
- ebf_symbol_error("new array name", token_text, typename(stypes[i]), slines[i]);
- else ebf_symbol_error("new global variable name", token_text, typename(stypes[i]), slines[i]);
+ ebf_symbol_error("new array name", token_text, typename(symbols[i].type), symbols[i].line);
+ else ebf_symbol_error("new global variable name", token_text, typename(symbols[i].type), symbols[i].line);
panic_mode_error_recovery(); return;
}
- if ((!array_flag) && (sflags[i] & USED_SFLAG))
+ if ((!array_flag) && (symbols[i].flags & USED_SFLAG))
error_named("Variable must be defined before use:", token_text);
directive_keywords.enabled = TRUE;
if (array_flag)
{ if (!is_static) {
- if (!glulx_mode)
- assign_symbol(i, dynamic_array_area_size, ARRAY_T);
- else
- assign_symbol(i,
- dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES, ARRAY_T);
+ assign_symbol(i, dynamic_array_area_size, ARRAY_T);
}
else {
assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
}
- if (no_arrays == MAX_ARRAYS)
- memoryerror("MAX_ARRAYS", MAX_ARRAYS);
- array_symbols[no_arrays] = i;
+ ensure_memory_list_available(&arrays_memlist, no_arrays+1);
+ arrays[no_arrays].symbol = i;
}
else
{ if (!glulx_mode && no_globals==233)
panic_mode_error_recovery();
return;
}
- if (glulx_mode && no_globals==MAX_GLOBAL_VARIABLES)
- { discard_token_location(beginning_debug_location);
- memoryerror("MAX_GLOBAL_VARIABLES", MAX_GLOBAL_VARIABLES);
- panic_mode_error_recovery();
- return;
- }
-
- variable_tokens[MAX_LOCAL_VARIABLES+no_globals] = i;
+
+ ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+no_globals+1);
+ variables[MAX_LOCAL_VARIABLES+no_globals].token = i;
+ variables[MAX_LOCAL_VARIABLES+no_globals].usage = FALSE;
assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
- variable_tokens[svals[i]] = i;
- if (name_only) import_symbol(i);
- else global_initial_value[no_globals++]=0;
+ if (name_only) {
+ import_symbol(i);
+ }
+ else {
+ ensure_memory_list_available(&global_initial_value_memlist, no_globals+1);
+ global_initial_value[no_globals++]=0;
+ }
}
directive_keywords.enabled = TRUE;
}
put_token_back();
if (debugfile_switch && !array_flag)
- { debug_file_printf("<global-variable>");
+ {
+ char *global_name = current_array_name.data;
+ debug_file_printf("<global-variable>");
debug_file_printf("<identifier>%s</identifier>", global_name);
debug_file_printf("<address>");
- write_debug_global_backpatch(svals[global_symbol]);
+ write_debug_global_backpatch(symbols[global_symbol].value);
debug_file_printf("</address>");
write_debug_locations
(get_token_location_end(beginning_debug_location));
}
global_initial_value[no_globals-1] = AO.value;
if (debugfile_switch)
- { debug_file_printf("<global-variable>");
+ {
+ char *global_name = current_array_name.data;
+ debug_file_printf("<global-variable>");
debug_file_printf("<identifier>%s</identifier>", global_name);
debug_file_printf("<address>");
- write_debug_global_backpatch(svals[global_symbol]);
+ write_debug_global_backpatch(symbols[global_symbol].value);
debug_file_printf("</address>");
write_debug_locations
(get_token_location_end(beginning_debug_location));
else {
backpatch_zmachine(ARRAY_MV, GLOBALVAR_ZA, 4*(no_globals-1));
global_initial_value[no_globals-1]
- = dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES;
+ = dynamic_array_area_size;
}
}
static_array_area_size += extraspace;
}
- array_types[no_arrays] = array_type;
- array_locs[no_arrays] = is_static;
+ arrays[no_arrays].type = array_type;
+ arrays[no_arrays].loc = is_static;
+ /* Note that, from this point, we must continue through finish_array().
+ Exiting this routine on error causes problems. */
+
switch(data_type)
{
case NULLS_AI:
i=0;
do
- { get_next_token();
+ {
+ /* This isn't the start of a statement, but it's safe to
+ release token texts anyway. Expressions in an array
+ list are independent of each other. */
+ release_token_texts();
+ get_next_token();
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
break;
{ discard_token_location(beginning_debug_location);
error("Missing ';' to end the initial array values "
"before \"[\" or \"]\"");
- return;
}
put_token_back();
i = 0;
while (TRUE)
- { get_next_token();
+ {
+ /* This isn't the start of a statement, but it's safe to
+ release token texts anyway. Expressions in an array
+ list are independent of each other. */
+ release_token_texts();
+ get_next_token();
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
continue;
if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
if (debugfile_switch)
{
int32 new_area_size;
+ char *global_name = current_array_name.data;
debug_file_printf("<array>");
debug_file_printf("<identifier>%s</identifier>", global_name);
debug_file_printf("<value>");
- write_debug_array_backpatch(svals[global_symbol]);
+ write_debug_array_backpatch(symbols[global_symbol].value);
debug_file_printf("</value>");
new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
debug_file_printf
if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
- array_sizes[no_arrays++] = i;
+ arrays[no_arrays++].size = i;
}
extern int32 begin_table_array(void)
dynamic_array_area_size += array_entry_size;
- if (!glulx_mode)
- return array_base;
- else
- return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
+ return array_base;
}
extern int32 begin_word_array(void)
array_base = dynamic_array_area_size;
array_entry_size = WORDSIZE;
- if (!glulx_mode)
- return array_base;
- else
- return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
+ return array_base;
}
/* ========================================================================= */
extern void init_arrays_vars(void)
{ dynamic_array_area = NULL;
static_array_area = NULL;
+ arrays = NULL;
global_initial_value = NULL;
- array_sizes = NULL; array_symbols = NULL; array_types = NULL;
+ variables = NULL;
}
extern void arrays_begin_pass(void)
-{ no_arrays = 0;
- if (!glulx_mode)
- no_globals=0;
- else
- no_globals=11;
- dynamic_array_area_size = WORDSIZE * MAX_GLOBAL_VARIABLES;
+{
+ int ix, totalvar;
+
+ no_arrays = 0;
+ if (!glulx_mode) {
+ no_globals = 0;
+ /* The compiler-defined globals start at 239 and go down, so
+ we need to initialize the entire list from the start. */
+ totalvar = MAX_ZCODE_GLOBAL_VARS;
+ }
+ else {
+ /* The compiler-defined globals run from 0 to 10. */
+ no_globals = 11;
+ totalvar = no_globals;
+ }
+
+ ensure_memory_list_available(&global_initial_value_memlist, totalvar);
+ for (ix=0; ix<totalvar; ix++) {
+ global_initial_value[ix] = 0;
+ }
+
+ ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+totalvar);
+ for (ix=0; ix<MAX_LOCAL_VARIABLES+totalvar; ix++) {
+ variables[ix].token = 0;
+ variables[ix].usage = FALSE;
+ }
+
+ dynamic_array_area_size = 0;
+
+ if (!glulx_mode) {
+ int ix;
+ /* This initial segment of dynamic_array_area is never used. It's
+ notionally space for the global variables, but that data is
+ kept in the global_initial_value array. Nonetheless, all the
+ Z-compiler math is set up with the idea that arrays start at
+ WORDSIZE * MAX_ZCODE_GLOBAL_VARS, so we need the blank segment.
+ */
+ dynamic_array_area_size = WORDSIZE * MAX_ZCODE_GLOBAL_VARS;
+ ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size);
+ for (ix=0; ix<WORDSIZE * MAX_ZCODE_GLOBAL_VARS; ix++)
+ dynamic_array_area[ix] = 0;
+ }
+
static_array_area_size = 0;
}
extern void arrays_allocate_arrays(void)
-{ dynamic_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA,
+{
+ initialise_memory_list(&dynamic_array_area_memlist,
+ sizeof(uchar), 10000, (void**)&dynamic_array_area,
"dynamic array data");
- static_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA,
+ initialise_memory_list(&static_array_area_memlist,
+ sizeof(uchar), 0, (void**)&static_array_area,
"static array data");
- array_sizes = my_calloc(sizeof(int), MAX_ARRAYS, "array sizes");
- array_types = my_calloc(sizeof(int), MAX_ARRAYS, "array types");
- array_locs = my_calloc(sizeof(int), MAX_ARRAYS, "array locations");
- array_symbols = my_calloc(sizeof(int32), MAX_ARRAYS, "array symbols");
- global_initial_value = my_calloc(sizeof(int32), MAX_GLOBAL_VARIABLES,
- "global values");
+ initialise_memory_list(&arrays_memlist,
+ sizeof(arrayinfo), 64, (void**)&arrays,
+ "array info");
+ initialise_memory_list(&global_initial_value_memlist,
+ sizeof(int32), 200, (void**)&global_initial_value,
+ "global variable values");
+
+ initialise_memory_list(¤t_array_name,
+ sizeof(char), MAX_IDENTIFIER_LENGTH+1, NULL,
+ "array name currently being defined");
}
extern void arrays_free_arrays(void)
-{ my_free(&dynamic_array_area, "dynamic array data");
- my_free(&static_array_area, "static array data");
- my_free(&global_initial_value, "global values");
- my_free(&array_sizes, "array sizes");
- my_free(&array_types, "array types");
- my_free(&array_locs, "array locations");
- my_free(&array_symbols, "array sizes");
+{
+ deallocate_memory_list(&dynamic_array_area_memlist);
+ deallocate_memory_list(&static_array_area_memlist);
+ deallocate_memory_list(&arrays_memlist);
+ deallocate_memory_list(&global_initial_value_memlist);
+ deallocate_memory_list(¤t_array_name);
}
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* "asm" : The Inform assembler */
/* */
-/* 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 */
#include "header.h"
-uchar *zcode_holding_area; /* Area holding code yet to be transferred
+static uchar *zcode_holding_area; /* Area holding code yet to be transferred
to either zcode_area or temp file no 1 */
-uchar *zcode_markers; /* Bytes holding marker values for this
+static memory_list zcode_holding_area_memlist;
+static uchar *zcode_markers; /* Bytes holding marker values for this
code */
+static memory_list zcode_markers_memlist;
static int zcode_ha_size; /* Number of bytes in holding area */
-memory_block zcode_area; /* Block to hold assembled code (if
- temporary files are not being used) */
+uchar *zcode_area; /* Array to hold assembled code */
+
+memory_list zcode_area_memlist; /* Manages zcode_area */
int32 zmachine_pc; /* PC position of assembly (byte offset
from start of Z-code area) */
int32 no_instructions; /* Number of instructions assembled */
-int execution_never_reaches_here, /* TRUE if the current PC value in the
+int execution_never_reaches_here; /* nonzero if the current PC value in the
code area cannot be reached: e.g. if
the previous instruction was a "quit"
- opcode and no label is set to here */
- next_label, /* Used to count the labels created all
+ opcode and no label is set to here
+ (see EXECSTATE flags for more) */
+int next_label, /* Used to count the labels created all
over Inform in current routine, from 0 */
next_sequence_point; /* Likewise, for sequence points */
-int no_sequence_points; /* Kept for statistics purposes only */
+int no_sequence_points; /* Total over all routines; kept for
+ statistics purposes only */
static int label_moved_error_already_given;
/* When one label has moved, all subsequent
features? */
int uses_float_features; /* Makes use of Glulx floating-point (3.1.2)
features? */
+int uses_extundo_features; /* Makes use of Glulx extended undo (3.1.3)
+ features? */
debug_location statement_debug_location;
/* Location of current statement */
-int32 *variable_tokens; /* The allocated size is
- (MAX_LOCAL_VARIABLES +
- MAX_GLOBAL_VARIABLES). The entries
- MAX_LOCAL_VARIABLES and up give the
- symbol table index for the names of
- the global variables */
-int *variable_usage; /* TRUE if referred to, FALSE otherwise */
+variableinfo *variables; /* The allocated size is
+ (MAX_LOCAL_VARIABLES + no_globals).
+ Local variables first, then globals. */
+memory_list variables_memlist;
assembly_instruction AI; /* A structure used to hold the full
specification of a single Z-code
static int routine_symbol; /* The symbol index of the routine currently
being compiled */
-static char *routine_name; /* The name of the routine currently being
- compiled */
+static memory_list current_routine_name; /* The name of the routine currently
+ being compiled. (This may be longer
+ than MAX_IDENTIFIER_LENGTH, e.g. for
+ an "obj.prop" property routine.) */
static int routine_locals; /* The number of local variables used by
the routine currently being compiled */
static int32 routine_start_pc;
-int32 *named_routine_symbols;
+int32 *named_routine_symbols; /* Allocated up to no_named_routines */
+static memory_list named_routine_symbols_memlist;
static void transfer_routine_z(void);
static void transfer_routine_g(void);
/* Label data */
/* ------------------------------------------------------------------------- */
+static labelinfo *labels; /* Label offsets (i.e. zmachine_pc values).
+ These are allocated sequentially, but accessed
+ as a double-linked list from first_label
+ to last_label (in PC order). */
+static memory_list labels_memlist;
static int first_label, last_label;
-static int32 *label_offsets; /* Double-linked list of label offsets */
-static int *label_next, /* (i.e. zmachine_pc values) in PC order */
- *label_prev;
-static int32 *label_symbols; /* Symbol numbers if defined in source */
-static int *sequence_point_labels;
- /* Label numbers for each */
-static debug_location *sequence_point_locations;
- /* Source code references for each */
- /* (used for making debugging file) */
+static int *labeluse; /* Flags indicating whether a given label has been
+ used as a branch target yet. */
+static memory_list labeluse_memlist;
+static int labeluse_size; /* Entries up to here are initialized */
+
+static sequencepointinfo *sequence_points; /* Allocated to next_sequence_point.
+ Only used when debugfile_switch
+ is set. */
+static memory_list sequence_points_memlist;
+
+/* ------------------------------------------------------------------------- */
+/* Label management */
+/* ------------------------------------------------------------------------- */
+
+/* The stripping of unreachable code requires a bit of explanation.
+
+ As we compile a function, we update the execution_never_reaches_here
+ flag to reflect whether the current line is reachable. If the flag
+ is set (EXECSTATE_UNREACHABLE), we skip generating opcodes,
+ compiling strings, and so on. (See assemblez_instruction(),
+ assembleg_instruction(), and compile_string() for these checks.)
+
+ If we're *between* functions, the execution_never_reaches_here flag
+ is always clear (EXECSTATE_REACHABLE), so global strings are
+ compiled correctly.
+
+ In general, every time we compile a JUMP or RETURN opcode, the flag
+ gets set. Every time we compile a label, the flag gets cleared.
+ This makes sense if you consider a common "while" loop:
+
+ while (true) {
+ ...
+ if (flag) break;
+ ...
+ }
+ ...
+
+ This is compiled as:
+
+ .TopLabel;
+ ...
+ @jnz flag ?ExitLabel;
+ ...
+ @jump TopLabel;
+ .ExitLabel;
+ ...
+
+ Code after an unconditional JUMP is obviously unreachable. But the
+ next thing that happens is the .ExitLabel, which is the target of a
+ branch, so the next line is reachable again.
+
+ However, if the unreachable flag is set when we *begin* a statement
+ (or braced block of statements), we can get tougher. We set the
+ EXECSTATE_ENTIRE flag for the entire duration of the statement or
+ block. This flag cannot be cleared by compiling labels. An example
+ of this:
+
+ if (DOSTUFF) {
+ while (true) {
+ if (flag) break;
+ }
+ }
+
+ If the DOSTUFF constant is false, the entire "while" loop is definitely
+ unreachable. So we should skip .TopLabel, .ExitLabel, and everything
+ in between. To ensure this, we set EXECSTATE_ENTIRE upon entering the
+ "if {...}" braced block, and reset it upon leaving.
+
+ (See parse_code_block() and parse_statement() for the (slightly fugly)
+ bit-fidding that accomplishes this.)
+
+ As an added optimization, some labels are known to be "forward"; they
+ are only reached by forward jumps. (.ExitLabel above is an example.)
+ If we reach a forward label and nothing has in fact jumped there,
+ the label is dead and we can skip it. (And thus also skip clearing
+ the unreachable flag!)
+
+ To understand *that*, consider a "while true" loop with no "break":
+
+ while (true) {
+ ...
+ if (flag) return;
+ ...
+ }
+
+ This never branches to .ExitLabel. So when we reach .ExitLabel,
+ we can say for sure that *nothing* branches there. So we skip
+ compiling that label. The unreachable flag is left set (because we
+ just finished the jump to .TopLabel). Thus, any code following the
+ entire loop is known to be unreachable, and we can righteously
+ complain about it.
+
+ (In contrast, .TopLabel cannot be skipped because it might be the
+ target of a *backwards* branch later on. In fact there might be
+ several -- any "continue" in the loop will jump to .TopLabel.)
+*/
+
+/* Set the position of the given label. The offset will be the current
+ zmachine_pc, or -1 if the label is definitely unused.
+ This adds the label to a linked list (via first_label, last_label).
+
+ The linked list must be in increasing PC order. We know this will
+ be true because we call this as we run through the function, so
+ zmachine_pc always increases.
+*/
static void set_label_offset(int label, int32 offset)
{
- if (label >= MAX_LABELS) memoryerror("MAX_LABELS", MAX_LABELS);
-
- label_offsets[label] = offset;
+ ensure_memory_list_available(&labels_memlist, label+1);
+
+ labels[label].offset = offset;
+ labels[label].symbol = -1;
+ if (offset < 0) {
+ /* Mark this label as invalid and don't put it in the linked list. */
+ labels[label].prev = -1;
+ labels[label].next = -1;
+ return;
+ }
+
if (last_label == -1)
- { label_prev[label] = -1;
+ { labels[label].prev = -1;
first_label = label;
}
else
- { label_prev[label] = last_label;
- label_next[last_label] = label;
+ { labels[label].prev = last_label;
+ labels[last_label].next = label;
}
last_label = label;
- label_next[label] = -1;
- label_symbols[label] = -1;
+ labels[label].next = -1;
+}
+
+/* Set a flag indicating that the given label has been jumped to. */
+static void mark_label_used(int label)
+{
+ if (label < 0)
+ return;
+
+ /* Entries from 0 to labeluse_size have meaningful values.
+ If we have to increase labeluse_size, initialize the new
+ entries to FALSE. */
+ ensure_memory_list_available(&labeluse_memlist, label+1);
+ for (; labeluse_size < label+1; labeluse_size++) {
+ labeluse[labeluse_size] = FALSE;
+ }
+ labeluse[label] = TRUE;
}
/* ------------------------------------------------------------------------- */
extern char *variable_name(int32 i)
{
if (i==0) return("sp");
- if (i<MAX_LOCAL_VARIABLES) return local_variable_texts[i-1];
+ if (i<MAX_LOCAL_VARIABLES) return local_variable_names[i-1].text;
if (!glulx_mode) {
if (i==255) return("TEMP1");
}
}
- return ((char *) symbs[variable_tokens[i]]);
+ return (symbols[variables[i].token].name);
}
-static void print_operand_z(assembly_operand o)
-{ switch(o.type)
+/* Print symbolic information about the AO, if there is any. */
+static void print_operand_annotation(const assembly_operand *o)
+{
+ int any = FALSE;
+ if (o->marker) {
+ printf((!any) ? " (" : ": ");
+ any = TRUE;
+ printf("%s", describe_mv(o->marker));
+ switch (o->marker) {
+ case VROUTINE_MV:
+ printf(": %s", veneer_routine_name(o->value));
+ break;
+ case INCON_MV:
+ printf(": %s", name_of_system_constant(o->value));
+ break;
+ case DWORD_MV:
+ printf(": '");
+ print_dict_word(o->value);
+ printf("'");
+ break;
+ }
+ }
+ if (o->symindex >= 0 && o->symindex < no_symbols) {
+ printf((!any) ? " (" : ": ");
+ any = TRUE;
+ printf("%s", symbols[o->symindex].name);
+ }
+ if (any) printf(")");
+}
+
+static void print_operand_z(const assembly_operand *o, int annotate)
+{ switch(o->type)
{ case EXPRESSION_OT: printf("expr_"); break;
case LONG_CONSTANT_OT: printf("long_"); break;
case SHORT_CONSTANT_OT: printf("short_"); break;
case VARIABLE_OT:
- if (o.value==0) { printf("sp"); return; }
- printf("%s", variable_name(o.value)); return;
+ if (o->value==0) { printf("sp"); return; }
+ printf("%s", variable_name(o->value)); return;
case OMITTED_OT: printf("<no value>"); return;
}
- printf("%d", o.value);
+ printf("%d", o->value);
+ if (annotate)
+ print_operand_annotation(o);
}
-static void print_operand_g(assembly_operand o)
+static void print_operand_g(const assembly_operand *o, int annotate)
{
- switch (o.type) {
+ switch (o->type) {
case EXPRESSION_OT: printf("expr_"); break;
case CONSTANT_OT: printf("long_"); break;
case HALFCONSTANT_OT: printf("short_"); break;
case ZEROCONSTANT_OT: printf("zero_"); return;
case DEREFERENCE_OT: printf("*"); break;
case GLOBALVAR_OT:
- printf("%s (global_%d)", variable_name(o.value), o.value);
+ printf("global_%d (%s)", o->value, variable_name(o->value));
return;
case LOCALVAR_OT:
- if (o.value == 0)
+ if (o->value == 0)
printf("stackptr");
else
- printf("%s (local_%d)", variable_name(o.value), o.value-1);
+ printf("local_%d (%s)", o->value-1, variable_name(o->value));
return;
case SYSFUN_OT:
- if (o.value >= 0 && o.value < NUMBER_SYSTEM_FUNCTIONS)
- printf("%s", system_functions.keywords[o.value]);
+ if (o->value >= 0 && o->value < NUMBER_SYSTEM_FUNCTIONS)
+ printf("%s", system_functions.keywords[o->value]);
else
printf("<unnamed system function>");
return;
case OMITTED_OT: printf("<no value>"); return;
default: printf("???_"); break;
}
- printf("%d", o.value);
+ printf("%d", o->value);
+ if (annotate)
+ print_operand_annotation(o);
}
-extern void print_operand(assembly_operand o)
+extern void print_operand(const assembly_operand *o, int annotate)
{
if (!glulx_mode)
- print_operand_z(o);
+ print_operand_z(o, annotate);
else
- print_operand_g(o);
+ print_operand_g(o, annotate);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
static void byteout(int32 i, int mv)
-{ if (zcode_ha_size >= MAX_ZCODE_SIZE)
- memoryerror("MAX_ZCODE_SIZE",MAX_ZCODE_SIZE);
+{
+ ensure_memory_list_available(&zcode_markers_memlist, zcode_ha_size+1);
+ ensure_memory_list_available(&zcode_holding_area_memlist, zcode_ha_size+1);
zcode_markers[zcode_ha_size] = (uchar) mv;
zcode_holding_area[zcode_ha_size++] = (uchar) i;
zmachine_pc++;
/* ------------------------------------------------------------------------- */
/* A database of the 115 canonical Infocom opcodes in Versions 3 to 6 */
-/* And of the however-many-there-are Glulx opcode */
+/* And of the however-many-there-are Glulx opcodes */
/* ------------------------------------------------------------------------- */
typedef struct opcodez
#define GOP_MemHeap 2 /* uses_memheap_features */
#define GOP_Acceleration 4 /* uses_acceleration_features */
#define GOP_Float 8 /* uses_float_features */
+#define GOP_ExtUndo 16 /* uses_extundo_features */
/* Codes for the number of operands */
{ (uchar *) "jfge", 0x1C5, Br, GOP_Float, 3 },
{ (uchar *) "jisnan", 0x1C8, Br, GOP_Float, 2 },
{ (uchar *) "jisinf", 0x1C9, Br, GOP_Float, 2 },
+ { (uchar *) "hasundo", 0x128, St, GOP_ExtUndo, 1 },
+ { (uchar *) "discardundo",0x129, 0, GOP_ExtUndo, 0 },
};
/* The opmacros table is used for fake opcodes. The opcode numbers are
}
}
-extern void assemblez_instruction(assembly_instruction *AI)
+extern void assemblez_instruction(const assembly_instruction *AI)
{
- uchar *start_pc, *operands_pc;
+ int32 operands_pc;
+ int32 start_pc;
int32 offset, j, topbits=0, types_byte1, types_byte2;
int operand_rules, min=0, max=0, no_operands_given, at_seq_point = FALSE;
assembly_operand o1, o2;
ASSERT_ZCODE();
+ if (execution_never_reaches_here) {
+ if (!(execution_never_reaches_here & EXECSTATE_NOWARN)) {
+ warning("This statement can never be reached");
+ /* only show the warning once */
+ execution_never_reaches_here |= EXECSTATE_NOWARN;
+ }
+ return;
+ }
+
offset = zmachine_pc;
no_instructions++;
if (sequence_point_follows)
{ sequence_point_follows = FALSE; at_seq_point = TRUE;
if (debugfile_switch)
- { sequence_point_labels[next_sequence_point] = next_label;
- sequence_point_locations[next_sequence_point] =
+ {
+ ensure_memory_list_available(&sequence_points_memlist, next_sequence_point+1);
+ sequence_points[next_sequence_point].label = next_label;
+ sequence_points[next_sequence_point].location =
statement_debug_location;
set_label_offset(next_label++, zmachine_pc);
}
return;
}
- if (execution_never_reaches_here)
- warning("This statement can never be reached");
-
operand_rules = opco.op_rules;
- execution_never_reaches_here = ((opco.flags & Rf) != 0);
+ execution_never_reaches_here = ((opco.flags & Rf) ? EXECSTATE_UNREACHABLE : EXECSTATE_REACHABLE);
if (opco.flags2_set != 0) flags2_requirements[opco.flags2_set] = 1;
/* 1. Write the opcode byte(s) */
- start_pc = zcode_holding_area + zcode_ha_size;
+ start_pc = zcode_ha_size;
switch(opco.no)
{ case VAR_LONG: topbits=0xc0; min=0; max=8; break;
}
byteout(opco.code + topbits, 0);
- operands_pc = zcode_holding_area + zcode_ha_size;
+ operands_pc = zcode_ha_size;
/* 2. Dispose of the special rules LABEL and TEXT */
if (operand_rules==LABEL)
{ j = (AI->operand[0]).value;
+ mark_label_used(j);
byteout(j/256, LABEL_MV); byteout(j%256, 0);
goto Instruction_Done;
}
if (operand_rules==TEXT)
{ int32 i;
- uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text, STRCTX_GAMEOPC);
- if (!tmp)
- memoryerror("MAX_ZCODE_SIZE", MAX_ZCODE_SIZE);
- j = subtract_pointers(tmp, (zcode_holding_area + zcode_ha_size));
- for (i=0; i<j; i++) zcode_markers[zcode_ha_size++] = 0;
+ j = translate_text(-1, AI->text, STRCTX_GAMEOPC);
+ if (j < 0) {
+ error("text translation failed");
+ j = 0;
+ }
+ ensure_memory_list_available(&zcode_markers_memlist, zcode_ha_size+j);
+ ensure_memory_list_available(&zcode_holding_area_memlist, zcode_ha_size+j);
+ for (i=0; i<j; i++) {
+ zcode_holding_area[zcode_ha_size] = translated_text[i];
+ zcode_markers[zcode_ha_size] = 0;
+ zcode_ha_size++;
+ }
zmachine_pc += j;
goto Instruction_Done;
}
else
types_byte2 = (types_byte2 & (~mask)) + o1.type*multi;
}
- *operands_pc=types_byte1;
- if (opco.no == VAR_LONG) *(operands_pc+1)=types_byte2;
+ zcode_holding_area[operands_pc]=types_byte1;
+ if (opco.no == VAR_LONG) zcode_holding_area[operands_pc+1]=types_byte2;
break;
case ONE:
o1 = AI->operand[0];
- *start_pc=(*start_pc) + o1.type*0x10;
+ zcode_holding_area[start_pc] += o1.type*0x10;
write_operand(o1);
break;
/* Transfer to VAR form if either operand is a long constant */
if ((o1.type==LONG_CONSTANT_OT)||(o2.type==LONG_CONSTANT_OT))
- { *start_pc=(*start_pc) + 0xc0;
+ { zcode_holding_area[start_pc] += 0xc0;
byteout(o1.type*0x40 + o2.type*0x10 + 0x0f, 0);
}
else
- { if (o1.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x40;
- if (o2.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x20;
+ { if (o1.type==VARIABLE_OT) zcode_holding_area[start_pc] += 0x40;
+ if (o2.type==VARIABLE_OT) zcode_holding_area[start_pc] += 0x20;
}
write_operand(o1);
write_operand(o2);
/* 4. Assemble a Store destination, if needed */
if ((AI->store_variable_number) != -1)
- { if (AI->store_variable_number >= MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES) {
+ { if (AI->store_variable_number >= MAX_LOCAL_VARIABLES+MAX_ZCODE_GLOBAL_VARS) {
goto OpcodeSyntaxError;
}
o1.type = VARIABLE_OT;
o1.value = AI->store_variable_number;
- variable_usage[o1.value] = TRUE;
+ variables[o1.value].usage = TRUE;
o1.marker = 0;
/* Note that variable numbers 249 to 255 (i.e. globals 233 to 239)
if (AI->branch_label_number != -1)
{ int32 addr, long_form;
int branch_on_true = (AI->branch_flag)?1:0;
-
+ mark_label_used(AI->branch_label_number);
switch (AI->branch_label_number)
{ case -2: addr = 2; branch_on_true = 0; long_form = 0; break;
/* branch nowhere, carry on */
for (i=0; i<AI->operand_count; i++)
{ if ((i==0) && (opco.op_rules == VARIAB))
{ if ((AI->operand[0]).type == VARIABLE_OT)
- { printf("["); print_operand_z(AI->operand[i]); }
+ { printf("["); print_operand_z(&AI->operand[i], TRUE); }
else
printf("%s", variable_name((AI->operand[0]).value));
}
if ((i==0) && (opco.op_rules == LABEL))
{ printf("L%d", AI->operand[0].value);
}
- else print_operand_z(AI->operand[i]);
+ else print_operand_z(&AI->operand[i], TRUE);
printf(" ");
}
if (AI->store_variable_number != -1)
{ assembly_operand AO;
printf("-> ");
AO.type = VARIABLE_OT; AO.value = AI->store_variable_number;
- print_operand_z(AO); printf(" ");
+ print_operand_z(&AO, TRUE); printf(" ");
}
switch(AI->branch_label_number)
}
if (asm_trace_level>=2)
- { for (j=0;start_pc<zcode_holding_area + zcode_ha_size;
+ { for (j=0;start_pc<zcode_ha_size;
j++, start_pc++)
{ if (j%16==0) printf("\n ");
- printf("%02x ", *start_pc);
+ printf("%02x ", zcode_holding_area[start_pc]);
}
}
printf("\n");
error_named("Assembly mistake: syntax is", opcode_syntax_string);
}
-static void assembleg_macro(assembly_instruction *AI)
+static void assembleg_macro(const assembly_instruction *AI)
{
/* validate macro syntax first */
int ix, no_operands_given;
error_named("Assembly mistake: syntax is", opcode_syntax_string);
}
-extern void assembleg_instruction(assembly_instruction *AI)
+extern void assembleg_instruction(const assembly_instruction *AI)
{
- uchar *start_pc, *opmodes_pc;
+ int32 opmodes_pc;
+ int32 start_pc;
int32 offset, j;
int no_operands_given, at_seq_point = FALSE;
int ix, k;
ASSERT_GLULX();
+ if (execution_never_reaches_here) {
+ if (!(execution_never_reaches_here & EXECSTATE_NOWARN)) {
+ warning("This statement can never be reached");
+ /* only show the warning once */
+ execution_never_reaches_here |= EXECSTATE_NOWARN;
+ }
+ return;
+ }
+
offset = zmachine_pc;
no_instructions++;
if (sequence_point_follows)
{ sequence_point_follows = FALSE; at_seq_point = TRUE;
if (debugfile_switch)
- { sequence_point_labels[next_sequence_point] = next_label;
- sequence_point_locations[next_sequence_point] =
+ {
+ ensure_memory_list_available(&sequence_points_memlist, next_sequence_point+1);
+ sequence_points[next_sequence_point].label = next_label;
+ sequence_points[next_sequence_point].location =
statement_debug_location;
set_label_offset(next_label++, zmachine_pc);
}
opco = internal_number_to_opcode_g(AI->internal_number);
- if (execution_never_reaches_here)
- warning("This statement can never be reached");
-
- execution_never_reaches_here = ((opco.flags & Rf) != 0);
+ execution_never_reaches_here = ((opco.flags & Rf) ? EXECSTATE_UNREACHABLE : EXECSTATE_REACHABLE);
if (opco.op_rules & GOP_Unicode) {
uses_unicode_features = TRUE;
if (opco.op_rules & GOP_Float) {
uses_float_features = TRUE;
}
+ if (opco.op_rules & GOP_ExtUndo) {
+ uses_extundo_features = TRUE;
+ }
no_operands_given = AI->operand_count;
/* 1. Write the opcode byte(s) */
- start_pc = zcode_holding_area + zcode_ha_size;
+ start_pc = zcode_ha_size;
if (opco.code < 0x80) {
byteout(opco.code, 0);
every two operands (rounded up). We write zeroes for now;
when the operands are written, we'll go back and fix them. */
- opmodes_pc = zcode_holding_area + zcode_ha_size;
+ opmodes_pc = zcode_ha_size;
for (ix=0; ix<opco.no; ix+=2) {
byteout(0, 0);
compiler_error("Assembling branch without BRANCH_MV marker");
goto OpcodeSyntaxError;
}
+ mark_label_used(k);
if (k == -2) {
k = 2; /* branch no-op */
type = BYTECONSTANT_OT;
}
else {
/* branch to label k */
- j = subtract_pointers((zcode_holding_area + zcode_ha_size),
- opmodes_pc);
+ j = (zcode_ha_size - opmodes_pc);
j = 2*j - ix;
marker = BRANCH_MV + j;
if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
if (ix & 1)
j = (j << 4);
- opmodes_pc[ix/2] |= j;
+ zcode_holding_area[opmodes_pc+ix/2] |= j;
}
/* Print assembly trace. */
printf("to L%d", AI->operand[i].value);
}
else {
- print_operand_g(AI->operand[i]);
+ print_operand_g(&AI->operand[i], TRUE);
}
printf(" ");
}
if (asm_trace_level>=2) {
for (j=0;
- start_pc<zcode_holding_area + zcode_ha_size;
+ start_pc<zcode_ha_size;
j++, start_pc++) {
if (j%16==0) printf("\n ");
if (/* DISABLES CODE */ (0)) {
- printf("%02x ", *start_pc);
+ printf("%02x ", zcode_holding_area[start_pc]);
}
else {
- printf("%02x", *start_pc);
- if (zcode_markers[start_pc-zcode_holding_area])
- printf("{%02x}", zcode_markers[start_pc-zcode_holding_area]);
+ printf("%02x", zcode_holding_area[start_pc]);
+ if (zcode_markers[start_pc])
+ printf("{%02x}", zcode_markers[start_pc]);
printf(" ");
}
}
error_named("Assembly mistake: syntax is", opcode_syntax_string);
}
+/* Set up this label at zmachine_pc.
+ This resets the execution_never_reaches_here flag, since every label
+ is assumed to be reachable.
+ However, if STRIP_UNREACHABLE_LABELS and EXECSTATE_ENTIRE are both set,
+ that's not true. The entire statement is being skipped, so we can safely
+ skip all labels within it.
+ (If STRIP_UNREACHABLE_LABELS is not set, the ENTIRE flag is ignored.)
+*/
extern void assemble_label_no(int n)
{
+ if ((execution_never_reaches_here & EXECSTATE_ENTIRE) && STRIP_UNREACHABLE_LABELS) {
+ /* We're not going to compile this label at all. Set a negative
+ offset, which will trip an error if this label is jumped to. */
+ set_label_offset(n, -1);
+ return;
+ }
+
if (asm_trace_level > 0)
printf("%5d +%05lx .L%d\n", ErrorReport.line_number,
((long int) zmachine_pc), n);
set_label_offset(n, zmachine_pc);
- execution_never_reaches_here = FALSE;
+ execution_never_reaches_here = EXECSTATE_REACHABLE;
+}
+
+/* This is the same as assemble_label_no, except we only set up the label
+ if there has been a forward branch to it.
+ Returns whether the label is created.
+ Only use this for labels which never have backwards branches!
+*/
+extern int assemble_forward_label_no(int n)
+{
+ if (n >= 0 && n < labeluse_size && labeluse[n]) {
+ assemble_label_no(n);
+ return TRUE;
+ }
+ else {
+ /* There were no forward branches to this label and we promise
+ there will be no backwards branches to it. Set a negative
+ offset, which will trip an error if we break our promise. */
+ set_label_offset(n, -1);
+ return FALSE;
+ }
}
extern void define_symbol_label(int symbol)
-{ label_symbols[svals[symbol]] = symbol;
+{
+ int label = symbols[symbol].value;
+ /* We may be creating a new label (label = next_label) or filling in
+ the value of an old one. So we call ensure. */
+ ensure_memory_list_available(&labels_memlist, label+1);
+ labels[label].symbol = symbol;
}
extern int32 assemble_routine_header(int no_locals,
int stackargs = FALSE;
int name_length;
- execution_never_reaches_here = FALSE;
+ execution_never_reaches_here = EXECSTATE_REACHABLE;
routine_locals = no_locals;
- for (i=0; i<MAX_LOCAL_VARIABLES; i++) variable_usage[i] = FALSE;
+
+ ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES);
+ for (i=0; i<MAX_LOCAL_VARIABLES; i++) variables[i].usage = FALSE;
- if (no_locals >= 1
- && !strcmp(local_variables.keywords[0], "_vararg_count")) {
+ if (no_locals >= 1
+ && strcmpcis(local_variable_names[0].text, "_vararg_count")==0) {
stackargs = TRUE;
}
routine_symbol = the_symbol;
name_length = strlen(name) + 1;
- routine_name =
- my_malloc(name_length * sizeof(char), "temporary copy of routine name");
- strncpy(routine_name, name, name_length);
+ ensure_memory_list_available(¤t_routine_name, name_length);
+ strncpy(current_routine_name.data, name, name_length);
/* Update the routine counter */
for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
next_label = 0; next_sequence_point = 0; last_label = -1;
+ labeluse_size = 0;
/* Compile code to print out text like "a=3, b=4, c=5" when the */
/* function is called, if it's required. */
}
else
{ i = no_named_routines++;
- named_routine_symbols[i] = the_symbol;
+ ensure_memory_list_available(&named_routine_symbols_memlist, no_named_routines);
+ named_routine_symbols[i] = the_symbol;
CON.value = i/8; CON.type = LONG_CONSTANT_OT; CON.marker = 0;
RFA.value = routine_flags_array_SC;
RFA.type = LONG_CONSTANT_OT; RFA.marker = INCON_MV;
assemble_label_no(ln);
sprintf(fnt, ") ]^"); AI.text = fnt;
assemblez_0(print_zc);
+ AI.text = NULL;
assemble_label_no(ln2);
}
}
next_label = 0; next_sequence_point = 0; last_label = -1;
+ labeluse_size = 0;
if ((routine_asterisked) || (define_INFIX_switch)) {
int ix;
}
else {
i = no_named_routines++;
+ ensure_memory_list_available(&named_routine_symbols_memlist, no_named_routines);
named_routine_symbols[i] = the_symbol;
}
}
if (debugfile_switch)
{
+ char *routine_name = current_routine_name.data;
debug_file_printf("<routine>");
if (embedded_flag)
{ debug_file_printf
("<identifier artificial=\"true\">%s</identifier>",
routine_name);
}
- else if (sflags[routine_symbol] & REPLACE_SFLAG)
+ else if (symbols[routine_symbol].flags & REPLACE_SFLAG)
{ /* The symbol type will be set to ROUTINE_T once the replaced
version has been given; if it is already set, we must be dealing
with a replacement, and we can use the routine name as-is.
Otherwise we look for a rename. And if that doesn't work, we
fall back to an artificial identifier. */
- if (stypes[routine_symbol] == ROUTINE_T)
+ if (symbols[routine_symbol].type == ROUTINE_T)
{ /* Optional because there may be further replacements. */
write_debug_optional_identifier(routine_symbol);
}
else if (find_symbol_replacement(&routine_symbol))
{ debug_file_printf
- ("<identifier>%s</identifier>", symbs[routine_symbol]);
+ ("<identifier>%s</identifier>", symbols[routine_symbol].name);
}
else
{ debug_file_printf
{ debug_file_printf("<sequence-point>");
debug_file_printf("<address>");
write_debug_code_backpatch
- (label_offsets[sequence_point_labels[i]]);
+ (labels[sequence_points[i].label].offset);
debug_file_printf("</address>");
- write_debug_location(sequence_point_locations[i]);
+ write_debug_location(sequence_points[i].location);
debug_file_printf("</sequence-point>");
}
debug_file_printf("</routine>");
}
- my_free(&routine_name, "temporary copy of routine name");
-
/* Issue warnings about any local variables not used in the routine. */
for (i=1; i<=routine_locals; i++)
- if (!(variable_usage[i]))
+ if (!(variables[i].usage))
dbnu_warning("Local variable", variable_name(i),
routine_starts_line);
for (i=0; i<next_label; i++)
- { int j = label_symbols[i];
+ { int j = labels[i].symbol;
if (j != -1)
- { if (sflags[j] & CHANGE_SFLAG)
+ { if (symbols[j].flags & CHANGE_SFLAG)
error_named_at("Routine contains no such label as",
- (char *) symbs[j], slines[j]);
+ symbols[j].name, symbols[j].line);
else
- if ((sflags[j] & USED_SFLAG) == 0)
- dbnu_warning("Label", (char *) symbs[j], slines[j]);
- stypes[j] = CONSTANT_T;
- sflags[j] = UNKNOWN_SFLAG;
+ if ((symbols[j].flags & USED_SFLAG) == 0)
+ dbnu_warning("Label", symbols[j].name, symbols[j].line);
+ symbols[j].type = CONSTANT_T;
+ symbols[j].flags = UNKNOWN_SFLAG;
}
}
no_sequence_points += next_sequence_point;
next_label = 0; next_sequence_point = 0;
+ labeluse_size = 0;
+ execution_never_reaches_here = EXECSTATE_REACHABLE;
}
/* ------------------------------------------------------------------------- */
/* Called when the holding area contains an entire routine of code: */
/* backpatches the labels, issues module markers, then dumps the routine */
/* into longer-term storage. */
+/* */
/* Note that in the code received, all branches have long form, and their */
/* contents are not an offset but the label numbers they branch to. */
/* Similarly, LABEL operands (those of "jump" instructions) are label */
/* numbers. So this routine must change the label numbers to offsets, */
/* slimming the code down as it does so to take advantage of short-form */
/* branch operands where possible. */
+/* */
+/* zcode_ha_size is the number of bytes added since the last transfer */
+/* call. So we transfer starting at (zmachine_pc - zcode_ha_size). But we */
+/* might transfer fewer bytes than that. */
/* ------------------------------------------------------------------------- */
-static int32 adjusted_pc;
-
-static void transfer_to_temp_file(uchar *c)
-{ fputc(*c,Temp2_fp);
- adjusted_pc++;
-}
-
-static void transfer_to_zcode_area(uchar *c)
-{ write_byte_to_memory_block(&zcode_area, adjusted_pc++, *c);
-}
-
static void transfer_routine_z(void)
{ int32 i, j, pc, new_pc, label, long_form, offset_of_next, addr,
branch_on_true, rstart_pc;
- void (* transfer_byte)(uchar *);
+ int32 adjusted_pc;
adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
(long int) adjusted_pc, zcode_ha_size, next_label);
}
- transfer_byte =
- (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
-
/* (1) Scan through for branches and make short/long decisions in each
case. Mark omitted bytes (2nd bytes in branches converted to
- short form) with DELETED_MV. */
+ short form) with DELETED_MV.
+ We also look for jumps that can be entirely eliminated (because
+ they are jumping to the very next instruction). The opcode and
+ both label bytes get DELETED_MV. */
for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++)
{ if (zcode_markers[i] == BRANCH_MV)
printf("Branch detected at offset %04x\n", pc);
j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
if (asm_trace_level >= 4)
- printf("To label %d, which is %d from here\n",
- j, label_offsets[j]-pc);
- if ((label_offsets[j] >= pc+2) && (label_offsets[j] < pc+64))
- { if (asm_trace_level >= 4) printf("Short form\n");
+ printf("...To label %d, which is %d from here\n",
+ j, labels[j].offset-pc);
+ if ((labels[j].offset >= pc+2) && (labels[j].offset < pc+64))
+ { if (asm_trace_level >= 4) printf("...Using short form\n");
+ zcode_markers[i+1] = DELETED_MV;
+ }
+ }
+ else if (zcode_markers[i] == LABEL_MV)
+ {
+ if (asm_trace_level >= 4)
+ printf("Jump detected at offset %04x\n", pc);
+ j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
+ if (asm_trace_level >= 4)
+ printf("...To label %d, which is %d from here\n",
+ j, labels[j].offset-pc);
+ if (labels[j].offset-pc == 2 && i >= 1 && zcode_holding_area[i-1] == opcodes_table_z[jump_zc].code+128) {
+ if (asm_trace_level >= 4) printf("...Deleting jump\n");
+ zcode_markers[i-1] = DELETED_MV;
+ zcode_markers[i] = DELETED_MV;
zcode_markers[i+1] = DELETED_MV;
}
}
{ printf("Opening label: %d\n", first_label);
for (i=0;i<next_label;i++)
printf("Label %d offset %04x next -> %d previous -> %d\n",
- i, label_offsets[i], label_next[i], label_prev[i]);
+ i, labels[i].offset, labels[i].next, labels[i].prev);
}
+ /* label will advance through the linked list as pc increases. */
for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
i<zcode_ha_size; i++, pc++)
- { while ((label != -1) && (label_offsets[label] == pc))
+ { while ((label != -1) && (labels[label].offset == pc))
{ if (asm_trace_level >= 4)
printf("Position of L%d corrected from %04x to %04x\n",
- label, label_offsets[label], new_pc);
- label_offsets[label] = new_pc;
- label = label_next[label];
+ label, labels[label].offset, new_pc);
+ labels[label].offset = new_pc;
+ label = labels[label].next;
}
if (zcode_markers[i] != DELETED_MV) new_pc++;
}
operands with offsets to those labels. Also issue markers, now
that we know where they occur in the final Z-code area. */
+ ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+zcode_ha_size);
+
for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
{ switch(zcode_markers[i])
{ case BRANCH_MV:
branch_on_true = ((zcode_holding_area[i]) & 0x80);
offset_of_next = new_pc + long_form + 1;
- addr = label_offsets[j] - offset_of_next + 2;
+ if (labels[j].offset < 0) {
+ error("Attempt to jump to an unreachable label");
+ addr = 0;
+ }
+ else {
+ addr = labels[j].offset - offset_of_next + 2;
+ }
if (addr<-0x2000 || addr>0x1fff)
fatalerror("Branch out of range: divide the routine up?");
if (addr<0) addr+=(int32) 0x10000L;
}
zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
}
- transfer_byte(zcode_holding_area + i); new_pc++;
+ zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
break;
case LABEL_MV:
j = 256*zcode_holding_area[i] + zcode_holding_area[i+1];
- addr = label_offsets[j] - new_pc;
+ if (labels[j].offset < 0) {
+ error("Attempt to jump to an unreachable label");
+ addr = 0;
+ }
+ else {
+ addr = labels[j].offset - new_pc;
+ }
if (addr<-0x8000 || addr>0x7fff)
fatalerror("Jump out of range: divide the routine up?");
if (addr<0) addr += (int32) 0x10000L;
zcode_holding_area[i] = addr/256;
zcode_holding_area[i+1] = addr%256;
- transfer_byte(zcode_holding_area + i); new_pc++;
+ zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
break;
case DELETED_MV:
break;
}
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++,
- zcode_markers[i] + 32*(new_pc/65536));
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, (new_pc/256)%256);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, new_pc%256);
+ if (bpatch_trace_setting >= 2)
+ printf("BP added: MV %d PC %04x\n", zcode_markers[i], new_pc);
+
+ ensure_memory_list_available(&zcode_backpatch_table_memlist, zcode_backpatch_size+3);
+ zcode_backpatch_table[zcode_backpatch_size++] = zcode_markers[i] + 32*(new_pc/65536);
+ zcode_backpatch_table[zcode_backpatch_size++] = (new_pc/256)%256;
+ zcode_backpatch_table[zcode_backpatch_size++] = new_pc%256;
break;
}
- transfer_byte(zcode_holding_area + i); new_pc++;
+ zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
break;
}
}
+ /* Consistency check */
+ if (new_pc - rstart_pc > zcode_ha_size || adjusted_pc != new_pc)
+ {
+ fatalerror("Optimisation increased routine length or failed to match; should not happen");
+ }
+
if (asm_trace_level >= 3)
{ printf("After branch optimisation, routine length is %d bytes\n",
new_pc - rstart_pc);
/* Insert null bytes if necessary to ensure the next routine address is */
/* expressible as a packed address */
- { uchar zero[1];
- zero[0] = 0;
- if (oddeven_packing_switch)
- while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
- else
- while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
- }
+ ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+2*scale_factor);
+
+ if (oddeven_packing_switch)
+ while ((adjusted_pc%(scale_factor*2))!=0) zcode_area[adjusted_pc++] = 0;
+ else
+ while ((adjusted_pc%scale_factor)!=0) zcode_area[adjusted_pc++] = 0;
zmachine_pc = adjusted_pc;
zcode_ha_size = 0;
static void transfer_routine_g(void)
{ int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
rstart_pc;
- void (* transfer_byte)(uchar *);
+ int32 adjusted_pc;
adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
(long int) adjusted_pc, zcode_ha_size, next_label);
}
- transfer_byte =
- (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
-
/* (1) Scan through for branches and make short/long decisions in each
case. Mark omitted bytes (bytes 2-4 in branches converted to
- short form) with DELETED_MV. */
+ short form) with DELETED_MV.
+ We also look for branches that can be entirely eliminated (because
+ they are jumping to the very next instruction). The opcode and
+ all label bytes get DELETED_MV. */
for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++) {
if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
| (zcode_holding_area[i+2] << 8)
| (zcode_holding_area[i+3]));
offset_of_next = pc + 4;
- addr = (label_offsets[j] - offset_of_next) + 2;
+ addr = (labels[j].offset - offset_of_next) + 2;
+ opmodebyte = i - ((opmodeoffset+1)/2);
if (asm_trace_level >= 4)
- printf("To label %d, which is (%d-2) = %d from here\n",
- j, addr, label_offsets[j] - offset_of_next);
- if (addr >= -0x80 && addr < 0x80) {
+ printf("...To label %d, which is (%d-2) = %d from here\n",
+ j, addr, labels[j].offset - offset_of_next);
+ if (addr == 2 && i >= 2 && opmodeoffset == 2 && zcode_holding_area[opmodebyte-1] == opcodes_table_g[jump_gc].code) {
+ if (asm_trace_level >= 4) printf("...Deleting branch\n");
+ zcode_markers[i-2] = DELETED_MV;
+ zcode_markers[i-1] = DELETED_MV;
+ zcode_markers[i] = DELETED_MV;
+ zcode_markers[i+1] = DELETED_MV;
+ zcode_markers[i+2] = DELETED_MV;
+ zcode_markers[i+3] = DELETED_MV;
+ }
+ else if (addr >= -0x80 && addr < 0x80) {
if (asm_trace_level >= 4) printf("...Byte form\n");
zcode_markers[i+1] = DELETED_MV;
zcode_markers[i+2] = DELETED_MV;
zcode_markers[i+3] = DELETED_MV;
- opmodebyte = i - ((opmodeoffset+1)/2);
if ((opmodeoffset & 1) == 0)
zcode_holding_area[opmodebyte] =
(zcode_holding_area[opmodebyte] & 0xF0) | 0x01;
if (asm_trace_level >= 4) printf("...Short form\n");
zcode_markers[i+2] = DELETED_MV;
zcode_markers[i+3] = DELETED_MV;
- opmodebyte = i - ((opmodeoffset+1)/2);
if ((opmodeoffset & 1) == 0)
zcode_holding_area[opmodebyte] =
(zcode_holding_area[opmodebyte] & 0xF0) | 0x02;
printf("Opening label: %d\n", first_label);
for (i=0;i<next_label;i++)
printf("Label %d offset %04x next -> %d previous -> %d\n",
- i, label_offsets[i], label_next[i], label_prev[i]);
+ i, labels[i].offset, labels[i].next, labels[i].prev);
}
+ /* label will advance through the linked list as pc increases. */
for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
i<zcode_ha_size;
i++, pc++) {
- while ((label != -1) && (label_offsets[label] == pc)) {
+ while ((label != -1) && (labels[label].offset == pc)) {
if (asm_trace_level >= 4)
printf("Position of L%d corrected from %04x to %04x\n",
- label, label_offsets[label], new_pc);
- label_offsets[label] = new_pc;
- label = label_next[label];
+ label, labels[label].offset, new_pc);
+ labels[label].offset = new_pc;
+ label = labels[label].next;
}
if (zcode_markers[i] != DELETED_MV) new_pc++;
}
operands with offsets to those labels. Also issue markers, now
that we know where they occur in the final Z-code area. */
+ ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+zcode_ha_size);
+
for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
after it. */
offset_of_next = new_pc + form_len;
- addr = (label_offsets[j] - offset_of_next) + 2;
+ if (labels[j].offset < 0) {
+ error("Attempt to jump to an unreachable label");
+ addr = 0;
+ }
+ else {
+ addr = (labels[j].offset - offset_of_next) + 2;
+ }
if (asm_trace_level >= 4) {
printf("Branch at offset %04x: %04x (%s)\n",
new_pc, addr, ((form_len == 1) ? "byte" :
zcode_holding_area[i+2] = (addr >> 8) & 0xFF;
zcode_holding_area[i+3] = (addr) & 0xFF;
}
- transfer_byte(zcode_holding_area + i); new_pc++;
+ zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
}
else if (zcode_markers[i] == LABEL_MV) {
error("*** No LABEL opcodes in Glulx ***");
Then a byte indicating the data size to be patched (1, 2, 4).
Then the four-byte address (new_pc).
*/
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++,
- zcode_markers[i]);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++,
- 4);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, ((new_pc >> 24) & 0xFF));
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, ((new_pc >> 16) & 0xFF));
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, ((new_pc >> 8) & 0xFF));
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, (new_pc & 0xFF));
+ if (bpatch_trace_setting >= 2)
+ printf("BP added: MV %d size %d PC %04x\n", zcode_markers[i], 4, new_pc);
+ ensure_memory_list_available(&zcode_backpatch_table_memlist, zcode_backpatch_size+6);
+ zcode_backpatch_table[zcode_backpatch_size++] = zcode_markers[i];
+ zcode_backpatch_table[zcode_backpatch_size++] = 4;
+ zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 24) & 0xFF);
+ zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 16) & 0xFF);
+ zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 8) & 0xFF);
+ zcode_backpatch_table[zcode_backpatch_size++] = (new_pc & 0xFF);
break;
}
- transfer_byte(zcode_holding_area + i); new_pc++;
+ zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
}
}
+ /* Consistency check */
+ if (new_pc - rstart_pc > zcode_ha_size || adjusted_pc != new_pc)
+ {
+ fatalerror("Optimisation increased routine length or failed to match; should not happen");
+ }
+
if (asm_trace_level >= 3)
{ printf("After branch optimisation, routine length is %d bytes\n",
new_pc - rstart_pc);
void assemblez_1_branch(int internal_number,
assembly_operand o1, int label, int flag)
-{ AI.internal_number = internal_number;
+{
+ /* Some clever optimizations first. A constant is always or never equal
+ to zero. */
+ if (o1.marker == 0 && is_constant_ot(o1.type)) {
+ if (internal_number == jz_zc) {
+ if ((flag && o1.value == 0) || (!flag && o1.value != 0)) {
+ assemblez_jump(label);
+ return;
+ }
+ else {
+ /* assemble nothing at all! */
+ return;
+ }
+ }
+ }
+ AI.internal_number = internal_number;
AI.operand_count = 1;
AI.operand[0] = o1;
AI.branch_label_number = label;
if ((internal_number == jz_gc && o1.value == 0)
|| (internal_number == jnz_gc && o1.value != 0)) {
assembleg_0_branch(jump_gc, label);
- /* We clear the "can't reach statement" flag here,
- so that "if (1)" doesn't produce that warning. */
- execution_never_reaches_here = 0;
return;
}
if ((internal_number == jz_gc && o1.value != 0)
get_next_token();
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
{ assemblez_instruction(&AI);
+ AI.text = NULL;
return;
}
ebf_error("semicolon ';' after print string", token_text);
+ AI.text = NULL;
put_token_back();
return;
}
else
{ if (strcmp(token_text, "sp") == 0) n = 0;
else
- { if (stypes[token_value] != GLOBAL_VARIABLE_T)
+ { if (symbols[token_value].type != GLOBAL_VARIABLE_T)
error_named(
"Store '->' destination not 'sp' or a variable:",
token_text);
- else n = svals[token_value];
+ else n = symbols[token_value].value;
}
}
AI.store_variable_number = n;
int error_flag = FALSE, is_macro = FALSE;
AI.operand_count = 0;
+ AI.text = NULL;
opcode_names.enabled = TRUE;
opcode_macros.enabled = TRUE;
/* Data structure management routines */
/* ------------------------------------------------------------------------- */
-extern void asm_begin_pass(void)
-{ no_instructions = 0;
- zmachine_pc = 0;
- no_sequence_points = 0;
- next_label = 0;
- next_sequence_point = 0;
- zcode_ha_size = 0;
-}
-
extern void init_asm_vars(void)
{ int i;
uses_memheap_features = FALSE;
uses_acceleration_features = FALSE;
uses_float_features = FALSE;
+ uses_extundo_features = FALSE;
+ labels = NULL;
+ sequence_points = NULL;
sequence_point_follows = TRUE;
label_moved_error_already_given = FALSE;
- initialise_memory_block(&zcode_area);
+ zcode_area = NULL;
}
-extern void asm_allocate_arrays(void)
-{ if ((debugfile_switch) && (MAX_LABELS < 2000)) MAX_LABELS = 2000;
-
- variable_tokens = my_calloc(sizeof(int32),
- MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable tokens");
- variable_usage = my_calloc(sizeof(int),
- MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable usage");
-
- label_offsets = my_calloc(sizeof(int32), MAX_LABELS, "label offsets");
- label_symbols = my_calloc(sizeof(int32), MAX_LABELS, "label symbols");
- label_next = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
- label_prev = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
- sequence_point_labels
- = my_calloc(sizeof(int), MAX_LABELS, "sequence point labels");
- sequence_point_locations
- = my_calloc(sizeof(debug_location),
- MAX_LABELS,
- "sequence point locations");
-
- zcode_holding_area = my_malloc(MAX_ZCODE_SIZE,"compiled routine code area");
- zcode_markers = my_malloc(MAX_ZCODE_SIZE, "compiled routine code area");
+extern void asm_begin_pass(void)
+{ no_instructions = 0;
+ zmachine_pc = 0;
+ no_sequence_points = 0;
+ next_label = 0;
+ labeluse_size = 0;
+ next_sequence_point = 0;
+ zcode_ha_size = 0;
+ execution_never_reaches_here = EXECSTATE_REACHABLE;
+}
- named_routine_symbols
- = my_calloc(sizeof(int32), MAX_SYMBOLS, "named routine symbols");
+extern void asm_allocate_arrays(void)
+{
+ initialise_memory_list(&variables_memlist,
+ sizeof(variableinfo), 200, (void**)&variables,
+ "variables");
+
+ initialise_memory_list(&labels_memlist,
+ sizeof(labelinfo), 1000, (void**)&labels,
+ "labels");
+ initialise_memory_list(&labeluse_memlist,
+ sizeof(int), 1000, (void**)&labeluse,
+ "labeluse");
+ initialise_memory_list(&sequence_points_memlist,
+ sizeof(sequencepointinfo), 1000, (void**)&sequence_points,
+ "sequence points");
+
+ initialise_memory_list(&zcode_holding_area_memlist,
+ sizeof(uchar), 2000, (void**)&zcode_holding_area,
+ "compiled routine code area");
+ initialise_memory_list(&zcode_markers_memlist,
+ sizeof(uchar), 2000, (void**)&zcode_markers,
+ "compiled routine markers area");
+
+ initialise_memory_list(&named_routine_symbols_memlist,
+ sizeof(int32), 1000, (void**)&named_routine_symbols,
+ "named routine symbols");
+
+ initialise_memory_list(&zcode_area_memlist,
+ sizeof(uchar), 8192, (void**)&zcode_area,
+ "code area");
+
+ initialise_memory_list(¤t_routine_name,
+ sizeof(char), 3*MAX_IDENTIFIER_LENGTH, NULL,
+ "routine name currently being defined");
}
extern void asm_free_arrays(void)
{
- my_free(&variable_tokens, "variable tokens");
- my_free(&variable_usage, "variable usage");
+ deallocate_memory_list(&variables_memlist);
- my_free(&label_offsets, "label offsets");
- my_free(&label_symbols, "label symbols");
- my_free(&label_next, "label dll 1");
- my_free(&label_prev, "label dll 2");
- my_free(&sequence_point_labels, "sequence point labels");
- my_free(&sequence_point_locations, "sequence point locations");
+ deallocate_memory_list(&labels_memlist);
+ deallocate_memory_list(&sequence_points_memlist);
- my_free(&zcode_holding_area, "compiled routine code area");
- my_free(&zcode_markers, "compiled routine code markers");
+ deallocate_memory_list(&zcode_holding_area_memlist);
+ deallocate_memory_list(&zcode_markers_memlist);
- my_free(&named_routine_symbols, "named routine symbols");
- deallocate_memory_block(&zcode_area);
+ deallocate_memory_list(&named_routine_symbols_memlist);
+ deallocate_memory_list(&zcode_area_memlist);
+ deallocate_memory_list(¤t_routine_name);
}
/* ========================================================================= */
/* "bpatch" : Keeps track of, and finally acts on, backpatch markers, */
/* correcting symbol values not known at compilation time */
/* */
-/* 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 */
#include "header.h"
-memory_block zcode_backpatch_table, staticarray_backpatch_table,
- zmachine_backpatch_table;
+uchar *staticarray_backpatch_table; /* Allocated to staticarray_backpatch_size */
+memory_list staticarray_backpatch_table_memlist;
+uchar *zmachine_backpatch_table; /* Allocated to zmachine_backpatch_size */
+memory_list zmachine_backpatch_table_memlist;
+uchar *zcode_backpatch_table; /* Allocated to zcode_backpatch_size */
+memory_list zcode_backpatch_table_memlist;
int32 zcode_backpatch_size, staticarray_backpatch_size,
zmachine_backpatch_size;
ASSERT_ZCODE();
- if (asm_trace_level >= 4)
+ if (bpatch_trace_setting)
printf("BP %s applied to %04x giving ",
describe_mv(backpatch_marker), value);
value = value_of_system_constant(value); break;
case DWORD_MV:
value = dictionary_offset + 7 +
- final_dict_order[value]*((version_number==3)?7:9);
+ final_dict_order[value]*(DICT_ENTRY_BYTE_LENGTH);
break;
case ACTION_MV:
break;
break;
case MAIN_MV:
value = symbol_index("Main", -1);
- if (stypes[value] != ROUTINE_T)
+ if (symbols[value].type != ROUTINE_T)
error("No 'Main' routine has been defined");
- sflags[value] |= USED_SFLAG;
- value = svals[value];
+ symbols[value].flags |= USED_SFLAG;
+ value = symbols[value].value;
if (OMIT_UNUSED_ROUTINES)
value = df_stripped_address_for_address(value);
value += code_offset/scale_factor;
value = 0;
break;
}
- if (sflags[value] & UNKNOWN_SFLAG)
- { if (!(sflags[value] & UERROR_SFLAG))
- { sflags[value] |= UERROR_SFLAG;
+ if (symbols[value].flags & UNKNOWN_SFLAG)
+ { if (!(symbols[value].flags & UERROR_SFLAG))
+ { symbols[value].flags |= UERROR_SFLAG;
error_named_at("No such constant as",
- (char *) symbs[value], slines[value]);
+ symbols[value].name, symbols[value].line);
}
}
else
- if (sflags[value] & CHANGE_SFLAG)
- { sflags[value] &= (~(CHANGE_SFLAG));
- backpatch_marker = (svals[value]/0x10000);
+ if (symbols[value].flags & CHANGE_SFLAG)
+ { symbols[value].flags &= (~(CHANGE_SFLAG));
+ backpatch_marker = (symbols[value].marker);
if ((backpatch_marker < 0)
|| (backpatch_marker > LARGEST_BPATCH_MV))
{
if (no_link_errors == 0)
{ compiler_error_named(
"Illegal backpatch marker attached to symbol",
- (char *) symbs[value]);
+ symbols[value].name);
backpatch_error_flag = TRUE;
}
}
else
- svals[value] = backpatch_value_z((svals[value]) % 0x10000);
+ symbols[value].value = backpatch_value_z((symbols[value].value) % 0x10000);
}
- sflags[value] |= USED_SFLAG;
- { int t = stypes[value];
- value = svals[value];
+ symbols[value].flags |= USED_SFLAG;
+ { int t = symbols[value].type;
+ value = symbols[value].value;
switch(t)
{ case ROUTINE_T:
if (OMIT_UNUSED_ROUTINES)
break;
}
- if (asm_trace_level >= 4) printf(" %04x\n", value);
+ if (bpatch_trace_setting) printf(" %04x\n", value);
return(value);
}
ASSERT_GLULX();
- if (asm_trace_level >= 4)
+ if (bpatch_trace_setting)
printf("BP %s applied to %04x giving ",
describe_mv(backpatch_marker), value);
break;
case MAIN_MV:
value = symbol_index("Main", -1);
- if (stypes[value] != ROUTINE_T)
+ if (symbols[value].type != ROUTINE_T)
error("No 'Main' routine has been defined");
- sflags[value] |= USED_SFLAG;
- value = svals[value];
+ symbols[value].flags |= USED_SFLAG;
+ value = symbols[value].value;
if (OMIT_UNUSED_ROUTINES)
value = df_stripped_address_for_address(value);
value += code_offset;
value = 0;
break;
}
- if (sflags[value] & UNKNOWN_SFLAG)
- { if (!(sflags[value] & UERROR_SFLAG))
- { sflags[value] |= UERROR_SFLAG;
+ if (symbols[value].flags & UNKNOWN_SFLAG)
+ { if (!(symbols[value].flags & UERROR_SFLAG))
+ { symbols[value].flags |= UERROR_SFLAG;
error_named_at("No such constant as",
- (char *) symbs[value], slines[value]);
+ symbols[value].name, symbols[value].line);
}
}
else
- if (sflags[value] & CHANGE_SFLAG)
- { sflags[value] &= (~(CHANGE_SFLAG));
- backpatch_marker = smarks[value];
+ if (symbols[value].flags & CHANGE_SFLAG)
+ { symbols[value].flags &= (~(CHANGE_SFLAG));
+ backpatch_marker = symbols[value].marker;
if ((backpatch_marker < 0)
|| (backpatch_marker > LARGEST_BPATCH_MV))
{
if (no_link_errors == 0)
{ compiler_error_named(
"Illegal backpatch marker attached to symbol",
- (char *) symbs[value]);
+ symbols[value].name);
backpatch_error_flag = TRUE;
}
}
else
- svals[value] = backpatch_value_g(svals[value]);
+ symbols[value].value = backpatch_value_g(symbols[value].value);
}
- sflags[value] |= USED_SFLAG;
- { int t = stypes[value];
- value = svals[value];
+ symbols[value].flags |= USED_SFLAG;
+ { int t = symbols[value].type;
+ value = symbols[value].value;
switch(t)
{
case ROUTINE_T:
break;
}
- if (asm_trace_level >= 4) printf(" %04x\n", value);
+ if (bpatch_trace_setting) printf(" %04x\n", value);
return(value);
}
if (mv == ACTION_MV) return;
}
- /* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
+ if (bpatch_trace_setting >= 2)
+ printf("BP added: MV %d ZA %d Off %04x\n", mv, zmachine_area, offset);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, mv);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, zmachine_area);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, offset/256);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, offset%256);
+ ensure_memory_list_available(&zmachine_backpatch_table_memlist, zmachine_backpatch_size+4);
+ zmachine_backpatch_table[zmachine_backpatch_size++] = mv;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = zmachine_area;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = offset/256;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = offset%256;
}
static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
Then the four-byte address.
*/
-/* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
-
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, mv);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, zmachine_area);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, (offset >> 24) & 0xFF);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, (offset >> 16) & 0xFF);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, (offset >> 8) & 0xFF);
- write_byte_to_memory_block(&zmachine_backpatch_table,
- zmachine_backpatch_size++, (offset) & 0xFF);
+ if (bpatch_trace_setting >= 2)
+ printf("BP added: MV %d ZA %d Off %06x\n", mv, zmachine_area, offset);
+
+ ensure_memory_list_available(&zmachine_backpatch_table_memlist, zmachine_backpatch_size+6);
+ zmachine_backpatch_table[zmachine_backpatch_size++] = mv;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = zmachine_area;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 24) & 0xFF;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 16) & 0xFF;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 8) & 0xFF;
+ zmachine_backpatch_table[zmachine_backpatch_size++] = (offset) & 0xFF;
}
extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
backpatch_error_flag = FALSE;
while (bm < zmachine_backpatch_size)
{ backpatch_marker
- = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
+ = zmachine_backpatch_table[bm];
zmachine_area
- = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
+ = zmachine_backpatch_table[bm+1];
offset
- = 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
- + read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
+ = 256*zmachine_backpatch_table[bm+2]
+ + zmachine_backpatch_table[bm+3];
bm += 4;
switch(zmachine_area)
backpatch_error_flag = FALSE;
while (bm < zmachine_backpatch_size)
{ backpatch_marker
- = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
+ = zmachine_backpatch_table[bm];
zmachine_area
- = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
- offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
+ = zmachine_backpatch_table[bm+1];
+ offset = zmachine_backpatch_table[bm+2];
offset = (offset << 8) |
- read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
+ zmachine_backpatch_table[bm+3];
offset = (offset << 8) |
- read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
+ zmachine_backpatch_table[bm+4];
offset = (offset << 8) |
- read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
- bm += 6;
-
- /* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
+ zmachine_backpatch_table[bm+5];
+ bm += 6;
switch(zmachine_area) {
case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
/* ------------------------------------------------------------------------- */
extern void init_bpatch_vars(void)
-{ initialise_memory_block(&zcode_backpatch_table);
- initialise_memory_block(&staticarray_backpatch_table);
- initialise_memory_block(&zmachine_backpatch_table);
+{ zcode_backpatch_table = NULL;
+ staticarray_backpatch_table = NULL;
+ zmachine_backpatch_table = NULL;
}
extern void bpatch_begin_pass(void)
extern void bpatch_allocate_arrays(void)
{
+ initialise_memory_list(&zcode_backpatch_table_memlist,
+ sizeof(uchar), 128, (void**)&zcode_backpatch_table,
+ "code backpatch table");
+ initialise_memory_list(&staticarray_backpatch_table_memlist,
+ sizeof(uchar), 128, (void**)&staticarray_backpatch_table,
+ "static array backpatch table");
+ initialise_memory_list(&zmachine_backpatch_table_memlist,
+ sizeof(uchar), 128, (void**)&zmachine_backpatch_table,
+ "machine backpatch table");
}
extern void bpatch_free_arrays(void)
-{ deallocate_memory_block(&zcode_backpatch_table);
- deallocate_memory_block(&staticarray_backpatch_table);
- deallocate_memory_block(&zmachine_backpatch_table);
+{ deallocate_memory_list(&zcode_backpatch_table_memlist);
+ deallocate_memory_list(&staticarray_backpatch_table_memlist);
+ deallocate_memory_list(&zmachine_backpatch_table_memlist);
}
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* "chars" : Character set mappings and the Z-machine alphabet table */
/* */
-/* 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 */
/* ------------------------------------------------------------------------- */
/* "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 */
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. */
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);
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("<constant>");
debug_file_printf("<identifier>%s</identifier>", constant_name);
write_debug_symbol_optional_backpatch(i);
}
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("<constant>");
debug_file_printf("<identifier>%s</identifier>", constant_name);
write_debug_symbol_optional_backpatch(i);
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");
}
}
- if (debugfile_switch && !(sflags[i] & REDEFINABLE_SFLAG))
+ if (debugfile_switch && !(symbols[i].flags & REDEFINABLE_SFLAG))
{ debug_file_printf("<constant>");
debug_file_printf("<identifier>%s</identifier>", constant_name);
write_debug_symbol_optional_backpatch(i);
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();
{ 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);
}
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");
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:
{ 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:
{ 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;
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;
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)
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" */
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. */
{ 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
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;
}
{
/* 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,
/* 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());
}
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:
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;
/* --------------------------------------------------------------------- */
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;
}
{ write_debug_undef(token_value);
}
end_symbol_scope(token_value);
- sflags[token_value] |= USED_SFLAG;
+ symbols[token_value].flags |= USED_SFLAG;
break;
/* --------------------------------------------------------------------- */
}
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" */
/* "errors" : Warnings, errors and fatal errors */
/* (with error throwback code for RISC OS machines) */
/* */
-/* 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 */
#endif
#ifdef MAC_FACE
close_all_source();
- if (temporary_files_switch) remove_temp_files();
abort_transcript_file();
free_arrays();
- if (store_the_text)
- my_free(&all_text,"transcription text");
longjmp(g_fallback, 1);
#endif
exit(1);
fatalerror(error_message_buff);
}
-extern void memoryerror(char *s, int32 size)
-{
- snprintf(error_message_buff, ERROR_BUFLEN,
- "The memory setting %s (which is %ld at present) has been \
-exceeded. Try running Inform again with $%s=<some-larger-number> on the \
-command line.",s,(long int) size,s);
- ellipsize_error_message_buff();
- fatalerror(error_message_buff);
-}
-
/* ------------------------------------------------------------------------- */
/* Survivable diagnostics: */
/* compilation errors style 1 */
/* indicate a bug in Inform) */
/* ------------------------------------------------------------------------- */
-static int errors[MAX_ERRORS];
-
int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
no_compiler_errors;
int forerrors_pointer;
static void message(int style, char *s)
-{ int throw_style = style;
+{
if (hash_printed_since_newline) printf("\n");
hash_printed_since_newline = FALSE;
print_preamble();
{ case 1: printf("Error: "); no_errors++; break;
case 2: printf("Warning: "); no_warnings++; break;
case 3: printf("Error: [linking '%s'] ", current_module_filename);
- no_link_errors++; no_errors++; throw_style=1; break;
+ no_link_errors++; no_errors++; break;
case 4: printf("*** Compiler error: ");
- no_compiler_errors++; throw_style=1; break;
+ no_compiler_errors++; break;
}
printf(" %s\n", s);
#ifdef ARC_THROWBACK
- throwback(throw_style, s);
+ throwback(((style <= 2) ? style : 1), s);
#endif
#ifdef MAC_FACE
ProcessEvents (&g_proc);
if (g_proc != true)
{ free_arrays();
- if (store_the_text)
- my_free(&all_text,"transcription text");
close_all_source ();
- if (temporary_files_switch) remove_temp_files();
abort_transcript_file();
longjmp (g_fallback, 1);
}
extern void error(char *s)
{ if (no_errors == MAX_ERRORS)
fatalerror("Too many errors: giving up");
- errors[no_errors] = no_syntax_lines;
message(1,s);
}
error(error_message_buff);
}
+extern void error_max_dynamic_strings(int index)
+{
+ if (index >= 96 && !glulx_mode)
+ snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(95) may be used in Z-code");
+ else if (MAX_DYNAMIC_STRINGS == 0)
+ snprintf(error_message_buff, ERROR_BUFLEN, "Dynamic strings may not be used, because $MAX_DYNAMIC_STRINGS has been set to 0. Increase MAX_DYNAMIC_STRINGS.");
+ else if (MAX_DYNAMIC_STRINGS == 32 && !glulx_mode)
+ snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has its default value of %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has been set to %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
+
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+extern void error_max_abbreviations(int index)
+{
+ /* This is only called for Z-code. */
+ if (index >= 96)
+ error("The number of abbreviations has exceeded 96, the limit in Z-code");
+ else
+ error("The number of abbreviations has exceeded MAX_ABBREVS. Increase MAX_ABBREVS.");
+}
+
/* ------------------------------------------------------------------------- */
/* Style 2: Warning message routines */
/* ------------------------------------------------------------------------- */
message(2,error_message_buff);
}
+extern void symtype_warning(char *context, char *name, char *type, char *wanttype)
+{
+ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ if (name)
+ snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s \"%s\"", context, wanttype, type, name);
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s", context, wanttype, type);
+ ellipsize_error_message_buff();
+ message(2,error_message_buff);
+}
+
extern void dbnu_warning(char *type, char *name, brief_location report_line)
{ int i;
ErrorPosition E = ErrorReport;
extern void link_error(char *s)
{ if (no_errors==MAX_ERRORS) fatalerror("Too many errors: giving up");
- errors[no_errors] = no_syntax_lines;
message(3,s);
}
extern void print_sorry_message(void)
{ printf(
"***********************************************************************\n\
-Compiler errors should never occur if Inform is working properly.\n\
-Check to see if there is a more recent version available, from which\n\
-the problem may have been removed. If not, please report this fault\n\
-and if at all possible, please include your source code, as faults\n\
-such as these are rare and often difficult to reproduce. Sorry.\n\
+* 'Compiler errors' should never occur if Inform is working properly. *\n\
+* Check to see if there is a more recent version available, from which\n\
+* the problem may have been removed. If not, please report this fault\n\
+* and if at all possible, please include your source code, as faults\n\
+* such as these are rare and often difficult to reproduce. Sorry.\n\
***********************************************************************\n");
}
}
extern void errors_allocate_arrays(void)
-{ forerrors_buff = my_malloc(512, "errors buffer");
+{ forerrors_buff = my_malloc(FORERRORS_SIZE, "errors buffer");
}
extern void errors_free_arrays(void)
/* ------------------------------------------------------------------------- */
/* "expressc" : The expression code generator */
/* */
-/* 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 */
case SHORT_CONSTANT_OT:
t = "<constant>";
if (AO.marker == SYMBOL_MV)
- t = (char *) (symbs[AO.value]);
+ t = (symbols[AO.value].name);
break;
case VARIABLE_OT:
t = variable_name(AO.value);
size_ao = zero_ao; size_ao.value = -1;
for (x=0; x<no_arrays; x++)
- { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
- && (AO1.value == svals[array_symbols[x]]))
- { size_ao.value = array_sizes[x]; y=x;
+ { if (((AO1.marker == ARRAY_MV) == (!arrays[x].loc))
+ && (AO1.value == symbols[arrays[x].symbol].value))
+ { size_ao.value = arrays[x].size; y=x;
}
}
- if (array_locs[y] && !read_flag) {
+ if (arrays[y].loc && !read_flag) {
error("Cannot write to a static array");
}
from_module=TRUE;
else {
from_module=FALSE;
- type_ao = zero_ao; type_ao.value = array_types[y];
+ type_ao = zero_ao; type_ao.value = arrays[y].type;
if ((!is_systemfile()))
{ if (byte_flag)
{
- if ((array_types[y] == WORD_ARRAY)
- || (array_types[y] == TABLE_ARRAY))
+ if ((arrays[y].type == WORD_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY))
warning("Using '->' to access a --> or table array");
}
else
{
- if ((array_types[y] == BYTE_ARRAY)
- || (array_types[y] == STRING_ARRAY))
+ if ((arrays[y].type == BYTE_ARRAY)
+ || (arrays[y].type == STRING_ARRAY))
warning("Using '-->' to access a -> or string array");
}
}
max_ao = size_ao;
if (byte_flag
- && ((array_types[y] == WORD_ARRAY)
- || (array_types[y] == TABLE_ARRAY)))
+ && ((arrays[y].type == WORD_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY)))
{ max_ao.value = size_ao.value*2 + 1;
type_ao.value += 8;
}
if ((!byte_flag)
- && ((array_types[y] == BYTE_ARRAY)
- || (array_types[y] == STRING_ARRAY)
- || (array_types[y] == BUFFER_ARRAY)))
+ && ((arrays[y].type == BYTE_ARRAY)
+ || (arrays[y].type == STRING_ARRAY)
+ || (arrays[y].type == BUFFER_ARRAY)))
{ if ((size_ao.value % 2) == 0)
max_ao.value = size_ao.value/2 - 1;
else max_ao.value = (size_ao.value-1)/2;
if (max_ao.value >= 256) max_ao.type = LONG_CONSTANT_OT;
/* Can't write to the size entry in a string or table */
- if (((array_types[y] == STRING_ARRAY)
- || (array_types[y] == TABLE_ARRAY))
+ if (((arrays[y].type == STRING_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY))
&& (!read_flag))
- { if ((array_types[y] == TABLE_ARRAY) && byte_flag)
+ { if ((arrays[y].type == TABLE_ARRAY) && byte_flag)
zero_ao.value = 2;
else zero_ao.value = 1;
}
ASSERT_ZCODE();
+ switch (oc) {
+ case test_attr_zc:
+ check_warn_symbol_type(&AO1, OBJECT_T, 0, "\"has/hasnt\" expression");
+ check_warn_symbol_type(&AO2, ATTRIBUTE_T, 0, "\"has/hasnt\" expression");
+ break;
+ case jin_zc:
+ check_warn_symbol_type(&AO1, OBJECT_T, 0, "\"in/notin\" expression");
+ check_warn_symbol_type(&AO2, OBJECT_T, CLASS_T, "\"in/notin\" expression");
+ break;
+ case 200:
+ /* first argument can be anything */
+ check_warn_symbol_type(&AO2, CLASS_T, 0, "\"ofclass\" expression");
+ break;
+ case 201:
+ /* first argument can be anything */
+ check_warn_symbol_type(&AO2, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"provides\" expression");
+ break;
+ }
+
if (oc<200)
{ if ((runtime_error_checking_switch) && (oc == jin_zc))
{ if (flag) error_label = next_label++;
case ZEROCONSTANT_OT:
t = "<constant>";
if (AO.marker == SYMBOL_MV)
- t = (char *) (symbs[AO.value]);
+ t = (symbols[AO.value].name);
break;
case GLOBALVAR_OT:
case LOCALVAR_OT:
{
size_ao = zero_ao; size_ao.value = -1;
for (x=0; x<no_arrays; x++)
- { if (((AO1.marker == ARRAY_MV) == (!array_locs[x]))
- && (AO1.value == svals[array_symbols[x]]))
- { size_ao.value = array_sizes[x]; y=x;
+ { if (((AO1.marker == ARRAY_MV) == (!arrays[x].loc))
+ && (AO1.value == symbols[arrays[x].symbol].value))
+ { size_ao.value = arrays[x].size; y=x;
}
}
if (size_ao.value==-1) compiler_error("Array size can't be found");
- type_ao = zero_ao; type_ao.value = array_types[y];
+ type_ao = zero_ao; type_ao.value = arrays[y].type;
- if (array_locs[y] && !read_flag) {
+ if (arrays[y].loc && !read_flag) {
error("Cannot write to a static array");
}
if ((!is_systemfile()))
{ if (data_len == 1)
{
- if ((array_types[y] == WORD_ARRAY)
- || (array_types[y] == TABLE_ARRAY))
+ if ((arrays[y].type == WORD_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY))
warning("Using '->' to access a --> or table array");
}
else
{
- if ((array_types[y] == BYTE_ARRAY)
- || (array_types[y] == STRING_ARRAY))
+ if ((arrays[y].type == BYTE_ARRAY)
+ || (arrays[y].type == STRING_ARRAY))
warning("Using '-->' to access a -> or string array");
}
}
Here "size_ao.value" = largest permitted entry of its own kind */
max_ao = size_ao;
if (data_len == 1
- && ((array_types[y] == WORD_ARRAY)
- || (array_types[y] == TABLE_ARRAY)))
+ && ((arrays[y].type == WORD_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY)))
{ max_ao.value = size_ao.value*4 + 3;
type_ao.value += 8;
}
if (data_len == 4
- && ((array_types[y] == BYTE_ARRAY)
- || (array_types[y] == STRING_ARRAY)
- || (array_types[y] == BUFFER_ARRAY)))
+ && ((arrays[y].type == BYTE_ARRAY)
+ || (arrays[y].type == STRING_ARRAY)
+ || (arrays[y].type == BUFFER_ARRAY)))
{ max_ao.value = (size_ao.value-3)/4;
type_ao.value += 16;
}
max_ao.value++;
/* Can't write to the size entry in a string or table */
- if (((array_types[y] == STRING_ARRAY)
- || (array_types[y] == TABLE_ARRAY))
+ if (((arrays[y].type == STRING_ARRAY)
+ || (arrays[y].type == TABLE_ARRAY))
&& (!read_flag))
- { if ((array_types[y] == TABLE_ARRAY) && data_len == 1)
+ { if ((arrays[y].type == TABLE_ARRAY) && data_len == 1)
zero_ao.value = 4;
else zero_ao.value = 1;
}
assembly_operand AO, AO2, AO3;
int ln;
int check_sp = FALSE, passed_label, failed_label, last_label;
-
+ int pre_unreach;
+
if (veneer_mode)
return AO1;
return AO1;
}
+ pre_unreach = execution_never_reaches_here;
+
passed_label = next_label++;
failed_label = next_label++;
/* Allow classes */
/* Test if zero... */
assembleg_1_branch(jz_gc, AO, failed_label);
+ if (!pre_unreach && execution_never_reaches_here)
+ execution_never_reaches_here |= EXECSTATE_NOWARN;
/* Test if first byte is 0x70... */
assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
INITAO(&AO3);
else {
/* Test if zero... */
assembleg_1_branch(jz_gc, AO, failed_label);
+ if (!pre_unreach && execution_never_reaches_here)
+ execution_never_reaches_here |= EXECSTATE_NOWARN;
/* Test if first byte is 0x70... */
assembleg_3(aloadb_gc, AO, zero_operand, stack_pointer);
INITAO(&AO3);
INITAOTV(&AO3, BYTECONSTANT_OT, GOBJFIELD_PARENT());
assembleg_3(aload_gc, AO, AO3, stack_pointer);
ln = symbol_index("Class", -1);
- AO3.value = svals[ln];
+ AO3.value = symbols[ln].value;
AO3.marker = OBJECT_MV;
AO3.type = CONSTANT_OT;
assembleg_2_branch(jne_gc, stack_pointer, AO3, passed_label);
else {
/* Build the symbol for "Object" */
ln = symbol_index("Object", -1);
- AO2.value = svals[ln];
+ AO2.value = symbols[ln].value;
AO2.marker = OBJECT_MV;
AO2.type = CONSTANT_OT;
if (check_sp) {
switch ((cc-condclasses)*2 + 500) {
case HAS_CC:
+ check_warn_symbol_type(&AO1, OBJECT_T, 0, "\"has/hasnt\" expression");
+ check_warn_symbol_type(&AO2, ATTRIBUTE_T, 0, "\"has/hasnt\" expression");
if (runtime_error_checking_switch) {
if (flag)
error_label = next_label++;
break;
case IN_CC:
+ check_warn_symbol_type(&AO1, OBJECT_T, 0, "\"in/notin\" expression");
+ check_warn_symbol_type(&AO2, OBJECT_T, CLASS_T, "\"in/notin\" expression");
if (runtime_error_checking_switch) {
if (flag)
error_label = next_label++;
break;
case OFCLASS_CC:
+ /* first argument can be anything */
+ check_warn_symbol_type(&AO2, CLASS_T, 0, "\"ofclass\" expression");
assembleg_call_2(veneer_routine(OC__Cl_VR), AO1, AO2, stack_pointer);
the_zc = (flag ? jnz_gc : jz_gc);
AO1 = stack_pointer;
break;
case PROVIDES_CC:
+ /* first argument can be anything */
+ check_warn_symbol_type(&AO2, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"provides\" expression");
assembleg_call_2(veneer_routine(OP__Pr_VR), AO1, AO2, stack_pointer);
the_zc = (flag ? jnz_gc : jz_gc);
AO1 = stack_pointer;
if ((opnum == LOGAND_OP) || (opnum == LOGOR_OP))
{ generate_code_from(below, FALSE);
+ if (execution_never_reaches_here) {
+ /* If the condition never falls through to here, then it
+ was an "... && 0 && ..." test. Our convention is to skip
+ the "not reached" warnings for this case. */
+ execution_never_reaches_here |= EXECSTATE_NOWARN;
+ }
generate_code_from(ET[below].right, FALSE);
goto OperatorGenerated;
}
case PROP_ADD_OP:
{ assembly_operand AO = ET[below].value;
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".&\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".&\" expression");
if (runtime_error_checking_switch && (!veneer_mode))
AO = check_nonzero_at_runtime(AO, -1, PROP_ADD_RTE);
assemblez_2_to(get_prop_addr_zc, AO,
case PROP_NUM_OP:
{ assembly_operand AO = ET[below].value;
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".#\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".#\" expression");
if (runtime_error_checking_switch && (!veneer_mode))
AO = check_nonzero_at_runtime(AO, -1, PROP_NUM_RTE);
assemblez_2_to(get_prop_addr_zc, AO,
break;
case PROPERTY_OP:
- { assembly_operand AO = ET[below].value;
-
+ {
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
if (runtime_error_checking_switch && (!veneer_mode))
assemblez_3_to(call_vs_zc, veneer_routine(RT__ChPR_VR),
- AO, ET[ET[below].right].value, temp_var1);
+ ET[below].value, ET[ET[below].right].value, temp_var1);
else
- assemblez_2_to(get_prop_zc, AO,
+ assemblez_2_to(get_prop_zc, ET[below].value,
ET[ET[below].right].value, temp_var1);
if (!void_flag) write_result_z(Result, temp_var1);
}
break;
case MESSAGE_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
j=1; AI.operand[0] = veneer_routine(RV__Pr_VR);
goto GenFunctionCallZ;
case MPROP_ADD_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".&\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".&\" expression");
j=1; AI.operand[0] = veneer_routine(RA__Pr_VR);
goto GenFunctionCallZ;
case MPROP_NUM_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".#\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".#\" expression");
j=1; AI.operand[0] = veneer_routine(RL__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_SETEQUALS_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
j=1; AI.operand[0] = veneer_routine(WV__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"++.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"++.\" expression");
j=1; AI.operand[0] = veneer_routine(IB__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"--.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"--.\" expression");
j=1; AI.operand[0] = veneer_routine(DB__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_POST_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".++\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".++\" expression");
j=1; AI.operand[0] = veneer_routine(IA__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_POST_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".--\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".--\" expression");
j=1; AI.operand[0] = veneer_routine(DA__Pr_VR);
goto GenFunctionCallZ;
case SUPERCLASS_OP:
j=1; AI.operand[0] = veneer_routine(RA__Sc_VR);
goto GenFunctionCallZ;
case PROP_CALL_OP:
+ check_warn_symbol_has_metaclass(&ET[below].value, "\".()\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".()\" expression");
j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
goto GenFunctionCallZ;
case MESSAGE_CALL_OP:
+ check_warn_symbol_has_metaclass(&ET[below].value, "\".()\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".()\" expression");
j=1; AI.operand[0] = veneer_routine(CA__Pr_VR);
goto GenFunctionCallZ;
case INDIRECT_SYSF:
j=0; i = ET[below].right;
+ check_warn_symbol_type(&ET[i].value, ROUTINE_T, 0, "indirect function call");
goto IndirectFunctionCallZ;
case CHILDREN_SYSF:
}
break;
}
+ check_warn_symbol_type(&ET[below].value, ROUTINE_T, 0, "function call");
GenFunctionCallZ:
break;
case PROPERTY_SETEQUALS_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
if (!void_flag)
{ if (runtime_error_checking_switch)
assemblez_4_to(call_zc, veneer_routine(RT__ChPS_VR),
break;
case PROPERTY_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"++.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"++.\" expression");
assemblez_store(temp_var1, ET[below].value);
assemblez_store(temp_var2, ET[ET[below].right].value);
assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
break;
case PROPERTY_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"--.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"--.\" expression");
assemblez_store(temp_var1, ET[below].value);
assemblez_store(temp_var2, ET[ET[below].right].value);
assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
break;
case PROPERTY_POST_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".++\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".++\" expression");
assemblez_store(temp_var1, ET[below].value);
assemblez_store(temp_var2, ET[ET[below].right].value);
assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
break;
case PROPERTY_POST_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".--\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".--\" expression");
assemblez_store(temp_var1, ET[below].value);
assemblez_store(temp_var2, ET[ET[below].right].value);
assemblez_2_to(get_prop_zc, temp_var1, temp_var2, temp_var3);
compiler_error("Expr code gen: Can't generate yet");
}
}
- else {
+ else { /* Glulx */
assembly_operand AO, AO2;
if (operators[opnum].opcode_number_g != -1)
{
case PROPERTY_OP:
case MESSAGE_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
AO = veneer_routine(RV__Pr_VR);
goto TwoArgFunctionCall;
case MPROP_ADD_OP:
case PROP_ADD_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".&\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".&\" expression");
AO = veneer_routine(RA__Pr_VR);
goto TwoArgFunctionCall;
case MPROP_NUM_OP:
case PROP_NUM_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".#\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".#\" expression");
AO = veneer_routine(RL__Pr_VR);
goto TwoArgFunctionCall;
case PROP_CALL_OP:
case MESSAGE_CALL_OP:
+ check_warn_symbol_has_metaclass(&ET[below].value, "\".()\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".()\" expression");
AO2 = veneer_routine(CA__Pr_VR);
i = below;
goto DoFunctionCall;
case MESSAGE_INC_OP:
case PROPERTY_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"++.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"++.\" expression");
AO = veneer_routine(IB__Pr_VR);
goto TwoArgFunctionCall;
case MESSAGE_DEC_OP:
case PROPERTY_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\"--.\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\"--.\" expression");
AO = veneer_routine(DB__Pr_VR);
goto TwoArgFunctionCall;
case MESSAGE_POST_INC_OP:
case PROPERTY_POST_INC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".++\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".++\" expression");
AO = veneer_routine(IA__Pr_VR);
goto TwoArgFunctionCall;
case MESSAGE_POST_DEC_OP:
case PROPERTY_POST_DEC_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".--\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".--\" expression");
AO = veneer_routine(DA__Pr_VR);
goto TwoArgFunctionCall;
case SUPERCLASS_OP:
case PROPERTY_SETEQUALS_OP:
case MESSAGE_SETEQUALS_OP:
+ check_warn_symbol_type(&ET[below].value, OBJECT_T, CLASS_T, "\".\" expression");
+ check_warn_symbol_type(&ET[ET[below].right].value, PROPERTY_T, INDIVIDUAL_PROPERTY_T, "\".\" expression");
if (runtime_error_checking_switch && (!veneer_mode))
AO = veneer_routine(RT__ChPS_VR);
else
case INDIRECT_SYSF:
i = ET[below].right;
+ check_warn_symbol_type(&ET[i].value, ROUTINE_T, 0, "indirect function call");
goto IndirectFunctionCallG;
case GLK_SYSF:
break;
}
+ check_warn_symbol_type(&ET[below].value, ROUTINE_T, 0, "function call");
i = below;
IndirectFunctionCallG:
if (ET[n].to_expression)
{
+ int32 donelabel;
if (void_flag) {
warning("Logical expression has no side-effects");
if (ET[n].true_label != -1)
assemble_label_no(ET[n].false_label);
}
else if (ET[n].true_label != -1)
- { assemblez_1(push_zc, zero_operand);
- assemblez_jump(next_label++);
+ {
+ donelabel = next_label++;
+ if (!execution_never_reaches_here) {
+ assemblez_1(push_zc, zero_operand);
+ assemblez_jump(donelabel);
+ }
assemble_label_no(ET[n].true_label);
assemblez_1(push_zc, one_operand);
- assemble_label_no(next_label-1);
+ assemble_forward_label_no(donelabel);
}
else
- { assemblez_1(push_zc, one_operand);
- assemblez_jump(next_label++);
+ {
+ donelabel = next_label++;
+ if (!execution_never_reaches_here) {
+ assemblez_1(push_zc, one_operand);
+ assemblez_jump(donelabel);
+ }
assemble_label_no(ET[n].false_label);
assemblez_1(push_zc, zero_operand);
- assemble_label_no(next_label-1);
+ assemble_forward_label_no(donelabel);
}
ET[n].value = stack_pointer;
}
if (ET[n].to_expression)
{
+ int32 donelabel;
if (void_flag) {
warning("Logical expression has no side-effects");
if (ET[n].true_label != -1)
assemble_label_no(ET[n].false_label);
}
else if (ET[n].true_label != -1)
- { assembleg_store(stack_pointer, zero_operand);
- assembleg_jump(next_label++);
+ {
+ donelabel = next_label++;
+ if (!execution_never_reaches_here) {
+ assembleg_store(stack_pointer, zero_operand);
+ assembleg_jump(donelabel);
+ }
assemble_label_no(ET[n].true_label);
assembleg_store(stack_pointer, one_operand);
- assemble_label_no(next_label-1);
+ assemble_forward_label_no(donelabel);
}
else
- { assembleg_store(stack_pointer, one_operand);
- assembleg_jump(next_label++);
+ {
+ donelabel = next_label++;
+ if (!execution_never_reaches_here) {
+ assembleg_store(stack_pointer, one_operand);
+ assembleg_jump(donelabel);
+ }
assemble_label_no(ET[n].false_label);
assembleg_store(stack_pointer, zero_operand);
- assemble_label_no(next_label-1);
+ assemble_forward_label_no(donelabel);
}
ET[n].value = stack_pointer;
}
/* ------------------------------------------------------------------------- */
/* "expressp" : The expression parser */
/* */
-/* 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 */
array_init_ambiguity, action_ambiguity,
etoken_count, inserting_token, bracket_level;
-extern int *variable_usage;
-
-/* Must be at least as many as keyword_group system_functions (currently 12) */
-int system_function_usage[32];
+int system_function_usage[NUMBER_SYSTEM_FUNCTIONS];
static int get_next_etoken(void)
{ int v, symbol = 0, mark_symbol_as_used = FALSE,
current_token.value = token_value;
current_token.type = token_type;
current_token.marker = 0;
+ current_token.symindex = -1;
current_token.symtype = 0;
current_token.symflags = -1;
}
switch(current_token.type)
{ case LOCAL_VARIABLE_TT:
current_token.type = VARIABLE_TT;
- variable_usage[current_token.value] = TRUE;
+ variables[current_token.value].usage = TRUE;
break;
case DQ_TT:
mark_symbol_as_used = TRUE;
- v = svals[symbol];
+ v = symbols[symbol].value;
- current_token.symtype = stypes[symbol];
- current_token.symflags = sflags[symbol];
- switch(stypes[symbol])
+ current_token.symindex = symbol;
+ current_token.symtype = symbols[symbol].type;
+ current_token.symflags = symbols[symbol].flags;
+ switch(symbols[symbol].type)
{ case ROUTINE_T:
/* Replaced functions must always be backpatched
because there could be another definition coming. */
- if (sflags[symbol] & REPLACE_SFLAG)
+ if (symbols[symbol].flags & REPLACE_SFLAG)
{ current_token.marker = SYMBOL_MV;
if (module_switch) import_symbol(symbol);
v = symbol;
if (module_switch) current_token.marker = IDENT_MV;
break;
case CONSTANT_T:
- if (sflags[symbol] & (UNKNOWN_SFLAG + CHANGE_SFLAG))
+ if (symbols[symbol].flags & (UNKNOWN_SFLAG + CHANGE_SFLAG))
{ current_token.marker = SYMBOL_MV;
if (module_switch) import_symbol(symbol);
v = symbol;
current_token.marker = 0;
break;
}
- if (sflags[symbol] & SYSTEM_SFLAG)
+ if (symbols[symbol].flags & SYSTEM_SFLAG)
current_token.marker = 0;
current_token.value = v;
else current_token.type = SMALL_NUMBER_TT;
}
- if (stypes[symbol] == GLOBAL_VARIABLE_T)
+ if (symbols[symbol].type == GLOBAL_VARIABLE_T)
{ current_token.type = VARIABLE_TT;
- variable_usage[current_token.value] = TRUE;
+ variables[current_token.value].usage = TRUE;
}
break;
current_token.text += 3;
current_token.type = SYMBOL_TT;
symbol = symbol_index(current_token.text, -1);
- if (stypes[symbol] != GLOBAL_VARIABLE_T) {
+ if (symbols[symbol].type != GLOBAL_VARIABLE_T) {
ebf_error(
"global variable name after '#g$'",
current_token.text);
break;
}
mark_symbol_as_used = TRUE;
- current_token.value = svals[symbol] - MAX_LOCAL_VARIABLES;
+ current_token.value = symbols[symbol].value - MAX_LOCAL_VARIABLES;
current_token.marker = 0;
if (!glulx_mode) {
if (current_token.value >= 0x100)
if (token_type_allowable[current_token.type]==0)
{ if (expr_trace_level >= 3)
{ printf("Discarding as not allowable: '%s' ", current_token.text);
- describe_token(current_token);
+ describe_token(¤t_token);
printf("\n");
}
current_token.type = ENDEXP_TT;
|| (operators[current_token.value].usage == PRE_U)))
{ if (expr_trace_level >= 3)
{ printf("Discarding as no longer part: '%s' ", current_token.text);
- describe_token(current_token);
+ describe_token(¤t_token);
printf("\n");
}
current_token.type = ENDEXP_TT;
}
else
- { if (mark_symbol_as_used) sflags[symbol] |= USED_SFLAG;
+ { if (mark_symbol_as_used) symbols[symbol].flags |= USED_SFLAG;
if (expr_trace_level >= 3)
{ printf("Expr token = '%s' ", current_token.text);
- describe_token(current_token);
+ describe_token(¤t_token);
printf("\n");
}
}
};
-static int find_prec(token_data a, token_data b)
+static int find_prec(const token_data *a, const token_data *b)
{
/* We are comparing the precedence of tokens a and b
(where a occurs to the left of b). If the expression is correct,
int i, j, l1, l2;
- switch(a.type)
+ switch(a->type)
{ case SUBOPEN_TT: i=0; break;
case SUBCLOSE_TT: i=1; break;
case ENDEXP_TT: i=2; break;
case OP_TT: i=3; break;
default: i=4; break;
}
- switch(b.type)
+ switch(b->type)
{ case SUBOPEN_TT: i+=0; break;
case SUBCLOSE_TT: i+=5; break;
case ENDEXP_TT: i+=10; break;
j = prec_table[i]; if (j != -1) return j;
- l1 = operators[a.value].precedence;
- l2 = operators[b.value].precedence;
- if (operators[b.value].usage == PRE_U) return LOWER_P;
- if (operators[a.value].usage == POST_U) return GREATER_P;
+ l1 = operators[a->value].precedence;
+ l2 = operators[b->value].precedence;
+ if (operators[b->value].usage == PRE_U) return LOWER_P;
+ if (operators[a->value].usage == POST_U) return GREATER_P;
/* Anomalous rule to resolve the function call precedence, which is
different on the right from on the left, e.g., in:
if (l1 < l2) return LOWER_P;
if (l1 > l2) return GREATER_P;
- switch(operators[a.value].associativity)
+ switch(operators[a->value].associativity)
{ case L_A: return GREATER_P;
case R_A: return LOWER_P;
case 0: return e5;
/* --- Converting token to operand ----------------------------------------- */
-/* Must match the switch statement below */
+/* List used to generate gameinfo.dbg.
+ Must match the switch statement below. */
int z_system_constant_list[] =
{ adjectives_table_SC,
actions_table_SC,
highest_class_number_SC,
class_objects_array_SC,
highest_object_number_SC,
+ dictionary_table_SC,
+ grammar_table_SC,
-1 };
static int32 value_of_system_constant_z(int t)
case ipv__end_SC:
return variables_offset;
case array__start_SC:
- return variables_offset + (MAX_GLOBAL_VARIABLES*WORDSIZE);
+ return variables_offset + (MAX_ZCODE_GLOBAL_VARS*WORDSIZE);
case array__end_SC:
return static_memory_offset;
+ case dictionary_table_SC:
+ return dictionary_offset;
+ case grammar_table_SC:
+ return static_memory_offset;
case highest_attribute_number_SC:
return no_attributes-1;
return(0);
}
-/* Must match the switch statement below */
+/* List used to generate gameinfo.dbg.
+ Must match the switch statement below. */
int glulx_system_constant_list[] =
{ classes_table_SC,
identifiers_table_SC,
return value_of_system_constant_g(t);
}
-static int evaluate_term(token_data t, assembly_operand *o)
+extern char *name_of_system_constant(int t)
+{
+ if (t < 0 || t >= NO_SYSTEM_CONSTANTS) {
+ return "???";
+ }
+ return system_constants.keywords[t];
+}
+
+static int evaluate_term(const token_data *t, assembly_operand *o)
{
/* If the given token is a constant, evaluate it into the operand.
For now, the identifiers are considered variables.
int32 v;
- o->marker = t.marker;
- o->symtype = t.symtype;
- o->symflags = t.symflags;
+ o->marker = t->marker;
+ o->symindex = t->symindex;
- switch(t.type)
+ switch(t->type)
{ case LARGE_NUMBER_TT:
- v = t.value;
+ v = t->value;
if (!glulx_mode) {
if (v < 0) v = v + 0x10000;
o->type = LONG_CONSTANT_OT;
}
return(TRUE);
case SMALL_NUMBER_TT:
- v = t.value;
+ v = t->value;
if (!glulx_mode) {
if (v < 0) v = v + 0x10000;
o->type = SHORT_CONSTANT_OT;
o->type = LONG_CONSTANT_OT;
else
o->type = CONSTANT_OT;
- o->value = dictionary_add(t.text, 0x80, 0, 0);
+ o->value = dictionary_add(t->text, 0x80, 0, 0);
return(TRUE);
case DQ_TT:
/* Create as a static string */
o->type = LONG_CONSTANT_OT;
else
o->type = CONSTANT_OT;
- o->value = compile_string(t.text, STRCTX_GAME);
+ o->value = compile_string(t->text, STRCTX_GAME);
return(TRUE);
case VARIABLE_TT:
if (!glulx_mode) {
o->type = VARIABLE_OT;
}
else {
- if (t.value >= MAX_LOCAL_VARIABLES) {
+ if (t->value >= MAX_LOCAL_VARIABLES) {
o->type = GLOBALVAR_OT;
}
else {
o->type = LOCALVAR_OT;
}
}
- o->value = t.value;
+ o->value = t->value;
return(TRUE);
case SYSFUN_TT:
if (!glulx_mode) {
o->type = VARIABLE_OT;
- o->value = t.value + 256;
+ o->value = t->value + 256;
}
else {
o->type = SYSFUN_OT;
- o->value = t.value;
+ o->value = t->value;
}
- system_function_usage[t.value] = 1;
+ system_function_usage[t->value] = 1;
return(TRUE);
case ACTION_TT:
- *o = action_of_name(t.text);
+ *o = action_of_name(t->text);
return(TRUE);
case SYSTEM_CONSTANT_TT:
/* Certain system constants depend only on the
them immediately. */
if (!glulx_mode) {
o->type = LONG_CONSTANT_OT;
- switch(t.value)
+ switch(t->value)
{
case version_number_SC:
o->type = SHORT_CONSTANT_OT;
case dict_par3_SC:
o->type = SHORT_CONSTANT_OT;
o->marker = 0;
+ if (ZCODE_LESS_DICT_DATA)
+ error("#dict_par3 is unavailable when ZCODE_LESS_DICT_DATA is set");
v = (version_number==3)?6:8; break;
case lowest_attribute_number_SC:
case lowest_action_number_SC:
o->type = SHORT_CONSTANT_OT; o->marker = 0;
v = oddeven_packing_switch; break;
default:
- v = t.value;
+ v = t->value;
o->marker = INCON_MV;
break;
}
}
else {
o->type = CONSTANT_OT;
- switch(t.value)
+ switch(t->value)
{
/* The three dict_par flags point at the lower byte
of the flag field, because the library is written
/* ###fix: need to fill more of these in! */
default:
- v = t.value;
+ v = t->value;
o->marker = INCON_MV;
break;
}
/* --- Emitter ------------------------------------------------------------- */
-expression_tree_node *ET;
+expression_tree_node *ET; /* Allocated to ET_used */
+static memory_list ET_memlist;
static int ET_used;
extern void clear_expression_space(void)
{ ET_used = 0;
}
-static assembly_operand *emitter_stack;
-static int *emitter_markers;
-static int *emitter_bracket_counts;
+typedef struct emitterstackinfo_s {
+ assembly_operand op;
+ int marker;
+ int bracket_count;
+} emitterstackinfo;
#define FUNCTION_VALUE_MARKER 1
#define ARGUMENT_VALUE_MARKER 2
#define OR_VALUE_MARKER 3
+static emitterstackinfo *emitter_stack; /* Allocated to emitter_sp */
+static memory_list emitter_stack_memlist;
static int emitter_sp;
static int is_property_t(int symbol_type)
{ return ((symbol_type == PROPERTY_T) || (symbol_type == INDIVIDUAL_PROPERTY_T));
}
-static void mark_top_of_emitter_stack(int marker, token_data t)
+static void mark_top_of_emitter_stack(int marker, const token_data *t)
{ if (emitter_sp < 1)
{ compiler_error("SR error: Attempt to add a marker to the top of an empty emitter stack");
return;
}
if (expr_trace_level >= 2)
{ printf("Marking top of emitter stack (which is ");
- print_operand(emitter_stack[emitter_sp-1]);
+ print_operand(&emitter_stack[emitter_sp-1].op, FALSE);
printf(") as ");
switch(marker)
{
}
printf("\n");
}
- if (emitter_markers[emitter_sp-1])
+ if (emitter_stack[emitter_sp-1].marker)
{ if (marker == ARGUMENT_VALUE_MARKER)
{
warning("Ignoring spurious leading comma");
return;
}
- error_named("Missing operand for", t.text);
- if (emitter_sp == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
- emitter_markers[emitter_sp] = 0;
- emitter_bracket_counts[emitter_sp] = 0;
- emitter_stack[emitter_sp] = zero_operand;
+ error_named("Missing operand for", t->text);
+ ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+ emitter_stack[emitter_sp].marker = 0;
+ emitter_stack[emitter_sp].bracket_count = 0;
+ emitter_stack[emitter_sp].op = zero_operand;
emitter_sp++;
}
- emitter_markers[emitter_sp-1] = marker;
+ emitter_stack[emitter_sp-1].marker = marker;
}
static void add_bracket_layer_to_emitter_stack(int depth)
if (emitter_sp < depth + 1) return;
if (expr_trace_level >= 2)
printf("Adding bracket layer\n");
- ++emitter_bracket_counts[emitter_sp-depth-1];
+ ++emitter_stack[emitter_sp-depth-1].bracket_count;
}
static void remove_bracket_layer_from_emitter_stack()
if (emitter_sp < 2) return;
if (expr_trace_level >= 2)
printf("Removing bracket layer\n");
- if (emitter_bracket_counts[emitter_sp-2] <= 0)
+ if (emitter_stack[emitter_sp-2].bracket_count <= 0)
{ compiler_error("SR error: Attempt to remove a nonexistent bracket layer from the emitter stack");
return;
}
- --emitter_bracket_counts[emitter_sp-2];
+ --emitter_stack[emitter_sp-2].bracket_count;
}
-static void emit_token(token_data t)
+static void emit_token(const token_data *t)
{ assembly_operand o1, o2; int arity, stack_size, i;
int op_node_number, operand_node_number, previous_node_number;
int32 x = 0;
if (expr_trace_level >= 2)
- { printf("Output: %-19s%21s ", t.text, "");
+ { printf("Output: %-19s%21s ", t->text, "");
for (i=0; i<emitter_sp; i++)
- { print_operand(emitter_stack[i]); printf(" ");
- if (emitter_markers[i] == FUNCTION_VALUE_MARKER) printf(":FUNCTION ");
- if (emitter_markers[i] == ARGUMENT_VALUE_MARKER) printf(":ARGUMENT ");
- if (emitter_markers[i] == OR_VALUE_MARKER) printf(":OR ");
- if (emitter_bracket_counts[i]) printf(":BRACKETS(%d) ", emitter_bracket_counts[i]);
+ { print_operand(&emitter_stack[i].op, FALSE); printf(" ");
+ if (emitter_stack[i].marker == FUNCTION_VALUE_MARKER) printf(":FUNCTION ");
+ if (emitter_stack[i].marker == ARGUMENT_VALUE_MARKER) printf(":ARGUMENT ");
+ if (emitter_stack[i].marker == OR_VALUE_MARKER) printf(":OR ");
+ if (emitter_stack[i].bracket_count) printf(":BRACKETS(%d) ", emitter_stack[i].bracket_count);
}
printf("\n");
}
- if (t.type == SUBOPEN_TT) return;
+ if (t->type == SUBOPEN_TT) return;
stack_size = 0;
while ((stack_size < emitter_sp) &&
- !emitter_markers[emitter_sp-stack_size-1] &&
- !emitter_bracket_counts[emitter_sp-stack_size-1])
+ !emitter_stack[emitter_sp-stack_size-1].marker &&
+ !emitter_stack[emitter_sp-stack_size-1].bracket_count)
stack_size++;
- if (t.type == SUBCLOSE_TT)
- { if (stack_size < emitter_sp && emitter_bracket_counts[emitter_sp-stack_size-1])
+ if (t->type == SUBCLOSE_TT)
+ { if (stack_size < emitter_sp && emitter_stack[emitter_sp-stack_size-1].bracket_count)
{ if (stack_size == 0)
{ error("No expression between brackets '(' and ')'");
- emitter_stack[emitter_sp] = zero_operand;
- emitter_markers[emitter_sp] = 0;
- emitter_bracket_counts[emitter_sp] = 0;
- ++emitter_sp;
+ ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+ emitter_stack[emitter_sp].op = zero_operand;
+ emitter_stack[emitter_sp].marker = 0;
+ emitter_stack[emitter_sp].bracket_count = 0;
+ emitter_sp++;
}
else if (stack_size < 1)
compiler_error("SR error: emitter stack empty in subexpression");
return;
}
- if (t.type != OP_TT)
- { emitter_markers[emitter_sp] = 0;
- emitter_bracket_counts[emitter_sp] = 0;
+ if (t->type != OP_TT)
+ {
+ ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+ emitter_stack[emitter_sp].marker = 0;
+ emitter_stack[emitter_sp].bracket_count = 0;
- if (emitter_sp == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
- if (!evaluate_term(t, &(emitter_stack[emitter_sp++])))
- compiler_error_named("Emit token error:", t.text);
+ if (!evaluate_term(t, &(emitter_stack[emitter_sp++].op)))
+ compiler_error_named("Emit token error:", t->text);
return;
}
call, since we ignore spurious leading commas in function argument lists)
with no intervening brackets. Function calls are variadic, so we don't
apply argument-separating commas. */
- if (t.value == COMMA_OP &&
+ if (t->value == COMMA_OP &&
stack_size < emitter_sp &&
- (emitter_markers[emitter_sp-stack_size-1] == ARGUMENT_VALUE_MARKER ||
- emitter_markers[emitter_sp-stack_size-1] == FUNCTION_VALUE_MARKER) &&
- !emitter_bracket_counts[emitter_sp-stack_size-1])
+ (emitter_stack[emitter_sp-stack_size-1].marker == ARGUMENT_VALUE_MARKER ||
+ emitter_stack[emitter_sp-stack_size-1].marker == FUNCTION_VALUE_MARKER) &&
+ !emitter_stack[emitter_sp-stack_size-1].bracket_count)
{ if (expr_trace_level >= 2)
printf("Treating comma as argument-separating\n");
return;
}
- if (t.value == OR_OP)
+ if (t->value == OR_OP)
return;
arity = 1;
- if (t.value == FCALL_OP)
+ if (t->value == FCALL_OP)
{ if (expr_trace_level >= 3)
{ printf("FCALL_OP finds marker stack: ");
- for (x=0; x<emitter_sp; x++) printf("%d ", emitter_markers[x]);
+ for (x=0; x<emitter_sp; x++) printf("%d ", emitter_stack[x].marker);
printf("\n");
}
- if (emitter_markers[emitter_sp-1] == ARGUMENT_VALUE_MARKER)
+ if (emitter_stack[emitter_sp-1].marker == ARGUMENT_VALUE_MARKER)
warning("Ignoring spurious trailing comma");
- while (emitter_markers[emitter_sp-arity] != FUNCTION_VALUE_MARKER)
+ while (emitter_stack[emitter_sp-arity].marker != FUNCTION_VALUE_MARKER)
{
if ((glulx_mode &&
- emitter_stack[emitter_sp-arity].type == SYSFUN_OT) ||
+ emitter_stack[emitter_sp-arity].op.type == SYSFUN_OT) ||
(!glulx_mode &&
- emitter_stack[emitter_sp-arity].type == VARIABLE_OT &&
- emitter_stack[emitter_sp-arity].value >= 256 &&
- emitter_stack[emitter_sp-arity].value < 288))
- { int index = emitter_stack[emitter_sp-arity].value;
+ emitter_stack[emitter_sp-arity].op.type == VARIABLE_OT &&
+ emitter_stack[emitter_sp-arity].op.value >= 256 &&
+ emitter_stack[emitter_sp-arity].op.value < 288))
+ { int index = emitter_stack[emitter_sp-arity].op.value;
if(!glulx_mode)
index -= 256;
if(index >= 0 && index < NUMBER_SYSTEM_FUNCTIONS)
error_named("System function name used as a value:", system_functions.keywords[index]);
else
compiler_error("Found unnamed system function used as a value");
- emitter_stack[emitter_sp-arity] = zero_operand;
+ emitter_stack[emitter_sp-arity].op = zero_operand;
}
++arity;
}
}
else
{ arity = 1;
- if (operators[t.value].usage == IN_U) arity = 2;
+ if (operators[t->value].usage == IN_U) arity = 2;
- if (operators[t.value].precedence == 3)
+ if (operators[t->value].precedence == 3)
{ arity = 2;
x = emitter_sp-1;
- if(!emitter_markers[x] && !emitter_bracket_counts[x])
- { for (--x; emitter_markers[x] == OR_VALUE_MARKER && !emitter_bracket_counts[x]; --x)
+ if(!emitter_stack[x].marker && !emitter_stack[x].bracket_count)
+ { for (--x; emitter_stack[x].marker == OR_VALUE_MARKER && !emitter_stack[x].bracket_count; --x)
{ ++arity;
++stack_size;
}
- for (;x >= 0 && !emitter_markers[x] && !emitter_bracket_counts[x]; --x)
+ for (;x >= 0 && !emitter_stack[x].marker && !emitter_stack[x].bracket_count; --x)
++stack_size;
}
}
if (arity > stack_size)
- { error_named("Missing operand for", t.text);
+ { error_named("Missing operand for", t->text);
while (arity > stack_size)
- { if (emitter_sp == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
- emitter_markers[emitter_sp] = 0;
- emitter_bracket_counts[emitter_sp] = 0;
- emitter_stack[emitter_sp] = zero_operand;
+ { ensure_memory_list_available(&emitter_stack_memlist, emitter_sp+1);
+ emitter_stack[emitter_sp].marker = 0;
+ emitter_stack[emitter_sp].bracket_count = 0;
+ emitter_stack[emitter_sp].op = zero_operand;
emitter_sp++;
stack_size++;
}
}
}
- /* pseudo-typecheck in 6.30 */
+ /* pseudo-typecheck in 6.30: catch an unqualified property name */
for (i = 1; i <= arity; i++)
{
- o1 = emitter_stack[emitter_sp - i];
- if (is_property_t(o1.symtype) ) {
- switch(t.value)
+ o1 = emitter_stack[emitter_sp - i].op;
+ if ((o1.symindex >= 0)
+ && is_property_t(symbols[o1.symindex].type)) {
+ switch(t->value)
{
case FCALL_OP:
case SETEQUALS_OP: case NOTEQUAL_OP:
case PROPERTY_OP:
if (i < arity) break;
case GE_OP: case LE_OP:
- if ((i < arity) && (o1.symflags & STAR_SFLAG)) break;
+ /* Direction properties "n_to", etc *are* compared
+ in some libraries. They have STAR_SFLAG to tell us
+ to skip the warning. */
+ if ((i < arity)
+ && (symbols[o1.symindex].flags & STAR_SFLAG)) break;
default:
warning("Property name in expression is not qualified by object");
}
switch(arity)
{ case 1:
- o1 = emitter_stack[emitter_sp - 1];
+ o1 = emitter_stack[emitter_sp - 1].op;
if ((o1.marker == 0) && is_constant_ot(o1.type))
- { switch(t.value)
+ { switch(t->value)
{ case UNARY_MINUS_OP: x = -o1.value; goto FoldConstant;
case ARTNOT_OP:
if (!glulx_mode)
break;
case 2:
- o1 = emitter_stack[emitter_sp - 2];
- o2 = emitter_stack[emitter_sp - 1];
+ o1 = emitter_stack[emitter_sp - 2].op;
+ o2 = emitter_stack[emitter_sp - 1].op;
if ((o1.marker == 0) && (o2.marker == 0)
&& is_constant_ot(o1.type) && is_constant_ot(o2.type))
ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value;
}
- switch(t.value)
+ switch(t->value)
{
case PLUS_OP: x = ov1 + ov2; goto FoldConstantC;
case MINUS_OP: x = ov1 - ov2; goto FoldConstantC;
if (ov2 == 0)
error("Division of constant by zero");
else
- if (t.value == DIVIDE_OP) {
+ if (t->value == DIVIDE_OP) {
if (ov2 < 0) {
ov1 = -ov1;
ov2 = -ov2;
}
}
+
+ /* We can also fold logical operations if they are certain
+ to short-circuit. The right-hand argument is skipped even
+ if it's non-constant or has side effects. */
+
+ if ((o1.marker == 0)
+ && is_constant_ot(o1.type)) {
+
+ if (t->value == LOGAND_OP && o1.value == 0)
+ {
+ x = 0;
+ goto FoldConstant;
+ }
+
+ if (t->value == LOGOR_OP && o1.value != 0)
+ {
+ x = 1;
+ goto FoldConstant;
+ }
+ }
}
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
op_node_number = ET_used++;
- if (op_node_number == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
- ET[op_node_number].operator_number = t.value;
+ ET[op_node_number].operator_number = t->value;
ET[op_node_number].up = -1;
ET[op_node_number].down = -1;
ET[op_node_number].right = -1;
if (expr_trace_level >= 3)
printf("i=%d, emitter_sp=%d, arity=%d, ETU=%d\n",
i, emitter_sp, arity, ET_used);
- if (emitter_stack[i].type == EXPRESSION_OT)
- operand_node_number = emitter_stack[i].value;
+ if (emitter_stack[i].op.type == EXPRESSION_OT)
+ operand_node_number = emitter_stack[i].op.value;
else
- { operand_node_number = ET_used++;
- if (operand_node_number == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+ {
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
+ operand_node_number = ET_used++;
ET[operand_node_number].down = -1;
- ET[operand_node_number].value = emitter_stack[i];
+ ET[operand_node_number].value = emitter_stack[i].op;
}
ET[operand_node_number].up = op_node_number;
ET[operand_node_number].right = -1;
emitter_sp = emitter_sp - arity + 1;
- emitter_stack[emitter_sp - 1].type = EXPRESSION_OT;
- emitter_stack[emitter_sp - 1].value = op_node_number;
+ emitter_stack[emitter_sp - 1].op.type = EXPRESSION_OT;
+ emitter_stack[emitter_sp - 1].op.value = op_node_number;
+ emitter_stack[emitter_sp - 1].op.marker = 0;
emitter_stack[emitter_sp - 1].marker = 0;
- emitter_markers[emitter_sp - 1] = 0;
- emitter_bracket_counts[emitter_sp - 1] = 0;
+ emitter_stack[emitter_sp - 1].bracket_count = 0;
/* Remove the marker for the brackets implied by operator precedence */
remove_bracket_layer_from_emitter_stack();
{ char folding_error[40];
int32 ov1 = (o1.value >= 0x8000) ? (o1.value - 0x10000) : o1.value;
int32 ov2 = (o2.value >= 0x8000) ? (o2.value - 0x10000) : o2.value;
- switch(t.value)
+ switch(t->value)
{
case PLUS_OP:
sprintf(folding_error, "%d + %d = %d", ov1, ov2, x);
if (!glulx_mode) {
if (x<256)
- emitter_stack[emitter_sp - 1].type = SHORT_CONSTANT_OT;
- else emitter_stack[emitter_sp - 1].type = LONG_CONSTANT_OT;
+ emitter_stack[emitter_sp - 1].op.type = SHORT_CONSTANT_OT;
+ else emitter_stack[emitter_sp - 1].op.type = LONG_CONSTANT_OT;
}
else {
if (x == 0)
- emitter_stack[emitter_sp - 1].type = ZEROCONSTANT_OT;
+ emitter_stack[emitter_sp - 1].op.type = ZEROCONSTANT_OT;
else if (x >= -128 && x <= 127)
- emitter_stack[emitter_sp - 1].type = BYTECONSTANT_OT;
+ emitter_stack[emitter_sp - 1].op.type = BYTECONSTANT_OT;
else if (x >= -32768 && x <= 32767)
- emitter_stack[emitter_sp - 1].type = HALFCONSTANT_OT;
+ emitter_stack[emitter_sp - 1].op.type = HALFCONSTANT_OT;
else
- emitter_stack[emitter_sp - 1].type = CONSTANT_OT;
+ emitter_stack[emitter_sp - 1].op.type = CONSTANT_OT;
}
- emitter_stack[emitter_sp - 1].value = x;
+ emitter_stack[emitter_sp - 1].op.value = x;
+ emitter_stack[emitter_sp - 1].op.marker = 0;
emitter_stack[emitter_sp - 1].marker = 0;
- emitter_markers[emitter_sp - 1] = 0;
- emitter_bracket_counts[emitter_sp - 1] = 0;
+ emitter_stack[emitter_sp - 1].bracket_count = 0;
if (expr_trace_level >= 2)
{ printf("Folding constant to: ");
- print_operand(emitter_stack[emitter_sp - 1]);
+ print_operand(&emitter_stack[emitter_sp - 1].op, FALSE);
printf("\n");
}
for (j=0; j<2*depth+2; j++) printf(" ");
if (ET[n].down == -1)
- { print_operand(ET[n].value);
- if (annotate && (ET[n].value.marker != 0))
- printf(" [%s]", describe_mv(ET[n].value.marker));
+ { print_operand(&ET[n].value, annotate);
printf("\n");
}
else
extern void show_tree(assembly_operand AO, int annotate)
{ if (AO.type == EXPRESSION_OT) show_node(AO.value, 0, annotate);
else
- { printf("Constant: "); print_operand(AO);
- if (annotate && (AO.marker != 0))
- printf(" [%s]", describe_mv(AO.marker));
+ { printf("Constant: "); print_operand(&AO, annotate);
printf("\n");
}
}
(etc) to delete the ~~ operator from the tree. Since this is
depth first, the ~~ being deleted has no ~~s beneath it, which
- is important to make "negate_condition" work. */
+ is important to make "negate_condition" work.
+
+ We also do the check for (x <= y or z) here. This must be done
+ before negate_condition.
+ */
int i;
+ if (ET[n].operator_number == LE_OP || ET[n].operator_number == GE_OP) {
+ if (ET[n].down != -1
+ && ET[ET[n].down].right != -1
+ && ET[ET[ET[n].down].right].right != -1) {
+ if (ET[n].operator_number == LE_OP)
+ warning("The behavior of (<= or) may be unexpected.");
+ else
+ warning("The behavior of (>= or) may be unexpected.");
+ }
+ }
+
if (ET[n].right != -1) delete_negations(ET[n].right, context);
if (ET[n].down == -1) return;
delete_negations(ET[n].down, context);
if (ET[n].down == -1)
{ if (context==CONDITION_CONTEXT)
- { new = ET_used++;
- if (new == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+ {
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
+ new = ET_used++;
ET[new] = ET[n];
ET[n].down = new; ET[n].operator_number = NONZERO_OP;
ET[new].up = n; ET[new].right = -1;
default:
if (context != CONDITION_CONTEXT) break;
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
new = ET_used++;
- if (new == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
ET[new] = ET[n];
ET[n].down = new; ET[n].operator_number = NONZERO_OP;
ET[new].up = n; ET[new].right = -1;
|| ET[fnaddr].value.value == INDIRECT_SYSF
|| ET[fnaddr].value.value == GLK_SYSF))) {
if (etoken_num_children(pn) > (unsigned int)(opnum == FCALL_OP ? 4:3)) {
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
new = ET_used++;
- if (new == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
ET[new] = ET[n];
ET[n].down = new;
ET[n].operator_number = PUSH_OP;
if (AO.type != EXPRESSION_OT)
{ if (context != CONDITION_CONTEXT) return AO;
+ ensure_memory_list_available(&ET_memlist, ET_used+1);
n = ET_used++;
- if (n == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
ET[n].down = -1;
ET[n].up = -1;
ET[n].right = -1;
/* --- Shift-reduce parser ------------------------------------------------- */
static int sr_sp;
-static token_data *sr_stack;
+static token_data *sr_stack; /* Allocated to sr_sp */
+static memory_list sr_stack_memlist;
extern assembly_operand parse_expression(int context)
{
previous_token.type = ENDEXP_TT;
previous_token.value = 0;
+ ensure_memory_list_available(&sr_stack_memlist, 1);
sr_sp = 1;
sr_stack[0] = previous_token;
return AO;
}
- AO = emitter_stack[0];
+ AO = emitter_stack[0].op;
if (AO.type == EXPRESSION_OT)
{ if (expr_trace_level >= 3)
{ printf("Tree before lvalue checking:\n");
ET[AO.value].up = -1;
}
else {
- if ((context != CONSTANT_CONTEXT) && is_property_t(AO.symtype)
+ if ((context != CONSTANT_CONTEXT)
+ && (AO.symindex >= 0)
+ && is_property_t(symbols[AO.symindex].type)
&& (arrow_allowed) && (!bare_prop_allowed))
warning("Bare property name found. \"self.prop\" intended?");
}
return(AO);
}
- switch(find_prec(a,b))
+ switch(find_prec(&a,&b))
{
case e5: /* Associativity error */
error_named("Brackets mandatory to clarify order of:",
case LOWER_P:
case EQUAL_P:
- if (sr_sp == MAX_EXPRESSION_NODES)
- memoryerror("MAX_EXPRESSION_NODES", MAX_EXPRESSION_NODES);
+ ensure_memory_list_available(&sr_stack_memlist, sr_sp+1);
sr_stack[sr_sp++] = b;
switch(b.type)
{
case SUBOPEN_TT:
if (sr_sp >= 2 && sr_stack[sr_sp-2].type == OP_TT && sr_stack[sr_sp-2].value == FCALL_OP)
- mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, b);
+ mark_top_of_emitter_stack(FUNCTION_VALUE_MARKER, &b);
else
add_bracket_layer_to_emitter_stack(0);
break;
case OR_OP:
if (sr_stack[sr_sp-2].type == OP_TT &&
operators[sr_stack[sr_sp-2].value].precedence == 3)
- mark_top_of_emitter_stack(OR_VALUE_MARKER, b);
+ mark_top_of_emitter_stack(OR_VALUE_MARKER, &b);
else
{ error("'or' not between values to the right of a condition");
/* Convert to + for error recovery purposes */
if (shallowest_open_bracket_index > 0 &&
sr_stack[shallowest_open_bracket_index-1].type == OP_TT &&
sr_stack[shallowest_open_bracket_index-1].value == FCALL_OP)
- { mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, b);
+ { mark_top_of_emitter_stack(ARGUMENT_VALUE_MARKER, &b);
break;
}
/* Non-argument-separating commas get treated like any other operator; we fall through to the default case. */
case GREATER_P:
do
{ pop = sr_stack[sr_sp - 1];
- emit_token(pop);
+ emit_token(&pop);
sr_sp--;
- } while (find_prec(sr_stack[sr_sp-1], pop) != LOWER_P);
+ } while (find_prec(&sr_stack[sr_sp-1], &pop) != LOWER_P);
break;
case e1: /* Missing operand error */
{ int i;
/* make_operands(); */
make_lexical_interface_tables();
- for (i=0;i<32;i++) system_function_usage[i] = 0;
+ for (i=0; i<NUMBER_SYSTEM_FUNCTIONS; i++)
+ system_function_usage[i] = 0;
+
+ ET = NULL;
+ emitter_stack = NULL;
+ sr_stack = NULL;
}
extern void expressp_begin_pass(void)
}
extern void expressp_allocate_arrays(void)
-{ ET = my_calloc(sizeof(expression_tree_node), MAX_EXPRESSION_NODES,
+{
+ initialise_memory_list(&ET_memlist,
+ sizeof(expression_tree_node), 100, (void**)&ET,
"expression parse trees");
- emitter_markers = my_calloc(sizeof(int), MAX_EXPRESSION_NODES,
- "emitter markers");
- emitter_bracket_counts = my_calloc(sizeof(int), MAX_EXPRESSION_NODES,
- "emitter bracket layer counts");
- emitter_stack = my_calloc(sizeof(assembly_operand), MAX_EXPRESSION_NODES,
- "emitter stack");
- sr_stack = my_calloc(sizeof(token_data), MAX_EXPRESSION_NODES,
+
+ initialise_memory_list(&emitter_stack_memlist,
+ sizeof(emitterstackinfo), 100, (void**)&emitter_stack,
+ "expression stack");
+
+ initialise_memory_list(&sr_stack_memlist,
+ sizeof(token_data), 100, (void**)&sr_stack,
"shift-reduce parser stack");
}
extern void expressp_free_arrays(void)
-{ my_free(&ET, "expression parse trees");
- my_free(&emitter_markers, "emitter markers");
- my_free(&emitter_bracket_counts, "emitter bracket layer counts");
- my_free(&emitter_stack, "emitter stack");
- my_free(&sr_stack, "shift-reduce parser stack");
+{
+ deallocate_memory_list(&ET_memlist);
+
+ deallocate_memory_list(&emitter_stack_memlist);
+
+ deallocate_memory_list(&sr_stack_memlist);
}
/* ========================================================================= */
/* routines in "inform.c", since they are tied up with ICL */
/* settings and are very host OS-dependent. */
/* */
-/* 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 */
/* level is only concerned with file names and handles. */
/* ------------------------------------------------------------------------- */
-FileId *InputFiles=NULL; /* Ids for all the source files */
-static char *filename_storage, /* Translated filenames */
- *filename_storage_p;
-static int filename_storage_left;
+FileId *InputFiles=NULL; /* Ids for all the source files
+ Allocated to total_files */
+static memory_list InputFiles_memlist;
/* ------------------------------------------------------------------------- */
/* When emitting debug information, we won't have addresses of routines, */
static debug_backpatch_accumulator array_backpatch_accumulator;
static debug_backpatch_accumulator grammar_backpatch_accumulator;
-/* ------------------------------------------------------------------------- */
-/* File handles and names for temporary files. */
-/* ------------------------------------------------------------------------- */
-
-FILE *Temp1_fp=NULL, *Temp2_fp=NULL, *Temp3_fp=NULL;
-char Temp1_Name[PATHLEN], Temp2_Name[PATHLEN], Temp3_Name[PATHLEN];
-
/* ------------------------------------------------------------------------- */
/* Opening and closing source code files */
/* ------------------------------------------------------------------------- */
int x = 0;
FILE *handle;
- if (total_files == MAX_SOURCE_FILES)
- memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
+ ensure_memory_list_available(&InputFiles_memlist, total_files+1);
do
{ x = translate_in_filename(x, name, filename_given, same_directory_flag,
handle = fopen(name,"r");
} while ((handle == NULL) && (x != 0));
- if (filename_storage_left <= (int)strlen(name))
- memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
-
- filename_storage_left -= strlen(name)+1;
- strcpy(filename_storage_p, name);
- InputFiles[total_files].filename = filename_storage_p;
-
- filename_storage_p += strlen(name)+1;
+ InputFiles[total_files].filename = my_malloc(strlen(name)+1, "filename storage");
+ strcpy(InputFiles[total_files].filename, name);
if (debugfile_switch)
{ debug_file_printf("<source index=\"%d\">", total_files);
fatalerror_named("Couldn't open source file", name);
InputFiles[total_files].is_input = TRUE;
+ InputFiles[total_files].initial_buffering = TRUE;
- if (line_trace_level > 0) printf("\nOpening file \"%s\"\n",name);
+ if (files_trace_setting > 0)
+ printf("Opening file \"%s\"\n",name);
total_files++;
total_input_files++;
{
if (InputFiles[file_number-1].handle == NULL) return;
- /* Close this file. */
+ /* Close this file. But keep the InputFiles entry around, including
+ its filename. */
if (ferror(InputFiles[file_number-1].handle))
fatalerror_named("I/O failure: couldn't read from source file",
InputFiles[file_number-1].handle = NULL;
- if (line_trace_level > 0) printf("\nClosing file\n");
+ if (files_trace_setting > 0) {
+ char *str = (InputFiles[file_number-1].initial_buffering ? " (in initial buffering)" : "");
+ printf("Closing file \"%s\"%s\n", InputFiles[file_number-1].filename, str);
+ }
}
extern void close_all_source(void)
name = filename; /* no translation */
- if (total_files == MAX_SOURCE_FILES)
- memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
-
- if (filename_storage_left <= (int)strlen(name))
- memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
-
- filename_storage_left -= strlen(name)+1;
- strcpy(filename_storage_p, name);
- InputFiles[total_files].filename = filename_storage_p;
+ ensure_memory_list_available(&InputFiles_memlist, total_files+1);
- filename_storage_p += strlen(name)+1;
+ InputFiles[total_files].filename = my_malloc(strlen(name)+1, "filename storage");
+ strcpy(InputFiles[total_files].filename, name);
if (debugfile_switch)
{ debug_file_printf("<source index=\"%d\">", total_files);
InputFiles[total_files].handle = NULL;
InputFiles[total_files].is_input = FALSE;
+ InputFiles[total_files].initial_buffering = FALSE;
total_files++;
current_origsource_file = total_files;
}
static void output_file_z(void)
-{ FILE *fin=NULL; char new_name[PATHLEN];
+{ char new_name[PATHLEN];
int32 length, blanks=0, size, i, j, offset;
uint32 code_length, size_before_code, next_cons_check;
int use_function;
/* (2) Output the compiled code area. */
- if (temporary_files_switch)
- { fclose(Temp2_fp);
- Temp2_fp = NULL;
- fin=fopen(Temp2_Name,"rb");
- if (fin==NULL)
- fatalerror("I/O failure: couldn't reopen temporary file 2");
- }
-
if (!OMIT_UNUSED_ROUTINES) {
/* This is the old-fashioned case, which is easy. All of zcode_area
(zmachine_pc bytes) will be output. next_cons_check will be
for (i=0; i<zcode_backpatch_size; i=i+3)
{ int long_flag = TRUE;
offset
- = 256*read_byte_from_memory_block(&zcode_backpatch_table, i+1)
- + read_byte_from_memory_block(&zcode_backpatch_table, i+2);
+ = 256*zcode_backpatch_table[i+1]
+ + zcode_backpatch_table[i+2];
backpatch_error_flag = FALSE;
backpatch_marker
- = read_byte_from_memory_block(&zcode_backpatch_table, i);
+ = zcode_backpatch_table[i];
if (backpatch_marker >= 0x80) long_flag = FALSE;
backpatch_marker &= 0x7f;
offset = offset + (backpatch_marker/32)*0x10000;
while (j<offset) {
if (!use_function) {
while (j<offset && j<next_cons_check) {
- /* get dummy value */
- ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
j++;
}
}
else {
while (j<offset && j<next_cons_check) {
size++;
- sf_put((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
+ sf_put(zcode_area[j]);
j++;
}
}
}
if (long_flag)
- { int32 v = (temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j);
- v = 256*v + ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j+1));
+ { int32 v = zcode_area[j];
+ v = 256*v + (zcode_area[j+1]);
j += 2;
if (use_function) {
v = backpatch_value(v);
}
}
else
- { int32 v = (temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j);
+ { int32 v = zcode_area[j];
j++;
if (use_function) {
v = backpatch_value(v);
while (j<offset) {
if (!use_function) {
while (j<offset && j<next_cons_check) {
- /* get dummy value */
- ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
j++;
}
}
else {
while (j<offset && j<next_cons_check) {
size++;
- sf_put((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
+ sf_put(zcode_area[j]);
j++;
}
}
next_cons_check = df_next_function_iterate(&use_function);
}
- if (temporary_files_switch)
- { if (ferror(fin))
- fatalerror("I/O failure: couldn't read from temporary file 2");
- fclose(fin);
- fin = NULL;
- }
-
if (size_before_code + code_length != size)
compiler_error("Code output length did not match");
/* (4) Output the static strings area. */
- if (temporary_files_switch)
- { fclose(Temp1_fp);
- Temp1_fp = NULL;
- fin=fopen(Temp1_Name,"rb");
- if (fin==NULL)
- fatalerror("I/O failure: couldn't reopen temporary file 1");
- for (i=0; i<static_strings_extent; i++) sf_put(fgetc(fin));
- if (ferror(fin))
- fatalerror("I/O failure: couldn't read from temporary file 1");
- fclose(fin);
- fin = NULL;
- remove(Temp1_Name); remove(Temp2_Name);
- }
- else
- for (i=0; i<static_strings_extent; i++) {
- sf_put(read_byte_from_memory_block(&static_strings_area,i));
+ for (i=0; i<static_strings_extent; i++) {
+ sf_put(static_strings_area[i]);
size++;
- }
+ }
/* (5) Output the linking data table (in the case of a module). */
- if (temporary_files_switch)
- { if (module_switch)
- { fclose(Temp3_fp);
- Temp3_fp = NULL;
- fin=fopen(Temp3_Name,"rb");
- if (fin==NULL)
- fatalerror("I/O failure: couldn't reopen temporary file 3");
- for (j=0; j<link_data_size; j++) sf_put(fgetc(fin));
- if (ferror(fin))
- fatalerror("I/O failure: couldn't read from temporary file 3");
- fclose(fin);
- fin = NULL;
- remove(Temp3_Name);
- }
- }
- else
- if (module_switch)
- for (i=0; i<link_data_size; i++)
- sf_put(read_byte_from_memory_block(&link_data_area,i));
+ if (module_switch)
+ for (i=0; i<link_data_size; i++)
+ sf_put(link_data_area[i]);
if (module_switch)
{ for (i=0; i<zcode_backpatch_size; i++)
- sf_put(read_byte_from_memory_block(&zcode_backpatch_table, i));
+ sf_put(zcode_backpatch_table[i]);
for (i=0; i<zmachine_backpatch_size; i++)
- sf_put(read_byte_from_memory_block(&zmachine_backpatch_table, i));
+ sf_put(zmachine_backpatch_table[i]);
}
/* (6) Output null bytes to reach a multiple of 0.5K. */
}
static void output_file_g(void)
-{ FILE *fin=NULL; char new_name[PATHLEN];
+{ char new_name[PATHLEN];
int32 size, i, j, offset;
int32 VersionNum;
uint32 code_length, size_before_code, next_cons_check;
if (uses_float_features) {
VersionNum = 0x00030102;
}
+ if (uses_extundo_features) {
+ VersionNum = 0x00030103;
+ }
/* And check if the user has requested a specific version. */
if (requested_glulx_version) {
/* (2) Output the compiled code area. */
- if (temporary_files_switch)
- { fclose(Temp2_fp);
- Temp2_fp = NULL;
- fin=fopen(Temp2_Name,"rb");
- if (fin==NULL)
- fatalerror("I/O failure: couldn't reopen temporary file 2");
- }
-
if (!OMIT_UNUSED_ROUTINES) {
/* This is the old-fashioned case, which is easy. All of zcode_area
(zmachine_pc bytes) will be output. next_cons_check will be
int data_len;
int32 v;
offset =
- (read_byte_from_memory_block(&zcode_backpatch_table, i+2) << 24)
- | (read_byte_from_memory_block(&zcode_backpatch_table, i+3) << 16)
- | (read_byte_from_memory_block(&zcode_backpatch_table, i+4) << 8)
- | (read_byte_from_memory_block(&zcode_backpatch_table, i+5));
+ (zcode_backpatch_table[i+2] << 24)
+ | (zcode_backpatch_table[i+3] << 16)
+ | (zcode_backpatch_table[i+4] << 8)
+ | (zcode_backpatch_table[i+5]);
backpatch_error_flag = FALSE;
backpatch_marker =
- read_byte_from_memory_block(&zcode_backpatch_table, i);
+ zcode_backpatch_table[i];
data_len =
- read_byte_from_memory_block(&zcode_backpatch_table, i+1);
+ zcode_backpatch_table[i+1];
/* All code up until the next backpatch marker gets flushed out
as-is. (Unless we're in a stripped-out function.) */
while (j<offset) {
if (!use_function) {
while (j<offset && j<next_cons_check) {
- /* get dummy value */
- ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
j++;
}
}
else {
while (j<offset && j<next_cons_check) {
size++;
- sf_put((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
+ sf_put(zcode_area[j]);
j++;
}
}
switch (data_len) {
case 4:
- v = ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
- v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j+1));
- v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j+2));
- v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j+3));
+ v = (zcode_area[j]);
+ v = (v << 8) | (zcode_area[j+1]);
+ v = (v << 8) | (zcode_area[j+2]);
+ v = (v << 8) | (zcode_area[j+3]);
j += 4;
if (!use_function)
break;
break;
case 2:
- v = ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
- v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j+1));
+ v = (zcode_area[j]);
+ v = (v << 8) | (zcode_area[j+1]);
j += 2;
if (!use_function)
break;
break;
case 1:
- v = ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
+ v = (zcode_area[j]);
j += 1;
if (!use_function)
break;
while (j<offset) {
if (!use_function) {
while (j<offset && j<next_cons_check) {
- /* get dummy value */
- ((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
j++;
}
}
else {
while (j<offset && j<next_cons_check) {
size++;
- sf_put((temporary_files_switch)?fgetc(fin):
- read_byte_from_memory_block(&zcode_area, j));
+ sf_put(zcode_area[j]);
j++;
}
}
next_cons_check = df_next_function_iterate(&use_function);
}
- if (temporary_files_switch)
- { if (ferror(fin))
- fatalerror("I/O failure: couldn't read from temporary file 2");
- fclose(fin);
- fin = NULL;
- }
-
if (size_before_code + code_length != size)
compiler_error("Code output length did not match");
/* (4) Output the static strings area. */
- if (temporary_files_switch) {
- fseek(Temp1_fp, 0, SEEK_SET);
- }
{
int32 ix, lx;
int ch, jx, curbyte, bx;
jx = 0;
curbyte = 0;
while (!done) {
- if (temporary_files_switch)
- ch = fgetc(Temp1_fp);
- else
- ch = read_byte_from_memory_block(&static_strings_area, ix);
+ ch = static_strings_area[ix];
ix++;
if (ix > static_strings_extent || ch < 0)
compiler_error("Read too much not-yet-compressed text.");
int32 val, ix, jx;
for (ix=0, jx=0; ix<staticarray_backpatch_size; ix += 5) {
backpatch_error_flag = FALSE;
- backpatch_marker = read_byte_from_memory_block(&staticarray_backpatch_table, ix);
+ backpatch_marker = staticarray_backpatch_table[ix];
/* datalen is always 4 for array backpatching */
offset =
- (read_byte_from_memory_block(&staticarray_backpatch_table, ix+1) << 24)
- | (read_byte_from_memory_block(&staticarray_backpatch_table, ix+2) << 16)
- | (read_byte_from_memory_block(&staticarray_backpatch_table, ix+3) << 8)
- | (read_byte_from_memory_block(&staticarray_backpatch_table, ix+4));
+ (staticarray_backpatch_table[ix+1] << 24)
+ | (staticarray_backpatch_table[ix+2] << 16)
+ | (staticarray_backpatch_table[ix+3] << 8)
+ | (staticarray_backpatch_table[ix+4]);
while (jx<offset) {
sf_put(static_array_area[jx]);
size++;
}
extern void write_debug_optional_identifier(int32 symbol_index)
-{ if (stypes[symbol_index] != ROUTINE_T)
+{ if (symbols[symbol_index].type != ROUTINE_T)
{ compiler_error
("Attempt to write a replaceable identifier for a non-routine");
}
- if (replacement_debug_backpatch_positions[symbol_index].valid)
+ if (symbol_debug_info[symbol_index].replacement_backpatch_pos.valid)
{ if (fsetpos
(Debug_fp,
- &replacement_debug_backpatch_positions[symbol_index].position))
+ &symbol_debug_info[symbol_index].replacement_backpatch_pos.position))
{ fatalerror("I/O failure: can't seek in debugging information file");
}
debug_file_printf
("<identifier artificial=\"true\">%s "
"(superseded replacement)</identifier>",
- symbs[symbol_index]);
+ symbols[symbol_index].name);
if (fseek(Debug_fp, 0L, SEEK_END))
{ fatalerror("I/O failure: can't seek in debugging information file");
}
}
fgetpos
- (Debug_fp, &replacement_debug_backpatch_positions[symbol_index].position);
- replacement_debug_backpatch_positions[symbol_index].valid = TRUE;
- debug_file_printf("<identifier>%s</identifier>", symbs[symbol_index]);
+ (Debug_fp, &symbol_debug_info[symbol_index].replacement_backpatch_pos.position);
+ symbol_debug_info[symbol_index].replacement_backpatch_pos.valid = TRUE;
+ debug_file_printf("<identifier>%s</identifier>", symbols[symbol_index].name);
/* Space for: artificial="true" (superseded replacement) */
debug_file_printf(" ");
}
extern void write_debug_symbol_backpatch(int32 symbol_index)
-{ if (symbol_debug_backpatch_positions[symbol_index].valid) {
+{ if (symbol_debug_info[symbol_index].backpatch_pos.valid) {
compiler_error("Symbol entry incorrectly reused in debug information "
"file backpatching");
}
- fgetpos(Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position);
- symbol_debug_backpatch_positions[symbol_index].valid = TRUE;
+ fgetpos(Debug_fp, &symbol_debug_info[symbol_index].backpatch_pos.position);
+ symbol_debug_info[symbol_index].backpatch_pos.valid = TRUE;
/* Reserve space for up to 10 digits plus a negative sign. */
debug_file_printf("*BACKPATCH*");
}
extern void write_debug_symbol_optional_backpatch(int32 symbol_index)
-{ if (symbol_debug_backpatch_positions[symbol_index].valid) {
+{ if (symbol_debug_info[symbol_index].backpatch_pos.valid) {
compiler_error("Symbol entry incorrectly reused in debug information "
"file backpatching");
}
so that we'll be in the same case as above if the symbol is eventually
defined. */
debug_file_printf("<value>");
- fgetpos(Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position);
- symbol_debug_backpatch_positions[symbol_index].valid = TRUE;
+ fgetpos(Debug_fp, &symbol_debug_info[symbol_index].backpatch_pos.position);
+ symbol_debug_info[symbol_index].backpatch_pos.valid = TRUE;
debug_file_printf("*BACKPATCH*</value>");
}
}
extern void write_debug_undef(int32 symbol_index)
-{ if (!symbol_debug_backpatch_positions[symbol_index].valid)
+{ if (!symbol_debug_info[symbol_index].backpatch_pos.valid)
{ compiler_error
("Attempt to erase debugging information never written or since "
"erased");
}
- if (stypes[symbol_index] != CONSTANT_T)
+ if (symbols[symbol_index].type != CONSTANT_T)
{ compiler_error
("Attempt to erase debugging information for a non-constant "
"because of an #undef");
}
if (fsetpos
- (Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position))
+ (Debug_fp, &symbol_debug_info[symbol_index].backpatch_pos.position))
{ fatalerror("I/O failure: can't seek in debugging information file");
}
/* There are 7 characters in ``<value>''. */
/* Overwrite: <value>*BACKPATCH*</value> */
debug_file_printf(" ");
nullify_debug_file_position
- (&symbol_debug_backpatch_positions[symbol_index]);
+ (&symbol_debug_info[symbol_index].backpatch_pos);
if (fseek(Debug_fp, 0L, SEEK_END))
{ fatalerror("I/O failure: can't seek in debugging information file");
}
static void apply_debug_information_symbol_backpatches()
{ int backpatch_symbol;
for (backpatch_symbol = no_symbols; backpatch_symbol--;)
- { if (symbol_debug_backpatch_positions[backpatch_symbol].valid)
+ { if (symbol_debug_info[backpatch_symbol].backpatch_pos.valid)
{ if (fsetpos(Debug_fp,
- &symbol_debug_backpatch_positions
- [backpatch_symbol].position))
+ &symbol_debug_info[backpatch_symbol].backpatch_pos.position))
{ fatalerror
("I/O failure: can't seek in debugging information file");
}
- debug_file_printf("%11d", svals[backpatch_symbol]);
+ debug_file_printf("%11d", symbols[backpatch_symbol].value);
}
}
}
close_debug_file();
}
-/* ------------------------------------------------------------------------- */
-/* Temporary storage files: */
-/* */
-/* Temp file 1 is used to hold the static strings area, as compiled */
-/* 2 to hold compiled routines of Z-code */
-/* 3 to hold the link data table (but only for modules) */
-/* */
-/* (Though annoying, this procedure typically saves about 200K of memory, */
-/* an important point for Amiga and sub-386 PC users of Inform) */
-/* ------------------------------------------------------------------------- */
-
-extern void open_temporary_files(void)
-{ translate_temp_filename(1);
- Temp1_fp=fopen(Temp1_Name,"wb");
- if (Temp1_fp==NULL) fatalerror_named("Couldn't open temporary file 1",
- Temp1_Name);
- translate_temp_filename(2);
- Temp2_fp=fopen(Temp2_Name,"wb");
- if (Temp2_fp==NULL) fatalerror_named("Couldn't open temporary file 2",
- Temp2_Name);
-
- if (!module_switch) return;
- translate_temp_filename(3);
- Temp3_fp=fopen(Temp3_Name,"wb");
- if (Temp3_fp==NULL) fatalerror_named("Couldn't open temporary file 3",
- Temp3_Name);
-}
-
-extern void check_temp_files(void)
-{
- if (ferror(Temp1_fp))
- fatalerror("I/O failure: couldn't write to temporary file 1");
- if (ferror(Temp2_fp))
- fatalerror("I/O failure: couldn't write to temporary file 2");
- if (module_switch && ferror(Temp3_fp))
- fatalerror("I/O failure: couldn't write to temporary file 3");
-}
-
-extern void remove_temp_files(void)
-{ if (Temp1_fp != NULL) fclose(Temp1_fp);
- Temp1_fp = NULL;
- if (Temp2_fp != NULL) fclose(Temp2_fp);
- Temp2_fp = NULL;
- remove(Temp1_Name); remove(Temp2_Name);
- if (module_switch)
- { if (Temp3_fp != NULL) fclose(Temp3_fp);
- Temp3_fp = NULL;
- remove(Temp3_Name);
- }
-}
-
/* ========================================================================= */
/* Data structure management routines */
/* ------------------------------------------------------------------------- */
extern void files_begin_pass(void)
{ total_chars_read=0;
- if (temporary_files_switch)
- open_temporary_files();
}
static void initialise_accumulator
}
extern void files_allocate_arrays(void)
-{ filename_storage = my_malloc(MAX_SOURCE_FILES*64, "filename storage");
- filename_storage_p = filename_storage;
- filename_storage_left = MAX_SOURCE_FILES*64;
- InputFiles = my_malloc(MAX_SOURCE_FILES*sizeof(FileId),
+{
+ initialise_memory_list(&InputFiles_memlist,
+ sizeof(FileId), 16, (void**)&InputFiles,
"input file storage");
if (debugfile_switch)
{ if (glulx_mode)
}
extern void files_free_arrays(void)
-{ my_free(&filename_storage, "filename storage");
- my_free(&InputFiles, "input file storage");
+{
+ int ix;
+ for (ix=0; ix<total_files; ix++)
+ {
+ my_free(&InputFiles[ix].filename, "filename storage");
+ }
+ deallocate_memory_list(&InputFiles_memlist);
+
if (debugfile_switch)
{ if (!glulx_mode)
{ tear_down_accumulator(&object_backpatch_accumulator);
/* ------------------------------------------------------------------------- */
/* Header file for Inform: Z-machine ("Infocom" format) compiler */
/* */
-/* Inform 6.35 */
+/* Inform 6.40 */
/* */
/* This header file and the others making up the Inform source code are */
-/* copyright (c) Graham Nelson 1993 - 2021 */
-/* */
-/* This file is part of Inform. */
+/* 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 */
/* You should have received a copy of the GNU General Public License */
/* along with Inform. If not, see https://gnu.org/licenses/ */
/* */
-/* For detailed documentation on how this program internally works, and */
-/* how to port it to a new environment, see the Technical Manual. */
-/* */
/* *** To compile this program in one of the existing ports, you must */
/* at least change the machine definition (on the next page). */
/* In most cases no other work will be needed. *** */
/* ------------------------------------------------------------------------- */
/* For releases, set to the release date in the form "1st January 2000" */
-#define RELEASE_DATE "22nd May 2021"
-#define RELEASE_NUMBER 1635
+#define RELEASE_DATE "in development"
+#define RELEASE_NUMBER 1640
#define GLULX_RELEASE_NUMBER 38
#define MODULE_VERSION_NUMBER 1
#define VNUMBER RELEASE_NUMBER
/* #define VMS - for VAX or ALPHA under DEC C, but not VAX C */
/* */
/* In most cases executables are already available at */
-/* http://www.ifarchive.org/, and these are sometimes enhanced with */
+/* https://www.ifarchive.org/, and these are sometimes enhanced with */
/* e.g. windowed interfaces whose source is not archived with the */
/* main Inform source.] */
/* */
/* out a block of definitions like those below.) */
/* ------------------------------------------------------------------------- */
-/* #define UNIX */
-
/* ------------------------------------------------------------------------- */
/* The first task is to include the ANSI header files, and typedef */
/* suitable 32-bit integer types. */
/* 2. Some miscellaneous #define options (set if the constant is */
/* defined, otherwise not set): */
/* */
-/* USE_TEMPORARY_FILES - use scratch files for workspace, not memory, */
-/* by default */
/* PROMPT_INPUT - prompt input (don't use Unix-style command line) */
/* TIME_UNAVAILABLE - don't use ANSI time routines to work out today's */
/* date */
/* HAS_REALPATH - the POSIX realpath() function is available to */
/* find the absolute path to a file */
/* */
-/* 3. An estimate of the typical amount of memory likely to be free */
-/* should be given in DEFAULT_MEMORY_SIZE. */
-/* For most modern machines, HUGE_SIZE is the appropriate setting, but */
-/* some older micros may benefit from SMALL_SIZE. */
+/* 3. This was DEFAULT_MEMORY_SIZE, now withdrawn. */
/* ------------------------------------------------------------------------- */
-#define LARGE_SIZE 1
-#define SMALL_SIZE 2
-#define HUGE_SIZE 3
-
/* ------------------------------------------------------------------------- */
/* 4. Filenaming definitions: */
/* */
/* is set without STANDARD_DIRECTORIES, as then Inform may */
/* overwrite its source with object code. */
/* */
-/* 5. Filenames (or code related to filenames) for the three temporary */
-/* files. These only exist during compilation (and only if -F1 is set). */
-/* Temporary_Name is the body of a filename to use */
-/* (if you don't set this, it becomes "Inftemp") and Temporary_Directory */
-/* is the directory path for the files to go in (which can be altered on */
-/* the command line). On some multi-tasking OSs these filenames ought to */
-/* include a number uniquely identifying the process: to indicate this, */
-/* define INCLUDE_TASK_ID and provide some code... */
-/* */
-/* #define INCLUDE_TASK_ID */
-/* #ifdef INFORM_FILE */
-/* static int32 unique_task_id(void) */
-/* { ...some code returning your task ID... */
-/* } */
-/* #endif */
+/* 5. Filenames (or code related to filenames) for temporary files. */
+/* These included Temporary_Name, Temporary_Directory, and */
+/* INCLUDE_TASK_ID. These options have been removed, and are listed here */
+/* only for people who might ask "what happened to 5?" */
/* */
/* 6. Any other definitions specific to the OS or machine. */
/* (In particular DEFAULT_ERROR_FORMAT is 0 on most machines and 1 on PCs; */
#ifdef AMIGA
/* 1 */
#define MACHINE_STRING "Amiga"
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '/'
-/* 5 */
-#define __USE_SYSBASE
-#include <proto/exec.h>
-#define INCLUDE_TASK_ID
-#define Temporary_Directory "T:"
-#ifdef MAIN_INFORM_FILE
-static int32 unique_task_id(void)
-{ return (int32)FindTask(NULL);
-}
-#endif
#endif
/* ------------------------------------------------------------------------- */
/* ARCHIMEDES block: Acorn/RISC OS settings */
#define MACHINE_STRING "RISC OS"
/* 2 */
#define CHAR_IS_UNSIGNED
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '.'
#define STANDARD_DIRECTORIES
#define NO_FILE_EXTENSIONS
#define Source_Directory "inform"
#define ICL_Directory "ICL"
-/* 5 */
-#define ENABLE_TEMPORARY_PATH
-#define Temporary_Directory "ram:"
/* 6 */
#define ARC_THROWBACK
#endif
#ifdef ATARIST
/* 1 */
#define MACHINE_STRING "Atari ST"
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '/'
-/* 5 */
-#ifndef TOSFS
-#define Temporary_Directory "/tmp"
-#define INCLUDE_TASK_ID
-#ifdef MAIN_INFORM_FILE
-static int32 unique_task_id(void)
-{ return (int32)getpid();
-}
-#endif
-#endif
#endif
/* ------------------------------------------------------------------------- */
/* BEOS block */
#ifdef BEOS
/* 1 */
#define MACHINE_STRING "BeOS"
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '/'
#define FILE_EXTENSIONS
-/* 5 */
-#define Temporary_Directory "/tmp"
#endif
/* ------------------------------------------------------------------------- */
/* LINUX block */
#define MACHINE_STRING "Linux"
/* 2 */
#define HAS_REALPATH
-/* 3 */
-#define DEFAULT_MEMORY_SIZE HUGE_SIZE
/* 4 */
#define FN_SEP '/'
-/* 5 */
-#define Temporary_Directory "/tmp"
/* 6 */
#define PATHLEN 8192
+#if defined(__STDC__) && (__STDC_VERSION__ >= 201112L)
+#define USE_C11_TIME_API
+#endif
#endif
/* ------------------------------------------------------------------------- */
/* Macintosh block */
#define PROMPT_INPUT
#endif
#endif
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP ':'
#ifdef MAC_MPW
#define MACHINE_STRING "OS/2"
/* 2 */
#define CHAR_IS_UNSIGNED
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '/'
#endif
#define MACHINE_STRING "MacOS"
/* 2 */
#define HAS_REALPATH
-/* 3 */
-#define DEFAULT_MEMORY_SIZE HUGE_SIZE
/* 4 */
#define FN_SEP '/'
-/* 5 */
-#define Temporary_Directory "/tmp"
-#define INCLUDE_TASK_ID
-#define _POSIX_C_SOURCE 199506L
-#define _XOPEN_SOURCE 500
-#ifdef MAIN_INFORM_FILE
-#include <sys/types.h>
-#include <unistd.h>
-static int32 unique_task_id(void)
-{ return (int32)getpid();
-}
-#endif
/* 6 */
#define PATHLEN 8192
+#if defined(__STDC__) && (__STDC_VERSION__ >= 201112L)
+#define USE_C11_TIME_API
+#endif
#endif
/* ------------------------------------------------------------------------- */
/* PC and PC_QUICKC block */
#ifdef PC
/* 1 */
#define MACHINE_STRING "PC"
-/* 2 */
-#define USE_TEMPORARY_FILES
-/* 3 */
-#ifdef PC_QUICKC
-#define DEFAULT_MEMORY_SIZE SMALL_SIZE
-#else
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
-#endif
/* 4 */
#define FN_SEP '\\'
/* 6 */
#define MACHINE_STRING "Win32"
/* 2 */
#define HAS_REALPATH
-/* 3 */
-#define DEFAULT_MEMORY_SIZE HUGE_SIZE
/* 4 */
#define FN_SEP '\\'
/* 6 */
#define DEFAULT_ERROR_FORMAT 1
#define PATHLEN 512
-#ifdef _MSC_VER /* Microsoft Visual C++ */
-#define snprintf _snprintf
-#define isnan _isnan
-#define isinf(x) (!_isnan(x) && !_finite(x))
+#if _MSC_VER >= 1920 /* Visual C++ 2019 */
+#define USE_C11_TIME_API
#endif
#endif
/* ------------------------------------------------------------------------- */
#endif
/* 2 */
#define HAS_REALPATH
-/* 3 */
-#define DEFAULT_MEMORY_SIZE HUGE_SIZE
/* 4 */
#define FN_SEP '/'
-/* 5 */
-#define PATHLEN 512
-#define Temporary_Directory "/tmp"
-#define INCLUDE_TASK_ID
-#ifdef MAIN_INFORM_FILE
-#include <unistd.h>
-static int32 unique_task_id(void)
-{ return (int32)getpid();
-}
-#endif
#endif
/* ------------------------------------------------------------------------- */
/* VMS (Dec VAX and Alpha) block */
#endif
/* 2 */
#define CHAR_IS_UNSIGNED
-/* 3 */
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
/* 4 */
#define FN_SEP '/'
#define Code_Extension ".zip"
#ifndef Module_Directory
#define Module_Directory "modules"
#endif
-#ifndef Temporary_Directory
-#define Temporary_Directory ""
-#endif
#ifndef ICL_Directory
#define ICL_Directory ""
#endif
#ifndef Module_Directory
#define Module_Directory ""
#endif
-#ifndef Temporary_Directory
-#define Temporary_Directory ""
-#endif
#ifndef ICL_Directory
#define ICL_Directory ""
#endif
#define PATHLEN 128
#endif
-#ifndef Temporary_File
-#define Temporary_File "Inftemp"
-#endif
-
#ifndef DEFAULT_ERROR_FORMAT
#define DEFAULT_ERROR_FORMAT 0
#endif
-#ifndef DEFAULT_MEMORY_SIZE
-#define DEFAULT_MEMORY_SIZE LARGE_SIZE
-#endif
-
#ifndef CHAR_IS_UNSIGNED
typedef unsigned char uchar;
#else
#endif
/* ------------------------------------------------------------------------- */
-/* A macro (rather than constant) definition: */
+/* subtract_pointers() measures an address difference in bytes. This is */
+/* a macro. */
+/* We also declare some memory functions for PC_QUICKC. */
/* ------------------------------------------------------------------------- */
#ifdef PC_QUICKC
#define subtract_pointers(p1,p2) (((char *) p1)-((char *) p2))
#endif
+
+/* ------------------------------------------------------------------------- */
+/* Definitions for time measurement. TIMEVALUE is a type; TIMEVALUE_NOW() */
+/* sets it; TIMEVALUE_DIFFERENCE() determines a difference in seconds, */
+/* as a float. */
+/* Modern platforms should support timespec_get() or clock_gettime(). To */
+/* use timespec_get(), #define USE_C11_TIME_API. To use clock_gettime(), */
+/* #define USE_POSIX_TIME_API. To use the old implementation using */
+/* time(), #define USE_OLD_TIME_API. This can only measure in integer */
+/* second counts, but it's better than waiting for gnomon. */
+/* ------------------------------------------------------------------------- */
+
+#if !defined(USE_C11_TIME_API) && !defined(USE_POSIX_TIME_API) && !defined(USE_OLD_TIME_API)
+#define USE_OLD_TIME_API
+#endif
+
+#if defined(USE_OLD_TIME_API)
+ #define TIMEVALUE time_t
+ #define TIMEVALUE_NOW(t) (*t) = time(0)
+ #define TIMEVALUE_DIFFERENCE(begt, endt) (float)(*(endt) - *(begt))
+#elif defined(USE_C11_TIME_API)
+ #define TIMEVALUE struct timespec
+ #define TIMEVALUE_NOW(t) timespec_get((t), TIME_UTC)
+ #define TIMEVALUE_DIFFERENCE(begt, endt) ((float)((endt)->tv_sec - (begt)->tv_sec) + (float)((endt)->tv_nsec - (begt)->tv_nsec) / 1000000000.0F)
+#elif defined(USE_POSIX_TIME_API)
+ #define TIMEVALUE struct timespec
+ #define TIMEVALUE_NOW(t) clock_gettime(CLOCK_REALTIME, (t))
+ #define TIMEVALUE_DIFFERENCE(begt, endt) ((float)((endt)->tv_sec - (begt)->tv_sec) + (float)((endt)->tv_nsec - (begt)->tv_nsec) / 1000000000.0F)
+#endif
+
/* ------------------------------------------------------------------------- */
/* SEEK_SET is a constant which should be defined in the ANSI header files */
/* but which is not present in some implementations: it's used as a */
/* Structure definitions (there are a few others local to files) */
/* ------------------------------------------------------------------------- */
+/* A memory list is a sequential array of items. The list grows as
+ necessary, but it is *not* sparse.
+ This can optionally maintain an external pointer (of any type) which
+ also refers to the allocated array. The external pointer will always
+ have the same value as data.
+ (Note: the external pointer must itself have a stable location, because
+ we keep a pointer *to* it. It cannot live in another memory list or
+ realloced array. Most of our memory lists refer to global or static
+ variables, so that's fine.)
+*/
+typedef struct memory_list_s
+{
+ char *whatfor; /* must be a static string */
+ void *data; /* allocated array of count*itemsize bytes */
+ void **extpointer; /* pointer to keep in sync */
+ size_t itemsize; /* item size in bytes */
+ size_t count; /* number of items allocated */
+} memory_list;
+
+typedef struct identstruct_s
+{
+ char text[MAX_IDENTIFIER_LENGTH+1];
+} identstruct;
+
typedef struct assembly_operand_t
-{ int type;
+{ int type; /* ?_OT value */
int32 value;
- int symtype; /* 6.30 */
- int symflags; /* 6.30 */
- int marker;
+ int symindex; /* index in symbols array, if derived from a symbol */
+ int marker; /* ?_MV value */
} assembly_operand;
-#define INITAOTV(aop, typ, val) ((aop)->type=(typ), (aop)->value=(val), (aop)->marker=0, (aop)->symtype=0, (aop)->symflags=0)
+#define INITAOTV(aop, typ, val) ((aop)->type=(typ), (aop)->value=(val), (aop)->marker=0, (aop)->symindex=-1)
#define INITAOT(aop, typ) INITAOTV(aop, typ, 0)
#define INITAO(aop) INITAOTV(aop, 0, 0)
-#define MAX_LINES_PER_VERB 32
+typedef struct variableinfo_s {
+ int32 token; /* Symbol table index for variable name */
+ int usage; /* TRUE if referred to */
+} variableinfo;
+
typedef struct verbt {
int lines;
- int l[MAX_LINES_PER_VERB];
+ int *l; /* alloced array */
+ int size; /* allocated size of l */
} verbt;
+typedef struct actioninfo_s {
+ int32 symbol; /* The symbol table index of the action name */
+ int32 byte_offset; /* The (byte) offset in the Z-machine code area of
+ the ...Sub routine */
+} actioninfo;
+
+/* Information about an object class. */
+typedef struct classinfo_s {
+ /* The number of the prototype-object for this class */
+ int object_number;
+ /* The offset of properties block for this class (always an offset inside the properties table) */
+ int32 begins_at;
+ /* Class name symbol number */
+ int32 symbol;
+} classinfo;
+
+/* Common property information. */
+typedef struct commonpropinfo_s {
+ int32 default_value; /* Common property default value */
+ int is_long; /* "Long" means "never write a 1-byte value to
+ this property", and is an obsolete feature:
+ since Inform 5 all properties have been "long" */
+ int is_additive; /* "Additive" means that values accumulate rather
+ than erase each other during class inheritance */
+} commonpropinfo;
+
+/* Property entry record (Z). */
typedef struct prop {
uchar l, num;
assembly_operand ao[32];
} prop;
+/* Properties and attributes of the object currently being constructed (Z). */
/* Only one of this object. */
typedef struct fpropt {
uchar atts[6];
int l;
prop pp[64];
+ int32 symbol; /* name symbol or 0 */
} fpropt;
+/* Constructed object (Z). */
typedef struct objecttz {
uchar atts[6];
int parent, next, child;
int propsize;
+ int32 symbol; /* name symbol or 0 */
} objecttz;
+/* Property entry record (G). */
typedef struct propg {
int num;
int continuation;
int32 datalen;
} propg;
+/* Properties and attributes of the object currently being constructed (G). */
/* Only one of this object. */
typedef struct fproptg {
uchar atts[MAX_NUM_ATTR_BYTES];
int numprops;
- propg *props;
+ propg *props; /* allocated to numprops */
+ memory_list props_memlist;
int propdatasize;
- assembly_operand *propdata;
+ assembly_operand *propdata; /* allocated to propdatasize */
+ memory_list propdata_memlist;
int32 finalpropaddr;
+ /* It's safe to use memory_lists in this object because there's just
+ one and it's static. */
+ int32 symbol; /* name symbol or 0 */
} fproptg;
+/* Constructed object (G). */
typedef struct objecttg {
/* attributes are stored in a separate array */
int32 shortname;
int32 parent, next, child;
int32 propaddr;
int32 propsize;
+ int32 symbol; /* name symbol or 0 */
} objecttg;
+typedef struct abbreviation_s {
+ int value;
+ int quality;
+ int freq;
+} abbreviation;
+
typedef struct maybe_file_position_S
{ int valid;
fpos_t position;
int32 orig_beg_char_number;
} debug_location_beginning;
+#define MAX_KEYWORD_GROUP_SIZE (119)
+
typedef struct keyword_group_s
-{ char *keywords[120];
+{ char *keywords[MAX_KEYWORD_GROUP_SIZE+1]; /* empty-string-terminated */
int change_token_type;
int enabled;
int case_sensitive;
} keyword_group;
-typedef struct token_data_s
-{ char *text;
- int32 value; /* ###-long */
- int type;
- int symtype; /* 6.30 */
- int symflags; /* 6.30 */
- int marker;
+typedef struct lexeme_data_s {
+ char *text; /* points at lextexts array */
+ int32 value;
+ int type; /* a *_TT value */
debug_location location;
+ int lextext; /* index of text string in lextexts */
+ int context; /* lexical context used to interpret this token */
+} lexeme_data;
+
+typedef struct token_data_s {
+ char *text;
+ int32 value;
+ int type; /* a *_TT value */
+ int symindex;
+ int symtype;
+ int symflags;
+ int marker;
} token_data;
+typedef struct symbolinfo_s {
+ char *name; /* Points into a symbol_name_space_chunk */
+ int32 value;
+ int marker; /* ?_MV value */
+ brief_location line;
+ unsigned int flags; /* ?_SFLAGS bitmask */
+ uchar type; /* ?_T value */
+ int next_entry; /* Linked list for symbol hash table */
+} symbolinfo;
+
+typedef struct symboldebuginfo_s {
+ maybe_file_position backpatch_pos;
+ maybe_file_position replacement_backpatch_pos;
+} symboldebuginfo;
+
+typedef struct arrayinfo_s {
+ int32 symbol; /* index in symbols[] */
+ int size; /* length of array */
+ int type; /* BYTE_ARRAY, WORD_ARRAY, etc */
+ int loc; /* true for static, false for dynamic (regular) arrays */
+} arrayinfo;
+
+typedef struct labelinfo_s {
+ int32 offset; /* Offset (zmachine_pc) value */
+ int32 symbol; /* Symbol numbers if defined in source */
+ int next; /* For linked list */
+ int prev; /* For linked list */
+} labelinfo;
+
+typedef struct sequencepointinfo_s {
+ int label; /* Label number */
+ debug_location location; /* Source code reference (used for making
+ debugging file) */
+} sequencepointinfo;
+
typedef struct FileId_s /* Source code file identifier: */
{ char *filename; /* The filename (after translation) */
FILE *handle; /* Handle of file (when open), or
parsing? If not, this is an
origsource filename (and handle
is NULL). */
+ int initial_buffering; /* Are we still in the initial
+ begin_buffering_file() call? */
} FileId;
typedef struct ErrorPosition_s
int32 orig_char;
} ErrorPosition;
-/* A memory block can hold at most ALLOC_CHUNK_SIZE * 72: */
-
-extern int ALLOC_CHUNK_SIZE;
-
-typedef struct memory_block_s
-{ int chunks;
- int extent_of_last;
- uchar *chunk[72];
- int write_pos;
-} memory_block;
-
/* This serves for both Z-code and Glulx instructions. Glulx doesn't use
the text, store_variable_number, branch_label_number, or branch_flag
fields. */
int store_variable_number;
int32 branch_label_number;
int branch_flag;
- char *text;
+ char *text; /* if set, generally points to token_text */
int operand_count;
assembly_operand operand[8];
} assembly_instruction;
#define FAKE_ACTION_T 11
#define STATIC_ARRAY_T 12
+/* These types never occur in the symbol table; they exist only as
+ type-checking requirements. */
+#define STRING_REQ_T 13
+#define DICT_WORD_REQ_T 14
+
/* ------------------------------------------------------------------------- */
/* Statusline_flag values */
/* ------------------------------------------------------------------------- */
#define WARNING_DK 34
#define TERMINATING_DK 35
#define STATIC_DK 36
+#define INDIVIDUAL_DK 37
/* Index numbers into the keyword group "trace_keywords" (see "lexer.c") */
#define oddeven_packing_SC 58
-#define grammar_table_SC 59 /* Glulx-only */
-#define dictionary_table_SC 60 /* Glulx-only */
+#define grammar_table_SC 59
+#define dictionary_table_SC 60
#define dynam_string_table_SC 61 /* Glulx-only */
#define STRCTX_SYMBOL 9 /* prop/attr/etc names */
#define STRCTX_INFIX 10 /* text printed in asterisk traces */
+/* ------------------------------------------------------------------------- */
+/* Bit-flags applying to the execution_never_reaches_here variable. */
+/* Note that if any flags are set, UNREACHABLE is set, so we can easily */
+/* test "if (execution_never_reaches_here)..." */
+/* ------------------------------------------------------------------------- */
+
+#define EXECSTATE_REACHABLE 0 /* compile normally */
+#define EXECSTATE_UNREACHABLE 1 /* execution cannot reach this line */
+#define EXECSTATE_ENTIRE 2 /* execution cannot reach this entire
+ statement or code block */
+#define EXECSTATE_NOWARN 4 /* do not print a warning about unreachable
+ code */
+
/* ========================================================================= */
/* Initialisation extern definitions */
/* */
/* Extern definitions for "arrays" */
/* ------------------------------------------------------------------------- */
+#define MAX_ZCODE_GLOBAL_VARS (240)
+
extern int no_globals, no_arrays;
extern int dynamic_array_area_size;
-extern int *dynamic_array_area;
+extern uchar *dynamic_array_area;
+extern memory_list dynamic_array_area_memlist;
extern int static_array_area_size;
-extern int *static_array_area;
+extern uchar *static_array_area;
+extern memory_list static_array_area_memlist;
extern int32 *global_initial_value;
-extern int32 *array_symbols;
-extern int *array_sizes, *array_types, *array_locs;
+extern arrayinfo *arrays;
extern void make_global(int array_flag, int name_only);
extern void set_variable_value(int i, int32 v);
/* Extern definitions for "asm" */
/* ------------------------------------------------------------------------- */
-extern memory_block zcode_area;
+extern uchar *zcode_area;
+extern memory_list zcode_area_memlist;
extern int32 zmachine_pc;
extern int32 no_instructions;
extern int sequence_point_follows;
extern int uses_unicode_features, uses_memheap_features,
- uses_acceleration_features, uses_float_features;
+ uses_acceleration_features, uses_float_features,
+ uses_extundo_features;
extern debug_location statement_debug_location;
extern int execution_never_reaches_here;
-extern int *variable_usage;
+extern variableinfo *variables;
+extern memory_list variables_memlist;
extern int next_label, no_sequence_points;
-extern int32 *variable_tokens;
extern assembly_instruction AI;
extern int32 *named_routine_symbols;
-extern void print_operand(assembly_operand o);
+extern void print_operand(const assembly_operand *o, int annotate);
extern char *variable_name(int32 i);
extern void set_constant_ot(assembly_operand *AO);
extern int is_constant_ot(int otval);
extern int is_variable_ot(int otval);
-extern void assemblez_instruction(assembly_instruction *a);
-extern void assembleg_instruction(assembly_instruction *a);
+extern void assemblez_instruction(const assembly_instruction *a);
+extern void assembleg_instruction(const assembly_instruction *a);
extern void assemble_label_no(int n);
+extern int assemble_forward_label_no(int n);
extern void assemble_jump(int n);
extern void define_symbol_label(int symbol);
extern int32 assemble_routine_header(int no_locals, int debug_flag,
/* Extern definitions for "bpatch" */
/* ------------------------------------------------------------------------- */
-extern memory_block zcode_backpatch_table, staticarray_backpatch_table,
- zmachine_backpatch_table;
+extern uchar *staticarray_backpatch_table;
+extern memory_list staticarray_backpatch_table_memlist;
+extern uchar *zmachine_backpatch_table;
+extern memory_list zmachine_backpatch_table_memlist;
+extern uchar *zcode_backpatch_table;
+extern memory_list zcode_backpatch_table_memlist;
extern int32 zcode_backpatch_size, staticarray_backpatch_size,
zmachine_backpatch_size;
extern int backpatch_marker, backpatch_error_flag;
/* Extern definitions for "errors" */
/* ------------------------------------------------------------------------- */
+#define FORERRORS_SIZE (512)
extern char *forerrors_buff;
extern int forerrors_pointer;
extern int no_errors, no_warnings, no_suppressed_warnings,
extern void fatalerror(char *s) NORETURN;
extern void fatalerror_named(char *s1, char *s2) NORETURN;
extern void memory_out_error(int32 size, int32 howmany, char *name) NORETURN;
-extern void memoryerror(char *s, int32 size) NORETURN;
+extern void error_max_dynamic_strings(int index);
+extern void error_max_abbreviations(int index);
extern void error(char *s);
extern void error_named(char *s1, char *s2);
extern void error_numbered(char *s1, int val);
extern void warning(char *s);
extern void warning_numbered(char *s1, int val);
extern void warning_named(char *s1, char *s2);
+extern void symtype_warning(char *context, char *name, char *type, char *wanttype);
extern void dbnu_warning(char *type, char *name, brief_location report_line);
extern void uncalled_routine_warning(char *type, char *name, brief_location report_line);
extern void obsolete_warning(char *s1);
extern int glulx_system_constant_list[];
extern int32 value_of_system_constant(int t);
+extern char *name_of_system_constant(int t);
extern void clear_expression_space(void);
extern void show_tree(assembly_operand AO, int annotate);
extern assembly_operand parse_expression(int context);
extern int total_input_files;
extern FileId *InputFiles;
-extern FILE *Temp1_fp, *Temp2_fp, *Temp3_fp;
-extern char Temp1_Name[], Temp2_Name[], Temp3_Name[];
extern int32 total_chars_read;
-extern void open_temporary_files(void);
-extern void check_temp_files(void);
-extern void remove_temp_files(void);
-
extern void open_transcript_file(char *what_of);
extern void write_to_transcript_file(char *text, int linetype);
extern void close_transcript_file(void);
OBJECT_BYTE_LENGTH, DICT_ENTRY_BYTE_LENGTH, DICT_ENTRY_FLAG_POS;
extern int32 MAXINTWORD;
-extern int asm_trace_level, line_trace_level, expr_trace_level,
+extern int asm_trace_level, expr_trace_level,
linker_trace_level, tokens_trace_level;
extern int
- bothpasses_switch, concise_switch,
- economy_switch, frequencies_switch,
- ignore_switches_switch, listobjects_switch, debugfile_switch,
- listing_switch, memout_switch, printprops_switch,
- offsets_switch, percentages_switch, obsolete_switch,
+ concise_switch,
+ economy_switch, frequencies_setting,
+ ignore_switches_switch, debugfile_switch,
+ files_trace_setting, memout_switch, printprops_switch,
+ printactions_switch,
+ obsolete_switch, optabbrevs_trace_setting,
transcript_switch, statistics_switch, optimise_switch,
version_set_switch, nowarnings_switch, hash_switch,
- memory_map_switch, module_switch, temporary_files_switch,
+ memory_map_setting, module_switch,
define_DEBUG_switch, define_USE_MODULES_switch, define_INFIX_switch,
- runtime_error_checking_switch;
+ runtime_error_checking_switch,
+ list_verbs_setting, list_dict_setting, list_objects_setting,
+ list_symbols_setting;
extern int oddeven_packing_switch;
extern int32 requested_glulx_version;
extern int error_format, store_the_text, asm_trace_setting,
+ expr_trace_setting, linker_trace_setting, tokens_trace_setting,
+ bpatch_trace_setting, symdef_trace_setting,
double_space_setting, trace_fns_setting, character_set_setting,
character_set_unicode;
extern void translate_out_filename(char *new_name, char *old_name);
extern int translate_link_filename(int last_value,
char *new_name, char *old_name);
-extern void translate_temp_filename(int i);
#ifdef ARCHIMEDES
extern char *riscos_file_type(void);
extern int dont_enter_into_symbol_table;
extern int return_sp_as_variable;
extern int next_token_begins_syntax_line;
-extern char **local_variable_texts;
+extern identstruct *local_variable_names;
extern int32 token_value;
extern int token_type;
extern void discard_token_location(debug_location_beginning beginning);
extern debug_locations get_token_location_end(debug_location_beginning beginning);
-extern void describe_token(token_data t);
+extern void describe_token_triple(const char *text, int32 value, int type);
+/* The describe_token() macro works on both token_data and lexeme_data structs. */
+#define describe_token(t) describe_token_triple((t)->text, (t)->value, (t)->type)
extern void construct_local_variable_tables(void);
extern void declare_systemfile(void);
extern void put_token_back(void);
extern void get_next_token(void);
+extern void release_token_texts(void);
extern void restart_lexer(char *lexical_source, char *name);
extern keyword_group directives, statements, segment_markers,
/* Extern definitions for "linker" */
/* ------------------------------------------------------------------------- */
-extern memory_block link_data_area;
+extern uchar *link_data_area;
extern int32 link_data_size;
extern char current_module_filename[];
/* Extern definitions for "memory" */
/* ------------------------------------------------------------------------- */
-extern int32 malloced_bytes;
+extern size_t malloced_bytes;
-extern int MAX_QTEXT_SIZE, MAX_SYMBOLS, HASH_TAB_SIZE, MAX_DICT_ENTRIES,
- MAX_OBJECTS, MAX_ACTIONS, MAX_ADJECTIVES, MAX_ABBREVS,
- MAX_STATIC_DATA, MAX_PROP_TABLE_SIZE, SYMBOLS_CHUNK_SIZE,
- MAX_EXPRESSION_NODES, MAX_LABELS, MAX_LINESPACE,
- MAX_LOW_STRINGS, MAX_CLASSES, MAX_VERBS,
- MAX_VERBSPACE, MAX_ARRAYS, MAX_INCLUSION_DEPTH,
- MAX_SOURCE_FILES, MAX_DYNAMIC_STRINGS;
+extern int HASH_TAB_SIZE,
+ MAX_ABBREVS,
+ MAX_DYNAMIC_STRINGS;
-extern int32 MAX_STATIC_STRINGS, MAX_ZCODE_SIZE, MAX_LINK_DATA_SIZE,
- MAX_TRANSCRIPT_SIZE, MAX_INDIV_PROP_TABLE_SIZE,
- MAX_NUM_STATIC_STRINGS, MAX_UNICODE_CHARS,
- MAX_STACK_SIZE, MEMORY_MAP_EXTENSION;
+extern int32 MAX_STACK_SIZE, MEMORY_MAP_EXTENSION;
-extern int32 MAX_OBJ_PROP_COUNT, MAX_OBJ_PROP_TABLE_SIZE;
-extern int MAX_LOCAL_VARIABLES, MAX_GLOBAL_VARIABLES;
+extern int MAX_LOCAL_VARIABLES;
extern int DICT_WORD_SIZE, DICT_CHAR_SIZE, DICT_WORD_BYTES;
extern int ZCODE_HEADER_EXT_WORDS, ZCODE_HEADER_FLAGS_3;
+extern int ZCODE_LESS_DICT_DATA;
extern int NUM_ATTR_BYTES, GLULX_OBJECT_EXT_BYTES;
extern int WARN_UNUSED_ROUTINES, OMIT_UNUSED_ROUTINES;
+extern int STRIP_UNREACHABLE_LABELS;
extern int TRANSCRIPT_FORMAT;
/* These macros define offsets that depend on the value of NUM_ATTR_BYTES.
#define GOBJFIELD_SIBLING() (5+((NUM_ATTR_BYTES)/4))
#define GOBJFIELD_CHILD() (6+((NUM_ATTR_BYTES)/4))
-extern void *my_malloc(int32 size, char *whatfor);
-extern void my_realloc(void *pointer, int32 oldsize, int32 size,
+extern void *my_malloc(size_t size, char *whatfor);
+extern void my_realloc(void *pointer, size_t oldsize, size_t size,
char *whatfor);
-extern void *my_calloc(int32 size, int32 howmany, char *whatfor);
-extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
- int32 howmany, char *whatfor);
+extern void *my_calloc(size_t size, size_t howmany, char *whatfor);
+extern void my_recalloc(void *pointer, size_t size, size_t oldhowmany,
+ size_t howmany, char *whatfor);
extern void my_free(void *pointer, char *whatitwas);
-extern void set_memory_sizes(int size_flag);
+extern void set_memory_sizes(void);
extern void adjust_memory_sizes(void);
extern void memory_command(char *command);
extern void print_memory_usage(void);
-extern void initialise_memory_block(memory_block *MB);
-extern void deallocate_memory_block(memory_block *MB);
-extern int read_byte_from_memory_block(memory_block *MB, int32 index);
-extern void write_byte_to_memory_block(memory_block *MB,
- int32 index, int value);
+extern void initialise_memory_list(memory_list *ML, size_t itemsize, size_t initalloc, void **extpointer, char *whatfor);
+extern void deallocate_memory_list(memory_list *ML);
+extern void ensure_memory_list_available(memory_list *ML, size_t count);
/* ------------------------------------------------------------------------- */
/* Extern definitions for "objects" */
extern int no_individual_properties;
extern int individuals_length;
extern uchar *individuals_table;
+extern memory_list individuals_table_memlist;
extern int no_classes, no_objects;
extern objecttz *objectsz;
+extern memory_list objectsz_memlist;
extern objecttg *objectsg;
extern uchar *objectatts;
-extern int *class_object_numbers;
-extern int32 *class_begins_at;
+extern classinfo *class_info;
+extern memory_list class_info_memlist;
-extern int32 *prop_default_value;
-extern int *prop_is_long;
-extern int *prop_is_additive;
-extern char *properties_table;
+extern commonpropinfo *commonprops;
+extern uchar *properties_table;
+extern memory_list properties_table_memlist;
extern int properties_table_size;
extern void make_attribute(void);
extern int no_named_constants;
extern int no_symbols;
-extern int32 **symbs;
-extern int32 *svals;
-extern int *smarks;
-extern brief_location *slines;
-extern int *sflags;
-#ifdef VAX
- extern char *stypes;
-#else
- extern signed char *stypes;
-#endif
-extern maybe_file_position *symbol_debug_backpatch_positions;
-extern maybe_file_position *replacement_debug_backpatch_positions;
+extern symbolinfo *symbols;
+extern symboldebuginfo *symbol_debug_info;
extern int32 *individual_name_strings;
extern int32 *attribute_name_strings;
extern int32 *action_name_strings;
extern char *typename(int type);
extern int hash_code_from_string(char *p);
extern int strcmpcis(char *p, char *q);
+extern int get_symbol_index(char *p);
extern int symbol_index(char *lexeme_text, int hashcode);
extern void end_symbol_scope(int k);
extern void describe_symbol(int k);
extern void list_symbols(int level);
extern void assign_marked_symbol(int index, int marker, int32 value, int type);
extern void assign_symbol(int index, int32 value, int type);
+extern void check_warn_symbol_type(const assembly_operand *AO, int wanttype, int wanttype2, char *label);
+extern void check_warn_symbol_has_metaclass(const assembly_operand *AO, char *context);
extern void issue_unused_warnings(void);
+extern void issue_debug_symbol_warnings(void);
extern void add_config_symbol_definition(char *symbol, int32 value);
extern void add_symbol_replacement_mapping(int original, int renamed);
extern int find_symbol_replacement(int *value);
/* Extern definitions for "text" */
/* ------------------------------------------------------------------------- */
-extern uchar *low_strings, *low_strings_top;
-extern char *all_text, *all_text_top;
+extern uchar *translated_text;
+
+extern uchar *low_strings;
+extern int32 low_strings_top;
extern int no_abbreviations;
extern int abbrevs_lookup_table_made, is_abbreviation;
extern uchar *abbreviations_at;
-extern int *abbrev_values;
-extern int *abbrev_quality;
-extern int *abbrev_freqs;
+extern abbreviation *abbreviations;
extern int32 total_chars_trans, total_bytes_trans,
zchars_trans_in_last_string;
extern int put_strings_in_low_memory;
extern int dict_entries;
-extern uchar *dictionary, *dictionary_top;
+extern uchar *dictionary;
+extern int32 dictionary_top;
extern int *final_dict_order;
-extern memory_block static_strings_area;
+extern uchar *static_strings_area;
+extern memory_list static_strings_area_memlist;
extern int32 static_strings_extent;
/* And now, a great many declarations for dealing with Glulx string
typedef struct unicode_usage_s unicode_usage_t;
struct unicode_usage_s {
int32 ch;
- unicode_usage_t *next;
+ int next; /* index in unicode_usage_entries of next */
};
extern unicode_usage_t *unicode_usage_entries;
int type;
union {
int branch[2];
- unsigned char ch;
+ uchar ch;
int val;
} u;
int depth;
/* end of the Glulx string compression stuff */
extern void ao_free_arrays(void);
+extern void extract_all_text(void);
extern int32 compile_string(char *b, int strctx);
-extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx);
+extern int32 translate_text(int32 p_limit, char *s_text, int strctx);
extern void optimise_abbreviations(void);
extern void make_abbreviation(char *text);
-extern void show_dictionary(void);
+extern void show_dictionary(int level);
extern void word_to_ascii(uchar *p, char *result);
+extern void print_dict_word(int node);
extern void write_dictionary_to_transcript(void);
extern void sort_dictionary(void);
extern void dictionary_prepare(char *dword, uchar *optresult);
extern void compile_initial_routine(void);
extern assembly_operand veneer_routine(int code);
+extern char *veneer_routine_name(int code);
extern void compile_veneer(void);
/* ------------------------------------------------------------------------- */
extern verbt *Inform_verbs;
extern uchar *grammar_lines;
extern int32 grammar_lines_top;
-extern int32 *action_byte_offset,
- *grammar_token_routine,
+extern actioninfo *actions;
+extern memory_list actions_memlist;
+extern int32 *grammar_token_routine,
*adjectives;
extern void find_the_actions(void);
/* "inform" : The top level of Inform: switches, pathnames, filenaming */
/* conventions, ICL (Inform Command Line) files, main */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
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");
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 */
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);
}
}
- 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 (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 (DICT_WORD_SIZE > MAX_DICT_WORD_SIZE) {
DICT_WORD_SIZE = MAX_DICT_WORD_SIZE;
warning_numbered(
/* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */
}
- if (MAX_ADJECTIVES > 255) {
- MAX_ADJECTIVES = 255;
- warning("MAX_ADJECTIVES cannot exceed 255; resetting to 255");
- /* Only used under Grammar__Version 1, which is obsolete. */
- }
-
/* Set up a few more variables that depend on the above values */
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 {
MAX_ABBREVS = 64;
}
}
- else {
- if (MAX_DYNAMIC_STRINGS > 100) {
- MAX_DYNAMIC_STRINGS = 100;
- warning("MAX_DYNAMIC_STRINGS cannot exceed 100; resetting to 100");
- /* This is because they are specified in text literals like "@00",
- with two digits. */
- }
- }
}
/* ------------------------------------------------------------------------- */
/* 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 */
+ linker_trace_level, /* linker tracing: 0 to 4 levels */
+ 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 */
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 */
+ linker_trace_setting, /* $!LINKER: initial value of
+ linker_trace_level */
+ 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;
+ linker_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
compression_switch = TRUE;
glulx_mode = FALSE;
requested_glulx_version = 0;
+
+ /* These aren't switches, but for clarity we reset them too. */
+ asm_trace_level = 0;
+ expr_trace_level = 0;
+ linker_trace_level = 0;
+ tokens_trace_level = 0;
}
/* ------------------------------------------------------------------------- */
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;
+ tokens_trace_level = tokens_trace_setting;
linker_trace_level = linker_trace_setting;
- if (listing_switch) line_trace_level=1;
lexer_begin_pass();
linker_begin_pass();
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];
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);
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;
name_or_unset(Code_Path));
printf(
-" Temporary file (out) temporary_path %s\n\
- ICL command file (in) icl_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));
printf(
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",
Source_Extension, Include_Extension,
Code_Extension, V4Code_Extension, V5Code_Extension, V6Code_Extension,
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;
- default: return;
- }
- 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
static char riscos_ft_buffer[4];
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();
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();
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);
+ }
}
/* ------------------------------------------------------------------------- */
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;
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);
{ 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;
}
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 - 2021.\n\n");
+Copyright (c) Graham Nelson 1993 - 2022.\n\n");
/* For people typing just "inform", a summary only: */
printf(
" $list list current 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\
$?SETTING explain briefly what SETTING is for\n\
$SETTING=number change SETTING to given number\n\
- $#SYMBOL=number define SYMBOL as a constant in the story\n\n",
- (DEFAULT_MEMORY_SIZE==HUGE_SIZE)?"(default)":"",
- (DEFAULT_MEMORY_SIZE==LARGE_SIZE)?"(default)":"",
- (DEFAULT_MEMORY_SIZE==SMALL_SIZE)?"(default)":"");
+ $!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\
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\
- --define 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");
+ printf("For example: \"inform -dexs curses\".\n");
#endif
return;
/* 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\
printf("\
i ignore default switches set within the file\n\
- j list objects as constructed\n\
- k output debugging information to \"%s\"\n\
- l list every statement run through Inform (not implemented)\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("\
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("\
(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");
}
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;
}
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;
}
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;
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;
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') {
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;
}
}
- 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;
}
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;
}
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;
banner();
- set_memory_sizes(DEFAULT_MEMORY_SIZE); set_default_paths();
+ set_memory_sizes(); set_default_paths();
reset_switch_settings(); select_version(5);
cli_files_specified = 0; no_compilations = 0;
/* ------------------------------------------------------------------------- */
/* "lexer" : Lexical analyser */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
int32 last_mapped_line; /* Last syntax line reported to debugging file */
/* ------------------------------------------------------------------------- */
-/* The lexer's output is a sequence of triples, each called a "token", */
+/* The lexer's output is a sequence of structs, each called a "token", */
/* representing one lexical unit (or "lexeme") each. Instead of providing */
/* "lookahead" (that is, always having available the next token after the */
/* current one, so that syntax analysers higher up in Inform can have */
/* ------------------------------------------------------------------------- */
/* These three variables are set to the current token on a call to */
/* get_next_token() (but are not changed by a call to put_token_back()). */
+/* (It would be tidier to use a token_data structure, rather than having */
+/* get_next_token() unpack three values. But this is the way it is.) */
/* ------------------------------------------------------------------------- */
int token_type;
/* maximum number of tokens ever put back at once, plus 1 (in effect, the */
/* maximum token lookahead ever needed in syntax analysis, plus 1). */
/* */
+/* Note that the circle struct type is lexeme_data, whereas the expression */
+/* code all works in token_data. They have slightly different needs. The */
+/* data is exported through the token_text, token_value, token_type */
+/* globals, so there's no need to use the same struct at both levels. */
+/* */
/* Unlike some compilers, Inform does not have a context-free lexer: in */
/* fact it has 12288 different possible states. However, the context only */
/* affects the interpretation of "identifiers": lexemes beginning with a */
old-style "objectloop (a in b)" and a new "objectloop (a in b ...)".) */
static int circle_position;
-static token_data circle[CIRCLE_SIZE];
-
-static int token_contexts[CIRCLE_SIZE];
+static lexeme_data circle[CIRCLE_SIZE];
/* ------------------------------------------------------------------------- */
/* A complication, however, is that the text of some lexemes needs to be */
/* held in Inform's memory for much longer periods: for example, a */
/* dictionary word lexeme (like "'south'") must have its text preserved */
/* until the code generation time for the expression it occurs in, when */
-/* the dictionary reference is actually made. Code generation in general */
-/* occurs as early as possible in Inform: pending some better method of */
-/* garbage collection, we simply use a buffer so large that unless */
-/* expressions spread across 10K of source code are found, there can be */
-/* no problem. */
+/* the dictionary reference is actually made. We handle this by keeping */
+/* all lexeme text until the end of the statement (or, for top-level */
+/* directives, until the end of the directive). Then we call */
+/* release_token_texts() to start over. The lextexts array will therefore */
+/* grow to the largest number of lexemes in a single statement or */
+/* directive. */
/* ------------------------------------------------------------------------- */
-static char *lexeme_memory;
-static char *lex_p; /* Current write position */
+typedef struct lextext_s {
+ char *text;
+ size_t size; /* Allocated size (including terminal null)
+ This is always at least MAX_IDENTIFIER_LENGTH+1 */
+} lextext;
+
+static lextext *lextexts; /* Allocated to no_lextexts */
+static memory_list lextexts_memlist;
+static int no_lextexts;
+
+static int cur_lextexts; /* Number of lextexts in current use
+ (cur_lextexts <= no_lextexts) */
+
+static int lex_index; /* Index of lextext being written to */
+static int lex_pos; /* Current write position in that lextext */
/* ------------------------------------------------------------------------- */
/* The lexer itself needs up to 3 characters of lookahead (it uses an */
moves made from the last-read
token */
-extern void describe_token(token_data t)
+/* This gets called for both token_data and lexeme_data structs. It prints
+ a description of the common part (the text, value, type fields).
+*/
+extern void describe_token_triple(const char *text, int32 value, int type)
{
/* Many of the token types are not set in this file, but later on in
Inform's higher stages (for example, in the expression evaluator);
printf("{ ");
- switch(t.type)
+ switch(type)
{
/* The following token types occur in lexer output: */
case SYMBOL_TT: printf("symbol ");
- describe_symbol(t.value);
+ describe_symbol(value);
break;
- case NUMBER_TT: printf("literal number %d", t.value);
+ case NUMBER_TT: printf("literal number %d", value);
break;
- case DQ_TT: printf("string \"%s\"", t.text);
+ case DQ_TT: printf("string \"%s\"", text);
break;
- case SQ_TT: printf("string '%s'", t.text);
+ case SQ_TT: printf("string '%s'", text);
break;
- case SEP_TT: printf("separator '%s'", t.text);
+ case SEP_TT: printf("separator '%s'", text);
break;
case EOF_TT: printf("end of file");
break;
- case STATEMENT_TT: printf("statement name '%s'", t.text);
+ case STATEMENT_TT: printf("statement name '%s'", text);
break;
- case SEGMENT_MARKER_TT: printf("object segment marker '%s'", t.text);
+ case SEGMENT_MARKER_TT: printf("object segment marker '%s'", text);
break;
- case DIRECTIVE_TT: printf("directive name '%s'", t.text);
+ case DIRECTIVE_TT: printf("directive name '%s'", text);
break;
- case CND_TT: printf("textual conditional '%s'", t.text);
+ case CND_TT: printf("textual conditional '%s'", text);
break;
- case OPCODE_NAME_TT: printf("opcode name '%s'", t.text);
+ case OPCODE_NAME_TT: printf("opcode name '%s'", text);
break;
- case SYSFUN_TT: printf("built-in function name '%s'", t.text);
+ case SYSFUN_TT: printf("built-in function name '%s'", text);
break;
- case LOCAL_VARIABLE_TT: printf("local variable name '%s'", t.text);
+ case LOCAL_VARIABLE_TT: printf("local variable name '%s'", text);
break;
- case MISC_KEYWORD_TT: printf("statement keyword '%s'", t.text);
+ case MISC_KEYWORD_TT: printf("statement keyword '%s'", text);
break;
- case DIR_KEYWORD_TT: printf("directive keyword '%s'", t.text);
+ case DIR_KEYWORD_TT: printf("directive keyword '%s'", text);
break;
- case TRACE_KEYWORD_TT: printf("'trace' keyword '%s'", t.text);
+ case TRACE_KEYWORD_TT: printf("'trace' keyword '%s'", text);
break;
- case SYSTEM_CONSTANT_TT: printf("system constant name '%s'", t.text);
+ case SYSTEM_CONSTANT_TT: printf("system constant name '%s'", text);
break;
/* The remaining are etoken types, not set by the lexer */
case OP_TT: printf("operator '%s'",
- operators[t.value].description);
+ operators[value].description);
break;
case ENDEXP_TT: printf("end of expression");
break;
break;
case SUBCLOSE_TT: printf("close bracket");
break;
- case LARGE_NUMBER_TT: printf("large number: '%s'=%d",t.text,t.value);
+ case LARGE_NUMBER_TT: printf("large number: '%s'=%d",text,value);
break;
- case SMALL_NUMBER_TT: printf("small number: '%s'=%d",t.text,t.value);
+ case SMALL_NUMBER_TT: printf("small number: '%s'=%d",text,value);
break;
- case VARIABLE_TT: printf("variable '%s'=%d", t.text, t.value);
+ case VARIABLE_TT: printf("variable '%s'=%d", text, value);
break;
- case DICTWORD_TT: printf("dictionary word '%s'", t.text);
+ case DICTWORD_TT: printf("dictionary word '%s'", text);
break;
- case ACTION_TT: printf("action name '%s'", t.text);
+ case ACTION_TT: printf("action name '%s'", text);
break;
default:
printf("** unknown token type %d, text='%s', value=%d **",
- t.type, t.text, t.value);
+ type, text, value);
}
printf(" }");
}
/* ------------------------------------------------------------------------- */
-/* All but one of the 280 Inform keywords (118 of them opcode names used */
+/* All but one of the Inform keywords (most of them opcode names used */
/* only by the assembler). (The one left over is "sp", a keyword used in */
/* assembly language only.) */
/* */
/* "header.h" but is otherwise not significant. */
/* ------------------------------------------------------------------------- */
-#define MAX_KEYWORDS 350
+/* This must exceed the total number of keywords across all groups,
+ including opcodes. */
+#define MAX_KEYWORDS (350)
/* The values will be filled in at compile time, when we know
which opcode set to use. */
"sqrt", "exp", "log", "pow",
"sin", "cos", "tan", "asin", "acos", "atan", "atan2",
"jfeq", "jfne", "jflt", "jfle", "jfgt", "jfge", "jisnan", "jisinf",
+ "hasundo", "discardundo",
""
};
"string", "table", "buffer", "data", "initial", "initstr",
"with", "private", "has", "class",
"error", "fatalerror", "warning",
- "terminating", "static",
+ "terminating", "static", "individual",
"" },
DIR_KEYWORD_TT, FALSE, TRUE
};
&directive_keywords, &misc_keywords, &statements, &conditions,
&system_functions, &system_constants, &opcode_macros};
+/* These keywords are set to point to local_variable_names entries when
+ a routine header is parsed. See construct_local_variable_tables(). */
keyword_group local_variables =
-{ { "" }, /* Filled in when routine declared */
+{ { "" },
LOCAL_VARIABLE_TT, FALSE, FALSE
};
static int *local_variable_hash_table;
static int *local_variable_hash_codes;
-char **local_variable_texts;
-static char *local_variable_text_table;
+
+/* Note that MAX_LOCAL_VARIABLES is the maximum number of local variables
+ for this VM, *including* "sp" (the stack pointer "local").
+ This used to be a memory setting. Now it is a constant: 16 for Z-code,
+ 119 for Glulx.
+*/
+
+/* Names of local variables in the current routine.
+ This is allocated to MAX_LOCAL_VARIABLES-1. (The stack pointer "local"
+ is not included in this array.)
+
+ (This could be a memlist, growing as needed up to MAX_LOCAL_VARIABLES-1.
+ But right now we just allocate the max.)
+ */
+identstruct *local_variable_names;
static char one_letter_locals[128];
}
for (j=0; *(oplist[j]); j++) {
+ if (j >= MAX_KEYWORD_GROUP_SIZE) {
+ /* Gotta increase MAX_KEYWORD_GROUP_SIZE */
+ compiler_error("opcode_list has overflowed opcode_names.keywords");
+ break;
+ }
opcode_names.keywords[j] = oplist[j];
}
opcode_names.keywords[j] = "";
for (j=0; *(maclist[j]); j++) {
+ if (j >= MAX_KEYWORD_GROUP_SIZE) {
+ /* Gotta increase MAX_KEYWORD_GROUP_SIZE */
+ compiler_error("opmacro_list has overflowed opcode_macros.keywords");
+ break;
+ }
opcode_macros.keywords[j] = maclist[j];
}
opcode_macros.keywords[j] = "";
for (i=1; i<=11; i++)
{ keyword_group *kg = keyword_groups[i];
for (j=0; *(kg->keywords[j]) != 0; j++)
- { h = hash_code_from_string(kg->keywords[j]);
+ {
+ if (tp >= MAX_KEYWORDS) {
+ /* Gotta increase MAX_KEYWORDS */
+ compiler_error("keywords_data_table has overflowed MAX_KEYWORDS");
+ break;
+ }
+ h = hash_code_from_string(kg->keywords[j]);
if (keywords_hash_table[h] == -1)
keywords_hash_table[h] = tp;
else
}
}
+/* Look at the strings stored in local_variable_names (from 0 to no_locals).
+ Set local_variables.keywords to point to these, and also prepare the
+ hash tables. */
extern void construct_local_variable_tables(void)
-{ int i, h; char *p = local_variable_text_table;
+{ int i, h;
for (i=0; i<HASH_TAB_SIZE; i++) local_variable_hash_table[i] = -1;
for (i=0; i<128; i++) one_letter_locals[i] = MAX_LOCAL_VARIABLES;
for (i=0; i<no_locals; i++)
- { char *q = local_variables.keywords[i];
- if (q[1] == 0)
- { one_letter_locals[(uchar)q[0]] = i;
- if (isupper(q[0])) one_letter_locals[tolower(q[0])] = i;
- if (islower(q[0])) one_letter_locals[toupper(q[0])] = i;
+ {
+ char *p = local_variable_names[i].text;
+ local_variables.keywords[i] = p;
+ if (p[1] == 0)
+ { one_letter_locals[(uchar)p[0]] = i;
+ if (isupper(p[0])) one_letter_locals[tolower(p[0])] = i;
+ if (islower(p[0])) one_letter_locals[toupper(p[0])] = i;
}
- h = hash_code_from_string(q);
+ h = hash_code_from_string(p);
if (local_variable_hash_table[h] == -1)
local_variable_hash_table[h] = i;
local_variable_hash_codes[i] = h;
- local_variable_texts[i] = p;
- strcpy(p, q);
- p += strlen(p)+1;
}
- for (;i<MAX_LOCAL_VARIABLES-1;i++)
- local_variable_texts[i] = "<no such local variable>";
+ /* Clear the rest. */
+ for (;i<MAX_LOCAL_VARIABLES-1;i++) {
+ local_variables.keywords[i] = "";
+ local_variable_hash_codes[i] = 0;
+ }
}
-static void interpret_identifier(int pos, int dirs_only_flag)
-{ int index, hashcode; char *p = circle[pos].text;
+static void interpret_identifier(char *p, int pos, int dirs_only_flag)
+{ int index, hashcode;
/* An identifier is either a keyword or a "symbol", a name which the
lexical analyser leaves to higher levels of Inform to understand. */
if (index >= 0)
{ for (;index<no_locals;index++)
{ if (hashcode == local_variable_hash_codes[index])
- { if (strcmpcis(p, local_variable_texts[index])==0)
+ { if (strcmpcis(p, local_variable_names[index].text)==0)
{ circle[pos].type = LOCAL_VARIABLE_TT;
circle[pos].value = index+1;
return;
if (g_proc != true)
{ free_arrays();
close_all_source();
- if (temporary_files_switch)
- remove_temp_files();
- if (store_the_text)
- my_free(&all_text,"transcription text");
abort_transcript_file();
longjmp (g_fallback, 1);
}
}
/* Return the IEEE-754 single-precision encoding of a floating-point
- * number. See http://www.psc.edu/general/software/packages/ieee/ieee.php
- * for an explanation.
+ * number.
*
* The number is provided in the pieces it was parsed in:
* [+|-] intv "." fracv "e" [+|-]expo
LexicalBlock LB;
} Sourcefile;
-static Sourcefile *FileStack;
-static int File_sp; /* Stack pointer */
+static Sourcefile *FileStack; /* Allocated to FileStack_max */
+static memory_list FileStack_memlist;
+static int FileStack_max; /* The highest value that File_sp has
+ reached
+ (Filestack entries to this depth have
+ a buffer allocated) */
-static Sourcefile *CF; /* Top entry on stack */
+static int File_sp; /* Current stack pointer */
+static Sourcefile *CF; /* Top entry on stack (always equal to
+ FileStack[File_sp-1]) */
static int last_input_file;
+/* Set CF and CurrentLB.
+ This does not increment File_sp; the caller must do that. */
static void begin_buffering_file(int i, int file_no)
{ int j, cnt; uchar *p;
- if (i >= MAX_INCLUSION_DEPTH)
- memoryerror("MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
+ CF = NULL;
+ CurrentLB = NULL;
+
+ ensure_memory_list_available(&FileStack_memlist, i+1);
+ while (i >= FileStack_max) {
+ FileStack[FileStack_max++].buffer = my_malloc(SOURCE_BUFFER_SIZE+4, "source file buffer");
+ }
p = (uchar *) FileStack[i].buffer;
FileStack[i].file_no = file_no;
FileStack[i].size = file_load_chars(file_no,
(char *) p, SOURCE_BUFFER_SIZE);
+ /* If the file is shorter than SOURCE_BUFFER_SIZE, it's now closed already. We still need to set up the file entry though. */
+
lookahead = source_to_iso_grid[p[0]];
lookahead2 = source_to_iso_grid[p[1]];
lookahead3 = source_to_iso_grid[p[2]];
FileStack[i].LB.orig_source = NULL; FileStack[i].LB.orig_file = 0;
FileStack[i].LB.orig_line = 0; FileStack[i].LB.orig_char = 0;
+ InputFiles[file_no-1].initial_buffering = FALSE;
+
CurrentLB = &(FileStack[i].LB);
CF = &(FileStack[i]);
lookahead3 = source_to_iso_grid[p[CF->read_pos++]];
CurrentLB->chars_read++;
- if (forerrors_pointer < 511)
+ if (forerrors_pointer < FORERRORS_SIZE-1)
forerrors_buff[forerrors_pointer++] = current;
if (current == '\n') reached_new_line();
return(current);
else lookahead3 = source_to_iso_grid[p[3]];
CurrentLB->chars_read++;
- if (forerrors_pointer < 511)
+ if (forerrors_pointer < FORERRORS_SIZE-1)
forerrors_buff[forerrors_pointer++] = current;
if (current == '\n') reached_new_line();
return(current);
/* and move the read position forward */
/* by one */
/* */
+/* release_token_texts() discard all the tokens that have been */
+/* read in, except for put-back ones */
+/* */
/* restart_lexer(source, name) if source is NULL, initialise the lexer */
/* to read from source files; */
/* otherwise, to read from this string. */
/* ------------------------------------------------------------------------- */
+extern void release_token_texts(void)
+{
+ /* This is called at the beginning of every (top-level) directive and
+ every statement. It drops all token usage so that the lextexts
+ array can be reused.
+
+ Call this immediately before a get_next_token() call.
+
+ This should *not* be called within parse_expression(). Expression
+ code generation relies on token data being retained across the whole
+ expression.
+ */
+ int ix;
+
+ token_text = NULL;
+
+ if (tokens_put_back == 0) {
+ cur_lextexts = 0;
+ return;
+ }
+
+ /* If any tokens have been put back, we have to preserve their text.
+ Move their lextext usage to the head of the lextexts array. */
+
+ for (ix=0; ix<tokens_put_back; ix++) {
+ int oldpos;
+ lextext temp;
+ int pos = circle_position - tokens_put_back + 1 + ix;
+ if (pos < 0) pos += CIRCLE_SIZE;
+
+ oldpos = circle[pos].lextext;
+ circle[pos].lextext = ix;
+ /* Swap the entire lextext structure (including size) */
+ temp = lextexts[ix];
+ lextexts[ix] = lextexts[oldpos];
+ lextexts[oldpos] = temp;
+ }
+ cur_lextexts = tokens_put_back;
+}
+
extern void put_token_back(void)
{ tokens_put_back++;
}
}
+/* The get_next_token() code reads characters into the current lextext,
+ which is lextexts[lex_index]. It uses these routines to add and remove
+ characters, reallocing when necessary.
+
+ lex_pos is the current number of characters in the lextext. It is
+ not necessarily null-terminated until get_next_token() completes.
+ */
+
+/* Add one character */
+static void lexaddc(char ch)
+{
+ if ((size_t)lex_pos >= lextexts[lex_index].size) {
+ size_t newsize = lextexts[lex_index].size * 2;
+ my_realloc(&lextexts[lex_index].text, lextexts[lex_index].size, newsize, "one lexeme text");
+ lextexts[lex_index].size = newsize;
+ }
+ lextexts[lex_index].text[lex_pos++] = ch;
+}
+
+/* Remove the last character and ensure it's null-terminated */
+static void lexdelc(void)
+{
+ if (lex_pos > 0) {
+ lex_pos--;
+ }
+ lextexts[lex_index].text[lex_pos] = 0;
+}
+
+/* Return the last character */
+static char lexlastc(void)
+{
+ if (lex_pos == 0) {
+ return 0;
+ }
+ return lextexts[lex_index].text[lex_pos-1];
+}
+
+/* Add a string of characters (including the null) */
+static void lexadds(char *str)
+{
+ while (*str) {
+ lexaddc(*str);
+ str++;
+ }
+ lexaddc(0);
+}
+
extern void get_next_token(void)
{ int d, i, j, k, quoted_size, e, radix, context; int32 n; char *r;
int returning_a_put_back_token = TRUE;
-
+
context = lexical_context();
if (tokens_put_back > 0)
{ i = circle_position - tokens_put_back + 1;
if (i<0) i += CIRCLE_SIZE;
tokens_put_back--;
- if (context != token_contexts[i])
+ if (context != circle[i].context)
{ j = circle[i].type;
if ((j==0) || ((j>=100) && (j<200)))
- interpret_identifier(i, FALSE);
+ interpret_identifier(circle[i].text, i, FALSE);
+ circle[i].context = context;
}
goto ReturnBack;
}
if (circle_position == CIRCLE_SIZE-1) circle_position = 0;
else circle_position++;
- if (lex_p > lexeme_memory + 4*MAX_QTEXT_SIZE)
- lex_p = lexeme_memory;
-
- circle[circle_position].text = lex_p;
+ lex_index = cur_lextexts++;
+ if (lex_index >= no_lextexts) {
+ /* fresh lextext block; must init it */
+ no_lextexts = lex_index+1;
+ ensure_memory_list_available(&lextexts_memlist, no_lextexts);
+ lextexts[lex_index].size = MAX_IDENTIFIER_LENGTH + 1;
+ lextexts[lex_index].text = my_malloc(lextexts[lex_index].size, "one lexeme text");
+ }
+ lex_pos = 0;
+ lextexts[lex_index].text[0] = 0; /* start with an empty string */
+
+ circle[circle_position].lextext = lex_index;
+ circle[circle_position].text = NULL; /* will fill in later */
circle[circle_position].value = 0;
- *lex_p = 0;
+ circle[circle_position].type = 0;
+ circle[circle_position].context = context;
StartTokenAgain:
d = (*get_next_char)();
case EOF_CODE:
circle[circle_position].type = EOF_TT;
- strcpy(lex_p, "<end of file>");
- lex_p += strlen(lex_p) + 1;
+ lexadds("<end of file>");
break;
case DIGIT_CODE:
n=0;
do
{ n = n*radix + character_digit_value[d];
- *lex_p++ = d;
+ lexaddc(d);
} while ((character_digit_value[lookahead] < radix)
&& (d = (*get_next_char)(), TRUE));
- *lex_p++ = 0;
+ lexaddc(0);
circle[circle_position].type = NUMBER_TT;
circle[circle_position].value = n;
break;
{ int expo=0; double intv=0, fracv=0;
int expocount=0, intcount=0, fraccount=0;
int signbit = (d == '-');
- *lex_p++ = d;
+ lexaddc(d);
while (character_digit_value[lookahead] < 10) {
intv = 10.0*intv + character_digit_value[lookahead];
intcount++;
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
}
if (lookahead == '.') {
double fracpow = 1.0;
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
while (character_digit_value[lookahead] < 10) {
fracpow *= 0.1;
fracv = fracv + fracpow*character_digit_value[lookahead];
fraccount++;
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
}
}
if (lookahead == 'e' || lookahead == 'E') {
int exposign = 0;
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
if (lookahead == '+' || lookahead == '-') {
exposign = (lookahead == '-');
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
}
while (character_digit_value[lookahead] < 10) {
expo = 10*expo + character_digit_value[lookahead];
expocount++;
- *lex_p++ = lookahead;
+ lexaddc(lookahead);
(*get_next_char)();
}
if (expocount == 0)
error("Floating-point literal must have digits");
n = construct_float(signbit, intv, fracv, expo);
}
- *lex_p++ = 0;
+ lexaddc(0);
circle[circle_position].type = NUMBER_TT;
circle[circle_position].value = n;
if (!glulx_mode && dont_enter_into_symbol_table != -2) error("Floating-point literals are not available in Z-code");
case QUOTE_CODE: /* Single-quotes: scan a literal string */
quoted_size=0;
do
- { e = d; d = (*get_next_char)(); *lex_p++ = d;
+ { e = d; d = (*get_next_char)(); lexaddc(d);
if (quoted_size++==64)
{ error(
"Too much text for one pair of quotations '...' to hold");
- *lex_p='\''; break;
+ lexaddc('\''); break;
}
if ((d == '\'') && (e != '@'))
{ if (quoted_size == 1)
- { d = (*get_next_char)(); *lex_p++ = d;
+ { d = (*get_next_char)(); lexaddc(d);
if (d != '\'')
error("No text between quotation marks ''");
}
}
} while (d != EOF);
if (d==EOF) ebf_error("'\''", "end of file");
- *(lex_p-1) = 0;
+ lexdelc();
circle[circle_position].type = SQ_TT;
break;
case DQUOTE_CODE: /* Double-quotes: scan a literal string */
quoted_size=0;
do
- { d = (*get_next_char)(); *lex_p++ = d;
- if (quoted_size++==MAX_QTEXT_SIZE)
- { memoryerror("MAX_QTEXT_SIZE", MAX_QTEXT_SIZE);
- break;
- }
+ { d = (*get_next_char)(); lexaddc(d);
if (d == '\n')
- { lex_p--;
- while (*(lex_p-1) == ' ') lex_p--;
- if (*(lex_p-1) != '^') *lex_p++ = ' ';
+ { lex_pos--;
+ while (lexlastc() == ' ') lex_pos--;
+ if (lexlastc() != '^') lexaddc(' ');
while ((lookahead != EOF) &&
(tokeniser_grid[lookahead] == WHITESPACE_CODE))
(*get_next_char)();
}
else if (d == '\\')
{ int newline_passed = FALSE;
- lex_p--;
+ lex_pos--;
while ((lookahead != EOF) &&
(tokeniser_grid[lookahead] == WHITESPACE_CODE))
if ((d = (*get_next_char)()) == '\n')
}
} while ((d != EOF) && (d!='\"'));
if (d==EOF) ebf_error("'\"'", "end of file");
- *(lex_p-1) = 0;
+ lexdelc();
circle[circle_position].type = DQ_TT;
break;
case IDENTIFIER_CODE: /* Letter or underscore: an identifier */
- *lex_p++ = d; n=1;
+ lexaddc(d); n=1;
while ((n<=MAX_IDENTIFIER_LENGTH)
&& ((tokeniser_grid[lookahead] == IDENTIFIER_CODE)
|| (tokeniser_grid[lookahead] == DIGIT_CODE)))
- n++, *lex_p++ = (*get_next_char)();
+ n++, lexaddc((*get_next_char)());
- *lex_p++ = 0;
+ lexaddc(0);
if (n > MAX_IDENTIFIER_LENGTH)
{ char bad_length[100];
sprintf(bad_length,
"Name exceeds the maximum length of %d characters:",
MAX_IDENTIFIER_LENGTH);
- error_named(bad_length, circle[circle_position].text);
+ error_named(bad_length, lextexts[lex_index].text);
+ /* Eat any further extra characters in the identifier */
+ while (((tokeniser_grid[lookahead] == IDENTIFIER_CODE)
+ || (tokeniser_grid[lookahead] == DIGIT_CODE)))
+ (*get_next_char)();
/* Trim token so that it doesn't violate
MAX_IDENTIFIER_LENGTH during error recovery */
- circle[circle_position].text[MAX_IDENTIFIER_LENGTH] = 0;
+ lextexts[lex_index].text[MAX_IDENTIFIER_LENGTH] = 0;
}
if (dont_enter_into_symbol_table)
{ circle[circle_position].type = DQ_TT;
circle[circle_position].value = 0;
if (dont_enter_into_symbol_table == -2)
- interpret_identifier(circle_position, TRUE);
+ interpret_identifier(lextexts[lex_index].text, circle_position, TRUE);
break;
}
- interpret_identifier(circle_position, FALSE);
+ interpret_identifier(lextexts[lex_index].text, circle_position, FALSE);
break;
default:
for (j=e>>4, k=j+(e&0x0f); j<k; j++)
{ r = (char *) separators[j];
if (r[1]==0)
- { *lex_p++=d; *lex_p++=0;
+ { lexaddc(d);
+ lexaddc(0);
goto SeparatorMatched;
}
else
if (r[2]==0)
{ if (*(r+1) == lookahead)
- { *lex_p++=d;
- *lex_p++=(*get_next_char)();
- *lex_p++=0;
+ { lexaddc(d);
+ lexaddc((*get_next_char)());
+ lexaddc(0);
goto SeparatorMatched;
}
}
else
{ if ((*(r+1) == lookahead) && (*(r+2) == lookahead2))
- { *lex_p++=d;
- *lex_p++=(*get_next_char)();
- *lex_p++=(*get_next_char)();
- *lex_p++=0;
+ { lexaddc(d);
+ lexaddc((*get_next_char)());
+ lexaddc((*get_next_char)());
+ lexaddc(0);
goto SeparatorMatched;
}
}
/* The following contingency never in fact arises with the
current set of separators, but might in future */
- *lex_p++ = d; *lex_p++ = lookahead; *lex_p++ = lookahead2;
- *lex_p++ = 0;
- error_named("Unrecognised combination in source:", lex_p);
+ lexaddc(d); lexaddc(lookahead); lexaddc(lookahead2);
+ lexaddc(0);
+ error_named("Unrecognised combination in source:",
+ lextexts[lex_index].text);
goto StartTokenAgain;
SeparatorMatched:
case HASHWDOLLAR_SEP:
if (tokeniser_grid[lookahead] == WHITESPACE_CODE)
{ error_named("Character expected after",
- circle[circle_position].text);
+ lextexts[lex_index].text);
break;
}
- lex_p--;
- *lex_p++ = (*get_next_char)();
+ lex_pos--;
+ lexaddc((*get_next_char)());
while ((tokeniser_grid[lookahead] == IDENTIFIER_CODE)
|| (tokeniser_grid[lookahead] == DIGIT_CODE))
- *lex_p++ = (*get_next_char)();
- *lex_p++ = 0;
+ lexaddc((*get_next_char)());
+ lexaddc(0);
break;
case HASHADOLLAR_SEP:
case HASHGDOLLAR_SEP:
case HASHHASH_SEP:
if (tokeniser_grid[lookahead] != IDENTIFIER_CODE)
{ error_named("Alphabetic character expected after",
- circle[circle_position].text);
+ lextexts[lex_index].text);
break;
}
- lex_p--;
+ lex_pos--;
while ((tokeniser_grid[lookahead] == IDENTIFIER_CODE)
|| (tokeniser_grid[lookahead] == DIGIT_CODE))
- *lex_p++ = (*get_next_char)();
- *lex_p++ = 0;
+ lexaddc((*get_next_char)());
+ lexaddc(0);
break;
}
break;
}
+ /* We can now assign the text pointer, since the lextext has finished reallocing. */
+ circle[circle_position].text = lextexts[lex_index].text;
i = circle_position;
ReturnBack:
+ /* We've either parsed a new token or selected a put-back one.
+ i is the circle-position of the token in question. Time to
+ export the token data where higher-level code can find it. */
token_value = circle[i].value;
token_type = circle[i].type;
token_text = circle[i].text;
if (!returning_a_put_back_token)
{ set_token_location(circle[i].location);
}
- token_contexts[i] = context;
if (tokens_trace_level > 0)
- { if (tokens_trace_level == 1)
+ { if (tokens_trace_level == 1) {
printf("'%s' ", circle[i].text);
+ if (circle[i].type == EOF_TT) printf("\n");
+ }
else
- { printf("-> "); describe_token(circle[i]);
+ { printf("-> "); describe_token(&circle[i]);
printf(" ");
- if (tokens_trace_level > 2) print_context(token_contexts[i]);
+ if (tokens_trace_level > 2) print_context(circle[i].context);
printf("\n");
}
}
{ circle[i].type = 0;
circle[i].value = 0;
circle[i].text = "(if this is ever visible, there is a bug)";
- token_contexts[i] = 0;
+ circle[i].lextext = -1;
+ circle[i].context = 0;
}
- lex_p = lexeme_memory;
+ cur_lextexts = 0;
+ /* But we don't touch no_lextexts; those allocated blocks can be reused */
+ lex_index = -1;
+ lex_pos = -1;
+
tokens_put_back = 0;
forerrors_pointer = 0;
dont_enter_into_symbol_table = FALSE;
extern void init_lexer_vars(void)
{
+ FileStack = NULL;
+ FileStack_max = 0;
+ CF = NULL;
+ CurrentLB = NULL;
+
+ lextexts = NULL;
+ no_lextexts = 0;
+ cur_lextexts = 0;
+ lex_index = -1;
+ lex_pos = -1;
+
blank_brief_location.file_index = -1;
blank_brief_location.line_number = 0;
blank_brief_location.orig_file_index = 0;
}
extern void lexer_allocate_arrays(void)
-{ int i;
-
- FileStack = my_malloc(MAX_INCLUSION_DEPTH*sizeof(Sourcefile),
- "filestack buffer");
-
- for (i=0; i<MAX_INCLUSION_DEPTH; i++)
- FileStack[i].buffer = my_malloc(SOURCE_BUFFER_SIZE+4, "source file buffer");
+{
+ initialise_memory_list(&FileStack_memlist,
+ sizeof(Sourcefile), 4, (void**)&FileStack,
+ "source file stack");
+ FileStack_max = 0;
- lexeme_memory = my_malloc(5*MAX_QTEXT_SIZE, "lexeme memory");
+ initialise_memory_list(&lextexts_memlist,
+ sizeof(lextext), 200, (void**)&lextexts,
+ "lexeme texts list");
+ cur_lextexts = 0;
keywords_hash_table = my_calloc(sizeof(int), HASH_TAB_SIZE,
"keyword hash table");
"keyword hash end table");
keywords_data_table = my_calloc(sizeof(int), 3*MAX_KEYWORDS,
"keyword hashing linked list");
+
+ local_variable_names = my_calloc(sizeof(identstruct), MAX_LOCAL_VARIABLES-1,
+ "text of local variable names");
local_variable_hash_table = my_calloc(sizeof(int), HASH_TAB_SIZE,
"local variable hash table");
- local_variable_text_table = my_malloc(
- (MAX_LOCAL_VARIABLES-1)*(MAX_IDENTIFIER_LENGTH+1),
- "text of local variable names");
-
local_variable_hash_codes = my_calloc(sizeof(int), MAX_LOCAL_VARIABLES,
"local variable hash codes");
- local_variable_texts = my_calloc(sizeof(char *), MAX_LOCAL_VARIABLES,
- "local variable text pointers");
make_tokeniser_grid();
make_keywords_tables();
}
extern void lexer_free_arrays(void)
-{ int i; char *p;
+{ int ix;
+ CF = NULL;
+ CurrentLB = NULL;
- for (i=0; i<MAX_INCLUSION_DEPTH; i++)
- { p = FileStack[i].buffer;
- my_free(&p, "source file buffer");
+ for (ix=0; ix<FileStack_max; ix++) {
+ my_free(&FileStack[ix].buffer, "source file buffer");
}
- my_free(&FileStack, "filestack buffer");
- my_free(&lexeme_memory, "lexeme memory");
+ deallocate_memory_list(&FileStack_memlist);
+
+ for (ix=0; ix<no_lextexts; ix++) {
+ my_free(&lextexts[ix].text, "one lexeme text");
+ }
+ deallocate_memory_list(&lextexts_memlist);
my_free(&keywords_hash_table, "keyword hash table");
my_free(&keywords_hash_ends_table, "keyword hash end table");
my_free(&keywords_data_table, "keyword hashing linked list");
- my_free(&local_variable_hash_table, "local variable hash table");
- my_free(&local_variable_text_table, "text of local variable names");
+ my_free(&local_variable_names, "text of local variable names");
+ my_free(&local_variable_hash_table, "local variable hash table");
my_free(&local_variable_hash_codes, "local variable hash codes");
- my_free(&local_variable_texts, "local variable text pointers");
cleanup_token_locations(NULL);
}
/* ------------------------------------------------------------------------- */
/* "linker" : For compiling and linking modules */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
-memory_block link_data_area;
-uchar *link_data_holding_area, *link_data_top;
+uchar *link_data_holding_area; /* Allocated to link_data_ha_size */
+static memory_list link_data_holding_area_memlist;
+int32 link_data_ha_size;
+
+uchar *link_data_area;
+static memory_list link_data_area_memlist;
/* Start, current top, size of */
int32 link_data_size; /* link data table being written */
/* (holding import/export names) */
-extern int32 *action_symbol;
/* ------------------------------------------------------------------------- */
/* Marker values */
xref_table[IE.symbol_number] = index;
- if (!(sflags[index] & UNKNOWN_SFLAG))
+ if (!(symbols[index].flags & UNKNOWN_SFLAG))
{ if (IE.module_value == EXPORTAC_MV)
- { if ((!(sflags[index] & ACTION_SFLAG))
- && (stypes[index] != FAKE_ACTION_T))
+ { if ((!(symbols[index].flags & ACTION_SFLAG))
+ && (symbols[index].type != FAKE_ACTION_T))
link_error_named(
"action name clash with", IE.symbol_name);
}
else
- if (stypes[index] == IE.symbol_type)
+ if (symbols[index].type == IE.symbol_type)
{ switch(IE.symbol_type)
{ case CONSTANT_T:
- if ((!(svals[index] == IE.symbol_value))
+ if ((!(symbols[index].value == IE.symbol_value))
|| (IE.backpatch != 0))
link_error_named(
"program and module give differing values of", IE.symbol_name);
break;
case INDIVIDUAL_PROPERTY_T:
- property_identifier_map[IE.symbol_value] = svals[index];
+ property_identifier_map[IE.symbol_value] = symbols[index].value;
break;
case ROUTINE_T:
if ((IE.module_value == EXPORTSF_MV)
- && (sflags[index] & REPLACE_SFLAG))
+ && (symbols[index].flags & REPLACE_SFLAG))
break;
default:
sprintf(link_errorm,
else
{ sprintf(link_errorm,
"'%s' has type %s in program but type %s in module",
- IE.symbol_name, typename(stypes[index]),
+ IE.symbol_name, typename(symbols[index].type),
typename(IE.symbol_type));
link_error(link_errorm);
}
else
{ if (IE.module_value == EXPORTAC_MV)
{ IE.symbol_value = no_actions;
- action_symbol[no_actions++] = index;
+ ensure_memory_list_available(&actions_memlist, no_actions+1);
+ actions[no_actions].symbol = index;
+ actions[no_actions].byte_offset = 0; /* fill in later */
+ no_actions++;
if (linker_trace_level >= 4)
- printf("Creating action ##%s\n", (char *) symbs[index]);
+ printf("Creating action ##%s\n", symbols[index].name);
}
else
switch(IE.symbol_type)
{ case ROUTINE_T:
if ((IE.module_value == EXPORTSF_MV)
- && (sflags[index] & REPLACE_SFLAG))
+ && (symbols[index].flags & REPLACE_SFLAG))
{ routine_replace[no_rr] = IE.symbol_value;
routine_replace_with[no_rr++] = index;
return;
IE.symbol_value += no_objects;
break;
case ARRAY_T:
- IE.symbol_value += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
+ IE.symbol_value += dynamic_array_area_size - (MAX_ZCODE_GLOBAL_VARS*2);
break;
case GLOBAL_VARIABLE_T:
if (no_globals==233)
break;
}
- assign_symbol(index, IE.backpatch*0x10000 + IE.symbol_value,
+ assign_marked_symbol(index, IE.backpatch, IE.symbol_value,
IE.symbol_type);
- if (IE.backpatch != 0) sflags[index] |= CHANGE_SFLAG;
- sflags[index] |= EXPORT_SFLAG;
+ if (IE.backpatch != 0) symbols[index].flags |= CHANGE_SFLAG;
+ symbols[index].flags |= EXPORT_SFLAG;
if (IE.module_value == EXPORTSF_MV)
- sflags[index] |= INSF_SFLAG;
+ symbols[index].flags |= INSF_SFLAG;
if (IE.module_value == EXPORTAC_MV)
- sflags[index] |= ACTION_SFLAG;
+ symbols[index].flags |= ACTION_SFLAG;
}
if (IE.module_value == EXPORTAC_MV)
{ if (linker_trace_level >= 4)
printf("Map %d '%s' to %d\n",
- IE.symbol_value, (char *) (symbs[index]), svals[index]);
- actions_map[map_to] = svals[index];
+ IE.symbol_value, (symbols[index].name), symbols[index].value);
+ actions_map[map_to] = symbols[index].value;
}
}
{ int32 index;
index = symbol_index(IE.symbol_name, -1);
- sflags[index] |= USED_SFLAG;
+ symbols[index].flags |= USED_SFLAG;
xref_table[IE.symbol_number] = index;
- if (!(sflags[index] & UNKNOWN_SFLAG))
+ if (!(symbols[index].flags & UNKNOWN_SFLAG))
{ switch (IE.symbol_type)
{
case GLOBAL_VARIABLE_T:
- if (stypes[index] != GLOBAL_VARIABLE_T)
+ if (symbols[index].type != GLOBAL_VARIABLE_T)
link_error_named(
"module (wrongly) declared this a variable:", IE.symbol_name);
- variables_map[IE.symbol_value] = svals[index];
+ variables_map[IE.symbol_value] = symbols[index].value;
if (IE.symbol_value < lowest_imported_global_no)
lowest_imported_global_no = IE.symbol_value;
break;
default:
- switch(stypes[index])
+ switch(symbols[index].type)
{ case ATTRIBUTE_T:
link_error_named(
"this attribute is undeclared within module:", IE.symbol_name);; break;
{ switch (IE.symbol_type)
{
case GLOBAL_VARIABLE_T:
- if (stypes[index] != GLOBAL_VARIABLE_T)
+ if (symbols[index].type != GLOBAL_VARIABLE_T)
link_error_named(
"Module tried to import a Global variable not defined here:",
IE.symbol_name);
break;
case ARRAY_MV:
- if (v < (MAX_GLOBAL_VARIABLES*2))
+ if (v < (MAX_ZCODE_GLOBAL_VARS*2))
{ v = 2*(variables_map[v/2 + 16] - 16);
}
else
- { v += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
+ { v += dynamic_array_area_size - (MAX_ZCODE_GLOBAL_VARS*2);
}
break;
/* The main routine: linking in a module with the given filename. */
/* ------------------------------------------------------------------------- */
-char current_module_filename[128];
+char current_module_filename[PATHLEN];
void link_module(char *given_filename)
{ FILE *fin;
int record_type;
- char filename[128];
+ char filename[PATHLEN];
uchar *p, p0[64];
int32 last, i, j, k, l, m, vn, len, size, link_offset, module_size, map,
max_property_identifier, symbols_base = no_symbols;
no_rr = 0;
if ((linker_trace_level>=1) || transcript_switch)
- { char link_banner[128];
+ { char link_banner[PATHLEN+128];
sprintf(link_banner,
"[Linking release %d.%c%c%c%c%c%c of module '%s' (size %dK)]",
p[2]*256 + p[3], p[18], p[19], p[20], p[21], p[22], p[23],
if (((record_type == EXPORT_MV) || (record_type == EXPORTSF_MV))
&& (IE.symbol_type == INDIVIDUAL_PROPERTY_T))
{ int32 si = symbol_index(IE.symbol_name, -1);
- property_identifier_map[IE.symbol_value] = svals[si];
+ property_identifier_map[IE.symbol_value] = symbols[si].value;
}
switch(record_type)
{ case EXPORT_MV:
for (i=0; i<module_map[6]; i++)
{ if (xref_table[i] != -1)
printf("module %4d -> story file '%s'\n", i,
- (char *) symbs[xref_table[i]]);
+ symbols[xref_table[i]].name);
}
}
/* (6) Backpatch the backpatch markers attached to exported symbols */
for (i=symbols_base; i<no_symbols; i++)
- { if ((sflags[i] & CHANGE_SFLAG) && (sflags[i] & EXPORT_SFLAG))
- { backpatch_marker = svals[i]/0x10000;
- j = svals[i] % 0x10000;
+ { if ((symbols[i].flags & CHANGE_SFLAG) && (symbols[i].flags & EXPORT_SFLAG))
+ { backpatch_marker = symbols[i].marker;
+ j = symbols[i].value % 0x10000;
j = backpatch_backpatch(j);
- svals[i] = backpatch_marker*0x10000 + j;
- if (backpatch_marker == 0) sflags[i] &= (~(CHANGE_SFLAG));
+ symbols[i].value = j;
+ if (backpatch_marker == 0) symbols[i].flags &= (~(CHANGE_SFLAG));
}
}
backpatch_module_image(p, marker_value, ZCODE_ZA, offset);
break;
default:
+ ensure_memory_list_available(&zcode_backpatch_table_memlist, zcode_backpatch_size+3);
backpatch_module_image(p, marker_value, ZCODE_ZA, offset);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, backpatch_marker);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, (offset + zmachine_pc)/256);
- write_byte_to_memory_block(&zcode_backpatch_table,
- zcode_backpatch_size++, (offset + zmachine_pc)%256);
+ zcode_backpatch_table[zcode_backpatch_size++] = backpatch_marker;
+ zcode_backpatch_table[zcode_backpatch_size++] = (offset + zmachine_pc)/256;
+ zcode_backpatch_table[zcode_backpatch_size++] = (offset + zmachine_pc)%256;
break;
}
}
case INDIVIDUAL_PROP_ZA:
offset += individuals_length; break;
case DYNAMIC_ARRAY_ZA:
- if (offset < (MAX_GLOBAL_VARIABLES*2))
+ if (offset < (MAX_ZCODE_GLOBAL_VARS*2))
{ offset = 2*(variables_map[offset/2 + 16] - 16);
}
else
- { offset += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
+ { offset += dynamic_array_area_size - (MAX_ZCODE_GLOBAL_VARS*2);
}
break;
}
/* (10) Glue in the dynamic array data */
- i = m_static_offset - m_vars_offset - MAX_GLOBAL_VARIABLES*2;
- if (dynamic_array_area_size + i >= MAX_STATIC_DATA)
- memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
+ i = m_static_offset - m_vars_offset - MAX_ZCODE_GLOBAL_VARS*2;
+ ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size + i);
if (linker_trace_level >= 2)
printf("Inserting dynamic array area, %04x to %04x, at %04x\n",
- m_vars_offset + MAX_GLOBAL_VARIABLES*2, m_static_offset,
+ m_vars_offset + MAX_ZCODE_GLOBAL_VARS*2, m_static_offset,
variables_offset + dynamic_array_area_size);
for (k=0;k<i;k++)
{ dynamic_array_area[dynamic_array_area_size+k]
- = p[m_vars_offset+MAX_GLOBAL_VARIABLES*2+k];
+ = p[m_vars_offset+MAX_ZCODE_GLOBAL_VARS*2+k];
}
dynamic_array_area_size+=i;
printf("Inserting code area, %04x to %04x, at code offset %04x (+%04x)\n",
m_code_offset, m_strs_offset, code_offset, zmachine_pc);
+ ensure_memory_list_available(&zcode_area_memlist, zmachine_pc + (m_strs_offset - m_code_offset));
+
for (k=m_code_offset;k<m_strs_offset;k++)
- { if (temporary_files_switch)
- { fputc(p[k],Temp2_fp);
- zmachine_pc++;
- }
- else
- write_byte_to_memory_block(&zcode_area, zmachine_pc++, p[k]);
+ {
+ zcode_area[zmachine_pc++] = p[k];
}
/* (12) Glue in the static strings area */
at strings offset %04x (+%04x)\n",
m_strs_offset, link_offset, strings_offset,
static_strings_extent);
+ ensure_memory_list_available(&static_strings_area_memlist, static_strings_extent+link_offset-m_strs_offset);
for (k=m_strs_offset;k<link_offset;k++)
- { if (temporary_files_switch)
- { fputc(p[k], Temp1_fp);
- static_strings_extent++;
- }
- else
- write_byte_to_memory_block(&static_strings_area,
- static_strings_extent++, p[k]);
+ {
+ static_strings_area[static_strings_extent++] = p[k];
}
/* (13) Append the class object-numbers table: note that modules
{ j = p[i]*256 + p[i+1]; i+=2;
if (j == 0) break;
- class_object_numbers[no_classes] = j + no_objects;
+ ensure_memory_list_available(&class_info_memlist, no_classes+1);
+
+ class_info[no_classes].object_number = j + no_objects;
j = p[i]*256 + p[i+1]; i+=2;
- class_begins_at[no_classes++] = j + properties_table_size;
+ class_info[no_classes++].begins_at = j + properties_table_size;
} while (TRUE);
printf("Joining on object tree of size %d\n", m_no_objects);
for (i=0, k=no_objects, last=m_props_offset;i<m_no_objects;i++)
- { objectsz[no_objects].atts[0]=p[m_objs_offset+14*i];
+ {
+ ensure_memory_list_available(&objectsz_memlist, no_objects+1);
+ objectsz[no_objects].atts[0]=p[m_objs_offset+14*i];
objectsz[no_objects].atts[1]=p[m_objs_offset+14*i+1];
objectsz[no_objects].atts[2]=p[m_objs_offset+14*i+2];
objectsz[no_objects].atts[3]=p[m_objs_offset+14*i+3];
/* (15) Glue on the properties */
if (last>m_props_offset)
- { i = m_static_offset - m_vars_offset - MAX_GLOBAL_VARIABLES*2;
- if (dynamic_array_area_size + i >= MAX_STATIC_DATA)
- memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
+ { i = m_static_offset - m_vars_offset - MAX_ZCODE_GLOBAL_VARS*2;
if (linker_trace_level >= 2)
printf("Inserting object properties area, %04x to %04x, at +%04x\n",
m_props_offset, last, properties_table_size);
+ ensure_memory_list_available(&properties_table_memlist, properties_table_size+last-m_props_offset);
for (k=0;k<last-m_props_offset;k++)
properties_table[properties_table_size++] = p[m_props_offset+k];
}
/* (17) Append the individual property values table */
i = m_individuals_length;
- if (individuals_length + i >= MAX_INDIV_PROP_TABLE_SIZE)
- memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
- MAX_INDIV_PROP_TABLE_SIZE);
+ ensure_memory_list_available(&individuals_table_memlist, individuals_length + i);
if (linker_trace_level >= 2)
printf("Inserting individual prop tables area, %04x to %04x, at +%04x\n",
/* ------------------------------------------------------------------------- */
static void write_link_byte(int x)
-{ *link_data_top=(unsigned char) x; link_data_top++; link_data_size++;
- if (subtract_pointers(link_data_top,link_data_holding_area)
- >= MAX_LINK_DATA_SIZE)
- { memoryerror("MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
- }
+{
+ ensure_memory_list_available(&link_data_holding_area_memlist, link_data_ha_size+1);
+ link_data_holding_area[link_data_ha_size] = (unsigned char) x;
+ link_data_ha_size++; link_data_size++;
}
extern void flush_link_data(void)
{ int32 i, j;
- j = subtract_pointers(link_data_top, link_data_holding_area);
- if (temporary_files_switch)
- for (i=0;i<j;i++) fputc(link_data_holding_area[i], Temp3_fp);
- else
- for (i=0;i<j;i++)
- write_byte_to_memory_block(&link_data_area, link_data_size-j+i,
- link_data_holding_area[i]);
- link_data_top=link_data_holding_area;
+ j = link_data_ha_size;
+ ensure_memory_list_available(&link_data_area_memlist, link_data_size);
+ for (i=0;i<j;i++)
+ link_data_area[link_data_size-j+i] = link_data_holding_area[i];
+ link_data_ha_size = 0;
}
static void write_link_word(int32 x)
for (symbol_number = 0; symbol_number < no_symbols; symbol_number++)
{ int export_flag = FALSE, import_flag = FALSE;
- if (stypes[symbol_number]==GLOBAL_VARIABLE_T)
- { if (svals[symbol_number] < LOWEST_SYSTEM_VAR_NUMBER)
- { if (sflags[symbol_number] & IMPORT_SFLAG)
+ if (symbols[symbol_number].type==GLOBAL_VARIABLE_T)
+ { if (symbols[symbol_number].value < LOWEST_SYSTEM_VAR_NUMBER)
+ { if (symbols[symbol_number].flags & IMPORT_SFLAG)
import_flag = TRUE;
else
- if (!(sflags[symbol_number] & SYSTEM_SFLAG))
+ if (!(symbols[symbol_number].flags & SYSTEM_SFLAG))
export_flag = TRUE;
}
}
else
- { if (!(sflags[symbol_number] & SYSTEM_SFLAG))
- { if (sflags[symbol_number] & UNKNOWN_SFLAG)
- { if (sflags[symbol_number] & IMPORT_SFLAG)
+ { if (!(symbols[symbol_number].flags & SYSTEM_SFLAG))
+ { if (symbols[symbol_number].flags & UNKNOWN_SFLAG)
+ { if (symbols[symbol_number].flags & IMPORT_SFLAG)
import_flag = TRUE;
}
else
- switch(stypes[symbol_number])
+ switch(symbols[symbol_number].type)
{ case LABEL_T:
case ATTRIBUTE_T:
case PROPERTY_T:
{ if (linker_trace_level >= 1)
{ IE.module_value = EXPORT_MV;
IE.symbol_number = symbol_number;
- IE.symbol_type = stypes[symbol_number];
- IE.symbol_value = svals[symbol_number];
- IE.symbol_name = (char *) (symbs[symbol_number]);
+ IE.symbol_type = symbols[symbol_number].type;
+ IE.symbol_value = symbols[symbol_number].value;
+ IE.symbol_name = (symbols[symbol_number].name);
describe_importexport(&IE);
}
- if (sflags[symbol_number] & ACTION_SFLAG)
+ if (symbols[symbol_number].flags & ACTION_SFLAG)
write_link_byte(EXPORTAC_MV);
else
- if (sflags[symbol_number] & INSF_SFLAG)
+ if (symbols[symbol_number].flags & INSF_SFLAG)
write_link_byte(EXPORTSF_MV);
else
write_link_byte(EXPORT_MV);
write_link_word(symbol_number);
- write_link_byte(stypes[symbol_number]);
- if (sflags[symbol_number] & CHANGE_SFLAG)
- write_link_byte(svals[symbol_number] / 0x10000);
+ write_link_byte(symbols[symbol_number].type);
+ if (symbols[symbol_number].flags & CHANGE_SFLAG)
+ write_link_byte(symbols[symbol_number].marker);
else write_link_byte(0);
- write_link_word(svals[symbol_number] % 0x10000);
- write_link_string((char *) (symbs[symbol_number]));
+ write_link_word(symbols[symbol_number].value % 0x10000);
+ write_link_string((symbols[symbol_number].name));
flush_link_data();
}
{ if (linker_trace_level >= 1)
{ IE.module_value = IMPORT_MV;
IE.symbol_number = symbol_number;
- IE.symbol_type = stypes[symbol_number];
- IE.symbol_value = svals[symbol_number];
- IE.symbol_name = (char *) (symbs[symbol_number]);
+ IE.symbol_type = symbols[symbol_number].type;
+ IE.symbol_value = symbols[symbol_number].value;
+ IE.symbol_name = (symbols[symbol_number].name);
describe_importexport(&IE);
}
write_link_byte(IMPORT_MV);
write_link_word(symbol_number);
- write_link_byte(stypes[symbol_number]);
- write_link_word(svals[symbol_number]);
- write_link_string((char *) (symbs[symbol_number]));
+ write_link_byte(symbols[symbol_number].type);
+ write_link_word(symbols[symbol_number].value);
+ write_link_string((symbols[symbol_number].name));
flush_link_data();
}
}
int mv_vref=LOWEST_SYSTEM_VAR_NUMBER-1;
void import_symbol(int32 symbol_number)
-{ sflags[symbol_number] |= IMPORT_SFLAG;
- switch(stypes[symbol_number])
+{ symbols[symbol_number].flags |= IMPORT_SFLAG;
+ switch(symbols[symbol_number].type)
{ case GLOBAL_VARIABLE_T:
- assign_symbol(symbol_number, mv_vref--, stypes[symbol_number]);
+ assign_symbol(symbol_number, mv_vref--, symbols[symbol_number].type);
break;
}
}
extern void init_linker_vars(void)
{ link_data_size = 0;
- initialise_memory_block(&link_data_area);
+ link_data_area = NULL;
+ link_data_ha_size = 0;
+ link_data_holding_area = NULL;
}
extern void linker_begin_pass(void)
-{ link_data_top = link_data_holding_area;
+{ link_data_ha_size = 0;
}
extern void linker_endpass(void)
}
extern void linker_allocate_arrays(void)
-{ if (!module_switch)
- link_data_holding_area
- = my_malloc(64, "link data holding area");
- else
- link_data_holding_area
- = my_malloc(MAX_LINK_DATA_SIZE, "link data holding area");
+{
+ int initlinksize = (module_switch ? 2000 : 0);
+ initialise_memory_list(&link_data_holding_area_memlist,
+ sizeof(uchar), initlinksize, (void**)&link_data_holding_area,
+ "link data holding area");
+ initialise_memory_list(&link_data_area_memlist,
+ sizeof(uchar), 128, (void**)&link_data_area,
+ "link data area");
}
extern void linker_free_arrays(void)
-{ my_free(&link_data_holding_area, "link data holding area");
- deallocate_memory_block(&link_data_area);
+{
+ deallocate_memory_list(&link_data_holding_area_memlist);
+ deallocate_memory_list(&link_data_area_memlist);
}
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* "memory" : Memory management and ICL memory setting commands */
-/* (For "memoryerror", see "errors.c") */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
-int32 malloced_bytes=0; /* Total amount of memory allocated */
+size_t malloced_bytes=0; /* Total amount of memory allocated */
+
+/* Wrappers for malloc(), realloc(), etc.
+
+ Note that all of these functions call memory_out_error() on failure.
+ This is a fatal error and does not return. However, we check my_malloc()
+ return values anyway as a matter of good habit.
+ */
#ifdef PC_QUICKC
-extern void *my_malloc(int32 size, char *whatfor)
+extern void *my_malloc(size_t size, char *whatfor)
{ char _huge *c;
if (memout_switch)
printf("Allocating %ld bytes for %s\n",size,whatfor);
if (size==0) return(NULL);
- c=(char _huge *)halloc(size,1); malloced_bytes+=size;
+ c=(char _huge *)halloc(size,1);
+ malloced_bytes+=size;
if (c==0) memory_out_error(size, 1, whatfor);
return(c);
}
-extern void my_realloc(void *pointer, int32 oldsize, int32 size,
+extern void my_realloc(void *pointer, size_t oldsize, size_t size,
char *whatfor)
{ char _huge *c;
if (size==0) {
my_free(pointer, whatfor);
return;
}
- c=halloc(size,1); malloced_bytes+=size;
+ c=halloc(size,1);
+ malloced_bytes+=(size-oldsize);
if (c==0) memory_out_error(size, 1, whatfor);
if (memout_switch)
- printf("Increasing allocation to %ld bytes for %s was (%08lx) \
-now (%08lx)\n",
- (long int) size,whatfor,(long int) (*(int **)pointer),
+ printf("Increasing allocation from %ld to %ld bytes for %s was (%08lx) now (%08lx)\n",
+ (long int) oldsize, (long int) size, whatfor,
+ (long int) (*(int **)pointer),
(long int) c);
memcpy(c, *(int **)pointer, MIN(oldsize, size));
hfree(*(int **)pointer);
*(int **)pointer = c;
}
-extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
+extern void *my_calloc(size_t size, size_t howmany, char *whatfor)
{ void _huge *c;
if (memout_switch)
printf("Allocating %d bytes: array (%ld entries size %ld) for %s\n",
size*howmany,howmany,size,whatfor);
if ((size*howmany) == 0) return(NULL);
- c=(void _huge *)halloc(howmany*size,1); malloced_bytes+=size*howmany;
+ c=(void _huge *)halloc(howmany*size,1);
+ malloced_bytes+=size*howmany;
if (c==0) memory_out_error(size, howmany, whatfor);
return(c);
}
-extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
+extern void my_recalloc(void *pointer, size_t size, size_t oldhowmany,
int32 howmany, char *whatfor)
{ void _huge *c;
if (size*howmany==0) {
my_free(pointer, whatfor);
return;
}
- c=(void _huge *)halloc(size*howmany,1); malloced_bytes+=size*howmany;
+ c=(void _huge *)halloc(size*howmany,1);
+ malloced_bytes+=size*(howmany-oldhowmany);
if (c==0) memory_out_error(size, howmany, whatfor);
if (memout_switch)
- printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
-for %s was (%08lx) now (%08lx)\n",
+ printf("Increasing allocation from %ld to %ld bytes: array (%ld entries size %ld) for %s was (%08lx) now (%08lx)\n",
+ ((long int)size) * ((long int)oldhowmany),
((long int)size) * ((long int)howmany),
- (long int)howmany,(long int)size,whatfor,
+ (long int)howmany, (long int)size, whatfor,
(long int) *(int **)pointer, (long int) c);
memcpy(c, *(int **)pointer, MIN(size*oldhowmany, size*howmany));
hfree(*(int **)pointer);
#else
-extern void *my_malloc(int32 size, char *whatfor)
+extern void *my_malloc(size_t size, char *whatfor)
{ char *c;
if (size==0) return(NULL);
- c=malloc((size_t) size); malloced_bytes+=size;
+ c=malloc(size);
+ malloced_bytes+=size;
if (c==0) memory_out_error(size, 1, whatfor);
if (memout_switch)
printf("Allocating %ld bytes for %s at (%08lx)\n",
return(c);
}
-extern void my_realloc(void *pointer, int32 oldsize, int32 size,
+extern void my_realloc(void *pointer, size_t oldsize, size_t size,
char *whatfor)
{ void *c;
if (size==0) {
my_free(pointer, whatfor);
return;
}
- c=realloc(*(int **)pointer, (size_t) size); malloced_bytes+=size;
+ c=realloc(*(int **)pointer, size);
+ malloced_bytes+=(size-oldsize);
if (c==0) memory_out_error(size, 1, whatfor);
if (memout_switch)
- printf("Increasing allocation to %ld bytes for %s was (%08lx) \
-now (%08lx)\n",
- (long int) size,whatfor,(long int) (*(int **)pointer),
+ printf("Increasing allocation from %ld to %ld bytes for %s was (%08lx) now (%08lx)\n",
+ (long int) oldsize, (long int) size, whatfor,
+ (long int) (*(int **)pointer),
(long int) c);
*(int **)pointer = c;
}
-extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
+extern void *my_calloc(size_t size, size_t howmany, char *whatfor)
{ void *c;
if (size*howmany==0) return(NULL);
- c=calloc(howmany,(size_t) size); malloced_bytes+=size*howmany;
+ c=calloc(howmany, size);
+ malloced_bytes+=size*howmany;
if (c==0) memory_out_error(size, howmany, whatfor);
if (memout_switch)
printf("Allocating %ld bytes: array (%ld entries size %ld) \
return(c);
}
-extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
- int32 howmany, char *whatfor)
+extern void my_recalloc(void *pointer, size_t size, size_t oldhowmany,
+ size_t howmany, char *whatfor)
{ void *c;
if (size*howmany==0) {
my_free(pointer, whatfor);
return;
}
- c=realloc(*(int **)pointer, (size_t)size*(size_t)howmany);
- malloced_bytes+=size*howmany;
+ c=realloc(*(int **)pointer, size*howmany);
+ malloced_bytes+=size*(howmany-oldhowmany);
if (c==0) memory_out_error(size, howmany, whatfor);
if (memout_switch)
- printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
-for %s was (%08lx) now (%08lx)\n",
+ printf("Increasing allocation from %ld to %ld bytes: array (%ld entries size %ld) for %s was (%08lx) now (%08lx)\n",
+ ((long int)size) * ((long int)oldhowmany),
((long int)size) * ((long int)howmany),
- (long int)howmany,(long int)size,whatfor,
+ (long int)howmany, (long int)size, whatfor,
(long int) *(int **)pointer, (long int) c);
*(int **)pointer = c;
}
}
/* ------------------------------------------------------------------------- */
-/* Extensible blocks of memory, providing a kind of RAM disc as an */
-/* alternative to the temporary files option */
+/* A dynamic memory array. This grows as needed (but never shrinks). */
+/* Call ensure_memory_list_available(N) before accessing array item N-1. */
+/* */
+/* whatfor must be a static string describing the list. initalloc is */
+/* (optionally) the number of items to allocate right away. */
/* */
-/* The allocation is slightly confusing. A block can store up to 72 */
-/* chunks, which are allocated as needed when data is written. (Data does */
-/* not have to be written in order, but you should not try to read a byte */
-/* before writing it.) The size of a chunk is defined by ALLOC_CHUNK_SIZE. */
-/* So any block can store any amount of data, but you increase the limit */
-/* (for all blocks) by increasing ALLOC_CHUNK_SIZE, not the number of */
-/* chunks. */
+/* You typically initialise this with extpointer referring to an array of */
+/* structs or whatever type you need. Whenever the memory list grows, the */
+/* external array will be updated to refer to the new data. */
+/* */
+/* Add "#define DEBUG_MEMLISTS" to allocate exactly the number of items */
+/* needed, rather than increasing allocations exponentially. This is very */
+/* slow but it lets us track down array overruns. */
/* ------------------------------------------------------------------------- */
-static char chunk_name_buffer[60];
-static char *chunk_name(memory_block *MB, int no)
-{ char *p = "(unknown)";
- if (MB == &static_strings_area) p = "static strings area";
- if (MB == &zcode_area) p = "Z-code area";
- if (MB == &link_data_area) p = "link data area";
- if (MB == &zcode_backpatch_table) p = "Z-code backpatch table";
- if (MB == &staticarray_backpatch_table) p = "Static array backpatch table";
- if (MB == &zmachine_backpatch_table) p = "Z-machine backpatch table";
- sprintf(chunk_name_buffer, "%s chunk %d", p, no);
- return(chunk_name_buffer);
-}
+void initialise_memory_list(memory_list *ML, size_t itemsize, size_t initalloc, void **extpointer, char *whatfor)
+{
+ #ifdef DEBUG_MEMLISTS
+ initalloc = 0; /* No initial allocation */
+ #endif
+
+ ML->whatfor = whatfor;
+ ML->itemsize = itemsize;
+ ML->count = 0;
+ ML->data = NULL;
+ ML->extpointer = extpointer;
-extern void initialise_memory_block(memory_block *MB)
-{ int i;
- MB->chunks = 0;
- for (i=0; i<72; i++) MB->chunk[i] = NULL;
- MB->extent_of_last = 0;
- MB->write_pos = 0;
-}
+ if (initalloc) {
+ ML->count = initalloc;
+ ML->data = my_calloc(ML->itemsize, ML->count, ML->whatfor);
+ if (ML->data == NULL) return;
+ }
-extern void deallocate_memory_block(memory_block *MB)
-{ int i;
- for (i=0; i<72; i++)
- if (MB->chunk[i] != NULL)
- my_free(&(MB->chunk[i]), chunk_name(MB, i));
- MB->chunks = 0;
- MB->extent_of_last = 0;
+ if (ML->extpointer)
+ *(ML->extpointer) = ML->data;
}
-extern int read_byte_from_memory_block(memory_block *MB, int32 index)
-{ uchar *p;
- p = MB->chunk[index/ALLOC_CHUNK_SIZE];
- if (p == NULL)
- { compiler_error_named("memory: read from unwritten byte in",
- chunk_name(MB, index/ALLOC_CHUNK_SIZE));
- return 0;
- }
- return p[index % ALLOC_CHUNK_SIZE];
+void deallocate_memory_list(memory_list *ML)
+{
+ ML->itemsize = 0;
+ ML->count = 0;
+
+ if (ML->data)
+ my_free(&(ML->data), ML->whatfor);
+
+ if (ML->extpointer)
+ *(ML->extpointer) = NULL;
+ ML->extpointer = NULL;
}
-extern void write_byte_to_memory_block(memory_block *MB, int32 index, int value)
-{ uchar *p; int ch = index/ALLOC_CHUNK_SIZE;
- if (ch < 0)
- { compiler_error_named("memory: negative index to", chunk_name(MB, 0));
+/* After this is called, at least count items will be available in the list.
+ That is, you can freely access array[0] through array[count-1]. */
+void ensure_memory_list_available(memory_list *ML, size_t count)
+{
+ size_t oldcount;
+
+ if (ML->itemsize == 0) {
+ /* whatfor is also null! */
+ compiler_error("memory: attempt to access uninitialized memory_list");
return;
}
- if (ch >= 72) memoryerror("ALLOC_CHUNK_SIZE", ALLOC_CHUNK_SIZE);
- if (MB->chunk[ch] == NULL)
- { int i;
- MB->chunk[ch] = my_malloc(ALLOC_CHUNK_SIZE, chunk_name(MB, ch));
- p = MB->chunk[ch];
- for (i=0; i<ALLOC_CHUNK_SIZE; i++) p[i] = 255;
+ if (ML->count >= count) {
+ return;
}
- p = MB->chunk[ch];
- p[index % ALLOC_CHUNK_SIZE] = value;
+ oldcount = ML->count;
+ ML->count = 2*count+8; /* Allow headroom for future growth */
+
+ #ifdef DEBUG_MEMLISTS
+ ML->count = count; /* No headroom */
+ #endif
+
+ if (ML->data == NULL)
+ ML->data = my_calloc(ML->itemsize, ML->count, ML->whatfor);
+ else
+ my_recalloc(&(ML->data), ML->itemsize, oldcount, ML->count, ML->whatfor);
+ if (ML->data == NULL) return;
+
+ if (ML->extpointer)
+ *(ML->extpointer) = ML->data;
}
/* ------------------------------------------------------------------------- */
/* Where the memory settings are declared as variables */
/* ------------------------------------------------------------------------- */
-int MAX_QTEXT_SIZE;
-int MAX_SYMBOLS;
-int SYMBOLS_CHUNK_SIZE;
int HASH_TAB_SIZE;
-int MAX_OBJECTS;
-int MAX_ARRAYS;
-int MAX_ACTIONS;
-int MAX_ADJECTIVES;
-int MAX_DICT_ENTRIES;
-int MAX_STATIC_DATA;
-int MAX_PROP_TABLE_SIZE;
int MAX_ABBREVS;
int MAX_DYNAMIC_STRINGS;
-int MAX_EXPRESSION_NODES;
-int MAX_VERBS;
-int MAX_VERBSPACE;
-int MAX_LABELS;
-int MAX_LINESPACE;
-int32 MAX_STATIC_STRINGS;
-int32 MAX_ZCODE_SIZE;
-int MAX_LOW_STRINGS;
-int32 MAX_TRANSCRIPT_SIZE;
-int MAX_CLASSES;
-int32 MAX_LINK_DATA_SIZE;
-int MAX_INCLUSION_DEPTH;
-int MAX_SOURCE_FILES;
-int32 MAX_INDIV_PROP_TABLE_SIZE;
-int32 MAX_OBJ_PROP_TABLE_SIZE;
-int MAX_OBJ_PROP_COUNT;
int MAX_LOCAL_VARIABLES;
-int MAX_GLOBAL_VARIABLES;
int DICT_WORD_SIZE; /* number of characters in a dict word */
int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */
int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */
int ZCODE_HEADER_EXT_WORDS; /* (zcode 1.0) requested header extension size */
int ZCODE_HEADER_FLAGS_3; /* (zcode 1.1) value to place in Flags 3 word */
+int ZCODE_LESS_DICT_DATA; /* (zcode) use 2 data bytes per dict word instead of 3 */
int NUM_ATTR_BYTES;
int GLULX_OBJECT_EXT_BYTES; /* (glulx) extra bytes for each object record */
-int32 MAX_NUM_STATIC_STRINGS;
-int32 MAX_UNICODE_CHARS;
int32 MAX_STACK_SIZE;
int32 MEMORY_MAP_EXTENSION;
-int ALLOC_CHUNK_SIZE;
int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
+int STRIP_UNREACHABLE_LABELS; /* 0: no, 1: yes (default) */
int TRANSCRIPT_FORMAT; /* 0: classic, 1: prefixed */
/* The way memory sizes are set causes great nuisance for those parameters
which have different defaults under Z-code and Glulx. We have to get
the defaults right whether the user sets "-G $HUGE" or "$HUGE -G".
And an explicit value set by the user should override both defaults. */
-static int32 MAX_ZCODE_SIZE_z, MAX_ZCODE_SIZE_g;
-static int MAX_PROP_TABLE_SIZE_z, MAX_PROP_TABLE_SIZE_g;
-static int MAX_GLOBAL_VARIABLES_z, MAX_GLOBAL_VARIABLES_g;
-static int MAX_LOCAL_VARIABLES_z, MAX_LOCAL_VARIABLES_g;
static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
-static int ALLOC_CHUNK_SIZE_z, ALLOC_CHUNK_SIZE_g;
static int MAX_DYNAMIC_STRINGS_z, MAX_DYNAMIC_STRINGS_g;
/* ------------------------------------------------------------------------- */
printf("| %25s = %-7s |\n","Memory setting","Value");
printf("+--------------------------------------+\n");
printf("| %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
- printf("| %25s = %-7d |\n","MAX_ACTIONS",MAX_ACTIONS);
- printf("| %25s = %-7d |\n","MAX_ADJECTIVES",MAX_ADJECTIVES);
- printf("| %25s = %-7d |\n","ALLOC_CHUNK_SIZE",ALLOC_CHUNK_SIZE);
- printf("| %25s = %-7d |\n","MAX_ARRAYS",MAX_ARRAYS);
printf("| %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
- printf("| %25s = %-7d |\n","MAX_CLASSES",MAX_CLASSES);
- printf("| %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
printf("| %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
if (glulx_mode)
printf("| %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
printf("| %25s = %-7d |\n","MAX_DYNAMIC_STRINGS",MAX_DYNAMIC_STRINGS);
- printf("| %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES);
- printf("| %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES);
printf("| %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
if (!glulx_mode)
printf("| %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
if (!glulx_mode)
printf("| %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
- printf("| %25s = %-7d |\n","MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
- printf("| %25s = %-7d |\n","MAX_INDIV_PROP_TABLE_SIZE", MAX_INDIV_PROP_TABLE_SIZE);
+ if (!glulx_mode)
+ printf("| %25s = %-7d |\n","ZCODE_LESS_DICT_DATA",ZCODE_LESS_DICT_DATA);
printf("| %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
- printf("| %25s = %-7d |\n","MAX_LABELS",MAX_LABELS);
- printf("| %25s = %-7d |\n","MAX_LINESPACE",MAX_LINESPACE);
- printf("| %25s = %-7d |\n","MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
- if (glulx_mode)
- printf("| %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
- printf("| %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
if (glulx_mode)
printf("| %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
MEMORY_MAP_EXTENSION);
- if (glulx_mode)
- printf("| %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
- MAX_NUM_STATIC_STRINGS);
- printf("| %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
if (glulx_mode)
printf("| %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
GLULX_OBJECT_EXT_BYTES);
- if (glulx_mode)
- printf("| %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
- MAX_OBJ_PROP_COUNT);
- if (glulx_mode)
- printf("| %25s = %-7d |\n","MAX_OBJ_PROP_TABLE_SIZE",
- MAX_OBJ_PROP_TABLE_SIZE);
- printf("| %25s = %-7d |\n","MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
- printf("| %25s = %-7d |\n","MAX_QTEXT_SIZE",MAX_QTEXT_SIZE);
- printf("| %25s = %-7d |\n","MAX_SOURCE_FILES",MAX_SOURCE_FILES);
if (glulx_mode)
printf("| %25s = %-7ld |\n","MAX_STACK_SIZE",
(long int) MAX_STACK_SIZE);
- printf("| %25s = %-7d |\n","MAX_STATIC_DATA",MAX_STATIC_DATA);
- printf("| %25s = %-7ld |\n","MAX_STATIC_STRINGS",
- (long int) MAX_STATIC_STRINGS);
- printf("| %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
- printf("| %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
printf("| %25s = %-7d |\n","TRANSCRIPT_FORMAT",TRANSCRIPT_FORMAT);
- printf("| %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
- (long int) MAX_TRANSCRIPT_SIZE);
- if (glulx_mode)
- printf("| %25s = %-7ld |\n","MAX_UNICODE_CHARS",
- (long int) MAX_UNICODE_CHARS);
printf("| %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
printf("| %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
- printf("| %25s = %-7d |\n","MAX_VERBS",MAX_VERBS);
- printf("| %25s = %-7d |\n","MAX_VERBSPACE",MAX_VERBSPACE);
- printf("| %25s = %-7ld |\n","MAX_ZCODE_SIZE",
- (long int) MAX_ZCODE_SIZE);
+ printf("| %25s = %-7d |\n","STRIP_UNREACHABLE_LABELS",STRIP_UNREACHABLE_LABELS);
printf("+--------------------------------------+\n");
}
-extern void set_memory_sizes(int size_flag)
+extern void set_memory_sizes(void)
{
- if (size_flag == HUGE_SIZE)
- {
- MAX_QTEXT_SIZE = 4000;
- MAX_SYMBOLS = 10000;
-
- SYMBOLS_CHUNK_SIZE = 5000;
- HASH_TAB_SIZE = 512;
-
- MAX_OBJECTS = 640;
-
- MAX_ACTIONS = 200;
- MAX_ADJECTIVES = 50;
- MAX_DICT_ENTRIES = 2000;
- MAX_STATIC_DATA = 10000;
-
- MAX_PROP_TABLE_SIZE_z = 30000;
- MAX_PROP_TABLE_SIZE_g = 60000;
-
- MAX_EXPRESSION_NODES = 100;
- MAX_VERBS = 200;
- MAX_VERBSPACE = 4096;
- MAX_LABELS = 1000;
- MAX_LINESPACE = 16000;
-
- MAX_STATIC_STRINGS = 8000;
- MAX_ZCODE_SIZE_z = 20000;
- MAX_ZCODE_SIZE_g = 40000;
- MAX_LINK_DATA_SIZE = 2000;
-
- MAX_LOW_STRINGS = 2048;
-
- MAX_TRANSCRIPT_SIZE = 200000;
- MAX_NUM_STATIC_STRINGS = 20000;
-
- MAX_CLASSES = 64;
-
- MAX_OBJ_PROP_COUNT = 128;
- MAX_OBJ_PROP_TABLE_SIZE = 4096;
-
- MAX_INDIV_PROP_TABLE_SIZE = 15000;
- MAX_ARRAYS = 128;
-
- MAX_GLOBAL_VARIABLES_z = 240;
- MAX_GLOBAL_VARIABLES_g = 512;
-
- ALLOC_CHUNK_SIZE_z = 8192;
- ALLOC_CHUNK_SIZE_g = 32768;
- }
- if (size_flag == LARGE_SIZE)
- {
- MAX_QTEXT_SIZE = 4000;
- MAX_SYMBOLS = 6400;
-
- SYMBOLS_CHUNK_SIZE = 5000;
- HASH_TAB_SIZE = 512;
-
- MAX_OBJECTS = 512;
-
- MAX_ACTIONS = 200;
- MAX_ADJECTIVES = 50;
- MAX_DICT_ENTRIES = 1300;
- MAX_STATIC_DATA = 10000;
-
- MAX_PROP_TABLE_SIZE_z = 15000;
- MAX_PROP_TABLE_SIZE_g = 30000;
-
- MAX_EXPRESSION_NODES = 100;
- MAX_VERBS = 140;
- MAX_VERBSPACE = 4096;
- MAX_LINESPACE = 10000;
-
- MAX_LABELS = 1000;
- MAX_STATIC_STRINGS = 8000;
- MAX_ZCODE_SIZE_z = 20000;
- MAX_ZCODE_SIZE_g = 40000;
- MAX_LINK_DATA_SIZE = 2000;
-
- MAX_LOW_STRINGS = 2048;
-
- MAX_TRANSCRIPT_SIZE = 200000;
- MAX_NUM_STATIC_STRINGS = 20000;
-
- MAX_CLASSES = 64;
-
- MAX_OBJ_PROP_COUNT = 64;
- MAX_OBJ_PROP_TABLE_SIZE = 2048;
-
- MAX_INDIV_PROP_TABLE_SIZE = 10000;
- MAX_ARRAYS = 128;
-
- MAX_GLOBAL_VARIABLES_z = 240;
- MAX_GLOBAL_VARIABLES_g = 512;
-
- ALLOC_CHUNK_SIZE_z = 8192;
- ALLOC_CHUNK_SIZE_g = 16384;
- }
- if (size_flag == SMALL_SIZE)
- {
- MAX_QTEXT_SIZE = 4000;
- MAX_SYMBOLS = 3000;
-
- SYMBOLS_CHUNK_SIZE = 2500;
- HASH_TAB_SIZE = 512;
-
- MAX_OBJECTS = 300;
-
- MAX_ACTIONS = 200;
- MAX_ADJECTIVES = 50;
- MAX_DICT_ENTRIES = 700;
- MAX_STATIC_DATA = 10000;
-
- MAX_PROP_TABLE_SIZE_z = 8000;
- MAX_PROP_TABLE_SIZE_g = 16000;
-
- MAX_EXPRESSION_NODES = 40;
- MAX_VERBS = 110;
- MAX_VERBSPACE = 2048;
- MAX_LINESPACE = 10000;
- MAX_LABELS = 1000;
-
- MAX_STATIC_STRINGS = 8000;
- MAX_ZCODE_SIZE_z = 10000;
- MAX_ZCODE_SIZE_g = 20000;
- MAX_LINK_DATA_SIZE = 1000;
-
- MAX_LOW_STRINGS = 1024;
-
- MAX_TRANSCRIPT_SIZE = 100000;
- MAX_NUM_STATIC_STRINGS = 10000;
-
- MAX_CLASSES = 32;
-
- MAX_OBJ_PROP_COUNT = 64;
- MAX_OBJ_PROP_TABLE_SIZE = 1024;
-
- MAX_INDIV_PROP_TABLE_SIZE = 5000;
- MAX_ARRAYS = 64;
-
- MAX_GLOBAL_VARIABLES_z = 240;
- MAX_GLOBAL_VARIABLES_g = 256;
-
- ALLOC_CHUNK_SIZE_z = 8192;
- ALLOC_CHUNK_SIZE_g = 8192;
- }
-
- /* Regardless of size_flag... */
- MAX_SOURCE_FILES = 256;
- MAX_INCLUSION_DEPTH = 5;
- MAX_LOCAL_VARIABLES_z = 16;
- MAX_LOCAL_VARIABLES_g = 32;
+ HASH_TAB_SIZE = 512;
DICT_CHAR_SIZE = 1;
DICT_WORD_SIZE_z = 6;
DICT_WORD_SIZE_g = 9;
NUM_ATTR_BYTES_g = 7;
MAX_ABBREVS = 64;
MAX_DYNAMIC_STRINGS_z = 32;
- MAX_DYNAMIC_STRINGS_g = 64;
+ MAX_DYNAMIC_STRINGS_g = 100;
/* Backwards-compatible behavior: allow for a unicode table
whether we need one or not. The user can set this to zero if
there's no unicode table. */
ZCODE_HEADER_EXT_WORDS = 3;
ZCODE_HEADER_FLAGS_3 = 0;
+ ZCODE_LESS_DICT_DATA = 0;
GLULX_OBJECT_EXT_BYTES = 0;
- MAX_UNICODE_CHARS = 64;
MEMORY_MAP_EXTENSION = 0;
/* We estimate the default Glulx stack size at 4096. That's about
enough for 90 nested function calls with 8 locals each -- the
MAX_STACK_SIZE = 4096;
OMIT_UNUSED_ROUTINES = 0;
WARN_UNUSED_ROUTINES = 0;
+ STRIP_UNREACHABLE_LABELS = 1;
TRANSCRIPT_FORMAT = 0;
adjust_memory_sizes();
extern void adjust_memory_sizes()
{
if (!glulx_mode) {
- MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_z;
- MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_z;
- MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_z;
- MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_z;
DICT_WORD_SIZE = DICT_WORD_SIZE_z;
NUM_ATTR_BYTES = NUM_ATTR_BYTES_z;
- ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_z;
MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_z;
INDIV_PROP_START = 64;
}
else {
- MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
- MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
- MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
- MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
DICT_WORD_SIZE = DICT_WORD_SIZE_g;
NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
- ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_g;
INDIV_PROP_START = 256;
}
static void explain_parameter(char *command)
{ printf("\n");
- if (strcmp(command,"MAX_QTEXT_SIZE")==0)
- { printf(
-" MAX_QTEXT_SIZE is the maximum length of a quoted string. Increasing\n\
- by 1 costs 5 bytes (for lexical analysis memory). Inform automatically\n\
- ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
- return;
- }
- if (strcmp(command,"MAX_SYMBOLS")==0)
- { printf(
-" MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
- objects, routines, the many internal Inform-generated names and so on.\n");
- return;
- }
- if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
- { printf(
-" The symbols names are stored in memory which is allocated in chunks \n\
- of size SYMBOLS_CHUNK_SIZE.\n");
- return;
- }
if (strcmp(command,"HASH_TAB_SIZE")==0)
{ printf(
" HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
symbols banks.\n");
return;
}
- if (strcmp(command,"MAX_OBJECTS")==0)
- { printf(
-" MAX_OBJECTS is the maximum number of objects. (If compiling a version-3 \n\
- game, 255 is an absolute maximum in any event.)\n");
- return;
- }
- if (strcmp(command,"MAX_ACTIONS")==0)
- { printf(
-" MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
- TakeSub which are referenced in the grammar table.\n");
- return;
- }
- if (strcmp(command,"MAX_ADJECTIVES")==0)
- { printf(
-" MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
- grammar table. Adjectives are misleadingly named: they are words such as \n\
- \"in\", \"under\" and the like.\n");
- return;
- }
- if (strcmp(command,"MAX_DICT_ENTRIES")==0)
- { printf(
-" MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
- into the game's dictionary. It costs 29 bytes to increase this by one.\n");
- return;
- }
if (strcmp(command,"DICT_WORD_SIZE")==0)
{ printf(
" DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
header extension table (Z-Spec 1.1).\n");
return;
}
+ if (strcmp(command,"ZCODE_LESS_DICT_DATA")==0)
+ { printf(
+" ZCODE_LESS_DICT_DATA, if set, provides each dict word with two data bytes\n\
+ rather than three. (Z-code only.)\n");
+ return;
+ }
if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
{ printf(
" GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
specifies the object structure.)\n");
return;
}
- if (strcmp(command,"MAX_STATIC_DATA")==0)
- { printf(
-" MAX_STATIC_DATA is the size of an array of integers holding initial \n\
- values for arrays and strings stored as ASCII inside the Z-machine. It \n\
- should be at least 1024 but seldom needs much more.\n");
- return;
- }
- if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
- { printf(
-" MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
- properties table.\n");
- return;
- }
if (strcmp(command,"MAX_ABBREVS")==0)
{ printf(
" MAX_ABBREVS is the maximum number of declared abbreviations. It is not \n\
- allowed to exceed 96 in Z-code.\n");
+ allowed to exceed 96 in Z-code. (This is not meaningful in Glulx, where \n\
+ there is no limit on abbreviations.)\n");
return;
}
if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
{ printf(
" MAX_DYNAMIC_STRINGS is the maximum number of string substitution variables\n\
- (\"@00\"). It is not allowed to exceed 96 in Z-code or 100 in Glulx.\n");
- return;
- }
- if (strcmp(command,"MAX_ARRAYS")==0)
- { printf(
-" MAX_ARRAYS is the maximum number of declared arrays.\n");
- return;
- }
- if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
- { printf(
-" MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
- evaluator's storage for parse trees. In effect, it measures how \n\
- complicated algebraic expressions are allowed to be. Increasing it by \n\
- one costs about 80 bytes.\n");
- return;
- }
- if (strcmp(command,"MAX_VERBS")==0)
- { printf(
-" MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
- defined, each with its own grammar. To increase it by one costs about\n\
- 128 bytes. A full game will contain at least 100.\n");
- return;
- }
- if (strcmp(command,"MAX_VERBSPACE")==0)
- { printf(
-" MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
- need increasing in games with many synonyms: unlikely to exceed 4K.\n");
- return;
- }
- if (strcmp(command,"MAX_LABELS")==0)
- { printf(
-" MAX_LABELS is the maximum number of label points in any one routine.\n\
- (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
- a minimum level of 2000, as about twice the normal number of label points\n\
- are needed to generate tables of how source code corresponds to positions\n\
- in compiled code.)");
- return;
- }
- if (strcmp(command,"MAX_LINESPACE")==0)
- { printf(
-" MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
- may need increasing in games with complex or extensive grammars.\n");
- return;
- }
- if (strcmp(command,"MAX_STATIC_STRINGS")==0)
- {
- printf(
-" MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
- strings before they're written into longer-term storage. 2000 bytes is \n\
- plenty, allowing string constants of up to about 3000 characters long.\n\
- Inform automatically ensures that this is at least twice the size of\n\
- MAX_QTEXT_SIZE, to be on the safe side.");
- return;
- }
- if (strcmp(command,"MAX_ZCODE_SIZE")==0)
- {
- printf(
-" MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
- code for a single routine. (It applies to both Z-code and Glulx, \n\
- despite the name.) As a guide, the longest library routine is \n\
- about 6500 bytes long in Z-code; about twice that in Glulx.");
- return;
- }
- if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
- {
- printf(
-" MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
- link data before it's written into longer-term storage. 2000 bytes \n\
- is plenty.");
- return;
- }
- if (strcmp(command,"MAX_LOW_STRINGS")==0)
- { printf(
-" MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
- compiled \"low strings\" which are to be written above the synonyms table \n\
- in the Z-machine. 1024 is plenty.\n");
- return;
- }
- if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
- { printf(
-" MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
- switch, and has the size in bytes of a buffer to hold the entire text of\n\
- the game being compiled: it has to be enormous, say 100000 to 200000.\n");
- return;
- }
- if (strcmp(command,"MAX_CLASSES")==0)
- { printf(
-" MAX_CLASSES maximum number of object classes which can be defined. This\n\
- is cheap to increase.\n");
- return;
- }
- if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
- { printf(
-" MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
- return;
- }
- if (strcmp(command,"MAX_SOURCE_FILES")==0)
- { printf(
-" MAX_SOURCE_FILES is the number of source files that can be read in the \n\
- compilation.\n");
- return;
- }
- if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
- { printf(
-" MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
- table of ..variable values.\n");
+ (\"@00\" or \"@(0)\"). It is not allowed to exceed 96 in Z-code.\n");
return;
}
if (strcmp(command,"INDIV_PROP_START")==0)
properties are numbered INDIV_PROP_START and up.\n");
return;
}
- if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
- { printf(
-" MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
- can have. (Glulx only)\n");
- return;
- }
- if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
- { printf(
-" MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
- single object's properties. (Glulx only)\n");
- return;
- }
- if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
- { printf(
-" MAX_LOCAL_VARIABLES is the number of local variables (including \n\
- arguments) allowed in a procedure. (Glulx only)\n");
- return;
- }
- if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
- { printf(
-" MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
- program. (Glulx only)\n");
- return;
- }
- if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
- {
- printf(
-" MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
- allowed in the program. (Glulx only)\n");
- return;
- }
- if (strcmp(command,"MAX_UNICODE_CHARS")==0)
- {
- printf(
-" MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
- (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
- (Glulx only)\n");
- return;
- }
- if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
- {
- printf(
-" ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
- for various structures.\n");
- return;
- }
if (strcmp(command,"MAX_STACK_SIZE")==0)
{
printf(
into the game file.\n");
return;
}
+ if (strcmp(command,"STRIP_UNREACHABLE_LABELS")==0)
+ {
+ printf(
+" STRIP_UNREACHABLE_LABELS, if set to 1, will skip labels in unreachable \n\
+ statements. Jumping to a skipped label is an error. If 0, all labels \n\
+ will be compiled, at the cost of less optimized code. The default is 1.\n");
+ return;
+ }
if (strcmp(command,"SERIAL")==0)
{
printf(
add_config_symbol_definition(command, value);
}
+static void set_trace_option(char *command)
+{
+ char *cx;
+ int value;
+
+ /* Parse options of the form STRING or STRING=NUM. (The $! has already been eaten.) If the string is null or empty, show help. */
+
+ if (!command || *command == '\0') {
+ printf("The full list of trace options:\n\n");
+ printf(" ACTIONS: show actions defined\n");
+ printf(" ASM: trace assembly (same as -a)\n");
+ printf(" ASM=2: also show hex dumps\n");
+ printf(" ASM=3: also show branch optimization info\n");
+ printf(" ASM=4: more verbose branch info\n");
+ printf(" BPATCH: show backpatch results\n");
+ printf(" BPATCH=2: also show markers added\n");
+ printf(" DICT: display the dictionary table\n");
+ printf(" DICT=2: also the byte encoding of entries\n");
+ printf(" EXPR: show expression trees\n");
+ printf(" EXPR=2: more verbose\n");
+ printf(" EXPR=3: even more verbose\n");
+ printf(" FILES: show files opened\n");
+ printf(" FINDABBREVS: show selection decisions during abbreviation optimization\n (only meaningful with -u)\n");
+ printf(" FINDABBREVS=2: also show three-letter-block decisions\n");
+ printf(" FREQ: show how efficient abbreviations were (same as -f)\n (only meaningful with -e)\n");
+ printf(" LINKER: show module linking info\n");
+ printf(" LINKER=2: more verbose (or 3, 4 for even more)\n");
+ printf(" MAP: print memory map of the virtual machine (same as -z)\n");
+ printf(" MAP=2: also show percentage of VM that each segment occupies\n");
+ printf(" MEM: show internal memory allocations\n");
+ printf(" OBJECTS: display the object table\n");
+ printf(" PROPS: show attributes and properties defined\n");
+ printf(" RUNTIME: show game function calls at runtime (same as -g)\n");
+ printf(" RUNTIME=2: also show library calls (not supported in Glulx)\n");
+ printf(" RUNTIME=3: also show veneer calls (not supported in Glulx)\n");
+ printf(" STATS: give compilation statistics (same as -s)\n");
+ printf(" SYMBOLS: display the symbol table\n");
+ printf(" SYMBOLS=2: also show compiler-defined symbols\n");
+ printf(" SYMDEF: show when symbols are noticed and defined\n");
+ printf(" TOKENS: show token lexing\n");
+ printf(" TOKENS=2: also show token types\n");
+ printf(" TOKENS=3: also show lexical context\n");
+ printf(" VERBS: display the verb grammar table\n");
+ return;
+ }
+
+ for (cx=command; *cx && *cx != '='; cx++) {
+ if (!(*cx >= 'A' && *cx <= 'Z')) {
+ printf("Invalid $! trace command \"%s\"\n", command);
+ return;
+ }
+ }
+
+ value = 1;
+ if (*cx == '=') {
+ char *ex;
+ value = strtol(cx+1, &ex, 10);
+
+ if (ex == cx+1 || *ex != '\0' || value < 0) {
+ printf("Bad numerical setting in $! trace command \"%s\"\n", command);
+ return;
+ }
+
+ *cx = '\0';
+ }
+
+ /* We accept some reasonable synonyms, including plausible singular/plural confusion. */
+
+ if (strcmp(command, "ASSEMBLY")==0 || strcmp(command, "ASM")==0) {
+ asm_trace_setting = value;
+ }
+ else if (strcmp(command, "ACTION")==0 || strcmp(command, "ACTIONS")==0) {
+ printactions_switch = value;
+ }
+ else if (strcmp(command, "BPATCH")==0 || strcmp(command, "BACKPATCH")==0) {
+ bpatch_trace_setting = value;
+ }
+ else if (strcmp(command, "DICTIONARY")==0 || strcmp(command, "DICT")==0) {
+ list_dict_setting = value;
+ }
+ else if (strcmp(command, "EXPR")==0 || strcmp(command, "EXPRESSION")==0 || strcmp(command, "EXPRESSIONS")==0) {
+ expr_trace_setting = value;
+ }
+ else if (strcmp(command, "FILE")==0 || strcmp(command, "FILES")==0) {
+ files_trace_setting = value;
+ }
+ else if (strcmp(command, "FINDABBREV")==0 || strcmp(command, "FINDABBREVS")==0) {
+ optabbrevs_trace_setting = value;
+ }
+ else if (strcmp(command, "FREQUENCY")==0 || strcmp(command, "FREQUENCIES")==0 || strcmp(command, "FREQ")==0) {
+ frequencies_setting = value;
+ }
+ else if (strcmp(command, "LINK")==0 || strcmp(command, "LINKER")==0) {
+ linker_trace_setting = value;
+ }
+ else if (strcmp(command, "MAP")==0) {
+ memory_map_setting = value;
+ }
+ else if (strcmp(command, "MEM")==0 || strcmp(command, "MEMORY")==0) {
+ memout_switch = value;
+ }
+ else if (strcmp(command, "OBJECTS")==0 || strcmp(command, "OBJECT")==0 || strcmp(command, "OBJS")==0 || strcmp(command, "OBJ")==0) {
+ list_objects_setting = value;
+ }
+ else if (strcmp(command, "PROP")==0 || strcmp(command, "PROPERTY")==0 || strcmp(command, "PROPS")==0 || strcmp(command, "PROPERTIES")==0) {
+ printprops_switch = value;
+ }
+ else if (strcmp(command, "RUNTIME")==0) {
+ trace_fns_setting = value;
+ }
+ else if (strcmp(command, "STATISTICS")==0 || strcmp(command, "STATS")==0 || strcmp(command, "STAT")==0) {
+ statistics_switch = value;
+ }
+ else if (strcmp(command, "SYMBOLS")==0 || strcmp(command, "SYMBOL")==0) {
+ list_symbols_setting = value;
+ }
+ else if (strcmp(command, "SYMDEF")==0 || strcmp(command, "SYMBOLDEF")==0) {
+ symdef_trace_setting = value;
+ }
+ else if (strcmp(command, "TOKEN")==0 || strcmp(command, "TOKENS")==0) {
+ tokens_trace_setting = value;
+ }
+ else if (strcmp(command, "VERBS")==0 || strcmp(command, "VERB")==0) {
+ list_verbs_setting = value;
+ }
+ else {
+ printf("Unrecognized $! trace command \"%s\"\n", command);
+ }
+}
+
/* Handle a dollar-sign command option: $LIST, $FOO=VAL, and so on.
The option may come from the command line, an ICL file, or a header
comment.
if (command[0]=='?') { explain_parameter(command+1); return; }
if (command[0]=='#') { add_predefined_symbol(command+1); return; }
+ if (command[0]=='!') { set_trace_option(command+1); return; }
- if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
- if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
- if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
+ if (strcmp(command, "HUGE")==0
+ || strcmp(command, "LARGE")==0
+ || strcmp(command, "SMALL")==0) {
+ if (!nowarnings_switch)
+ printf("The Inform 6 memory size commands (\"SMALL, LARGE, HUGE\") are no longer needed and has been withdrawn.\n");
+ return;
+ }
+
if (strcmp(command, "LIST")==0) { list_memory_sizes(); return; }
+
for (i=0; command[i]!=0; i++)
{ if (command[i]=='=')
{ command[i]=0;
if (strcmp(command,"BUFFER_LENGTH")==0)
flag=2;
if (strcmp(command,"MAX_QTEXT_SIZE")==0)
- { MAX_QTEXT_SIZE=j, flag=1;
- if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
- MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
- }
+ flag=3;
if (strcmp(command,"MAX_SYMBOLS")==0)
- MAX_SYMBOLS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_BANK_SIZE")==0)
flag=2;
if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
- SYMBOLS_CHUNK_SIZE=j, flag=1;
+ flag=3;
if (strcmp(command,"BANK_CHUNK_SIZE")==0)
flag=2;
if (strcmp(command,"HASH_TAB_SIZE")==0)
HASH_TAB_SIZE=j, flag=1;
if (strcmp(command,"MAX_OBJECTS")==0)
- MAX_OBJECTS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_ACTIONS")==0)
- MAX_ACTIONS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_ADJECTIVES")==0)
- MAX_ADJECTIVES=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_DICT_ENTRIES")==0)
- MAX_DICT_ENTRIES=j, flag=1;
+ flag=3;
if (strcmp(command,"DICT_WORD_SIZE")==0)
{ DICT_WORD_SIZE=j, flag=1;
DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
ZCODE_HEADER_EXT_WORDS=j, flag=1;
if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
ZCODE_HEADER_FLAGS_3=j, flag=1;
+ if (strcmp(command,"ZCODE_LESS_DICT_DATA")==0)
+ ZCODE_LESS_DICT_DATA=j, flag=1;
if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
GLULX_OBJECT_EXT_BYTES=j, flag=1;
if (strcmp(command,"MAX_STATIC_DATA")==0)
- MAX_STATIC_DATA=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_OLDEPTH")==0)
flag=2;
if (strcmp(command,"MAX_ROUTINES")==0)
if (strcmp(command,"MAX_GCONSTANTS")==0)
flag=2;
if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
- { MAX_PROP_TABLE_SIZE=j, flag=1;
- MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
- }
+ flag=3;
if (strcmp(command,"MAX_FORWARD_REFS")==0)
flag=2;
if (strcmp(command,"STACK_SIZE")==0)
MAX_DYNAMIC_STRINGS_g=MAX_DYNAMIC_STRINGS_z=j;
}
if (strcmp(command,"MAX_ARRAYS")==0)
- MAX_ARRAYS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
- MAX_EXPRESSION_NODES=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_VERBS")==0)
- MAX_VERBS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_VERBSPACE")==0)
- MAX_VERBSPACE=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_LABELS")==0)
- MAX_LABELS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_LINESPACE")==0)
- MAX_LINESPACE=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
- MAX_NUM_STATIC_STRINGS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_STATIC_STRINGS")==0)
- { MAX_STATIC_STRINGS=j, flag=1;
- if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
- MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
- }
+ flag=3;
if (strcmp(command,"MAX_ZCODE_SIZE")==0)
- { MAX_ZCODE_SIZE=j, flag=1;
- MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
- }
+ flag=3;
if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
- MAX_LINK_DATA_SIZE=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_LOW_STRINGS")==0)
- MAX_LOW_STRINGS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
- MAX_TRANSCRIPT_SIZE=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_CLASSES")==0)
- MAX_CLASSES=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
- MAX_INCLUSION_DEPTH=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_SOURCE_FILES")==0)
- MAX_SOURCE_FILES=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
- MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
+ flag=3;
if (strcmp(command,"INDIV_PROP_START")==0)
INDIV_PROP_START=j, flag=1;
if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
- MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
- MAX_OBJ_PROP_COUNT=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
- { MAX_LOCAL_VARIABLES=j, flag=1;
- MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
- }
+ flag=3;
if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
- { MAX_GLOBAL_VARIABLES=j, flag=1;
- MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
- }
+ flag=3;
if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
- { ALLOC_CHUNK_SIZE=j, flag=1;
- ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
- }
+ flag=3;
if (strcmp(command,"MAX_UNICODE_CHARS")==0)
- MAX_UNICODE_CHARS=j, flag=1;
+ flag=3;
if (strcmp(command,"MAX_STACK_SIZE")==0)
{
MAX_STACK_SIZE=j, flag=1;
if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
OMIT_UNUSED_ROUTINES = 1;
}
+ if (strcmp(command,"STRIP_UNREACHABLE_LABELS")==0)
+ {
+ STRIP_UNREACHABLE_LABELS=j, flag=1;
+ if (STRIP_UNREACHABLE_LABELS > 1 || STRIP_UNREACHABLE_LABELS < 0)
+ STRIP_UNREACHABLE_LABELS = 1;
+ }
if (strcmp(command,"SERIAL")==0)
{
if (j >= 0 && j <= 999999)
if (flag==0)
printf("No such memory setting as \"%s\"\n", command);
- if (flag==2)
- printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
-It should be safe to omit it (putting nothing in its place).\n", command);
+ if (flag==2 && !nowarnings_switch)
+ printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n", command);
+ if (flag==3 && !nowarnings_switch)
+ printf("The Inform 6 memory setting \"%s\" is no longer needed and has been withdrawn.\n", command);
return;
}
}
/* checks syntax and translates such directives into */
/* specifications for the object-maker. */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
sizeof(fpropt) is about 6200 bytes */
static fproptg full_object_g; /* Equivalent for Glulx. This object
is very small, since the large arrays
- are allocated dynamically by the
- Glulx compiler */
+ are allocated dynamically as
+ memory-lists */
+
static char shortname_buffer[766]; /* Text buffer to hold the short name
(which is read in first, but
written almost last) */
static int parent_of_this_obj;
-static char *classname_text, *objectname_text;
- /* For printing names of embedded
- routines only */
+static memory_list current_object_name; /* The name of the object currently
+ being defined. */
+
+static int current_classname_symbol; /* The symbol index of the class
+ currently being defined.
+ For error-checking and printing
+ names of embedded routines only. */
+
+static memory_list embedded_function_name; /* Temporary storage for inline
+ function name in property. */
/* ------------------------------------------------------------------------- */
/* Classes. */
/* ------------------------------------------------------------------------- */
/* Arrays defined below: */
/* */
-/* int32 class_begins_at[n] offset of properties block for */
-/* nth class (always an offset */
-/* inside the properties_table) */
+/* classinfo class_info[] Object number and prop offset */
/* int classes_to_inherit_from[] The list of classes to inherit */
/* from as taken from the current */
/* Nearby/Object/Class definition */
-/* int class_object_numbers[n] The number of the prototype-object */
-/* for the nth class */
/* ------------------------------------------------------------------------- */
int no_classes; /* Number of class defns made so far */
others itself, so the variable begins
the compilation pass set to 4) */
+/* Print a PROPS trace line. The f flag is 0 for an attribute, 1 for
+ a common property, 2 for an individual property. */
static void trace_s(char *name, int32 number, int f)
{ if (!printprops_switch) return;
- printf("%s %02ld ",(f==0)?"Attr":"Prop",(long int) number);
- if (f==0) printf(" ");
- else printf("%s%s",(prop_is_long[number])?"L":" ",
- (prop_is_additive[number])?"A":" ");
- printf(" %s\n",name);
+ char *stype = "";
+ if (f == 0) stype = "Attr";
+ else if (f == 1) stype = "Prop";
+ else if (f == 2) stype = "Indiv";
+ printf("%-5s %02ld ", stype, (long int) number);
+ if (f != 1) printf(" ");
+ else printf("%s%s",(commonprops[number].is_long)?"L":" ",
+ (commonprops[number].is_additive)?"A":" ");
+ printf(" %s\n", name);
}
extern void make_attribute(void)
get_next_token();
i = token_value; name = token_text;
+ /* We hold onto token_text through the end of this Property directive, which should be okay. */
if (token_type != SYMBOL_TT)
{ discard_token_location(beginning_debug_location);
ebf_error("new attribute name", token_text);
put_token_back();
return;
}
- if (!(sflags[i] & UNKNOWN_SFLAG))
+ if (!(symbols[i].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
- ebf_symbol_error("new attribute name", token_text, typename(stypes[i]), slines[i]);
+ ebf_symbol_error("new attribute name", token_text, typename(symbols[i].type), symbols[i].line);
panic_mode_error_recovery();
put_token_back();
return;
if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
{ get_next_token();
if (!((token_type == SYMBOL_TT)
- && (stypes[token_value] == ATTRIBUTE_T)))
+ && (symbols[token_value].type == ATTRIBUTE_T)))
{ discard_token_location(beginning_debug_location);
ebf_error("an existing attribute name after 'alias'",
token_text);
put_token_back();
return;
}
- assign_symbol(i, svals[token_value], ATTRIBUTE_T);
- sflags[token_value] |= ALIASED_SFLAG;
- sflags[i] |= ALIASED_SFLAG;
+ assign_symbol(i, symbols[token_value].value, ATTRIBUTE_T);
+ symbols[token_value].flags |= ALIASED_SFLAG;
+ symbols[i].flags |= ALIASED_SFLAG;
}
else
{ assign_symbol(i, no_attributes++, ATTRIBUTE_T);
if (debugfile_switch)
{ debug_file_printf("<attribute>");
debug_file_printf("<identifier>%s</identifier>", name);
- debug_file_printf("<value>%d</value>", svals[i]);
+ debug_file_printf("<value>%d</value>", symbols[i].value);
write_debug_locations(get_token_location_end(beginning_debug_location));
debug_file_printf("</attribute>");
}
- trace_s(name, svals[i], 0);
+ trace_s(name, symbols[i].value, 0);
return;
}
+/* Format:
+ Property [long] [additive] name
+ Property [long] [additive] name alias oldname
+ Property [long] [additive] name defaultvalue
+ Property [long] individual name
+ */
extern void make_property(void)
{ int32 default_value, i;
- int additive_flag=FALSE; char *name;
- assembly_operand AO;
+ int keywords, prevkeywords;
+ char *name;
+ int namelen;
+ int additive_flag, indiv_flag;
debug_location_beginning beginning_debug_location =
get_token_location_beginning();
- if (!glulx_mode) {
- if (no_properties==((version_number==3)?32:64))
- { discard_token_location(beginning_debug_location);
- if (version_number==3)
- error("All 30 properties already declared (compile as \
-Advanced game to get an extra 62)");
- else
- error("All 62 properties already declared");
- panic_mode_error_recovery();
- put_token_back();
- return;
- }
- }
- else {
- if (no_properties==INDIV_PROP_START) {
- discard_token_location(beginning_debug_location);
- error_numbered("All properties already declared -- max is",
- INDIV_PROP_START);
- panic_mode_error_recovery();
- put_token_back();
- return;
- }
- }
-
+ /* The next bit is tricky. We want to accept any number of the keywords
+ "long", "additive", "individual" before the property name. But we
+ also want to accept "Property long" -- that's a legitimate
+ property name.
+ The solution is to keep track of which keywords we've seen in
+ a bitmask, and another for one token previous. That way we
+ can back up one token if there's no name visible. */
+ keywords = prevkeywords = 0;
do
{ directive_keywords.enabled = TRUE;
get_next_token();
- if ((token_type == DIR_KEYWORD_TT) && (token_value == LONG_DK))
- obsolete_warning("all properties are now automatically 'long'");
- else
- if ((token_type == DIR_KEYWORD_TT) && (token_value == ADDITIVE_DK))
- additive_flag = TRUE;
- else break;
+ if ((token_type == DIR_KEYWORD_TT) && (token_value == LONG_DK)) {
+ prevkeywords = keywords;
+ keywords |= 1;
+ }
+ else if ((token_type == DIR_KEYWORD_TT) && (token_value == ADDITIVE_DK)) {
+ prevkeywords = keywords;
+ keywords |= 2;
+ }
+ else if ((token_type == DIR_KEYWORD_TT) && (token_value == INDIVIDUAL_DK)) {
+ prevkeywords = keywords;
+ keywords |= 4;
+ }
+ else {
+ break;
+ }
} while (TRUE);
-
+
+ /* Re-parse the name with keywords turned off. (This allows us to
+ accept a property name like "table".) */
put_token_back();
directive_keywords.enabled = FALSE;
get_next_token();
+ if (token_type != SYMBOL_TT && keywords) {
+ /* This can't be a name. Try putting back the last keyword. */
+ keywords = prevkeywords;
+ put_token_back();
+ put_token_back();
+ get_next_token();
+ }
+
+ additive_flag = indiv_flag = FALSE;
+ if (keywords & 1)
+ obsolete_warning("all properties are now automatically 'long'");
+ if (keywords & 2)
+ additive_flag = TRUE;
+ if (keywords & 4)
+ indiv_flag = TRUE;
+
i = token_value; name = token_text;
+ /* We hold onto token_text through the end of this Property directive, which should be okay. */
if (token_type != SYMBOL_TT)
{ discard_token_location(beginning_debug_location);
ebf_error("new property name", token_text);
put_token_back();
return;
}
- if (!(sflags[i] & UNKNOWN_SFLAG))
+ if (!(symbols[i].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
- ebf_symbol_error("new property name", token_text, typename(stypes[i]), slines[i]);
+ ebf_symbol_error("new property name", token_text, typename(symbols[i].type), symbols[i].line);
panic_mode_error_recovery();
put_token_back();
return;
}
+ if (indiv_flag) {
+ int this_identifier_number;
+
+ if (additive_flag)
+ { error("'individual' incompatible with 'additive'");
+ panic_mode_error_recovery();
+ put_token_back();
+ return;
+ }
+
+ this_identifier_number = no_individual_properties++;
+ assign_symbol(i, this_identifier_number, INDIVIDUAL_PROPERTY_T);
+ if (debugfile_switch) {
+ debug_file_printf("<property>");
+ debug_file_printf
+ ("<identifier>%s</identifier>", name);
+ debug_file_printf
+ ("<value>%d</value>", this_identifier_number);
+ debug_file_printf("</property>");
+ }
+ trace_s(name, symbols[i].value, 2);
+ return;
+ }
+
directive_keywords.enabled = TRUE;
get_next_token();
directive_keywords.enabled = FALSE;
- if (strcmp(name+strlen(name)-3, "_to") == 0) sflags[i] |= STAR_SFLAG;
+ namelen = strlen(name);
+ if (namelen > 3 && strcmp(name+namelen-3, "_to") == 0) {
+ /* Direction common properties "n_to", etc are compared in some
+ libraries. They have STAR_SFLAG to tell us to skip a warning. */
+ symbols[i].flags |= STAR_SFLAG;
+ }
+
+ /* Now we might have "alias" or a default value (but not both). */
if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
{ discard_token_location(beginning_debug_location);
}
get_next_token();
if (!((token_type == SYMBOL_TT)
- && (stypes[token_value] == PROPERTY_T)))
+ && (symbols[token_value].type == PROPERTY_T)))
{ ebf_error("an existing property name after 'alias'",
token_text);
panic_mode_error_recovery();
return;
}
- assign_symbol(i, svals[token_value], PROPERTY_T);
- trace_s(name, svals[i], 1);
- sflags[token_value] |= ALIASED_SFLAG;
- sflags[i] |= ALIASED_SFLAG;
+ assign_symbol(i, symbols[token_value].value, PROPERTY_T);
+ trace_s(name, symbols[i].value, 1);
+ symbols[token_value].flags |= ALIASED_SFLAG;
+ symbols[i].flags |= ALIASED_SFLAG;
return;
}
+ /* We now know we're allocating a new common property. Make sure
+ there's room. */
+ if (!glulx_mode) {
+ if (no_properties==((version_number==3)?32:64))
+ { discard_token_location(beginning_debug_location);
+ /* The maximum listed here includes "name" but not the
+ unused zero value or the two hidden properties (class
+ inheritance and indiv table). */
+ if (version_number==3)
+ error("All 29 properties already declared (compile as \
+Advanced game to get 32 more)");
+ else
+ error("All 61 properties already declared");
+ panic_mode_error_recovery();
+ put_token_back();
+ return;
+ }
+ }
+ else {
+ if (no_properties==INDIV_PROP_START) {
+ char error_b[128];
+ discard_token_location(beginning_debug_location);
+ sprintf(error_b,
+ "All %d properties already declared (increase INDIV_PROP_START to get more)",
+ INDIV_PROP_START-3);
+ error(error_b);
+ panic_mode_error_recovery();
+ put_token_back();
+ return;
+ }
+ }
+
default_value = 0;
put_token_back();
if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
- { AO = parse_expression(CONSTANT_CONTEXT);
+ {
+ assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
default_value = AO.value;
if (AO.marker != 0)
backpatch_zmachine(AO.marker, PROP_DEFAULTS_ZA,
(no_properties-1) * WORDSIZE);
}
- prop_default_value[no_properties] = default_value;
- prop_is_long[no_properties] = TRUE;
- prop_is_additive[no_properties] = additive_flag;
+ commonprops[no_properties].default_value = default_value;
+ commonprops[no_properties].is_long = TRUE;
+ commonprops[no_properties].is_additive = additive_flag;
assign_symbol(i, no_properties++, PROPERTY_T);
if (debugfile_switch)
{ debug_file_printf("<property>");
debug_file_printf("<identifier>%s</identifier>", name);
- debug_file_printf("<value>%d</value>", svals[i]);
+ debug_file_printf("<value>%d</value>", symbols[i].value);
write_debug_locations
(get_token_location_end(beginning_debug_location));
debug_file_printf("</property>");
}
- trace_s(name, svals[i], 1);
+ trace_s(name, symbols[i].value, 1);
}
/* ------------------------------------------------------------------------- */
/* Properties. */
/* ------------------------------------------------------------------------- */
-int32 *prop_default_value; /* Default values for properties */
-int *prop_is_long, /* Property modifiers, TRUE or FALSE:
- "long" means "never write a 1-byte
- value to this property", and is an
- obsolete feature: since Inform 5
- all properties have been "long" */
- *prop_is_additive; /* "additive" means that values
- accumulate rather than erase each
- other during class inheritance */
-char *properties_table; /* Holds the table of property values
+commonpropinfo *commonprops; /* Info about common properties
+ (fixed allocation of
+ INDIV_PROP_START entries) */
+
+uchar *properties_table; /* Holds the table of property values
(holding one block for each object
and coming immediately after the
object tree in Z-memory) */
+memory_list properties_table_memlist;
int properties_table_size; /* Number of bytes in this table */
/* ------------------------------------------------------------------------- */
properties so far for current obj */
uchar *individuals_table; /* Table of records, each being the
i.p. table for an object */
+ memory_list individuals_table_memlist;
int i_m; /* Write mark position in the above */
int individuals_length; /* Extent of individuals_table */
/* Arrays used by this file */
/* ------------------------------------------------------------------------- */
-objecttz *objectsz; /* Z-code only */
-objecttg *objectsg; /* Glulx only */
-uchar *objectatts; /* Glulx only */
-static int *classes_to_inherit_from;
-int *class_object_numbers;
-int32 *class_begins_at;
-
+objecttz *objectsz; /* Allocated to no_objects; Z-code only */
+memory_list objectsz_memlist;
+objecttg *objectsg; /* Allocated to no_objects; Glulx only */
+static memory_list objectsg_memlist;
+uchar *objectatts; /* Allocated to no_objects; Glulx only */
+static memory_list objectatts_memlist;
+static int *classes_to_inherit_from; /* Allocated to no_classes_to_inherit_from */
+static memory_list classes_to_inherit_from_memlist;
+classinfo *class_info; /* Allocated up to no_classes */
+memory_list class_info_memlist;
/* ------------------------------------------------------------------------- */
/* Tracing for compiler maintenance */
extern void list_object_tree(void)
{ int i;
- printf("obj par nxt chl Object tree:\n");
- for (i=0; i<no_objects; i++)
- printf("%3d %3d %3d %3d\n",
- i+1,objectsz[i].parent,objectsz[i].next, objectsz[i].child);
+ printf("Object tree:\n");
+ printf("obj name par nxt chl:\n");
+ for (i=0; i<no_objects; i++) {
+ if (!glulx_mode) {
+ int sym = objectsz[i].symbol;
+ char *symname = ((sym > 0) ? symbols[sym].name : "...");
+ printf("%3d %-32s %3d %3d %3d\n",
+ i+1, symname,
+ objectsz[i].parent, objectsz[i].next, objectsz[i].child);
+ }
+ else {
+ int sym = objectsg[i].symbol;
+ char *symname = ((sym > 0) ? symbols[sym].name : "...");
+ printf("%3d %-32s %3d %3d %3d\n",
+ i+1, symname,
+ objectsg[i].parent, objectsg[i].next, objectsg[i].child);
+ }
+ }
}
/* ------------------------------------------------------------------------- */
for (class=0; class<no_classes_to_inherit_from; class++)
{
j=0;
- mark = class_begins_at[classes_to_inherit_from[class]-1];
- class_prop_block = (uchar *) (properties_table + mark);
+ mark = class_info[classes_to_inherit_from[class] - 1].begins_at;
+ class_prop_block = (properties_table + mark);
while (class_prop_block[j]!=0)
{ if (version_number == 3)
prop_in_current_defn = FALSE;
kmax = full_object.l;
+ if (kmax > 64)
+ fatalerror("More than 64 property entries in an object");
for (k=0; k<kmax; k++)
if (full_object.pp[k].num == prop_number)
/* (Note that the built-in "name" property is additive) */
- if ((prop_number==1) || (prop_is_additive[prop_number]))
+ if ((prop_number==1) || (commonprops[prop_number].is_additive))
{
/* The additive case: we accumulate the class
property values onto the end of the full_object
so many values that the list has overflowed the maximum 32 entries");
break;
}
- full_object.pp[k].ao[i].value = mark + j;
+ INITAOTV(&full_object.pp[k].ao[i], LONG_CONSTANT_OT, mark + j);
j += 2;
full_object.pp[k].ao[i].marker = INHERIT_MV;
- full_object.pp[k].ao[i].type = LONG_CONSTANT_OT;
}
full_object.pp[k].l += prop_length/2;
}
if (prop_number==3)
{ int y, z, class_block_offset;
- uchar *p;
/* Property 3 holds the address of the table of
instance variables, so this is the case where
class_block_offset = class_prop_block[j-2]*256
+ class_prop_block[j-1];
- p = individuals_table + class_block_offset;
z = class_block_offset;
- while ((p[0]!=0)||(p[1]!=0))
+ while ((individuals_table[z]!=0)||(individuals_table[z+1]!=0))
{ int already_present = FALSE, l;
for (l = full_object.pp[k].ao[0].value; l < i_m;
l = l + 3 + individuals_table[l + 2])
- if (individuals_table[l] == p[0]
- && individuals_table[l + 1] == p[1])
+ if (individuals_table[l] == individuals_table[z]
+ && individuals_table[l + 1] == individuals_table[z+1])
{ already_present = TRUE; break;
}
if (already_present == FALSE)
{ if (module_switch)
backpatch_zmachine(IDENT_MV,
INDIVIDUAL_PROP_ZA, i_m);
- if (i_m+3+p[2] > MAX_INDIV_PROP_TABLE_SIZE)
- memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
- MAX_INDIV_PROP_TABLE_SIZE);
- individuals_table[i_m++] = p[0];
- individuals_table[i_m++] = p[1];
- individuals_table[i_m++] = p[2];
- for (y=0;y < p[2]/2;y++)
+ ensure_memory_list_available(&individuals_table_memlist, i_m+3+individuals_table[z+2]);
+ individuals_table[i_m++] = individuals_table[z];
+ individuals_table[i_m++] = individuals_table[z+1];
+ individuals_table[i_m++] = individuals_table[z+2];
+ for (y=0;y < individuals_table[z+2]/2;y++)
{ individuals_table[i_m++] = (z+3+y*2)/256;
individuals_table[i_m++] = (z+3+y*2)%256;
backpatch_zmachine(INHERIT_INDIV_MV,
INDIVIDUAL_PROP_ZA, i_m-2);
}
}
- z += p[2] + 3;
- p += p[2] + 3;
+ z += individuals_table[z+2] + 3;
}
individuals_length = i_m;
}
a new property added to full_object */
k=full_object.l++;
+ if (k >= 64)
+ fatalerror("More than 64 property entries in an object");
full_object.pp[k].num = prop_number;
full_object.pp[k].l = prop_length/2;
for (i=0; i<prop_length/2; i++)
- { full_object.pp[k].ao[i].value = mark + j;
+ {
+ INITAOTV(&full_object.pp[k].ao[i], LONG_CONSTANT_OT, mark + j);
j+=2;
full_object.pp[k].ao[i].marker = INHERIT_MV;
- full_object.pp[k].ao[i].type = LONG_CONSTANT_OT;
}
if (prop_number==3)
{ int y, z, class_block_offset;
- uchar *p;
/* Property 3 holds the address of the table of
instance variables, so this is the case where
if (individual_prop_table_size++ == 0)
{ full_object.pp[k].num = 3;
full_object.pp[k].l = 1;
- full_object.pp[k].ao[0].value
- = individuals_length;
+ INITAOTV(&full_object.pp[k].ao[0], LONG_CONSTANT_OT, individuals_length);
full_object.pp[k].ao[0].marker = INDIVPT_MV;
- full_object.pp[k].ao[0].type = LONG_CONSTANT_OT;
i_m = individuals_length;
}
class_block_offset = class_prop_block[j-2]*256
+ class_prop_block[j-1];
- p = individuals_table + class_block_offset;
z = class_block_offset;
- while ((p[0]!=0)||(p[1]!=0))
+ while ((individuals_table[z]!=0)||(individuals_table[z+1]!=0))
{ if (module_switch)
backpatch_zmachine(IDENT_MV, INDIVIDUAL_PROP_ZA, i_m);
- if (i_m+3+p[2] > MAX_INDIV_PROP_TABLE_SIZE)
- memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
- MAX_INDIV_PROP_TABLE_SIZE);
- individuals_table[i_m++] = p[0];
- individuals_table[i_m++] = p[1];
- individuals_table[i_m++] = p[2];
- for (y=0;y < p[2]/2;y++)
+ ensure_memory_list_available(&individuals_table_memlist, i_m+3+individuals_table[z+2]);
+ individuals_table[i_m++] = individuals_table[z];
+ individuals_table[i_m++] = individuals_table[z+1];
+ individuals_table[i_m++] = individuals_table[z+2];
+ for (y=0;y < individuals_table[z+2]/2;y++)
{ individuals_table[i_m++] = (z+3+y*2)/256;
individuals_table[i_m++] = (z+3+y*2)%256;
backpatch_zmachine(INHERIT_INDIV_MV,
INDIVIDUAL_PROP_ZA, i_m-2);
}
- z += p[2] + 3;
- p += p[2] + 3;
+ z += individuals_table[z+2] + 3;
}
individuals_length = i_m;
}
if (individual_prop_table_size > 0)
{
- if (i_m+2 > MAX_INDIV_PROP_TABLE_SIZE)
- memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
- MAX_INDIV_PROP_TABLE_SIZE);
+ ensure_memory_list_available(&individuals_table_memlist, i_m+2);
individuals_table[i_m++] = 0;
individuals_table[i_m++] = 0;
ASSERT_GLULX();
for (class=0; class<no_classes_to_inherit_from; class++) {
- mark = class_begins_at[classes_to_inherit_from[class]-1];
- cpb = (uchar *) (properties_table + mark);
+ mark = class_info[classes_to_inherit_from[class] - 1].begins_at;
+ cpb = (properties_table + mark);
/* This now points to the compiled property-table for the class.
We'll have to go through and decompile it. (For our sins.) */
num_props = ReadInt32(cpb);
if (prop_in_current_defn) {
if ((prop_number==1)
|| (prop_number < INDIV_PROP_START
- && prop_is_additive[prop_number])) {
+ && commonprops[prop_number].is_additive)) {
/* The additive case: we accumulate the class
property values onto the end of the full_object
properties. Remember that k is still the index number
}
}
k = full_object_g.numprops++;
+ ensure_memory_list_available(&full_object_g.props_memlist, k+1);
full_object_g.props[k].num = prop_number;
full_object_g.props[k].flags = 0;
full_object_g.props[k].datastart = full_object_g.propdatasize;
full_object_g.props[k].continuation = prevcont+1;
full_object_g.props[k].datalen = prop_length;
- if (full_object_g.propdatasize + prop_length
- > MAX_OBJ_PROP_TABLE_SIZE) {
- memoryerror("MAX_OBJ_PROP_TABLE_SIZE",MAX_OBJ_PROP_TABLE_SIZE);
- }
-
+
+ ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize + prop_length);
for (i=0; i<prop_length; i++) {
int ppos = full_object_g.propdatasize++;
- full_object_g.propdata[ppos].value = prop_addr + 4*i;
+ INITAOTV(&full_object_g.propdata[ppos], CONSTANT_OT, prop_addr + 4*i);
full_object_g.propdata[ppos].marker = INHERIT_MV;
- full_object_g.propdata[ppos].type = CONSTANT_OT;
}
}
else {
defined at all in full_object_g: we copy out the data into
a new property added to full_object_g. */
k = full_object_g.numprops++;
+ ensure_memory_list_available(&full_object_g.props_memlist, k+1);
full_object_g.props[k].num = prop_number;
full_object_g.props[k].flags = prop_flags;
full_object_g.props[k].datastart = full_object_g.propdatasize;
full_object_g.props[k].continuation = 0;
full_object_g.props[k].datalen = prop_length;
- if (full_object_g.propdatasize + prop_length
- > MAX_OBJ_PROP_TABLE_SIZE) {
- memoryerror("MAX_OBJ_PROP_TABLE_SIZE",MAX_OBJ_PROP_TABLE_SIZE);
- }
+ ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize + prop_length);
for (i=0; i<prop_length; i++) {
int ppos = full_object_g.propdatasize++;
- full_object_g.propdata[ppos].value = prop_addr + 4*i;
+ INITAOTV(&full_object_g.propdata[ppos], CONSTANT_OT, prop_addr + 4*i);
full_object_g.propdata[ppos].marker = INHERIT_MV;
- full_object_g.propdata[ppos].type = CONSTANT_OT;
}
}
- if (full_object_g.numprops == MAX_OBJ_PROP_COUNT) {
- memoryerror("MAX_OBJ_PROP_COUNT",MAX_OBJ_PROP_COUNT);
- }
}
}
/* Construction of Z-machine-format property blocks. */
/* ------------------------------------------------------------------------- */
-static int write_properties_between(uchar *p, int mark, int from, int to)
-{ int j, k, prop_number, prop_length;
- /* Note that p is properties_table. */
+static int write_properties_between(int mark, int from, int to)
+{ int j, k, prop_number;
+
for (prop_number=to; prop_number>=from; prop_number--)
{ for (j=0; j<full_object.l; j++)
{ if ((full_object.pp[j].num == prop_number)
&& (full_object.pp[j].l != 100))
- { prop_length = 2*full_object.pp[j].l;
- if (mark+2+prop_length >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
+ {
+ int prop_length = 2*full_object.pp[j].l;
+ ensure_memory_list_available(&properties_table_memlist, mark+2+prop_length);
if (version_number == 3)
- p[mark++] = prop_number + (prop_length - 1)*32;
+ properties_table[mark++] = prop_number + (prop_length - 1)*32;
else
{ switch(prop_length)
{ case 1:
- p[mark++] = prop_number; break;
+ properties_table[mark++] = prop_number; break;
case 2:
- p[mark++] = prop_number + 0x40; break;
+ properties_table[mark++] = prop_number + 0x40; break;
default:
- p[mark++] = prop_number + 0x80;
- p[mark++] = prop_length + 0x80; break;
+ properties_table[mark++] = prop_number + 0x80;
+ properties_table[mark++] = prop_length + 0x80; break;
}
}
{ if (full_object.pp[j].ao[k].marker != 0)
backpatch_zmachine(full_object.pp[j].ao[k].marker,
PROP_ZA, mark);
- p[mark++] = full_object.pp[j].ao[k].value/256;
- p[mark++] = full_object.pp[j].ao[k].value%256;
+ properties_table[mark++] = full_object.pp[j].ao[k].value/256;
+ properties_table[mark++] = full_object.pp[j].ao[k].value%256;
}
}
}
}
- p[mark++]=0;
+ ensure_memory_list_available(&properties_table_memlist, mark+1);
+ properties_table[mark++]=0;
return(mark);
}
Return the number of bytes written to the block. */
int32 mark = properties_table_size, i;
- uchar *p = (uchar *) properties_table;
/* printf("Object at %04x\n", mark); */
if (shortname != NULL)
- { uchar *tmp;
- if (mark+1+510 >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
- tmp = translate_text(p+mark+1,p+mark+1+510,shortname,STRCTX_OBJNAME);
- if (!tmp) error ("Short name of object exceeded 765 Z-characters");
- i = subtract_pointers(tmp,(p+mark+1));
- p[mark] = i/2;
+ {
+ i = translate_text(510,shortname,STRCTX_OBJNAME);
+ if (i < 0) {
+ error ("Short name of object exceeded 765 Z-characters");
+ i = 0;
+ }
+ ensure_memory_list_available(&properties_table_memlist, mark+1+i);
+ memcpy(properties_table + mark+1, translated_text, i);
+ properties_table[mark] = i/2;
mark += i+1;
}
if (current_defn_is_class)
- { mark = write_properties_between(p,mark,3,3);
+ { mark = write_properties_between(mark,3,3);
+ ensure_memory_list_available(&properties_table_memlist, mark+6);
for (i=0;i<6;i++)
- p[mark++] = full_object.atts[i];
- class_begins_at[no_classes++] = mark;
+ properties_table[mark++] = full_object.atts[i];
+ ensure_memory_list_available(&class_info_memlist, no_classes+1);
+ class_info[no_classes++].begins_at = mark;
}
- mark = write_properties_between(p, mark, 1, (version_number==3)?31:63);
+ mark = write_properties_between(mark, 1, (version_number==3)?31:63);
i = mark - properties_table_size;
properties_table_size = mark;
int ix, jx, kx, totalprops;
int32 mark = properties_table_size;
int32 datamark;
- uchar *p = (uchar *) properties_table;
if (current_defn_is_class) {
+ ensure_memory_list_available(&properties_table_memlist, mark+NUM_ATTR_BYTES);
for (i=0;i<NUM_ATTR_BYTES;i++)
- p[mark++] = full_object_g.atts[i];
- class_begins_at[no_classes++] = mark;
+ properties_table[mark++] = full_object_g.atts[i];
+ ensure_memory_list_available(&class_info_memlist, no_classes+1);
+ class_info[no_classes++].begins_at = mark;
}
qsort(full_object_g.props, full_object_g.numprops, sizeof(propg),
}
/* Write out the number of properties in this table. */
- if (mark+4 >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
- WriteInt32(p+mark, totalprops);
+ ensure_memory_list_available(&properties_table_memlist, mark+4);
+ WriteInt32(properties_table+mark, totalprops);
mark += 4;
datamark = mark + 10*totalprops;
jx<full_object_g.numprops && full_object_g.props[jx].num == propnum;
jx++) {
int32 datastart = full_object_g.props[jx].datastart;
- if (datamark+4*full_object_g.props[jx].datalen >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
+ ensure_memory_list_available(&properties_table_memlist, datamark+4*full_object_g.props[jx].datalen);
for (kx=0; kx<full_object_g.props[jx].datalen; kx++) {
int32 val = full_object_g.propdata[datastart+kx].value;
- WriteInt32(p+datamark, val);
+ WriteInt32(properties_table+datamark, val);
if (full_object_g.propdata[datastart+kx].marker != 0)
backpatch_zmachine(full_object_g.propdata[datastart+kx].marker,
PROP_ZA, datamark);
datamark += 4;
}
}
- if (mark+10 >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
- WriteInt16(p+mark, propnum);
+ ensure_memory_list_available(&properties_table_memlist, mark+10);
+ WriteInt16(properties_table+mark, propnum);
mark += 2;
- WriteInt16(p+mark, totallen);
+ WriteInt16(properties_table+mark, totallen);
mark += 2;
- WriteInt32(p+mark, datamarkstart);
+ WriteInt32(properties_table+mark, datamarkstart);
mark += 4;
- WriteInt16(p+mark, flags);
+ WriteInt16(properties_table+mark, flags);
mark += 2;
}
segment_markers.enabled = FALSE;
directives.enabled = TRUE;
+ ensure_memory_list_available(&objectsz_memlist, no_objects+1);
+
+ objectsz[no_objects].symbol = full_object.symbol;
+
property_inheritance_z();
objectsz[no_objects].parent = parent_of_this_obj;
j = write_property_block_z(shortname_buffer);
objectsz[no_objects].propsize = j;
- if (properties_table_size >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
if (current_defn_is_class)
for (i=0;i<6;i++) objectsz[no_objects].atts[i] = 0;
segment_markers.enabled = FALSE;
directives.enabled = TRUE;
+ ensure_memory_list_available(&objectsg_memlist, no_objects+1);
+ ensure_memory_list_available(&objectatts_memlist, no_objects+1);
+
+ objectsg[no_objects].symbol = full_object_g.symbol;
+
property_inheritance_g();
objectsg[no_objects].parent = parent_of_this_obj;
objectsg[no_objects].propaddr = full_object_g.finalpropaddr;
objectsg[no_objects].propsize = j;
- if (properties_table_size >= MAX_PROP_TABLE_SIZE)
- memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
if (current_defn_is_class)
for (i=0;i<NUM_ATTR_BYTES;i++)
return;
}
- individual_property = (stypes[token_value] != PROPERTY_T);
+ individual_property = (symbols[token_value].type != PROPERTY_T);
if (individual_property)
- { if (sflags[token_value] & UNKNOWN_SFLAG)
+ { if (symbols[token_value].flags & UNKNOWN_SFLAG)
{ this_identifier_number = no_individual_properties++;
assign_symbol(token_value, this_identifier_number,
INDIVIDUAL_PROPERTY_T);
debug_file_printf("</property>");
}
+ trace_s(token_text, symbols[token_value].value, 2);
}
else
- { if (stypes[token_value]==INDIVIDUAL_PROPERTY_T)
- this_identifier_number = svals[token_value];
+ { if (symbols[token_value].type==INDIVIDUAL_PROPERTY_T)
+ this_identifier_number = symbols[token_value].value;
else
- { ebf_symbol_error("property name", token_text, typename(stypes[token_value]), slines[token_value]);
+ { ebf_symbol_error("property name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
return;
}
}
defined_this_segment[def_t_s++] = token_value;
if (individual_prop_table_size++ == 0)
- { full_object.pp[full_object.l].num = 3;
- full_object.pp[full_object.l].l = 1;
- full_object.pp[full_object.l].ao[0].value
- = individuals_length;
- full_object.pp[full_object.l].ao[0].type = LONG_CONSTANT_OT;
- full_object.pp[full_object.l].ao[0].marker = INDIVPT_MV;
+ {
+ int k=full_object.l++;
+ if (k >= 64)
+ fatalerror("More than 64 property entries in an object");
+ full_object.pp[k].num = 3;
+ full_object.pp[k].l = 1;
+ INITAOTV(&full_object.pp[k].ao[0], LONG_CONSTANT_OT, individuals_length);
+ full_object.pp[k].ao[0].marker = INDIVPT_MV;
i_m = individuals_length;
- full_object.l++;
}
+ ensure_memory_list_available(&individuals_table_memlist, i_m+3);
individuals_table[i_m] = this_identifier_number/256;
if (this_segment == PRIVATE_SEGMENT)
individuals_table[i_m] |= 0x80;
individuals_table[i_m+2] = 0;
}
else
- { if (sflags[token_value] & UNKNOWN_SFLAG)
+ { if (symbols[token_value].flags & UNKNOWN_SFLAG)
{ error_named("No such property name as", token_text);
return;
}
if (def_t_s >= defined_this_segment_size)
ensure_defined_this_segment(def_t_s*2);
defined_this_segment[def_t_s++] = token_value;
- property_number = svals[token_value];
+ property_number = symbols[token_value].value;
next_prop=full_object.l++;
+ if (next_prop >= 64)
+ fatalerror("More than 64 property entries in an object");
full_object.pp[next_prop].num = property_number;
}
for (i=0; i<(def_t_s-1); i++)
if (defined_this_segment[i] == token_value)
{ error_named("Property given twice in the same declaration:",
- (char *) symbs[token_value]);
+ symbols[token_value].name);
}
else
- if (svals[defined_this_segment[i]] == svals[token_value])
- { char error_b[128];
+ if (symbols[defined_this_segment[i]].value == symbols[token_value].value)
+ { char error_b[128+2*MAX_IDENTIFIER_LENGTH];
sprintf(error_b,
"Property given twice in the same declaration, because \
the names '%s' and '%s' actually refer to the same property",
- (char *) symbs[defined_this_segment[i]],
- (char *) symbs[token_value]);
+ symbols[defined_this_segment[i]].name,
+ symbols[token_value].name);
error(error_b);
}
property_name_symbol = token_value;
- sflags[token_value] |= USED_SFLAG;
+ symbols[token_value].flags |= USED_SFLAG;
length=0;
do
warning ("'name' property should only contain dictionary words");
if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
- { char embedded_name[80];
+ {
+ char *prefix, *sep, *sym;
+ sym = symbols[property_name_symbol].name;
if (current_defn_is_class)
- { sprintf(embedded_name,
- "%s::%s", classname_text,
- (char *) symbs[property_name_symbol]);
+ {
+ prefix = symbols[current_classname_symbol].name;
+ sep = "::";
}
else
- { sprintf(embedded_name,
- "%s.%s", objectname_text,
- (char *) symbs[property_name_symbol]);
+ {
+ prefix = current_object_name.data;
+ sep = ".";
}
- AO.value = parse_routine(NULL, TRUE, embedded_name, FALSE, -1);
+ ensure_memory_list_available(&embedded_function_name, strlen(prefix)+strlen(sep)+strlen(sym)+1);
+ sprintf(embedded_function_name.data, "%s%s%s", prefix, sep, sym);
+
+ /* parse_routine() releases lexer text! */
+ AO.value = parse_routine(NULL, TRUE, embedded_function_name.data, FALSE, -1);
AO.type = LONG_CONSTANT_OT;
AO.marker = IROUTINE_MV;
{ if (length!=0)
{
if ((token_type == SYMBOL_TT)
- && (stypes[token_value]==PROPERTY_T))
+ && (symbols[token_value].type==PROPERTY_T))
{
/* This is not necessarily an error: it's possible
to imagine a property whose value is a list
if (length == 64)
{ error_named("Limit (of 32 values) exceeded for property",
- (char *) symbs[property_name_symbol]);
+ symbols[property_name_symbol].name);
break;
}
{ if (AO.marker != 0)
backpatch_zmachine(AO.marker, INDIVIDUAL_PROP_ZA,
i_m+3+length);
+ ensure_memory_list_available(&individuals_table_memlist, i_m+3+length+2);
individuals_table[i_m+3+length++] = AO.value/256;
individuals_table[i_m+3+length++] = AO.value%256;
}
if (length == 0)
{ if (individual_property)
- { individuals_table[i_m+3+length++] = 0;
+ {
+ ensure_memory_list_available(&individuals_table_memlist, i_m+3+length+2);
+ individuals_table[i_m+3+length++] = 0;
individuals_table[i_m+3+length++] = 0;
}
else
- { full_object.pp[next_prop].ao[0].value = 0;
- full_object.pp[next_prop].ao[0].type = LONG_CONSTANT_OT;
- full_object.pp[next_prop].ao[0].marker = 0;
+ {
+ INITAOTV(&full_object.pp[next_prop].ao[0], LONG_CONSTANT_OT, 0);
length = 2;
}
}
{
warning_named("Version 3 limit of 4 values per property exceeded \
(use -v5 to get 32), so truncating property",
- (char *) symbs[property_name_symbol]);
+ symbols[property_name_symbol].name);
length = 8;
}
}
if (individual_property)
{
- if (individuals_length+length+3 > MAX_INDIV_PROP_TABLE_SIZE)
- memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
- MAX_INDIV_PROP_TABLE_SIZE);
+ ensure_memory_list_available(&individuals_table_memlist, individuals_length+length+3);
individuals_table[i_m + 2] = length;
individuals_length += length+3;
i_m = individuals_length;
return;
}
- individual_property = (stypes[token_value] != PROPERTY_T);
+ individual_property = (symbols[token_value].type != PROPERTY_T);
if (individual_property)
- { if (sflags[token_value] & UNKNOWN_SFLAG)
+ { if (symbols[token_value].flags & UNKNOWN_SFLAG)
{ this_identifier_number = no_individual_properties++;
assign_symbol(token_value, this_identifier_number,
INDIVIDUAL_PROPERTY_T);
debug_file_printf("</property>");
}
+ trace_s(token_text, symbols[token_value].value, 2);
}
else
- { if (stypes[token_value]==INDIVIDUAL_PROPERTY_T)
- this_identifier_number = svals[token_value];
+ { if (symbols[token_value].type==INDIVIDUAL_PROPERTY_T)
+ this_identifier_number = symbols[token_value].value;
else
- { ebf_symbol_error("property name", token_text, typename(stypes[token_value]), slines[token_value]);
+ { ebf_symbol_error("property name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
return;
}
}
if (def_t_s >= defined_this_segment_size)
ensure_defined_this_segment(def_t_s*2);
defined_this_segment[def_t_s++] = token_value;
- property_number = svals[token_value];
+ property_number = symbols[token_value].value;
next_prop=full_object_g.numprops++;
+ ensure_memory_list_available(&full_object_g.props_memlist, next_prop+1);
full_object_g.props[next_prop].num = property_number;
full_object_g.props[next_prop].flags =
((this_segment == PRIVATE_SEGMENT) ? 1 : 0);
full_object_g.props[next_prop].datalen = 0;
}
else
- { if (sflags[token_value] & UNKNOWN_SFLAG)
+ { if (symbols[token_value].flags & UNKNOWN_SFLAG)
{ error_named("No such property name as", token_text);
return;
}
if (def_t_s >= defined_this_segment_size)
ensure_defined_this_segment(def_t_s*2);
defined_this_segment[def_t_s++] = token_value;
- property_number = svals[token_value];
+ property_number = symbols[token_value].value;
next_prop=full_object_g.numprops++;
+ ensure_memory_list_available(&full_object_g.props_memlist, next_prop+1);
full_object_g.props[next_prop].num = property_number;
full_object_g.props[next_prop].flags = 0;
full_object_g.props[next_prop].datastart = full_object_g.propdatasize;
for (i=0; i<(def_t_s-1); i++)
if (defined_this_segment[i] == token_value)
{ error_named("Property given twice in the same declaration:",
- (char *) symbs[token_value]);
+ symbols[token_value].name);
}
else
- if (svals[defined_this_segment[i]] == svals[token_value])
- { char error_b[128];
+ if (symbols[defined_this_segment[i]].value == symbols[token_value].value)
+ { char error_b[128+2*MAX_IDENTIFIER_LENGTH];
sprintf(error_b,
"Property given twice in the same declaration, because \
the names '%s' and '%s' actually refer to the same property",
- (char *) symbs[defined_this_segment[i]],
- (char *) symbs[token_value]);
+ symbols[defined_this_segment[i]].name,
+ symbols[token_value].name);
error(error_b);
}
- if (full_object_g.numprops == MAX_OBJ_PROP_COUNT) {
- memoryerror("MAX_OBJ_PROP_COUNT",MAX_OBJ_PROP_COUNT);
- }
-
property_name_symbol = token_value;
- sflags[token_value] |= USED_SFLAG;
+ symbols[token_value].flags |= USED_SFLAG;
length=0;
do
warning ("'name' property should only contain dictionary words");
if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
- { char embedded_name[80];
+ {
+ char *prefix, *sep, *sym;
+ sym = symbols[property_name_symbol].name;
if (current_defn_is_class)
- { sprintf(embedded_name,
- "%s::%s", classname_text,
- (char *) symbs[property_name_symbol]);
+ {
+ prefix = symbols[current_classname_symbol].name;
+ sep = "::";
}
else
- { sprintf(embedded_name,
- "%s.%s", objectname_text,
- (char *) symbs[property_name_symbol]);
+ {
+ prefix = current_object_name.data;
+ sep = ".";
}
- AO.value = parse_routine(NULL, TRUE, embedded_name, FALSE, -1);
- AO.type = CONSTANT_OT;
+ ensure_memory_list_available(&embedded_function_name, strlen(prefix)+strlen(sep)+strlen(sym)+1);
+ sprintf(embedded_function_name.data, "%s%s%s", prefix, sep, sym);
+
+ INITAOT(&AO, CONSTANT_OT);
+ /* parse_routine() releases lexer text! */
+ AO.value = parse_routine(NULL, TRUE, embedded_function_name.data, FALSE, -1);
AO.marker = IROUTINE_MV;
directives.enabled = FALSE;
{ if (length!=0)
{
if ((token_type == SYMBOL_TT)
- && (stypes[token_value]==PROPERTY_T))
+ && (symbols[token_value].type==PROPERTY_T))
{
/* This is not necessarily an error: it's possible
to imagine a property whose value is a list
if (length == 32768) /* VENEER_CONSTRAINT_ON_PROP_TABLE_SIZE? */
{ error_named("Limit (of 32768 values) exceeded for property",
- (char *) symbs[property_name_symbol]);
+ symbols[property_name_symbol].name);
break;
}
- if (full_object_g.propdatasize >= MAX_OBJ_PROP_TABLE_SIZE) {
- memoryerror("MAX_OBJ_PROP_TABLE_SIZE",MAX_OBJ_PROP_TABLE_SIZE);
- }
+ ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize+1);
full_object_g.propdata[full_object_g.propdatasize++] = AO;
length += 1;
if (length == 0)
{
assembly_operand AO;
- AO.value = 0;
- AO.type = CONSTANT_OT;
- AO.marker = 0;
+ INITAOTV(&AO, CONSTANT_OT, 0);
+ ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize+1);
full_object_g.propdata[full_object_g.propdatasize++] = AO;
length += 1;
}
}
if ((token_type != SYMBOL_TT)
- || (stypes[token_value] != ATTRIBUTE_T))
+ || (symbols[token_value].type != ATTRIBUTE_T))
{ ebf_error("name of an already-declared attribute", token_text);
return;
}
- attribute_number = svals[token_value];
- sflags[token_value] |= USED_SFLAG;
+ attribute_number = symbols[token_value].value;
+ symbols[token_value].flags |= USED_SFLAG;
if (!glulx_mode) {
bitmask = (1 << (7-attribute_number%8));
to be translated into its actual class number: */
for (i=0;i<no_classes;i++)
- if (class_number == class_object_numbers[i])
+ if (class_number == class_info[i].object_number)
{ class_number = i+1;
break;
}
/* Remember the inheritance list so that property inheritance can
be sorted out later on, when the definition has been finished: */
+ ensure_memory_list_available(&classes_to_inherit_from_memlist, no_classes_to_inherit_from+1);
+
classes_to_inherit_from[no_classes_to_inherit_from++] = class_number;
/* Inheriting attributes from the class at once: */
if (!glulx_mode) {
for (i=0; i<6; i++)
full_object.atts[i]
- |= properties_table[class_begins_at[class_number-1] - 6 + i];
+ |= properties_table[class_info[class_number-1].begins_at - 6 + i];
}
else {
for (i=0; i<NUM_ATTR_BYTES; i++)
full_object_g.atts[i]
- |= properties_table[class_begins_at[class_number-1]
+ |= properties_table[class_info[class_number-1].begins_at
- NUM_ATTR_BYTES + i];
}
}
if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) return;
if ((token_type != SYMBOL_TT)
- || (stypes[token_value] != CLASS_T))
+ || (symbols[token_value].type != CLASS_T))
{ ebf_error("name of an already-declared class", token_text);
return;
}
+ if (current_defn_is_class && token_value == current_classname_symbol)
+ { error("A class cannot inherit from itself");
+ return;
+ }
- sflags[token_value] |= USED_SFLAG;
- add_class_to_inheritance_list(svals[token_value]);
+ symbols[token_value].flags |= USED_SFLAG;
+ add_class_to_inheritance_list(symbols[token_value].value);
} while (TRUE);
}
{
int i;
if (!glulx_mode) {
+ full_object.symbol = 0;
full_object.l = 0;
full_object.atts[0] = 0;
full_object.atts[1] = 0;
full_object.atts[5] = 0;
}
else {
+ full_object_g.symbol = 0;
full_object_g.numprops = 0;
full_object_g.propdatasize = 0;
for (i=0; i<NUM_ATTR_BYTES; i++)
extern void make_class(char * metaclass_name)
{ int n, duplicates_to_make = 0, class_number = no_objects+1,
metaclass_flag = (metaclass_name != NULL);
- char duplicate_name[128];
debug_location_beginning beginning_debug_location =
get_token_location_beginning();
current_defn_is_class = TRUE; no_classes_to_inherit_from = 0;
individual_prop_table_size = 0;
- if (no_classes==MAX_CLASSES)
- memoryerror("MAX_CLASSES", MAX_CLASSES);
+ ensure_memory_list_available(&class_info_memlist, no_classes+1);
if (no_classes==VENEER_CONSTRAINT_ON_CLASSES)
fatalerror("Inform's maximum possible number of classes (whatever \
panic_mode_error_recovery();
return;
}
- if (!(sflags[token_value] & UNKNOWN_SFLAG))
+ if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
- ebf_symbol_error("new class name", token_text, typename(stypes[token_value]), slines[token_value]);
+ ebf_symbol_error("new class name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
panic_mode_error_recovery();
return;
}
strcpy(shortname_buffer, token_text);
assign_symbol(token_value, class_number, CLASS_T);
- classname_text = (char *) symbs[token_value];
+ current_classname_symbol = token_value;
if (!glulx_mode) {
- if (metaclass_flag) sflags[token_value] |= SYSTEM_SFLAG;
+ if (metaclass_flag) symbols[token_value].flags |= SYSTEM_SFLAG;
}
else {
/* In Glulx, metaclasses have to be backpatched too! So we can't
mark it as "system", but we should mark it "used". */
- if (metaclass_flag) sflags[token_value] |= USED_SFLAG;
+ if (metaclass_flag) symbols[token_value].flags |= USED_SFLAG;
}
/* "Class" (object 1) has no parent, whereas all other classes are
if (metaclass_flag) parent_of_this_obj = 0;
else parent_of_this_obj = (module_switch)?MAXINTWORD:1;
- class_object_numbers[no_classes] = class_number;
+ class_info[no_classes].object_number = class_number;
+ class_info[no_classes].symbol = current_classname_symbol;
+ class_info[no_classes].begins_at = 0;
initialise_full_object();
since property 2 is always set to "additive" -- see below) */
if (!glulx_mode) {
+ full_object.symbol = current_classname_symbol;
full_object.l = 1;
full_object.pp[0].num = 2;
full_object.pp[0].l = 1;
- full_object.pp[0].ao[0].value = no_objects + 1;
- full_object.pp[0].ao[0].type = LONG_CONSTANT_OT;
+ INITAOTV(&full_object.pp[0].ao[0], LONG_CONSTANT_OT, no_objects + 1);
full_object.pp[0].ao[0].marker = OBJECT_MV;
}
else {
+ full_object_g.symbol = current_classname_symbol;
full_object_g.numprops = 1;
+ ensure_memory_list_available(&full_object_g.props_memlist, 1);
full_object_g.props[0].num = 2;
full_object_g.props[0].flags = 0;
full_object_g.props[0].datastart = 0;
full_object_g.props[0].continuation = 0;
full_object_g.props[0].datalen = 1;
full_object_g.propdatasize = 1;
- full_object_g.propdata[0].value = no_objects + 1;
- full_object_g.propdata[0].type = CONSTANT_OT;
+ ensure_memory_list_available(&full_object_g.propdata_memlist, 1);
+ INITAOTV(&full_object_g.propdata[0], CONSTANT_OT, no_objects + 1);
full_object_g.propdata[0].marker = OBJECT_MV;
}
\"common properties\" using the 'Property' directive.");
if (duplicates_to_make > 0)
- { sprintf(duplicate_name, "%s_1", shortname_buffer);
+ {
+ int namelen = strlen(shortname_buffer);
+ char *duplicate_name = my_malloc(namelen+16, "temporary storage for object duplicate names");
+ strcpy(duplicate_name, shortname_buffer);
for (n=1; (duplicates_to_make--) > 0; n++)
- { if (n>1)
- { int i = strlen(duplicate_name);
- while (duplicate_name[i] != '_') i--;
- sprintf(duplicate_name+i+1, "%d", n);
- }
+ {
+ sprintf(duplicate_name+namelen, "_%d", n);
make_object(FALSE, duplicate_name, class_number, class_number, -1);
}
+ my_free(&duplicate_name, "temporary storage for object duplicate names");
}
+
+ /* Finished building the class. */
+ current_classname_symbol = 0;
}
/* ------------------------------------------------------------------------- */
The last is used to create instances of a particular class. */
int i, tree_depth, internal_name_symbol = 0;
- char internal_name[64];
debug_location_beginning beginning_debug_location =
get_token_location_beginning();
directives.enabled = FALSE;
- if (no_objects==MAX_OBJECTS) memoryerror("MAX_OBJECTS", MAX_OBJECTS);
-
- sprintf(internal_name, "nameless_obj__%d", no_objects+1);
- objectname_text = internal_name;
+ ensure_memory_list_available(¤t_object_name, 32);
+ sprintf(current_object_name.data, "nameless_obj__%d", no_objects+1);
current_defn_is_class = FALSE;
ebf_error("name for new object or its textual short name",
token_text);
}
- else if (!(sflags[token_value] & UNKNOWN_SFLAG)) {
- ebf_symbol_error("new object", token_text, typename(stypes[token_value]), slines[token_value]);
+ else if (!(symbols[token_value].flags & UNKNOWN_SFLAG)) {
+ ebf_symbol_error("new object", token_text, typename(symbols[token_value].type), symbols[token_value].line);
}
else
{ internal_name_symbol = token_value;
- strcpy(internal_name, token_text);
+ ensure_memory_list_available(¤t_object_name, strlen(token_text)+1);
+ strcpy(current_object_name.data, token_text);
}
}
}
else
{ if ((token_type != SYMBOL_TT)
- || (sflags[token_value] & UNKNOWN_SFLAG))
+ || (symbols[token_value].flags & UNKNOWN_SFLAG))
{ if (textual_name == NULL)
ebf_error("parent object or the object's textual short name",
token_text);
ebf_error("body of object definition", token_text);
else
{ SpecParent:
- if ((stypes[token_value] == OBJECT_T)
- || (stypes[token_value] == CLASS_T))
- { specified_parent = svals[token_value];
- sflags[token_value] |= USED_SFLAG;
+ if ((symbols[token_value].type == OBJECT_T)
+ || (symbols[token_value].type == CLASS_T))
+ { specified_parent = symbols[token_value].value;
+ symbols[token_value].flags |= USED_SFLAG;
}
else ebf_error("name of (the parent) object", token_text);
}
if (internal_name_symbol > 0)
assign_symbol(internal_name_symbol, no_objects + 1, OBJECT_T);
- if (listobjects_switch)
- printf("%3d \"%s\"\n", no_objects+1,
- (textual_name==NULL)?"(with no short name)":textual_name);
if (textual_name == NULL)
{ if (internal_name_symbol > 0)
sprintf(shortname_buffer, "(%s)",
- (char *) symbs[internal_name_symbol]);
+ symbols[internal_name_symbol].name);
else
sprintf(shortname_buffer, "(%d)", no_objects+1);
}
}
initialise_full_object();
+ if (!glulx_mode)
+ full_object.symbol = internal_name_symbol;
+ else
+ full_object_g.symbol = internal_name_symbol;
+
if (instance_of != -1) add_class_to_inheritance_list(instance_of);
if (specified_class == -1) parse_body_of_definition();
if (debugfile_switch)
{ debug_file_printf("<object>");
if (internal_name_symbol > 0)
- { debug_file_printf("<identifier>%s</identifier>", internal_name);
+ { debug_file_printf("<identifier>%s</identifier>",
+ current_object_name.data);
} else
{ debug_file_printf
("<identifier artificial=\"true\">%s</identifier>",
- internal_name);
+ current_object_name.data);
}
debug_file_printf("<value>");
write_debug_object_backpatch(no_objects + 1);
extern void init_objects_vars(void)
{
properties_table = NULL;
- prop_is_long = NULL;
- prop_is_additive = NULL;
- prop_default_value = NULL;
+ individuals_table = NULL;
+ commonprops = NULL;
objectsz = NULL;
objectsg = NULL;
objectatts = NULL;
classes_to_inherit_from = NULL;
- class_begins_at = NULL;
+ class_info = NULL;
+
+ full_object_g.props = NULL;
+ full_object_g.propdata = NULL;
}
extern void objects_begin_pass(void)
{
properties_table_size=0;
- prop_is_long[1] = TRUE; prop_is_additive[1] = TRUE; /* "name" */
- prop_is_long[2] = TRUE; prop_is_additive[2] = TRUE; /* inheritance prop */
- if (!glulx_mode)
- prop_is_long[3] = TRUE; prop_is_additive[3] = FALSE;
- /* instance variables table address */
+
+ /* The three predefined common properties: */
+ /* (Entry 0 is not used.) */
+
+ /* "name" */
+ commonprops[1].default_value = 0;
+ commonprops[1].is_long = TRUE;
+ commonprops[1].is_additive = TRUE;
+
+ /* class inheritance property */
+ commonprops[2].default_value = 0;
+ commonprops[2].is_long = TRUE;
+ commonprops[2].is_additive = TRUE;
+
+ /* instance variables table address */
+ /* (This property is only meaningful in Z-code; in Glulx its entry is
+ reserved but never used.) */
+ commonprops[3].default_value = 0;
+ commonprops[3].is_long = TRUE;
+ commonprops[3].is_additive = FALSE;
+
no_properties = 4;
if (debugfile_switch)
- { debug_file_printf("<property>");
+ {
+ /* These two properties are not symbols, so they won't be emitted
+ by emit_debug_information_for_predefined_symbol(). Do it
+ manually. */
+ debug_file_printf("<property>");
debug_file_printf
("<identifier artificial=\"true\">inheritance class</identifier>");
debug_file_printf("<value>2</value>");
else no_attributes = 0;
no_objects = 0;
+ /* Setting the info for object zero is probably a relic of very old code, but we do it. */
if (!glulx_mode) {
+ ensure_memory_list_available(&objectsz_memlist, 1);
objectsz[0].parent = 0; objectsz[0].child = 0; objectsz[0].next = 0;
no_individual_properties=72;
}
else {
+ ensure_memory_list_available(&objectsg_memlist, 1);
objectsg[0].parent = 0; objectsg[0].child = 0; objectsg[0].next = 0;
no_individual_properties = INDIV_PROP_START+8;
}
no_classes = 0;
+ current_classname_symbol = 0;
no_embedded_routines = 0;
objectsg = NULL;
objectatts = NULL;
- prop_default_value = my_calloc(sizeof(int32), INDIV_PROP_START,
- "property default values");
- prop_is_long = my_calloc(sizeof(int), INDIV_PROP_START,
- "property-is-long flags");
- prop_is_additive = my_calloc(sizeof(int), INDIV_PROP_START,
- "property-is-additive flags");
+ commonprops = my_calloc(sizeof(commonpropinfo), INDIV_PROP_START,
+ "common property info");
- classes_to_inherit_from = my_calloc(sizeof(int), MAX_CLASSES,
- "inherited classes list");
- class_begins_at = my_calloc(sizeof(int32), MAX_CLASSES,
- "pointers to classes");
- class_object_numbers = my_calloc(sizeof(int), MAX_CLASSES,
- "class object numbers");
+ initialise_memory_list(&class_info_memlist,
+ sizeof(classinfo), 64, (void**)&class_info,
+ "class info");
+ initialise_memory_list(&classes_to_inherit_from_memlist,
+ sizeof(int), 64, (void**)&classes_to_inherit_from,
+ "inherited classes list");
- properties_table = my_malloc(MAX_PROP_TABLE_SIZE,"properties table");
- individuals_table = my_malloc(MAX_INDIV_PROP_TABLE_SIZE,
- "individual properties table");
+ initialise_memory_list(&properties_table_memlist,
+ sizeof(uchar), 10000, (void**)&properties_table,
+ "properties table");
+ initialise_memory_list(&individuals_table_memlist,
+ sizeof(uchar), 10000, (void**)&individuals_table,
+ "individual properties table");
defined_this_segment_size = 128;
defined_this_segment = my_calloc(sizeof(int), defined_this_segment_size,
"defined this segment table");
+ initialise_memory_list(¤t_object_name,
+ sizeof(char), 32, NULL,
+ "object name currently being defined");
+ initialise_memory_list(&embedded_function_name,
+ sizeof(char), 32, NULL,
+ "temporary storage for inline function name");
+
if (!glulx_mode) {
- objectsz = my_calloc(sizeof(objecttz), MAX_OBJECTS,
- "z-objects");
+ initialise_memory_list(&objectsz_memlist,
+ sizeof(objecttz), 256, (void**)&objectsz,
+ "z-objects");
}
else {
- objectsg = my_calloc(sizeof(objecttg), MAX_OBJECTS,
- "g-objects");
- objectatts = my_calloc(NUM_ATTR_BYTES, MAX_OBJECTS,
- "g-attributes");
- full_object_g.props = my_calloc(sizeof(propg), MAX_OBJ_PROP_COUNT,
- "object property list");
- full_object_g.propdata = my_calloc(sizeof(assembly_operand),
- MAX_OBJ_PROP_TABLE_SIZE,
- "object property data table");
+ initialise_memory_list(&objectsg_memlist,
+ sizeof(objecttg), 256, (void**)&objectsg,
+ "g-objects");
+ initialise_memory_list(&objectatts_memlist,
+ NUM_ATTR_BYTES, 256, (void**)&objectatts,
+ "g-attributes");
+ initialise_memory_list(&full_object_g.props_memlist,
+ sizeof(propg), 64, (void**)&full_object_g.props,
+ "object property list");
+ initialise_memory_list(&full_object_g.propdata_memlist,
+ sizeof(assembly_operand), 1024, (void**)&full_object_g.propdata,
+ "object property data table");
}
}
extern void objects_free_arrays(void)
{
- my_free(&prop_default_value, "property default values");
- my_free(&prop_is_long, "property-is-long flags");
- my_free(&prop_is_additive, "property-is-additive flags");
-
- my_free(&objectsz, "z-objects");
- my_free(&objectsg, "g-objects");
- my_free(&objectatts, "g-attributes");
- my_free(&class_object_numbers,"class object numbers");
- my_free(&classes_to_inherit_from, "inherited classes list");
- my_free(&class_begins_at, "pointers to classes");
+ my_free(&commonprops, "common property info");
+
+ deallocate_memory_list(¤t_object_name);
+ deallocate_memory_list(&embedded_function_name);
+ deallocate_memory_list(&objectsz_memlist);
+ deallocate_memory_list(&objectsg_memlist);
+ deallocate_memory_list(&objectatts_memlist);
+ deallocate_memory_list(&class_info_memlist);
+ deallocate_memory_list(&classes_to_inherit_from_memlist);
- my_free(&properties_table, "properties table");
- my_free(&individuals_table,"individual properties table");
+ deallocate_memory_list(&properties_table_memlist);
+ deallocate_memory_list(&individuals_table_memlist);
my_free(&defined_this_segment,"defined this segment table");
if (!glulx_mode) {
- my_free(&full_object_g.props, "object property list");
- my_free(&full_object_g.propdata, "object property data table");
+ deallocate_memory_list(&full_object_g.props_memlist);
+ deallocate_memory_list(&full_object_g.propdata_memlist);
}
}
/* ------------------------------------------------------------------------- */
/* "states" : Statement translator */
/* */
-/* Part of Inform 6.35 */
-/* copyright (c) Graham Nelson 1993 - 2021 */
+/* Part of Inform 6.40 */
+/* copyright (c) Graham Nelson 1993 - 2022 */
/* */
/* Inform is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
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);
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:
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:
}
}
-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;
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();
}
else error("'do' without matching 'until'");
- assemble_label_no(ln3);
+ assemble_forward_label_no(ln3);
break;
/* -------------------------------------------------------------------- */
sequence_point_follows = FALSE;
if (!execution_never_reaches_here)
assemblez_jump(ln);
- assemble_label_no(ln2);
+ assemble_forward_label_no(ln2);
return;
}
goto ParseUpdate;
}
}
- assemble_label_no(ln3);
+ assemble_forward_label_no(ln3);
return;
/* -------------------------------------------------------------------- */
case GIVE_CODE:
AO = code_generate(parse_expression(QUANTITY_CONTEXT),
QUANTITY_CONTEXT, -1);
+ check_warn_symbol_type(&AO, OBJECT_T, 0, "\"give\" statement");
if ((AO.type == VARIABLE_OT) && (AO.value == 0))
{ INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
if (version_number != 6) assemblez_1(pull_zc, AO);
if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
ln = clear_attr_zc;
else
- { if ((token_type == SYMBOL_TT)
- && (stypes[token_value] != ATTRIBUTE_T))
- warning_named("This is not a declared Attribute:",
- token_text);
- ln = set_attr_zc;
+ { ln = set_attr_zc;
put_token_back();
}
AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
QUANTITY_CONTEXT, -1);
+ check_warn_symbol_type(&AO2, ATTRIBUTE_T, 0, "\"give\" statement");
if (runtime_error_checking_switch)
{ ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
if (version_number >= 5)
/* -------------------------------------------------------------------- */
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);
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();
}
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;
/* -------------------------------------------------------------------- */
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),
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;
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),
AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
QUANTITY_CONTEXT, -1);
if (is_constant_ot(AO2.type) && AO2.marker == 0) {
- if (AO2.value >= 96)
- { error("Z-machine dynamic strings are limited to 96");
+ /* Compile-time check */
+ if (AO2.value < 0 || AO2.value >= 96 || AO2.value >= MAX_DYNAMIC_STRINGS) {
+ error_max_dynamic_strings(AO2.value);
AO2.value = 0;
}
- if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
- memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
- }
}
get_next_token();
if (token_type == DQ_TT)
assemblez_store(AO2, AO);
parse_code_block(ln = next_label++, continue_label, 1);
- assemble_label_no(ln);
+ assemble_forward_label_no(ln);
return;
/* -------------------------------------------------------------------- */
parse_code_block(ln2, ln, 0);
sequence_point_follows = FALSE;
assemblez_jump(ln);
- assemble_label_no(ln2);
+ assemble_forward_label_no(ln2);
return;
/* -------------------------------------------------------------------- */
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;
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();
}
else error("'do' without matching 'until'");
- assemble_label_no(ln3);
+ assemble_forward_label_no(ln3);
break;
/* -------------------------------------------------------------------- */
sequence_point_follows = FALSE;
if (!execution_never_reaches_here)
assembleg_jump(ln);
- assemble_label_no(ln2);
+ assemble_forward_label_no(ln2);
return;
}
goto ParseUpdate;
}
}
- assemble_label_no(ln3);
+ assemble_forward_label_no(ln3);
return;
/* -------------------------------------------------------------------- */
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
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)) {
/* -------------------------------------------------------------------- */
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);
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();
}
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;
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);
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);
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);
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);
AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
QUANTITY_CONTEXT, -1);
if (is_constant_ot(AO2.type) && AO2.marker == 0) {
+ /* Compile-time check */
if (AO2.value < 0 || AO2.value >= MAX_DYNAMIC_STRINGS) {
- memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
+ error_max_dynamic_strings(AO2.value);
}
}
get_next_token();
assembleg_store(temp_var1, AO);
parse_code_block(ln = next_label++, continue_label, 1);
- assemble_label_no(ln);
+ assemble_forward_label_no(ln);
return;
/* -------------------------------------------------------------------- */
parse_code_block(ln2, ln, 0);
sequence_point_follows = FALSE;
assembleg_jump(ln);
- assemble_label_no(ln2);
+ assemble_forward_label_no(ln2);
return;
/* -------------------------------------------------------------------- */
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;
}
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* "symbols" : The symbols table; creating stock of reserved words */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
int no_named_constants; /* Copied into story file */
/* ------------------------------------------------------------------------- */
-/* Plus six arrays. Each symbol has its own index n (an int32) and */
+/* Plus an array of symbolinfo. Each symbol has its own index n (an */
+/* int32) in the array. The struct there contains: */
/* */
-/* svals[n] is its value (must be 32 bits wide, i.e. an int32, tho' */
-/* it is used to hold an unsigned 16 bit Z-machine value) */
-/* sflags[n] holds flags (see "header.h" for a list) */
-/* stypes[n] is the "type", distinguishing between the data type of */
+/* value is its value. In Z-code, this holds both the 16-bit value */
+/* and the 16-bit backpatch marker, so it is an int32. */
+/* marker is the backpatch marker in Glulx. */
+/* flags holds flags (see "header.h" for a list of ?_SFLAGS) */
+/* type is the "type", distinguishing between the data type of */
/* different kinds of constants/variables. */
-/* (See the "typename()" below.) */
-/* symbs[n] (needs to be cast to (char *) to be used) is the name */
-/* of the symbol, in the same case form as when created. */
-/* slines[n] is the source line on which the symbol value was first */
+/* (A ?_T constant; see the "typename()" below.) */
+/* name is the name of the symbol, in the same case form as */
+/* when created. */
+/* line is the source line on which the symbol value was first */
/* assigned */
-/* symbol_debug_backpatch_positions[n] */
+/* next_entry is the forward link in the symbol hash table. (See */
+/* start_of_list, below.) */
+/* */
+/* When generating a debug file (-k switch), we also allocate an array */
+/* of symboldebuginfo, which contains: */
+/* */
+/* backpatch_pos */
/* is a file position in the debug information file where */
/* the symbol's value should be written after backpatching, */
/* or else the null position if the value was known and */
/* written beforehand */
-/* replacement_debug_backpatch_positions[n] */
+/* replacement_backpatch_pos */
/* is a file position in the debug information file where */
/* the symbol's name can be erased if it is replaced, or */
/* else null if the name will never need to be replaced */
/* Comparison is case insensitive. */
/* Note that local variable names are not entered into the symbols table, */
/* as their numbers and scope are too limited for this to be efficient. */
-/* ------------------------------------------------------------------------- */
-/* Caveat editor: some array types are set up to work even on machines */
-/* where sizeof(int32 *) differs from, e.g., sizeof(char *): so do not */
-/* alter the types unless you understand what is going on! */
/* ------------------------------------------------------------------------- */
- int32 **symbs;
- int32 *svals;
- int *smarks; /* Glulx-only */
- brief_location *slines;
- int *sflags;
-#ifdef VAX
- char *stypes; /* In VAX C, insanely, "signed char" is illegal */
-#else
- signed char *stypes;
-#endif
- maybe_file_position *symbol_debug_backpatch_positions;
- maybe_file_position *replacement_debug_backpatch_positions;
+symbolinfo *symbols; /* Allocated up to no_symbols */
+static memory_list symbols_memlist;
+symboldebuginfo *symbol_debug_info; /* Allocated up to no_symbols */
+static memory_list symbol_debug_info_memlist;
/* ------------------------------------------------------------------------- */
/* Memory to hold the text of symbol names: note that this memory is */
/* allocated as needed in chunks of size SYMBOLS_CHUNK_SIZE. */
/* ------------------------------------------------------------------------- */
-#define MAX_SYMBOL_CHUNKS (100)
+#define SYMBOLS_CHUNK_SIZE (4096)
-static uchar *symbols_free_space, /* Next byte free to hold new names */
+static char *symbols_free_space, /* Next byte free to hold new names */
*symbols_ceiling; /* Pointer to the end of the current
allocation of memory for names */
static char** symbol_name_space_chunks; /* For chunks of memory used to hold
the name strings of symbols */
static int no_symbol_name_space_chunks;
+static memory_list symbol_name_space_chunks_memlist;
/* Symbol replacements (used by the "Replace X Y" directive). */
/* idea to choose HASH_TAB_SIZE as large as conveniently possible. */
/* ------------------------------------------------------------------------- */
-static int *next_entry;
-static int32 *start_of_list;
+static int32 *start_of_list; /* Allocated array of size HASH_TAB_SIZE */
+/* The next_entry field is part of the symbolinfo struct. */
/* ------------------------------------------------------------------------- */
/* Initialisation. */
/* ------------------------------------------------------------------------- */
extern void add_config_symbol_definition(char *symbol, int32 value)
-{
+{ char *str;
+
if (symbol_definitions_count == symbol_definitions_size) {
int oldsize = symbol_definitions_size;
if (symbol_definitions_size == 0)
symbol_definitions_size, "symbol definition table");
}
- char *str = my_malloc(strlen(symbol)+1, "symbol name");
+ str = my_malloc(strlen(symbol)+1, "symbol name");
strcpy(str, symbol);
symbol_definitions[symbol_definitions_count].symbol = str;
/* Symbol finding, creating, and removing. */
/* ------------------------------------------------------------------------- */
+extern int get_symbol_index(char *p)
+{
+ /* Return the index in the symbols array of symbol "p", or -1
+ if it isn't there. Does not create a new symbol or mark the
+ symbol as used. */
+
+ int32 new_entry, this;
+ char *r;
+ int hashcode = hash_code_from_string(p);
+
+ this = start_of_list[hashcode];
+
+ do
+ { if (this == -1) break;
+
+ r = symbols[this].name;
+ new_entry = strcmpcis(r, p);
+ if (new_entry == 0)
+ {
+ return this;
+ }
+ if (new_entry > 0) break;
+
+ this = symbols[this].next_entry;
+ } while (this != -1);
+
+ return -1;
+}
+
extern int symbol_index(char *p, int hashcode)
{
- /* Return the index in the symbs/svals/sflags/stypes/... arrays of symbol
- "p", creating a new symbol with that name if it isn't already there.
+ /* Return the index in the symbols array of symbol "p", creating a
+ new symbol with that name if it isn't already there.
New symbols are created with flag UNKNOWN_SFLAG, value 0x100
(a 2-byte quantity in Z-machine terms) and type CONSTANT_T.
The string "p" is undamaged. */
- int32 new_entry, this, last; char *r;
+ int32 new_entry, this, last;
+ char *r;
+ int len;
if (hashcode == -1) hashcode = hash_code_from_string(p);
do
{ if (this == -1) break;
- r = (char *)symbs[this];
+ r = symbols[this].name;
new_entry = strcmpcis(r, p);
if (new_entry == 0)
{
if (new_entry > 0) break;
last = this;
- this = next_entry[this];
+ this = symbols[this].next_entry;
} while (this != -1);
- if (no_symbols >= MAX_SYMBOLS)
- memoryerror("MAX_SYMBOLS", MAX_SYMBOLS);
+ if (symdef_trace_setting)
+ printf("Encountered symbol %d '%s'\n", no_symbols, p);
+
+ ensure_memory_list_available(&symbols_memlist, no_symbols+1);
+ if (debugfile_switch)
+ ensure_memory_list_available(&symbol_debug_info_memlist, no_symbols+1);
if (last == -1)
- { next_entry[no_symbols]=start_of_list[hashcode];
+ { symbols[no_symbols].next_entry=start_of_list[hashcode];
start_of_list[hashcode]=no_symbols;
}
else
- { next_entry[no_symbols]=this;
- next_entry[last]=no_symbols;
+ { symbols[no_symbols].next_entry=this;
+ symbols[last].next_entry=no_symbols;
}
- if (symbols_free_space+strlen(p)+1 >= symbols_ceiling)
+ len = strlen(p);
+ if (symbols_free_space+len+1 >= symbols_ceiling)
{ symbols_free_space
= my_malloc(SYMBOLS_CHUNK_SIZE, "symbol names chunk");
symbols_ceiling = symbols_free_space + SYMBOLS_CHUNK_SIZE;
- /* If we've passed MAX_SYMBOL_CHUNKS chunks, we print an error
- message telling the user to increase SYMBOLS_CHUNK_SIZE.
- That is the correct cure, even though the error comes out
- worded inaccurately. */
- if (no_symbol_name_space_chunks >= MAX_SYMBOL_CHUNKS)
- memoryerror("SYMBOLS_CHUNK_SIZE", SYMBOLS_CHUNK_SIZE);
+ ensure_memory_list_available(&symbol_name_space_chunks_memlist, no_symbol_name_space_chunks+1);
symbol_name_space_chunks[no_symbol_name_space_chunks++]
- = (char *) symbols_free_space;
- if (symbols_free_space+strlen(p)+1 >= symbols_ceiling)
- memoryerror("SYMBOLS_CHUNK_SIZE", SYMBOLS_CHUNK_SIZE);
+ = symbols_free_space;
+ if (symbols_free_space+len+1 >= symbols_ceiling)
+ {
+ /* This should be impossible, since SYMBOLS_CHUNK_SIZE > MAX_IDENTIFIER_LENGTH. */
+ fatalerror("Symbol exceeds the maximum possible length");
+ }
}
- strcpy((char *) symbols_free_space, p);
- symbs[no_symbols] = (int32 *) symbols_free_space;
- symbols_free_space += strlen((char *)symbols_free_space) + 1;
+ strcpy(symbols_free_space, p);
+ symbols[no_symbols].name = symbols_free_space;
+ symbols_free_space += (len+1);
- svals[no_symbols] = 0x100; /* ###-wrong? Would this fix the
+ symbols[no_symbols].value = 0x100; /* ###-wrong? Would this fix the
unbound-symbol-causes-asm-error? */
- sflags[no_symbols] = UNKNOWN_SFLAG;
- stypes[no_symbols] = CONSTANT_T;
- slines[no_symbols] = get_brief_location(&ErrorReport);
+ symbols[no_symbols].flags = UNKNOWN_SFLAG;
+ symbols[no_symbols].marker = 0;
+ symbols[no_symbols].type = CONSTANT_T;
+ symbols[no_symbols].line = get_brief_location(&ErrorReport);
if (debugfile_switch)
{ nullify_debug_file_position
- (&symbol_debug_backpatch_positions[no_symbols]);
+ (&symbol_debug_info[no_symbols].backpatch_pos);
nullify_debug_file_position
- (&replacement_debug_backpatch_positions[no_symbols]);
+ (&symbol_debug_info[no_symbols].replacement_backpatch_pos);
}
if (track_unused_routines)
*/
int j;
- j = hash_code_from_string((char *) symbs[k]);
+ j = hash_code_from_string(symbols[k].name);
if (start_of_list[j] == k)
- { start_of_list[j] = next_entry[k];
+ { start_of_list[j] = symbols[k].next_entry;
return;
}
j = start_of_list[j];
while (j != -1)
{
- if (next_entry[j] == k)
- { next_entry[j] = next_entry[k];
+ if (symbols[j].next_entry == k)
+ { symbols[j].next_entry = symbols[k].next_entry;
return;
}
- j = next_entry[j];
+ j = symbols[j].next_entry;
}
}
case OBJECT_T: return("Object");
case CLASS_T: return("Class");
case FAKE_ACTION_T: return("Fake action");
+
+ /* These are not symbol types, but they get printed in errors. */
+ case STRING_REQ_T: return("String");
+ case DICT_WORD_REQ_T: return("Dictionary word");
default: return("(Unknown type)");
}
static void describe_flags(int flags)
{ if (flags & UNKNOWN_SFLAG) printf("(?) ");
- if (flags & USED_SFLAG) printf("(used) ");
if (flags & REPLACE_SFLAG) printf("(Replaced) ");
+ if (flags & USED_SFLAG) printf("(used) ");
if (flags & DEFCON_SFLAG) printf("(Defaulted) ");
if (flags & STUB_SFLAG) printf("(Stubbed) ");
- if (flags & CHANGE_SFLAG) printf("(value will change) ");
if (flags & IMPORT_SFLAG) printf("(Imported) ");
if (flags & EXPORT_SFLAG) printf("(Exported) ");
+ if (flags & ALIASED_SFLAG) printf("(aliased) ");
+ if (flags & CHANGE_SFLAG) printf("(value will change) ");
if (flags & SYSTEM_SFLAG) printf("(System) ");
if (flags & INSF_SFLAG) printf("(created in sys file) ");
if (flags & UERROR_SFLAG) printf("('Unknown' error issued) ");
- if (flags & ALIASED_SFLAG) printf("(aliased) ");
if (flags & ACTION_SFLAG) printf("(Action name) ");
if (flags & REDEFINABLE_SFLAG) printf("(Redefinable) ");
+ if (flags & STAR_SFLAG) printf("(*) ");
}
extern void describe_symbol(int k)
{ printf("%4d %-16s %2d:%04d %04x %s ",
- k, (char *) (symbs[k]),
- (int)(slines[k].file_index),
- (int)(slines[k].line_number),
- svals[k], typename(stypes[k]));
- describe_flags(sflags[k]);
+ k, (symbols[k].name),
+ (int)(symbols[k].line.file_index),
+ (int)(symbols[k].line.line_number),
+ symbols[k].value, typename(symbols[k].type));
+ describe_flags(symbols[k].flags);
}
extern void list_symbols(int level)
{ int k;
for (k=0; k<no_symbols; k++)
- { if ((level==2) ||
- ((sflags[k] & (SYSTEM_SFLAG + UNKNOWN_SFLAG + INSF_SFLAG)) == 0))
+ { if ((level>=2) ||
+ ((symbols[k].flags & (SYSTEM_SFLAG + UNKNOWN_SFLAG + INSF_SFLAG)) == 0))
{ describe_symbol(k); printf("\n");
}
}
}
+/* Check that the operand is of the given symbol type (XXX_T). If wanttype2 is nonzero, that's a second allowable type.
+ Generate a warning if no match. */
+extern void check_warn_symbol_type(const assembly_operand *AO, int wanttype, int wanttype2, char *context)
+{
+ symbolinfo *sym;
+ int symtype;
+
+ if (AO->symindex < 0)
+ {
+ /* This argument is not a symbol; it's a local variable, a literal, or a computed expression. */
+ /* We can recognize and type-check some literals. */
+ if (AO->marker == DWORD_MV) {
+ if (wanttype != DICT_WORD_REQ_T && wanttype2 != DICT_WORD_REQ_T)
+ symtype_warning(context, NULL, typename(DICT_WORD_REQ_T), typename(wanttype));
+ }
+ if (AO->marker == STRING_MV) {
+ if (wanttype != STRING_REQ_T && wanttype2 != STRING_REQ_T)
+ symtype_warning(context, NULL, typename(STRING_REQ_T), typename(wanttype));
+ }
+ return;
+ }
+
+ sym = &symbols[AO->symindex];
+ symtype = sym->type;
+
+ if (symtype == GLOBAL_VARIABLE_T)
+ {
+ /* A global variable could have any value. No way to generate a warning. */
+ return;
+ }
+ if (symtype == CONSTANT_T)
+ {
+ /* A constant could also have any value. This case also includes forward-declared constants (UNKNOWN_SFLAG). */
+ /* We try inferring its type by looking at the backpatch marker. Sadly, this only works for objects. (And not in Z-code, where object values are not backpatched.) */
+ if (sym->marker == OBJECT_MV) {
+ /* Continue with inferred type. */
+ symtype = OBJECT_T;
+ }
+ else {
+ /* Give up. */
+ return;
+ }
+ }
+
+ if (!( (symtype == wanttype)
+ || (wanttype2 != 0 && symtype == wanttype2)))
+ {
+ symtype_warning(context, sym->name, typename(symtype), typename(wanttype));
+ }
+}
+
+/* Similar, but we allow any type that has a metaclass: Object, Class, String, or Routine.
+ Generate a warning if no match. */
+extern void check_warn_symbol_has_metaclass(const assembly_operand *AO, char *context)
+{
+ symbolinfo *sym;
+ int symtype;
+
+ if (AO->symindex < 0)
+ {
+ /* This argument is not a symbol; it's a local variable, a literal, or a computed expression. */
+ /* We can recognize and type-check some literals. */
+ if (AO->marker == DWORD_MV) {
+ symtype_warning(context, NULL, typename(DICT_WORD_REQ_T), "Object/Class/Routine/String");
+ }
+ if (AO->marker == STRING_MV) {
+ /* Strings are good here. */
+ }
+ return;
+ }
+
+ sym = &symbols[AO->symindex];
+ symtype = sym->type;
+
+ if (symtype == GLOBAL_VARIABLE_T)
+ {
+ /* A global variable could have any value. No way to generate a warning. */
+ return;
+ }
+ if (symtype == CONSTANT_T)
+ {
+ /* A constant could also have any value. This case also includes forward-declared constants (UNKNOWN_SFLAG). */
+ /* We try inferring its type by looking at the backpatch marker. Sadly, this only works for objects. (And not in Z-code, where object values are not backpatched.) */
+ if (sym->marker == OBJECT_MV) {
+ /* Continue with inferred type. */
+ symtype = OBJECT_T;
+ }
+ else {
+ /* Give up. */
+ return;
+ }
+ }
+
+ if (!(symtype == ROUTINE_T || symtype == CLASS_T || symtype == OBJECT_T))
+ {
+ symtype_warning(context, sym->name, typename(symtype), "Object/Class/Routine/String");
+ }
+}
+
extern void issue_unused_warnings(void)
{ int32 i;
/* Now back to mark anything necessary as used */
i = symbol_index("Main", -1);
- if (!(sflags[i] & UNKNOWN_SFLAG)) sflags[i] |= USED_SFLAG;
+ if (!(symbols[i].flags & UNKNOWN_SFLAG)) symbols[i].flags |= USED_SFLAG;
for (i=0;i<no_symbols;i++)
- { if (((sflags[i]
+ { if (((symbols[i].flags
& (SYSTEM_SFLAG + UNKNOWN_SFLAG + EXPORT_SFLAG
+ INSF_SFLAG + USED_SFLAG + REPLACE_SFLAG)) == 0)
- && (stypes[i] != OBJECT_T))
- dbnu_warning(typename(stypes[i]), (char *) symbs[i], slines[i]);
+ && (symbols[i].type != OBJECT_T))
+ dbnu_warning(typename(symbols[i].type), symbols[i].name, symbols[i].line);
+ }
+}
+
+extern void issue_debug_symbol_warnings(void)
+{
+ int value = get_symbol_index("DEBUG");
+ if (value >= 0 && (symbols[value].flags & USED_SFLAG) && !(symbols[value].flags & UNKNOWN_SFLAG)) {
+ value = get_symbol_index("debug_flag");
+ if (value >= 0 && (symbols[value].flags & USED_SFLAG) && (symbols[value].flags & UNKNOWN_SFLAG)) {
+ warning("DEBUG mode is on, but this story or library does not appear to support it");
+ }
}
}
for (i=0; i<NUM_ATTR_BYTES*8; i++) attribute_name_strings[i] = null_value;
for (i=0; i<no_symbols; i++)
- { t=stypes[i];
+ { t=symbols[i].type;
if ((t == INDIVIDUAL_PROPERTY_T) || (t == PROPERTY_T))
- { if (sflags[i] & ALIASED_SFLAG)
- { if (individual_name_strings[svals[i]] == 0)
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { if (symbols[i].flags & ALIASED_SFLAG)
+ { if (individual_name_strings[symbols[i].value] == 0)
+ { sprintf(idname_string, "%s", symbols[i].name);
for (j=i+1, k=0; (j<no_symbols && k<3); j++)
- { if ((stypes[j] == stypes[i])
- && (svals[j] == svals[i]))
+ { if ((symbols[j].type == symbols[i].type)
+ && (symbols[j].value == symbols[i].value))
{ sprintf(idname_string+strlen(idname_string),
- "/%s", (char *) symbs[j]);
+ "/%s", symbols[j].name);
k++;
}
}
- individual_name_strings[svals[i]]
+ individual_name_strings[symbols[i].value]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
else
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { sprintf(idname_string, "%s", symbols[i].name);
- individual_name_strings[svals[i]]
+ individual_name_strings[symbols[i].value]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
if (t == ATTRIBUTE_T)
- { if (sflags[i] & ALIASED_SFLAG)
- { if (attribute_name_strings[svals[i]] == null_value)
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { if (symbols[i].flags & ALIASED_SFLAG)
+ { if (attribute_name_strings[symbols[i].value] == null_value)
+ { sprintf(idname_string, "%s", symbols[i].name);
for (j=i+1, k=0; (j<no_symbols && k<3); j++)
- { if ((stypes[j] == stypes[i])
- && (svals[j] == svals[i]))
+ { if ((symbols[j].type == symbols[i].type)
+ && (symbols[j].value == symbols[i].value))
{ sprintf(idname_string+strlen(idname_string),
- "/%s", (char *) symbs[j]);
+ "/%s", symbols[j].name);
k++;
}
}
- attribute_name_strings[svals[i]]
+ attribute_name_strings[symbols[i].value]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
else
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { sprintf(idname_string, "%s", symbols[i].name);
- attribute_name_strings[svals[i]]
+ attribute_name_strings[symbols[i].value]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
- if (sflags[i] & ACTION_SFLAG)
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ if (symbols[i].flags & ACTION_SFLAG)
+ { sprintf(idname_string, "%s", symbols[i].name);
idname_string[strlen(idname_string)-3] = 0;
if (debugfile_switch)
{ debug_file_printf("<action>");
debug_file_printf
("<identifier>##%s</identifier>", idname_string);
- debug_file_printf("<value>%d</value>", svals[i]);
+ debug_file_printf("<value>%d</value>", symbols[i].value);
debug_file_printf("</action>");
}
- action_name_strings[svals[i]]
+ action_name_strings[symbols[i].value]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
for (i=0; i<no_symbols; i++)
- { if (stypes[i] == FAKE_ACTION_T)
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { if (symbols[i].type == FAKE_ACTION_T)
+ { sprintf(idname_string, "%s", symbols[i].name);
idname_string[strlen(idname_string)-3] = 0;
- action_name_strings[svals[i]
+ action_name_strings[symbols[i].value
- ((grammar_version_number==1)?256:4096) + no_actions]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
for (j=0; j<no_arrays; j++)
- { i = array_symbols[j];
- sprintf(idname_string, "%s", (char *) symbs[i]);
+ { i = arrays[j].symbol;
+ sprintf(idname_string, "%s", symbols[i].name);
array_name_strings[j]
= compile_string(idname_string, STRCTX_SYMBOL);
}
if (define_INFIX_switch)
{ for (i=0; i<no_symbols; i++)
- { if (stypes[i] == GLOBAL_VARIABLE_T)
- { sprintf(idname_string, "%s", (char *) symbs[i]);
- array_name_strings[no_arrays + svals[i] -16]
+ { if (symbols[i].type == GLOBAL_VARIABLE_T)
+ { sprintf(idname_string, "%s", symbols[i].name);
+ array_name_strings[no_arrays + symbols[i].value -16]
= compile_string(idname_string, STRCTX_SYMBOL);
}
}
for (i=0; i<no_named_routines; i++)
- { sprintf(idname_string, "%s", (char *) symbs[named_routine_symbols[i]]);
+ { sprintf(idname_string, "%s", symbols[named_routine_symbols[i]].name);
array_name_strings[no_arrays + no_globals + i]
= compile_string(idname_string, STRCTX_SYMBOL);
}
for (i=0, no_named_constants=0; i<no_symbols; i++)
- { if (((stypes[i] == OBJECT_T) || (stypes[i] == CLASS_T)
- || (stypes[i] == CONSTANT_T))
- && ((sflags[i] & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
- { sprintf(idname_string, "%s", (char *) symbs[i]);
+ { if (((symbols[i].type == OBJECT_T) || (symbols[i].type == CLASS_T)
+ || (symbols[i].type == CONSTANT_T))
+ && ((symbols[i].flags & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
+ { sprintf(idname_string, "%s", symbols[i].name);
array_name_strings[no_arrays + no_globals + no_named_routines
+ no_named_constants++]
= compile_string(idname_string, STRCTX_SYMBOL);
/* ------------------------------------------------------------------------- */
static void assign_symbol_base(int index, int32 value, int type)
-{ svals[index] = value;
- stypes[index] = type;
- if (sflags[index] & UNKNOWN_SFLAG)
- { sflags[index] &= (~UNKNOWN_SFLAG);
- if (is_systemfile()) sflags[index] |= INSF_SFLAG;
- slines[index] = get_brief_location(&ErrorReport);
+{ symbols[index].value = value;
+ symbols[index].type = type;
+ if (symbols[index].flags & UNKNOWN_SFLAG)
+ { symbols[index].flags &= (~UNKNOWN_SFLAG);
+ if (is_systemfile()) symbols[index].flags |= INSF_SFLAG;
+ symbols[index].line = get_brief_location(&ErrorReport);
}
}
extern void assign_symbol(int index, int32 value, int type)
{
- if (!glulx_mode) {
- assign_symbol_base(index, value, type);
- }
- else {
- smarks[index] = 0;
- assign_symbol_base(index, value, type);
- }
+ assign_symbol_base(index, value, type);
+ symbols[index].marker = 0;
+ if (symdef_trace_setting)
+ printf("Defined symbol %d '%s' as %d (%s)\n", index, symbols[index].name, value, typename(type));
}
extern void assign_marked_symbol(int index, int marker, int32 value, int type)
{
- if (!glulx_mode) {
- assign_symbol_base(index, (int32)marker*0x10000 + (value % 0x10000),
- type);
- }
- else {
- smarks[index] = marker;
- assign_symbol_base(index, value, type);
- }
+ assign_symbol_base(index, value, type);
+ symbols[index].marker = marker;
+ if (symdef_trace_setting)
+ printf("Defined symbol %d '%s' as %s %d (%s)\n", index, symbols[index].name, describe_mv(marker), value, typename(type));
}
static void emit_debug_information_for_predefined_symbol
static void create_symbol(char *p, int32 value, int type)
{ int i = symbol_index(p, -1);
- if (!(sflags[i] & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))) {
+ if (!(symbols[i].flags & (UNKNOWN_SFLAG + REDEFINABLE_SFLAG))) {
/* Symbol already defined! */
- if (svals[i] == value && stypes[i] == type) {
+ if (symbols[i].value == value && symbols[i].type == type) {
/* Special case: the symbol was already defined with this same
value. We let it pass. */
return;
}
else {
- ebf_symbol_error("new symbol", p, typename(stypes[i]), slines[i]);
+ ebf_symbol_error("new symbol", p, typename(symbols[i].type), symbols[i].line);
return;
}
}
- svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location;
+ symbols[i].value = value; symbols[i].type = type; symbols[i].line = blank_brief_location;
/* If the symbol already existed with REDEFINABLE_SFLAG, we keep that. */
- sflags[i] = USED_SFLAG + SYSTEM_SFLAG + (sflags[i] & REDEFINABLE_SFLAG);
+ symbols[i].flags = USED_SFLAG + SYSTEM_SFLAG + (symbols[i].flags & REDEFINABLE_SFLAG);
emit_debug_information_for_predefined_symbol(p, i, value, type);
}
{ int i = symbol_index(p, -1);
/* This is only called for a few symbols with known names.
They will not collide. */
- svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location;
- sflags[i] = USED_SFLAG + SYSTEM_SFLAG + REDEFINABLE_SFLAG;
+ symbols[i].value = value; symbols[i].type = type; symbols[i].line = blank_brief_location;
+ symbols[i].flags = USED_SFLAG + SYSTEM_SFLAG + REDEFINABLE_SFLAG;
emit_debug_information_for_predefined_symbol(p, i, value, type);
}
}
create_symbol("WORDSIZE", WORDSIZE, CONSTANT_T);
- create_symbol("DICT_ENTRY_BYTES", DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
+ /* DICT_ENTRY_BYTES must be REDEFINABLE_SFLAG because the Version directive can change it. */
+ create_rsymbol("DICT_ENTRY_BYTES", DICT_ENTRY_BYTE_LENGTH, CONSTANT_T);
if (!glulx_mode) {
create_symbol("DICT_WORD_SIZE", ((version_number==3)?4:6), CONSTANT_T);
create_symbol("NUM_ATTR_BYTES", ((version_number==3)?4:6), CONSTANT_T);
int ix;
if (original == renamed) {
- error_named("A routine cannot be 'Replace'd to itself:", (char *)symbs[original]);
+ error_named("A routine cannot be 'Replace'd to itself:", symbols[original].name);
return;
}
for (ix=0; ix<symbol_replacements_count; ix++) {
if (original == symbol_replacements[ix].original_symbol) {
- error_named("A routine cannot be 'Replace'd to more than one new name:", (char *)symbs[original]);
+ error_named("A routine cannot be 'Replace'd to more than one new name:", symbols[original].name);
}
if (renamed == symbol_replacements[ix].original_symbol) {
- error_named("A routine cannot be 'Replace'd to a 'Replace'd name:", (char *)symbs[original]);
+ error_named("A routine cannot be 'Replace'd to a 'Replace'd name:", symbols[original].name);
}
}
of a function being defined.) */
if (df_dont_note_global_symbols)
return;
+ /* If we're compiling an unreachable statement, no reference. */
+ if (execution_never_reaches_here)
+ return;
/* We are only interested in functions, or forward-declared symbols
that might turn out to be functions. */
- symtype = stypes[symbol];
+ symtype = symbols[symbol].type;
if (symtype != ROUTINE_T && symtype != CONSTANT_T)
return;
- if (symtype == CONSTANT_T && !(sflags[symbol] & UNKNOWN_SFLAG))
+ if (symtype == CONSTANT_T && !(symbols[symbol].flags & UNKNOWN_SFLAG))
return;
bucket = (df_current_function_addr ^ (uint32)symbol) % DF_SYMBOL_HASH_BUCKETS;
we'll mark them specially. */
ix = symbol_index("Main__", -1);
- if (stypes[ix] == ROUTINE_T) {
- uint32 addr = svals[ix] * (glulx_mode ? 1 : scale_factor);
+ if (symbols[ix].type == ROUTINE_T) {
+ uint32 addr = symbols[ix].value * (glulx_mode ? 1 : scale_factor);
tofunc = df_function_for_address(addr);
if (tofunc)
tofunc->usage |= DF_USAGE_MAIN;
}
ix = symbol_index("Main", -1);
- if (stypes[ix] == ROUTINE_T) {
- uint32 addr = svals[ix] * (glulx_mode ? 1 : scale_factor);
+ if (symbols[ix].type == ROUTINE_T) {
+ uint32 addr = symbols[ix].value * (glulx_mode ? 1 : scale_factor);
tofunc = df_function_for_address(addr);
if (tofunc)
tofunc->usage |= DF_USAGE_MAIN;
for (ent = func->refs; ent; ent=ent->refsnext) {
uint32 addr;
int symbol = ent->symbol;
- if (stypes[symbol] != ROUTINE_T)
+ if (symbols[symbol].type != ROUTINE_T)
continue;
- addr = svals[symbol] * (glulx_mode ? 1 : scale_factor);
+ addr = symbols[symbol].value * (glulx_mode ? 1 : scale_factor);
tofunc = df_function_for_address(addr);
if (!tofunc) {
- error_named("Internal error in stripping: global ROUTINE_T symbol is not found in df_function map:", (char *)symbs[symbol]);
+ error_named("Internal error in stripping: global ROUTINE_T symbol is not found in df_function map:", symbols[symbol].name);
continue;
}
/* A function may be marked here more than once. That's fine. */
for (ent = func->refs; ent; ent=ent->refsnext) {
uint32 addr;
int symbol = ent->symbol;
- if (stypes[symbol] != ROUTINE_T)
+ if (symbols[symbol].type != ROUTINE_T)
continue;
- addr = svals[symbol] * (glulx_mode ? 1 : scale_factor);
+ addr = symbols[symbol].value * (glulx_mode ? 1 : scale_factor);
tofunc = df_function_for_address(addr);
if (!tofunc) {
- error_named("Internal error in stripping: function ROUTINE_T symbol is not found in df_function map:", (char *)symbs[symbol]);
+ error_named("Internal error in stripping: function ROUTINE_T symbol is not found in df_function map:", symbols[symbol].name);
continue;
}
if (tofunc->usage)
extern void init_symbols_vars(void)
{
- symbs = NULL;
- svals = NULL;
- smarks = NULL;
- stypes = NULL;
- sflags = NULL;
- next_entry = NULL;
+ symbols = NULL;
start_of_list = NULL;
+ symbol_debug_info = NULL;
symbol_name_space_chunks = NULL;
no_symbol_name_space_chunks = 0;
symbols_free_space=NULL;
- symbols_ceiling=symbols_free_space;
+ symbols_ceiling=NULL;
no_symbols = 0;
extern void symbols_allocate_arrays(void)
{
- symbs = my_calloc(sizeof(char *), MAX_SYMBOLS, "symbols");
- svals = my_calloc(sizeof(int32), MAX_SYMBOLS, "symbol values");
- if (glulx_mode)
- smarks = my_calloc(sizeof(int), MAX_SYMBOLS, "symbol markers");
- slines = my_calloc(sizeof(brief_location), MAX_SYMBOLS, "symbol lines");
- stypes = my_calloc(sizeof(char), MAX_SYMBOLS, "symbol types");
- sflags = my_calloc(sizeof(int), MAX_SYMBOLS, "symbol flags");
+ initialise_memory_list(&symbols_memlist,
+ sizeof(symbolinfo), 6400, (void**)&symbols,
+ "symbols");
if (debugfile_switch)
- { symbol_debug_backpatch_positions =
- my_calloc(sizeof(maybe_file_position), MAX_SYMBOLS,
- "symbol debug information backpatch positions");
- replacement_debug_backpatch_positions =
- my_calloc(sizeof(maybe_file_position), MAX_SYMBOLS,
- "replacement debug information backpatch positions");
+ {
+ initialise_memory_list(&symbol_debug_info_memlist,
+ sizeof(symboldebuginfo), 6400, (void**)&symbol_debug_info,
+ "symbol debug backpatch info");
}
- next_entry = my_calloc(sizeof(int), MAX_SYMBOLS,
- "symbol linked-list forward links");
start_of_list = my_calloc(sizeof(int32), HASH_TAB_SIZE,
"hash code list beginnings");
- symbol_name_space_chunks
- = my_calloc(sizeof(char *), MAX_SYMBOL_CHUNKS, "symbol names chunk addresses");
+ initialise_memory_list(&symbol_name_space_chunks_memlist,
+ sizeof(char *), 32, (void**)&symbol_name_space_chunks,
+ "symbol names chunk addresses");
if (track_unused_routines) {
df_tables_closed = FALSE;
my_free(&(symbol_name_space_chunks[i]),
"symbol names chunk");
- my_free(&symbol_name_space_chunks, "symbol names chunk addresses");
+ deallocate_memory_list(&symbol_name_space_chunks_memlist);
- my_free(&symbs, "symbols");
- my_free(&svals, "symbol values");
- my_free(&smarks, "symbol markers");
- my_free(&slines, "symbol lines");
- my_free(&stypes, "symbol types");
- my_free(&sflags, "symbol flags");
+ deallocate_memory_list(&symbols_memlist);
if (debugfile_switch)
- { my_free
- (&symbol_debug_backpatch_positions,
- "symbol debug information backpatch positions");
- my_free
- (&replacement_debug_backpatch_positions,
- "replacement debug information backpatch positions");
+ {
+ deallocate_memory_list(&symbol_debug_info_memlist);
}
- my_free(&next_entry, "symbol linked-list forward links");
my_free(&start_of_list, "hash code list beginnings");
if (symbol_replacements)
/* ------------------------------------------------------------------------- */
/* "syntax" : Syntax analyser and compiler */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
extern int parse_directive(int internal_flag)
{
- /* Internal_flag is FALSE if the directive is encountered normally,
- TRUE if encountered with a # prefix inside a routine or object
- definition.
+ /* Internal_flag is FALSE if the directive is encountered normally
+ (at the top level of the program); TRUE if encountered with
+ a # prefix inside a routine or object definition.
(Only directives like #ifdef are permitted inside a definition.)
int is_renamed;
begin_syntax_line(FALSE);
+ if (!internal_flag) {
+ /* An internal directive can occur in the middle of an expression or
+ object definition. So we only release for top-level directives. */
+ release_token_texts();
+ }
get_next_token();
if (token_type == EOF_TT) return(FALSE);
{ ebf_error("routine name", token_text);
return(FALSE);
}
- if ((!(sflags[token_value] & UNKNOWN_SFLAG))
- && (!(sflags[token_value] & REPLACE_SFLAG)))
- { ebf_symbol_error("routine name", token_text, typename(stypes[token_value]), slines[token_value]);
+ if ((!(symbols[token_value].flags & UNKNOWN_SFLAG))
+ && (!(symbols[token_value].flags & REPLACE_SFLAG)))
+ { ebf_symbol_error("routine name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
return(FALSE);
}
rep_symbol = routine_symbol;
is_renamed = find_symbol_replacement(&rep_symbol);
- if ((sflags[routine_symbol] & REPLACE_SFLAG)
+ if ((symbols[routine_symbol].flags & REPLACE_SFLAG)
&& !is_renamed && (is_systemfile()))
{ /* The function is definitely being replaced (system_file
always loses priority in a replacement) but is not
{ /* Parse the function definition and assign its symbol. */
assign_symbol(routine_symbol,
parse_routine(lexical_source, FALSE,
- (char *) symbs[routine_symbol], FALSE, routine_symbol),
+ symbols[routine_symbol].name, FALSE, routine_symbol),
ROUTINE_T);
- slines[routine_symbol] = routine_starts_line;
+ symbols[routine_symbol].line = routine_starts_line;
}
if (is_renamed) {
The first time we see a definition for symbol X, we
copy it to Y -- that's the "original" form of the
function. */
- if (svals[rep_symbol] == 0) {
- assign_symbol(rep_symbol, svals[routine_symbol], ROUTINE_T);
+ if (symbols[rep_symbol].value == 0) {
+ assign_symbol(rep_symbol, symbols[routine_symbol].value, ROUTINE_T);
}
}
return TRUE;
}
- if ((token_type == SYMBOL_TT) && (stypes[token_value] == CLASS_T))
+ if ((token_type == SYMBOL_TT) && (symbols[token_value].type == CLASS_T))
{ if (internal_flag)
{ error("It is illegal to nest an object in a routine using '#classname'");
return(TRUE);
}
- sflags[token_value] |= USED_SFLAG;
- make_object(FALSE, NULL, -1, -1, svals[token_value]);
+ symbols[token_value].flags |= USED_SFLAG;
+ make_object(FALSE, NULL, -1, -1, symbols[token_value].value);
return TRUE;
}
return !(parse_given_directive(internal_flag));
}
+/* Check what's coming up after a switch case value. */
static int switch_sign(void)
{
if ((token_type == SEP_TT)&&(token_value == COLON_SEP)) return 1;
return 0;
}
-static assembly_operand spec_stack[32];
-static int spec_type[32];
+/* Info for the current switch statement. Both arrays indexed by spec_sp */
+#define MAX_SPEC_STACK (32)
+static assembly_operand spec_stack[MAX_SPEC_STACK];
+static int spec_type[MAX_SPEC_STACK];
static void compile_alternatives_z(assembly_operand switch_value, int n,
int stack_level, int label, int flag)
sequence_point_follows = FALSE;
do
- { if (spec_sp == 32)
+ { if (spec_sp >= MAX_SPEC_STACK)
{ error("At most 32 values can be given in a single 'switch' case");
panic_mode_error_recovery();
return;
no_locals = 0;
- for (i=0;i<MAX_LOCAL_VARIABLES-1;i++) local_variables.keywords[i] = "";
+ for (i=0;i<MAX_LOCAL_VARIABLES-1;i++)
+ local_variable_names[i].text[0] = 0;
do
{ statements.enabled = TRUE;
break;
}
- for (i=0;i<no_locals;i++)
- if (strcmpcis(token_text, local_variables.keywords[i])==0)
+ for (i=0;i<no_locals;i++) {
+ if (strcmpcis(token_text, local_variable_names[i].text)==0)
error_named("Local variable defined twice:", token_text);
- local_variables.keywords[no_locals++] = token_text;
+ }
+ strcpy(local_variable_names[no_locals++].text, token_text);
} while(TRUE);
+ /* Set up the local variable hash and the local_variables.keywords
+ table. */
construct_local_variable_tables();
if ((trace_fns_setting==3)
|| ((trace_fns_setting==1) && (is_systemfile()==FALSE)))
debug_flag = TRUE;
if ((embedded_flag == FALSE) && (veneer_mode == FALSE) && debug_flag)
- sflags[r_symbol] |= STAR_SFLAG;
+ symbols[r_symbol].flags |= STAR_SFLAG;
packed_address = assemble_routine_header(no_locals, debug_flag,
name, embedded_flag, r_symbol);
do
{ begin_syntax_line(TRUE);
-
+ release_token_texts();
get_next_token();
if (token_type == EOF_TT)
return packed_address;
}
+/* Parse one block of code (a statement or brace-delimited stanza).
+ This is used by the IF, DO, FOR, OBJECTLOOP, SWITCH, and WHILE
+ statements.
+ (Note that this is *not* called by the top-level parse_routine()
+ handler.)
+ The break_label and continue_label arguments are the labels in
+ the calling block to jump to on "break" or "continue". -1 means
+ we can't "break"/"continue" here (because we're not in a loop/switch).
+ If switch_rule is true, we're in a switch block; case labels are
+ accepted.
+*/
extern void parse_code_block(int break_label, int continue_label,
int switch_rule)
-{ int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label = 0,
- unary_minus_flag;
+{ int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label = 0;
+ int unary_minus_flag, saved_entire_flag;
+
+ saved_entire_flag = (execution_never_reaches_here & EXECSTATE_ENTIRE);
+ if (execution_never_reaches_here)
+ execution_never_reaches_here |= EXECSTATE_ENTIRE;
begin_syntax_line(TRUE);
+ release_token_texts();
get_next_token();
if (token_type == SEP_TT && token_value == OPEN_BRACE_SEP)
- { do
+ {
+ /* Parse a braced stanza of statements. */
+ do
{ begin_syntax_line(TRUE);
+ release_token_texts();
get_next_token();
if ((token_type == SEP_TT) && (token_value == HASH_SEP))
if (token_type == SEP_TT && token_value == CLOSE_BRACE_SEP)
{ if (switch_clause_made && (!default_clause_made))
assemble_label_no(switch_label);
- return;
+ break;
}
if (token_type == EOF_TT)
- { ebf_error("'}'", token_text); return; }
+ { ebf_error("'}'", token_text);
+ break;
+ }
if (switch_rule != 0)
{
}
while(TRUE);
}
+ else {
+ if (switch_rule != 0)
+ ebf_error("braced code block after 'switch'", token_text);
+
+ /* Parse a single statement. */
+ parse_statement(break_label, continue_label);
+ }
- if (switch_rule != 0)
- ebf_error("braced code block after 'switch'", token_text);
-
- parse_statement(break_label, continue_label);
- return;
+ if (saved_entire_flag)
+ execution_never_reaches_here |= EXECSTATE_ENTIRE;
+ else
+ execution_never_reaches_here &= ~EXECSTATE_ENTIRE;
}
/* ========================================================================= */
/* end of dynamic memory, gluing together all the required */
/* tables. */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
#endif
}
-static void percentage(char *name, int32 x, int32 total)
-{ printf(" %-20s %2d.%d%%\n",name,x*100/total,(x*1000/total)%10);
+static char percentage_buffer[32];
+
+static char *show_percentage(int32 x, int32 total)
+{
+ if (memory_map_setting < 2) {
+ percentage_buffer[0] = '\0';
+ }
+ else if (x == 0) {
+ sprintf(percentage_buffer, " ( --- )");
+ }
+ else {
+ sprintf(percentage_buffer, " (%.1f %%)", (float)x * 100.0 / (float)total);
+ }
+ return percentage_buffer;
}
static char *version_name(int v)
ASSERT_ZCODE();
total = 64 /* header */
- + 2 + subtract_pointers(low_strings_top, low_strings)
+ + 2 + low_strings_top
/* low strings pool */
+ 6*32; /* abbreviations table */
+ 2*no_actions /* action routines */
+ 2*no_grammar_token_routines; /* general parsing routines */
- total += (subtract_pointers(dictionary_top, dictionary)) /* dictionary */
+ total += (dictionary_top) /* dictionary size */
+ ((module_switch)?30:0); /* module map */
total += static_array_area_size; /* static arrays */
/* No header for us! */
total = 1000; /* bit of a fudge factor */
- total += dynamic_array_area_size; /* arrays and global variables */
+ total += no_globals * 4; /* global variables */
+ total += dynamic_array_area_size; /* arrays */
total += no_objects * OBJECT_BYTE_LENGTH; /* object tables */
total += properties_table_size; /* property tables */
total += 4 + no_actions * 4; /* actions functions table */
total += 4;
- total += subtract_pointers(dictionary_top, dictionary);
+ total += dictionary_top;
while (total % GPAGESIZE)
total++;
p[mark]=0x80; p[mark+1]=0; mark+=2; /* Start the low strings pool
with a useful default string, " " */
- for (i=0; i+low_strings<low_strings_top; mark++, i++) /* Low strings pool */
+ for (i=0; i<low_strings_top; mark++, i++) /* Low strings pool */
p[0x42+i]=low_strings[i];
abbrevs_at = mark;
strings". Write the abbreviations after these. */
k = abbrevs_at+2*MAX_DYNAMIC_STRINGS;
for (i=0; i<no_abbreviations; i++)
- { j=abbrev_values[i];
+ { j=abbreviations[i].value;
p[k++]=j/256;
p[k++]=j%256;
}
/* -------------------- Objects and Properties ------------------------ */
/* The object table must be word-aligned. The Z-machine spec does not
- require this, but the RA__Pr() veneer routine does. See
- http://inform7.com/mantis/view.php?id=1712.
+ require this, but the RA__Pr() veneer routine does.
*/
while ((mark%2) != 0) p[mark++]=0;
p[mark++]=0; p[mark++]=0;
for (i=2; i< ((version_number==3)?32:64); i++)
- { p[mark++]=prop_default_value[i]/256;
- p[mark++]=prop_default_value[i]%256;
+ { p[mark++]=commonprops[i].default_value/256;
+ p[mark++]=commonprops[i].default_value%256;
}
object_tree_at = mark;
class_numbers_offset = mark;
for (i=0; i<no_classes; i++)
- { p[mark++] = class_object_numbers[i]/256;
- p[mark++] = class_object_numbers[i]%256;
+ { p[mark++] = class_info[i].object_number/256;
+ p[mark++] = class_info[i].object_number%256;
if (module_switch)
- { p[mark++] = class_begins_at[i]/256;
- p[mark++] = class_begins_at[i]%256;
+ { p[mark++] = class_info[i].begins_at/256;
+ p[mark++] = class_info[i].begins_at%256;
}
}
p[mark++] = 0;
if (define_INFIX_switch)
{ for (i=0, k=1, l=0; i<no_named_routines; i++)
- { if (sflags[named_routine_symbols[i]] & STAR_SFLAG) l=l+k;
+ { if (symbols[named_routine_symbols[i]].flags & STAR_SFLAG) l=l+k;
k=k*2;
if (k==256) { p[mark++] = l; k=1; l=0; }
}
for (i=0; i<no_adjectives; i++)
{ j = final_dict_order[adjectives[no_adjectives-i-1]]
- *((version_number==3)?7:9)
+ *DICT_ENTRY_BYTE_LENGTH
+ dictionary_offset + 7;
p[mark++]=j/256; p[mark++]=j%256; p[mark++]=0;
p[mark++]=(256-no_adjectives+i);
dictionary[2]=','; /* force words apart */
dictionary[3]='"';
- dictionary[4]=(version_number==3)?7:9; /* Length of each entry */
+ dictionary[4]=DICT_ENTRY_BYTE_LENGTH; /* Length of each entry */
dictionary[5]=(dict_entries/256); /* Number of entries */
dictionary[6]=(dict_entries%256);
for (i=0; i<7; i++) p[mark++] = dictionary[i];
for (i=0; i<dict_entries; i++)
- { k = 7 + i*((version_number==3)?7:9);
- j = mark + final_dict_order[i]*((version_number==3)?7:9);
- for (l = 0; l<((version_number==3)?7:9); l++)
+ { k = 7 + i*DICT_ENTRY_BYTE_LENGTH;
+ j = mark + final_dict_order[i]*DICT_ENTRY_BYTE_LENGTH;
+ for (l = 0; l<DICT_ENTRY_BYTE_LENGTH; l++)
p[j++] = dictionary[k++];
}
- mark += dict_entries * ((version_number==3)?7:9);
+ mark += dict_entries * DICT_ENTRY_BYTE_LENGTH;
/* ------------------------- Module Map ------------------------------- */
size of the Z-machine format. See the memory map below: the start \
of the area marked \"above readable memory\" must be brought down to $FFFE \
or less.");
- memory_map_switch = TRUE;
+ memory_map_setting = 1;
/* Backpatching the grammar tables requires us to trust some of the */
/* addresses we've written into Z-machine memory, but they may have */
/* been truncated to 16 bits, so we can't do it. */
mark = actions_at;
for (i=0; i<no_actions; i++)
- { j=action_byte_offset[i];
+ { j=actions[i].byte_offset;
if (OMIT_UNUSED_ROUTINES)
j = df_stripped_address_for_address(j);
j += code_offset/scale_factor;
switch(topbits)
{ case 1:
value = final_dict_order[value]
- *((version_number==3)?7:9)
+ *DICT_ENTRY_BYTE_LENGTH
+ dictionary_offset + 7;
break;
case 2:
/* ---- From here on, it's all reportage: construction is finished ---- */
- if (statistics_switch)
- { int32 k_long, rate; char *k_str="";
- k_long=(Out_Size/1024);
- if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
- else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
- if (total_bytes_trans == 0) rate = 0;
- else rate=total_bytes_trans*1000/total_chars_trans;
-
- { printf("In:\
-%3d source code files %6d syntactic lines\n\
-%6d textual lines %8ld characters ",
- total_input_files, no_syntax_lines,
- total_source_line_count, (long int) total_chars_read);
- if (character_set_unicode) printf("(UTF-8)\n");
- else if (character_set_setting == 0) printf("(plain ASCII)\n");
- else
- { printf("(ISO 8859-%d %s)\n", character_set_setting,
- name_of_iso_set(character_set_setting));
- }
-
- printf("Allocated:\n\
-%6d symbols (maximum %4d) %8ld bytes of memory\n\
-Out: Version %d \"%s\" %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
- no_symbols, MAX_SYMBOLS,
- (long int) malloced_bytes,
- version_number,
- version_name(version_number),
- output_called,
- release_number, p[18], p[19], p[20], p[21], p[22], p[23],
- (long int) k_long, k_str);
-
- printf("\
-%6d classes (maximum %3d) %6d objects (maximum %3d)\n\
-%6d global vars (maximum 233) %6d variable/array space (maximum %d)\n",
- no_classes, MAX_CLASSES,
- no_objects, ((version_number==3)?255:(MAX_OBJECTS-1)),
- no_globals,
- dynamic_array_area_size, MAX_STATIC_DATA);
-
- printf(
-"%6d verbs (maximum %3d) %6d dictionary entries (maximum %d)\n\
-%6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\
-%6d actions (maximum %3d) %6d attributes (maximum %2d)\n\
-%6d common props (maximum %2d) %6d individual props (unlimited)\n",
- no_Inform_verbs, MAX_VERBS,
- dict_entries, MAX_DICT_ENTRIES,
- no_grammar_lines, grammar_version_number,
- no_grammar_tokens,
- no_actions, MAX_ACTIONS,
- no_attributes, ((version_number==3)?32:48),
- no_properties-2, ((version_number==3)?30:62),
- no_individual_properties - 64);
-
- if (track_unused_routines)
- {
- uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
- printf(
-"%6ld bytes of Z-code %6ld unused bytes %s (%.1f%%)\n",
- (long int) df_total_size_before_stripping, (long int) diff,
- (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
- 100 * (float)diff / (float)df_total_size_before_stripping);
- }
-
- printf(
-"%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\
-%6d abbreviations (maximum %d) %6d routines (unlimited)\n\
-%6ld instructions of Z-code %6d sequence points\n\
-%6ld bytes readable memory used (maximum 65536)\n\
-%6ld bytes used in Z-machine %6ld bytes free in Z-machine\n",
- (long int) total_chars_trans,
- (long int) total_bytes_trans,
- (total_chars_trans>total_bytes_trans)?0:1,
- (long int) rate,
- no_abbreviations, MAX_ABBREVS,
- no_routines,
- (long int) no_instructions, no_sequence_points,
- (long int) Write_Code_At,
- (long int) Out_Size,
- (long int)
- (((long int) (limit*1024L)) - ((long int) Out_Size)));
-
- }
- }
-
- if (offsets_switch)
- {
- { printf(
-"\nOffsets in %s:\n\
-%05lx Synonyms %05lx Defaults %05lx Objects %05lx Properties\n\
-%05lx Variables %05lx Parse table %05lx Actions %05lx Preactions\n\
-%05lx Adjectives %05lx Dictionary %05lx Code %05lx Strings\n",
- output_called,
- (long int) abbrevs_at,
- (long int) prop_defaults_at,
- (long int) object_tree_at,
- (long int) object_props_at,
- (long int) globals_at,
- (long int) grammar_table_at,
- (long int) actions_at,
- (long int) preactions_at,
- (long int) adjectives_offset,
- (long int) dictionary_at,
- (long int) Write_Code_At,
- (long int) Write_Strings_At);
- if (module_switch)
- printf("%05lx Linking data\n",(long int) link_table_at);
- }
- }
-
if (debugfile_switch)
{ begin_writing_debug_sections();
write_debug_section("abbreviations", 64);
end_writing_debug_sections(Out_Size);
}
- if (memory_map_switch)
+ if (memory_map_setting)
{
+ int32 addr;
{
printf("Dynamic +---------------------+ 00000\n");
-printf("memory | header |\n");
+printf("memory | header | %s\n",
+ show_percentage(0x40, Out_Size));
printf(" +---------------------+ 00040\n");
-printf(" | abbreviations |\n");
+printf(" | abbreviations | %s\n",
+ show_percentage(abbrevs_at-0x40, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n", (long int) abbrevs_at);
-printf(" | abbreviations table |\n");
+printf(" | abbreviations table | %s\n",
+ show_percentage(headerext_at-abbrevs_at, Out_Size));
printf(" +---------------------+ %05lx\n", (long int) headerext_at);
-printf(" | header extension |\n");
+addr = (alphabet_modified ? charset_at : (zscii_defn_modified ? unicode_at : prop_defaults_at));
+printf(" | header extension | %s\n",
+ show_percentage(addr-headerext_at, Out_Size));
if (alphabet_modified)
{
printf(" + - - - - - - - - - - + %05lx\n", (long int) charset_at);
-printf(" | alphabets table |\n");
+addr = (zscii_defn_modified ? unicode_at : prop_defaults_at);
+printf(" | alphabets table | %s\n",
+ show_percentage(addr-charset_at, Out_Size));
}
if (zscii_defn_modified)
{
printf(" + - - - - - - - - - - + %05lx\n", (long int) unicode_at);
-printf(" | Unicode table |\n");
+printf(" | Unicode table | %s\n",
+ show_percentage(prop_defaults_at-unicode_at, Out_Size));
}
printf(" +---------------------+ %05lx\n",
(long int) prop_defaults_at);
-printf(" | property defaults |\n");
+printf(" | property defaults | %s\n",
+ show_percentage(object_tree_at-prop_defaults_at, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n", (long int) object_tree_at);
-printf(" | objects |\n");
+printf(" | objects | %s\n",
+ show_percentage(object_props_at-object_tree_at, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
(long int) object_props_at);
printf(" | object short names, |\n");
-printf(" | common prop values |\n");
+printf(" | common prop values | %s\n",
+ show_percentage(class_numbers_offset-object_props_at, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
(long int) class_numbers_offset);
-printf(" | class numbers table |\n");
+printf(" | class numbers table | %s\n",
+ show_percentage(identifier_names_offset-class_numbers_offset, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
(long int) identifier_names_offset);
-printf(" | symbol names table |\n");
+printf(" | symbol names table | %s\n",
+ show_percentage(individuals_offset-identifier_names_offset, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
(long int) individuals_offset);
-printf(" | indiv prop values |\n");
+printf(" | indiv prop values | %s\n",
+ show_percentage(globals_at-individuals_offset, Out_Size));
printf(" +---------------------+ %05lx\n", (long int) globals_at);
-printf(" | global variables |\n");
+printf(" | global variables | %s\n",
+ show_percentage(480, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
((long int) globals_at)+480L);
-printf(" | arrays |\n");
+printf(" | arrays | %s\n",
+ show_percentage(grammar_table_at-(globals_at+480), Out_Size));
printf(" +=====================+ %05lx\n",
(long int) grammar_table_at);
-printf("Readable| grammar table |\n");
+printf("Readable| grammar table | %s\n",
+ show_percentage(actions_at-grammar_table_at, Out_Size));
printf("memory + - - - - - - - - - - + %05lx\n", (long int) actions_at);
-printf(" | actions |\n");
+printf(" | actions | %s\n",
+ show_percentage(preactions_at-actions_at, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n", (long int) preactions_at);
-printf(" | parsing routines |\n");
+printf(" | parsing routines | %s\n",
+ show_percentage(adjectives_offset-preactions_at, Out_Size));
printf(" + - - - - - - - - - - + %05lx\n",
(long int) adjectives_offset);
-printf(" | adjectives |\n");
+printf(" | adjectives | %s\n",
+ show_percentage(dictionary_at-adjectives_offset, Out_Size));
printf(" +---------------------+ %05lx\n", (long int) dictionary_at);
-printf(" | dictionary |\n");
+addr = (module_switch ? map_of_module : (static_array_area_size ? static_arrays_at : Write_Code_At));
+printf(" | dictionary | %s\n",
+ show_percentage(addr-dictionary_at, Out_Size));
if (module_switch)
{
printf(" + - - - - - - - - - - + %05lx\n",
(long int) map_of_module);
-printf(" | map of module addrs |\n");
+addr = (static_array_area_size ? static_arrays_at : Write_Code_At);
+printf(" | map of module addrs | %s\n",
+ show_percentage(addr-map_of_module, Out_Size));
}
if (static_array_area_size)
{
printf(" +---------------------+ %05lx\n", (long int) static_arrays_at);
-printf(" | static arrays |\n");
+printf(" | static arrays | %s\n",
+ show_percentage(Write_Code_At-static_arrays_at, Out_Size));
}
printf(" +=====================+ %05lx\n", (long int) Write_Code_At);
-printf("Above | Z-code |\n");
+printf("Above | Z-code | %s\n",
+ show_percentage(Write_Strings_At-Write_Code_At, Out_Size));
printf("readable+---------------------+ %05lx\n",
(long int) Write_Strings_At);
-printf("memory | strings |\n");
+addr = (module_switch ? link_table_at : Out_Size);
+printf("memory | strings | %s\n",
+ show_percentage(addr-Write_Strings_At, Out_Size));
if (module_switch)
{
printf(" +=====================+ %05lx\n", (long int) link_table_at);
-printf(" | module linking data |\n");
+printf(" | module linking data | %s\n",
+ show_percentage(Out_Size-link_table_at, Out_Size));
}
printf(" +---------------------+ %05lx\n", (long int) Out_Size);
}
}
- if (percentages_switch)
- { printf("Approximate percentage breakdown of %s:\n",
- output_called);
- percentage("Z-code", code_length,Out_Size);
- if (module_switch)
- percentage("Linking data", link_data_size,Out_Size);
- percentage("Static strings", strings_length,Out_Size);
- percentage("Dictionary", Write_Code_At-dictionary_at,Out_Size);
- percentage("Objects", globals_at-prop_defaults_at,Out_Size);
- percentage("Globals", grammar_table_at-globals_at,Out_Size);
- percentage("Parsing tables", dictionary_at-grammar_table_at,Out_Size);
- percentage("Header and synonyms", prop_defaults_at,Out_Size);
- percentage("Total of save area", grammar_table_at,Out_Size);
- percentage("Total of text", total_bytes_trans,Out_Size);
- }
- if (frequencies_switch)
- {
- { printf("How frequently abbreviations were used, and roughly\n");
- printf("how many bytes they saved: ('_' denotes spaces)\n");
- for (i=0; i<no_abbreviations; i++)
- { char abbrev_string[MAX_ABBREV_LENGTH];
- strcpy(abbrev_string,
- (char *)abbreviations_at+i*MAX_ABBREV_LENGTH);
- for (j=0; abbrev_string[j]!=0; j++)
- if (abbrev_string[j]==' ') abbrev_string[j]='_';
- printf("%10s %5d/%5d ",abbrev_string,abbrev_freqs[i],
- 2*((abbrev_freqs[i]-1)*abbrev_quality[i])/3);
- if ((i%3)==2) printf("\n");
- }
- if ((i%3)!=0) printf("\n");
- if (no_abbreviations==0) printf("None were declared.\n");
- }
- }
}
static void construct_storyfile_g(void)
{ uchar *p;
- int32 i, j, k, l, mark, strings_length, limit;
+ int32 i, j, k, l, mark, strings_length;
int32 globals_at, dictionary_at, actions_at, preactions_at,
abbrevs_at, prop_defaults_at, object_tree_at, object_props_at,
- grammar_table_at, charset_at, headerext_at,
- unicode_at, arrays_at, static_arrays_at;
+ grammar_table_at, arrays_at, static_arrays_at;
int32 threespaces, code_length;
- char *output_called = (module_switch)?"module":"story file";
ASSERT_GLULX();
}
arrays_at = mark;
- for (i=MAX_GLOBAL_VARIABLES*4; i<dynamic_array_area_size; i++)
+ for (i=0; i<dynamic_array_area_size; i++)
p[mark++] = dynamic_array_area[i];
/* -------------------------- Dynamic Strings -------------------------- */
mark += 4;
}
- /* ---------------- Various Things I'm Not Sure About ------------------ */
- /* Actually, none of these are relevant to Glulx. */
- headerext_at = mark;
- charset_at = 0;
- if (alphabet_modified)
- charset_at = mark;
- unicode_at = 0;
- if (zscii_defn_modified)
- unicode_at = mark;
-
/* -------------------- Objects and Properties ------------------------ */
object_tree_at = mark;
prop_defaults_at = mark;
for (i=0; i<no_properties; i++) {
- k = prop_default_value[i];
+ k = commonprops[i].default_value;
WriteInt32(p+mark, k);
mark += 4;
}
class_numbers_offset = mark;
for (i=0; i<no_classes; i++) {
j = Write_RAM_At + object_tree_at +
- (OBJECT_BYTE_LENGTH*(class_object_numbers[i]-1));
+ (OBJECT_BYTE_LENGTH*(class_info[i].object_number-1));
WriteInt32(p+mark, j);
mark += 4;
}
RAM_Size = mark;
Out_Size = Write_RAM_At + RAM_Size;
- limit=1024*1024;
/* --------------------------- Offsets -------------------------------- */
mark = actions_at + 4;
for (i=0; i<no_actions; i++) {
- j = action_byte_offset[i];
+ j = actions[i].byte_offset;
if (OMIT_UNUSED_ROUTINES)
j = df_stripped_address_for_address(j);
j += code_offset;
/* ---- From here on, it's all reportage: construction is finished ---- */
- if (statistics_switch)
- { int32 k_long, rate; char *k_str="";
- k_long=(Out_Size/1024);
- if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
- else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
- if (strings_length == 0) rate = 0;
- else rate=strings_length*1000/total_chars_trans;
-
- { printf("In:\
-%3d source code files %6d syntactic lines\n\
-%6d textual lines %8ld characters ",
- total_input_files, no_syntax_lines,
- total_source_line_count, (long int) total_chars_read);
- if (character_set_unicode) printf("(UTF-8)\n");
- else if (character_set_setting == 0) printf("(plain ASCII)\n");
- else
- { printf("(ISO 8859-%d %s)\n", character_set_setting,
- name_of_iso_set(character_set_setting));
- }
-
- {char serialnum[8];
- write_serial_number(serialnum);
- printf("Allocated:\n\
-%6d symbols (maximum %4d) %8ld bytes of memory\n\
-Out: %s %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
- no_symbols, MAX_SYMBOLS,
- (long int) malloced_bytes,
- version_name(version_number),
- output_called,
- release_number,
- serialnum[0], serialnum[1], serialnum[2],
- serialnum[3], serialnum[4], serialnum[5],
- (long int) k_long, k_str);
- }
-
- printf("\
-%6d classes (maximum %3d) %6d objects (maximum %3d)\n\
-%6d global vars (maximum %3d) %6d variable/array space (maximum %d)\n",
- no_classes, MAX_CLASSES,
- no_objects, MAX_OBJECTS,
- no_globals, MAX_GLOBAL_VARIABLES,
- dynamic_array_area_size, MAX_STATIC_DATA);
-
- printf(
-"%6d verbs (maximum %3d) %6d dictionary entries (maximum %d)\n\
-%6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\
-%6d actions (maximum %3d) %6d attributes (maximum %2d)\n\
-%6d common props (maximum %3d) %6d individual props (unlimited)\n",
- no_Inform_verbs, MAX_VERBS,
- dict_entries, MAX_DICT_ENTRIES,
- no_grammar_lines, grammar_version_number,
- no_grammar_tokens,
- no_actions, MAX_ACTIONS,
- no_attributes, NUM_ATTR_BYTES*8,
- no_properties, INDIV_PROP_START,
- no_individual_properties - INDIV_PROP_START);
-
- if (track_unused_routines)
- {
- uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
- printf(
-"%6ld bytes of code %6ld unused bytes %s (%.1f%%)\n",
- (long int) df_total_size_before_stripping, (long int) diff,
- (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
- 100 * (float)diff / (float)df_total_size_before_stripping);
- }
-
- printf(
-"%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\
-%6d abbreviations (maximum %d) %6d routines (unlimited)\n\
-%6ld instructions of code %6d sequence points\n\
-%6ld bytes writable memory used %6ld bytes read-only memory used\n\
-%6ld bytes used in machine %10ld bytes free in machine\n",
- (long int) total_chars_trans,
- (long int) strings_length,
- (total_chars_trans>strings_length)?0:1,
- (long int) rate,
- no_abbreviations, MAX_ABBREVS,
- no_routines,
- (long int) no_instructions, no_sequence_points,
- (long int) (Out_Size - Write_RAM_At),
- (long int) Write_RAM_At,
- (long int) Out_Size,
- (long int)
- (((long int) (limit*1024L)) - ((long int) Out_Size)));
-
- }
- }
-
- if (offsets_switch)
- {
- { printf(
-"\nOffsets in %s:\n\
-%05lx Synonyms %05lx Defaults %05lx Objects %05lx Properties\n\
-%05lx Variables %05lx Parse table %05lx Actions %05lx Preactions\n\
-%05lx Adjectives %05lx Dictionary %05lx Code %05lx Strings\n",
- output_called,
- (long int) abbrevs_at,
- (long int) prop_defaults_at,
- (long int) object_tree_at,
- (long int) object_props_at,
- (long int) globals_at,
- (long int) grammar_table_at,
- (long int) actions_at,
- (long int) preactions_at,
- (long int) adjectives_offset,
- (long int) dictionary_at,
- (long int) Write_Code_At,
- (long int) Write_Strings_At);
- }
- }
-
if (debugfile_switch)
{ begin_writing_debug_sections();
write_debug_section("memory layout id", GLULX_HEADER_SIZE);
end_writing_debug_sections(Out_Size + MEMORY_MAP_EXTENSION);
}
- if (memory_map_switch)
+ if (memory_map_setting)
{
-
+ int32 addr;
{
printf(" +---------------------+ 000000\n");
-printf("Read- | header |\n");
+printf("Read- | header | %s\n",
+ show_percentage(GLULX_HEADER_SIZE, Out_Size));
printf(" only +=====================+ %06lx\n", (long int) GLULX_HEADER_SIZE);
-printf("memory | memory layout id |\n");
+printf("memory | memory layout id | %s\n",
+ show_percentage(Write_Code_At-GLULX_HEADER_SIZE, Out_Size));
printf(" +---------------------+ %06lx\n", (long int) Write_Code_At);
-printf(" | code |\n");
+printf(" | code | %s\n",
+ show_percentage(Write_Strings_At-Write_Code_At, Out_Size));
printf(" +---------------------+ %06lx\n",
(long int) Write_Strings_At);
-printf(" | string decode table |\n");
+printf(" | string decode table | %s\n",
+ show_percentage(compression_table_size, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) Write_Strings_At + compression_table_size);
-printf(" | strings |\n");
+addr = (static_array_area_size ? static_arrays_at : Write_RAM_At+globals_at);
+printf(" | strings | %s\n",
+ show_percentage(addr-(Write_Strings_At + compression_table_size), Out_Size));
if (static_array_area_size)
{
printf(" +---------------------+ %06lx\n",
(long int) (static_arrays_at));
-printf(" | static arrays |\n");
+printf(" | static arrays | %s\n",
+ show_percentage(Write_RAM_At+globals_at-static_arrays_at, Out_Size));
}
printf(" +=====================+ %06lx\n",
(long int) (Write_RAM_At+globals_at));
-printf("Dynamic | global variables |\n");
+printf("Dynamic | global variables | %s\n",
+ show_percentage(arrays_at-globals_at, Out_Size));
printf("memory + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+arrays_at));
-printf(" | arrays |\n");
+printf(" | arrays | %s\n",
+ show_percentage(abbrevs_at-arrays_at, Out_Size));
printf(" +---------------------+ %06lx\n",
(long int) (Write_RAM_At+abbrevs_at));
-printf(" | printing variables |\n");
- if (alphabet_modified)
- {
-printf(" + - - - - - - - - - - + %06lx\n",
- (long int) (Write_RAM_At+charset_at));
-printf(" | alphabets table |\n");
- }
- if (zscii_defn_modified)
- {
-printf(" + - - - - - - - - - - + %06lx\n",
- (long int) (Write_RAM_At+unicode_at));
-printf(" | Unicode table |\n");
- }
+printf(" | printing variables | %s\n",
+ show_percentage(object_tree_at-abbrevs_at, Out_Size));
printf(" +---------------------+ %06lx\n",
(long int) (Write_RAM_At+object_tree_at));
-printf(" | objects |\n");
+printf(" | objects | %s\n",
+ show_percentage(object_props_at-object_tree_at, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+object_props_at));
-printf(" | property values |\n");
+printf(" | property values | %s\n",
+ show_percentage(prop_defaults_at-object_props_at, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+prop_defaults_at));
-printf(" | property defaults |\n");
+printf(" | property defaults | %s\n",
+ show_percentage(class_numbers_offset-prop_defaults_at, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+class_numbers_offset));
-printf(" | class numbers table |\n");
+printf(" | class numbers table | %s\n",
+ show_percentage(identifier_names_offset-class_numbers_offset, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+identifier_names_offset));
-printf(" | id names table |\n");
+printf(" | id names table | %s\n",
+ show_percentage(grammar_table_at-identifier_names_offset, Out_Size));
printf(" +---------------------+ %06lx\n",
(long int) (Write_RAM_At+grammar_table_at));
-printf(" | grammar table |\n");
+printf(" | grammar table | %s\n",
+ show_percentage(actions_at-grammar_table_at, Out_Size));
printf(" + - - - - - - - - - - + %06lx\n",
(long int) (Write_RAM_At+actions_at));
-printf(" | actions |\n");
+printf(" | actions | %s\n",
+ show_percentage(dictionary_offset-(Write_RAM_At+actions_at), Out_Size));
printf(" +---------------------+ %06lx\n",
(long int) dictionary_offset);
-printf(" | dictionary |\n");
+printf(" | dictionary | %s\n",
+ show_percentage(Out_Size-dictionary_offset, Out_Size));
if (MEMORY_MAP_EXTENSION == 0)
{
printf(" +---------------------+ %06lx\n", (long int) Out_Size);
else
{
printf(" +=====================+ %06lx\n", (long int) Out_Size);
-printf("Runtime | (empty) |\n");
+printf("Runtime | (empty) |\n"); /* no percentage */
printf(" extn +---------------------+ %06lx\n", (long int) Out_Size+MEMORY_MAP_EXTENSION);
}
}
}
+}
+static void display_frequencies()
+{
+ int i, j;
+
+ printf("How frequently abbreviations were used, and roughly\n");
+ printf("how many bytes they saved: ('_' denotes spaces)\n");
+
+ for (i=0; i<no_abbreviations; i++) {
+ int32 saving;
+ if (!glulx_mode)
+ saving = 2*((abbreviations[i].freq-1)*abbreviations[i].quality)/3;
+ else
+ saving = (abbreviations[i].freq-1)*abbreviations[i].quality;
+
+ char abbrev_string[MAX_ABBREV_LENGTH];
+ strcpy(abbrev_string,
+ (char *)abbreviations_at+i*MAX_ABBREV_LENGTH);
+ for (j=0; abbrev_string[j]!=0; j++)
+ if (abbrev_string[j]==' ') abbrev_string[j]='_';
+
+ printf("%10s %5d/%5d ",abbrev_string,abbreviations[i].freq, saving);
+
+ if ((i%3)==2) printf("\n");
+ }
+ if ((i%3)!=0) printf("\n");
+
+ if (no_abbreviations==0) printf("None were declared.\n");
+}
- if (percentages_switch)
- { printf("Approximate percentage breakdown of %s:\n",
- output_called);
- percentage("Code", code_length,Out_Size);
- if (module_switch)
- percentage("Linking data", link_data_size,Out_Size);
- percentage("Static strings", strings_length,Out_Size);
- percentage("Dictionary", Write_Code_At-dictionary_at,Out_Size);
- percentage("Objects", globals_at-prop_defaults_at,Out_Size);
- percentage("Globals", grammar_table_at-globals_at,Out_Size);
- percentage("Parsing tables", dictionary_at-grammar_table_at,Out_Size);
- percentage("Header and synonyms", prop_defaults_at,Out_Size);
- percentage("Total of save area", grammar_table_at,Out_Size);
- percentage("Total of text", strings_length,Out_Size);
- }
- if (frequencies_switch)
- {
- { printf("How frequently abbreviations were used, and roughly\n");
- printf("how many bytes they saved: ('_' denotes spaces)\n");
- for (i=0; i<no_abbreviations; i++)
- { char abbrev_string[MAX_ABBREV_LENGTH];
- strcpy(abbrev_string,
- (char *)abbreviations_at+i*MAX_ABBREV_LENGTH);
- for (j=0; abbrev_string[j]!=0; j++)
- if (abbrev_string[j]==' ') abbrev_string[j]='_';
- printf("%10s %5d/%5d ",abbrev_string,abbrev_freqs[i],
- 2*((abbrev_freqs[i]-1)*abbrev_quality[i])/3);
- if ((i%3)==2) printf("\n");
+static void display_statistics_z()
+{
+ int32 k_long, rate;
+ char *k_str = "";
+ uchar *p = (uchar *) zmachine_paged_memory;
+ char *output_called = (module_switch)?"module":"story file";
+ int limit = 0;
+
+ /* Yeah, we're repeating this calculation from construct_storyfile_z() */
+ switch(version_number)
+ { case 3: limit = 128; break;
+ case 4:
+ case 5: limit = 256; break;
+ case 6:
+ case 7:
+ case 8: limit = 512; break;
+ }
+
+ k_long=(Out_Size/1024);
+ if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
+ else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
+ if (total_bytes_trans == 0) rate = 0;
+ else rate=total_bytes_trans*1000/total_chars_trans;
+
+ { printf("In:\
+%3d source code files %6d syntactic lines\n\
+%6d textual lines %8ld characters ",
+ total_input_files, no_syntax_lines,
+ total_source_line_count, (long int) total_chars_read);
+ if (character_set_unicode) printf("(UTF-8)\n");
+ else if (character_set_setting == 0) printf("(plain ASCII)\n");
+ else
+ { printf("(ISO 8859-%d %s)\n", character_set_setting,
+ name_of_iso_set(character_set_setting));
}
- if ((i%3)!=0) printf("\n");
- if (no_abbreviations==0) printf("None were declared.\n");
- }
+
+ printf("Allocated:\n\
+%6d symbols %8ld bytes of memory\n\
+Out: Version %d \"%s\" %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
+ no_symbols,
+ (long int) malloced_bytes,
+ version_number,
+ version_name(version_number),
+ output_called,
+ release_number, p[18], p[19], p[20], p[21], p[22], p[23],
+ (long int) k_long, k_str);
+
+ printf("\
+%6d classes %6d objects\n\
+%6d global vars (maximum 233) %6d variable/array space\n",
+ no_classes,
+ no_objects,
+ no_globals,
+ dynamic_array_area_size);
+
+ printf(
+ "%6d verbs %6d dictionary entries\n\
+%6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\
+%6d actions %6d attributes (maximum %2d)\n\
+%6d common props (maximum %2d) %6d individual props (unlimited)\n",
+ no_Inform_verbs,
+ dict_entries,
+ no_grammar_lines, grammar_version_number,
+ no_grammar_tokens,
+ no_actions,
+ no_attributes, ((version_number==3)?32:48),
+ no_properties-3, ((version_number==3)?29:61),
+ no_individual_properties - 64);
+
+ if (track_unused_routines)
+ {
+ uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
+ printf(
+ "%6ld bytes of Z-code %6ld unused bytes %s (%.1f%%)\n",
+ (long int) df_total_size_before_stripping, (long int) diff,
+ (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
+ 100 * (float)diff / (float)df_total_size_before_stripping);
+ }
+
+ printf(
+ "%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\
+%6d abbreviations (maximum %d) %6d routines (unlimited)\n\
+%6ld instructions of Z-code %6d sequence points\n\
+%6ld bytes readable memory used (maximum 65536)\n\
+%6ld bytes used in Z-machine %6ld bytes free in Z-machine\n",
+ (long int) total_chars_trans,
+ (long int) total_bytes_trans,
+ (total_chars_trans>total_bytes_trans)?0:1,
+ (long int) rate,
+ no_abbreviations, MAX_ABBREVS,
+ no_routines,
+ (long int) no_instructions, no_sequence_points,
+ (long int) Write_Code_At,
+ (long int) Out_Size,
+ (long int)
+ (((long int) (limit*1024L)) - ((long int) Out_Size)));
+
+ }
+}
+
+static void display_statistics_g()
+{
+ int32 k_long, rate;
+ char *k_str = "";
+ int32 limit = 1024*1024;
+ int32 strings_length = compression_table_size + compression_string_size;
+ char *output_called = (module_switch)?"module":"story file";
+
+ k_long=(Out_Size/1024);
+ if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
+ else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
+
+ if (strings_length == 0) rate = 0;
+ else rate=strings_length*1000/total_chars_trans;
+
+ { printf("In:\
+%3d source code files %6d syntactic lines\n\
+%6d textual lines %8ld characters ",
+ total_input_files, no_syntax_lines,
+ total_source_line_count, (long int) total_chars_read);
+ if (character_set_unicode) printf("(UTF-8)\n");
+ else if (character_set_setting == 0) printf("(plain ASCII)\n");
+ else
+ { printf("(ISO 8859-%d %s)\n", character_set_setting,
+ name_of_iso_set(character_set_setting));
+ }
+
+ {char serialnum[8];
+ write_serial_number(serialnum);
+ printf("Allocated:\n\
+%6d symbols %8ld bytes of memory\n\
+Out: %s %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
+ no_symbols,
+ (long int) malloced_bytes,
+ version_name(version_number),
+ output_called,
+ release_number,
+ serialnum[0], serialnum[1], serialnum[2],
+ serialnum[3], serialnum[4], serialnum[5],
+ (long int) k_long, k_str);
+ }
+
+ printf("\
+%6d classes %6d objects\n\
+%6d global vars %6d variable/array space\n",
+ no_classes,
+ no_objects,
+ no_globals,
+ dynamic_array_area_size);
+
+ printf(
+ "%6d verbs %6d dictionary entries\n\
+%6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\
+%6d actions %6d attributes (maximum %2d)\n\
+%6d common props (maximum %3d) %6d individual props (unlimited)\n",
+ no_Inform_verbs,
+ dict_entries,
+ no_grammar_lines, grammar_version_number,
+ no_grammar_tokens,
+ no_actions,
+ no_attributes, NUM_ATTR_BYTES*8,
+ no_properties-3, INDIV_PROP_START-3,
+ no_individual_properties - INDIV_PROP_START);
+
+ if (track_unused_routines)
+ {
+ uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
+ printf(
+ "%6ld bytes of code %6ld unused bytes %s (%.1f%%)\n",
+ (long int) df_total_size_before_stripping, (long int) diff,
+ (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
+ 100 * (float)diff / (float)df_total_size_before_stripping);
+ }
+
+ printf(
+ "%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\
+%6d abbreviations (maximum %d) %6d routines (unlimited)\n\
+%6ld instructions of code %6d sequence points\n\
+%6ld bytes writable memory used %6ld bytes read-only memory used\n\
+%6ld bytes used in machine %10ld bytes free in machine\n",
+ (long int) total_chars_trans,
+ (long int) strings_length,
+ (total_chars_trans>strings_length)?0:1,
+ (long int) rate,
+ no_abbreviations, MAX_ABBREVS,
+ no_routines,
+ (long int) no_instructions, no_sequence_points,
+ (long int) (Out_Size - Write_RAM_At),
+ (long int) Write_RAM_At,
+ (long int) Out_Size,
+ (long int)
+ (((long int) (limit*1024L)) - ((long int) Out_Size)));
+
}
}
+
extern void construct_storyfile(void)
{
- if (!glulx_mode)
- construct_storyfile_z();
- else
- construct_storyfile_g();
+ if (!glulx_mode)
+ construct_storyfile_z();
+ else
+ construct_storyfile_g();
+
+ /* Display all the trace/stats info that came out of compilation.
+
+ (Except for the memory map, which uses a bunch of local variables
+ from construct_storyfile_z/g(), so it's easier to do that inside
+ that function.)
+ */
+
+ if (frequencies_setting)
+ display_frequencies();
+
+ if (list_symbols_setting)
+ list_symbols(list_symbols_setting);
+
+ if (list_dict_setting)
+ show_dictionary(list_dict_setting);
+
+ if (list_verbs_setting)
+ list_verb_table();
+
+ if (list_objects_setting)
+ list_object_tree();
+
+ if (statistics_switch) {
+ if (!glulx_mode)
+ display_statistics_z();
+ else
+ display_statistics_g();
+ }
}
/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/* "text" : Text translation, the abbreviations optimiser, the dictionary */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
-uchar *low_strings, *low_strings_top; /* Start and next free byte in the low
- strings pool */
+uchar *low_strings; /* Allocated to low_strings_top */
+int32 low_strings_top;
+static memory_list low_strings_memlist;
int32 static_strings_extent; /* Number of bytes of static strings
made so far */
-memory_block static_strings_area; /* Used if (!temporary_files_switch) to
- hold the static strings area so far */
+uchar *static_strings_area; /* Used to hold the static strings
+ area so far
+ Allocated to static_strings_extent */
+memory_list static_strings_area_memlist;
-static uchar *strings_holding_area; /* Area holding translated strings
- until they are moved into either
- a temporary file, or the
- static_strings_area below */
-
-char *all_text, *all_text_top; /* Start and next byte free in (large)
- text buffer holding the entire text
+static char *all_text; /* Text buffer holding the entire text
of the game, when it is being
- recorded */
+ recorded
+ (Allocated to all_text_top) */
+static memory_list all_text_memlist;
+static int32 all_text_top;
+
int abbrevs_lookup_table_made, /* The abbreviations lookup table is
constructed when the first non-
abbreviation string is translated:
with ASCII character n, or -1
if none of the abbreviations do */
int no_abbreviations; /* No of abbreviations defined so far */
-uchar *abbreviations_at; /* Memory to hold the text of any
- abbreviation strings declared */
/* ------------------------------------------------------------------------- */
/* Glulx string compression storage */
/* ------------------------------------------------------------------------- */
int no_unicode_chars; /* Number of distinct Unicode chars
used. (Beyond 0xFF.) */
-static int MAX_CHARACTER_SET; /* Number of possible entities */
huffentity_t *huff_entities; /* The list of entities (characters,
abbreviations, @.. escapes, and
the terminator) */
int32 *compressed_offsets; /* The beginning of every string in
the game, relative to the beginning
of the Huffman table. (So entry 0
- is equal to compression_table_size)*/
+ is equal to compression_table_size).
+ Allocated to no_strings at
+ compress_game_text() time. */
+static memory_list compressed_offsets_memlist;
+
+unicode_usage_t *unicode_usage_entries; /* Allocated to no_unicode_chars */
+static memory_list unicode_usage_entries_memlist;
#define UNICODE_HASH_BUCKETS (64)
-unicode_usage_t *unicode_usage_entries;
-static unicode_usage_t *unicode_usage_hash[UNICODE_HASH_BUCKETS];
+static int unicode_usage_hash[UNICODE_HASH_BUCKETS];
static int unicode_entity_index(int32 unicode);
/* Abbreviation arrays */
/* ------------------------------------------------------------------------- */
-int *abbrev_values;
-int *abbrev_quality;
-int *abbrev_freqs;
+abbreviation *abbreviations; /* Allocated up to no_abbreviations */
+static memory_list abbreviations_memlist;
+
+/* Memory to hold the text of any abbreviation strings declared. This is
+ counted in units of MAX_ABBREV_LENGTH bytes. (An abbreviation must fit
+ in that many bytes, null included.) */
+uchar *abbreviations_at; /* Allocated up to no_abbreviations */
+static memory_list abbreviations_at_memlist;
+
+static int *abbreviations_optimal_parse_schedule;
+static memory_list abbreviations_optimal_parse_schedule_memlist;
+
+static int *abbreviations_optimal_parse_scores;
+static memory_list abbreviations_optimal_parse_scores_memlist;
/* ------------------------------------------------------------------------- */
zchars_trans_in_last_string; /* Number of Z-chars in last string:
needed only for abbrev efficiency
calculation in "directs.c" */
-static int32 total_zchars_trans, /* Number of Z-chars of text out
+static int32 total_zchars_trans; /* Number of Z-chars of text out
(only used to calculate the above) */
- no_chars_transcribed; /* Number of ASCII chars written to
- the text transcription area (used
- for the -r and -u switches) */
static int zchars_out_buffer[3], /* During text translation, a buffer of
3 Z-chars at a time: when it's full
these are written as a 2-byte word */
zob_index; /* Index (0 to 2) into it */
-static unsigned char *text_out_pc; /* The "program counter" during text
- translation: the next address to
+uchar *translated_text; /* Area holding translated strings
+ until they are moved into the
+ static_strings_area below */
+static memory_list translated_text_memlist;
+
+static int32 text_out_pos; /* The "program counter" during text
+ translation: the next position to
write Z-coded text output to */
-static unsigned char *text_out_limit; /* The upper limit of text_out_pc
- during text translation */
+static int32 text_out_limit; /* The upper limit of text_out_pos
+ during text translation (or -1
+ for no limit) */
static int text_out_overflow; /* During text translation, becomes
- true if text_out_pc tries to pass
+ true if text_out_pos tries to pass
text_out_limit */
/* ------------------------------------------------------------------------- */
p2=(char *)abbreviations_at+k*MAX_ABBREV_LENGTH;
if (strcmp(p1,p2)<0)
{ strcpy(p,p1); strcpy(p1,p2); strcpy(p2,p);
- l=abbrev_values[j]; abbrev_values[j]=abbrev_values[k];
- abbrev_values[k]=l;
- l=abbrev_quality[j]; abbrev_quality[j]=abbrev_quality[k];
- abbrev_quality[k]=l;
+ l=abbreviations[j].value; abbreviations[j].value=abbreviations[k].value;
+ abbreviations[k].value=l;
+ l=abbreviations[j].quality; abbreviations[j].quality=abbreviations[k].quality;
+ abbreviations[k].quality=l;
bubble_sort = TRUE;
}
}
for (j=no_abbreviations-1; j>=0; j--)
{ p1=(char *)abbreviations_at+j*MAX_ABBREV_LENGTH;
abbrevs_lookup[(uchar)p1[0]]=j;
- abbrev_freqs[j]=0;
+ abbreviations[j].freq=0;
}
abbrevs_lookup_table_made = TRUE;
}
if (!glulx_mode) {
for (k=0; p[k]!=0; k++) text[i+k]=1;
}
- abbrev_freqs[j]++;
+ abbreviations[j].freq++;
return(j);
NotMatched: ;
}
extern void make_abbreviation(char *text)
{
+ ensure_memory_list_available(&abbreviations_memlist, no_abbreviations+1);
+ ensure_memory_list_available(&abbreviations_at_memlist, no_abbreviations+1);
+
strcpy((char *)abbreviations_at
+ no_abbreviations*MAX_ABBREV_LENGTH, text);
- abbrev_values[no_abbreviations] = compile_string(text, STRCTX_ABBREV);
+ abbreviations[no_abbreviations].value = compile_string(text, STRCTX_ABBREV);
+ abbreviations[no_abbreviations].freq = 0;
/* The quality is the number of Z-chars saved by using this */
/* abbreviation: note that it takes 2 Z-chars to print it. */
- abbrev_quality[no_abbreviations++] = zchars_trans_in_last_string - 2;
+ abbreviations[no_abbreviations].quality = zchars_trans_in_last_string - 2;
+
+ if (abbreviations[no_abbreviations].quality <= 0) {
+ warning_named("Abbreviation does not save any characters:", text);
+ }
+
+ no_abbreviations++;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
extern int32 compile_string(char *b, int strctx)
-{ int i, j; uchar *c;
-
+{ int32 i, j, k;
+ uchar *c;
+ int in_low_memory;
+
+ if (execution_never_reaches_here) {
+ /* No need to put strings into gametext.txt or the static/low
+ strings areas. */
+ if (strctx == STRCTX_GAME || strctx == STRCTX_GAMEOPC || strctx == STRCTX_LOWSTRING || strctx == STRCTX_INFIX) {
+ /* VENEER and VENEEROPC are only used at the translate_text level,
+ so we don't have to catch them here. */
+ return 0;
+ }
+ }
+
/* In Z-code, abbreviations go in the low memory pool (0x100). So
do strings explicitly defined with the Lowstring directive.
(In Glulx, the in_low_memory flag is ignored.) */
- int in_low_memory = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
+ in_low_memory = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
if (!glulx_mode && in_low_memory)
- { j=subtract_pointers(low_strings_top,low_strings);
- low_strings_top=translate_text(low_strings_top, low_strings+MAX_LOW_STRINGS, b, strctx);
- if (!low_strings_top)
- memoryerror("MAX_LOW_STRINGS", MAX_LOW_STRINGS);
+ {
+ k = translate_text(-1, b, strctx);
+ if (k<0) {
+ error("text translation failed");
+ k = 0;
+ }
+ ensure_memory_list_available(&low_strings_memlist, low_strings_top+k);
+ memcpy(low_strings+low_strings_top, translated_text, k);
+ j = low_strings_top;
+ low_strings_top += k;
return(0x21+(j/2));
}
if (glulx_mode && done_compression)
compiler_error("Tried to add a string after compression was done.");
- c = translate_text(strings_holding_area, strings_holding_area+MAX_STATIC_STRINGS, b, strctx);
- if (!c)
- memoryerror("MAX_STATIC_STRINGS",MAX_STATIC_STRINGS);
-
- i = subtract_pointers(c, strings_holding_area);
+ i = translate_text(-1, b, strctx);
+ if (i < 0) {
+ error("text translation failed");
+ i = 0;
+ }
/* Insert null bytes as needed to ensure that the next static string */
/* also occurs at an address expressible as a packed address */
textalign = scale_factor;
while ((i%textalign)!=0)
{
- if (i+2 > MAX_STATIC_STRINGS)
- memoryerror("MAX_STATIC_STRINGS",MAX_STATIC_STRINGS);
- i+=2; *c++ = 0; *c++ = 0;
+ ensure_memory_list_available(&translated_text_memlist, i+2);
+ translated_text[i++] = 0;
+ translated_text[i++] = 0;
}
}
j = static_strings_extent;
- if (temporary_files_switch)
- for (c=strings_holding_area; c<strings_holding_area+i;
- c++, static_strings_extent++)
- fputc(*c,Temp1_fp);
- else
- for (c=strings_holding_area; c<strings_holding_area+i;
- c++, static_strings_extent++)
- write_byte_to_memory_block(&static_strings_area,
- static_strings_extent, *c);
+ ensure_memory_list_available(&static_strings_area_memlist, static_strings_extent+i);
+ for (c=translated_text; c<translated_text+i;
+ c++, static_strings_extent++)
+ static_strings_area[static_strings_extent] = *c;
if (!glulx_mode) {
return(j/scale_factor);
zob_index=0;
j= zchars_out_buffer[0]*0x0400 + zchars_out_buffer[1]*0x0020
+ zchars_out_buffer[2];
- if (text_out_pc+2 > text_out_limit) {
- text_out_overflow = TRUE;
- return;
+
+ if (text_out_limit >= 0) {
+ if (text_out_pos+2 > text_out_limit) {
+ text_out_overflow = TRUE;
+ return;
+ }
}
- text_out_pc[0] = j/256; text_out_pc[1] = j%256; text_out_pc+=2;
+ else {
+ ensure_memory_list_available(&translated_text_memlist, text_out_pos+2);
+ }
+
+ translated_text[text_out_pos++] = j/256; translated_text[text_out_pos++] = j%256;
total_bytes_trans+=2;
}
/* ------------------------------------------------------------------------- */
static void end_z_chars(void)
-{ unsigned char *p;
+{
zchars_trans_in_last_string=total_zchars_trans-zchars_trans_in_last_string;
while (zob_index!=0) write_z_char_z(5);
- p=(unsigned char *) text_out_pc;
- *(p-2)= *(p-2)+128;
+ if (text_out_pos < 2) {
+ /* Something went wrong. */
+ text_out_overflow = TRUE;
+ return;
+ }
+ translated_text[text_out_pos-2] += 128;
}
/* Glulx handles this much more simply -- compression is done elsewhere. */
static void write_z_char_g(int i)
{
- ASSERT_GLULX();
- if (text_out_pc+1 > text_out_limit) {
- text_out_overflow = TRUE;
- return;
- }
- total_zchars_trans++;
- text_out_pc[0] = i;
- text_out_pc++;
- total_bytes_trans++;
+ ASSERT_GLULX();
+ if (text_out_limit >= 0) {
+ if (text_out_pos+1 > text_out_limit) {
+ text_out_overflow = TRUE;
+ return;
+ }
+ }
+ else {
+ ensure_memory_list_available(&translated_text_memlist, text_out_pos+1);
+ }
+ total_zchars_trans++;
+ translated_text[text_out_pos++] = i;
+ total_bytes_trans++;
+}
+
+/* Helper routine to compute the weight, in units, of a character handled by the Z-Machine */
+static int zchar_weight(int c)
+{
+ int lookup = iso_to_alphabet_grid[c];
+ if (lookup < 0) return 4;
+ if (lookup < 26) return 1;
+ return 2;
}
/* ------------------------------------------------------------------------- */
/* The main routine "text.c" provides to the rest of Inform: the text */
-/* translator. p is the address to write output to, s_text the source text */
-/* and the return value is the next free address to write output to. */
-/* The return value will not exceed p_limit. If the translation tries to */
-/* overflow this boundary, the return value will be NULL (and you should */
-/* display an error). */
+/* translator. s_text is the source text and the return value is the */
+/* number of bytes translated. */
+/* The translated text will be stored in translated_text. */
+/* */
+/* If p_limit is >= 0, the text length will not exceed that many bytes. */
+/* If the translation tries to overflow this boundary, the return value */
+/* will be -1. (You should display an error and not read translated_text.) */
+/* */
+/* If p_limit is negative, any amount of text is accepted (up to int32 */
+/* anyway). */
+/* */
/* Note that the source text may be corrupted by this routine. */
/* ------------------------------------------------------------------------- */
-extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx)
-{ int i, j, k, in_alphabet, lookup_value;
+extern int32 translate_text(int32 p_limit, char *s_text, int strctx)
+{ int i, j, k, in_alphabet, lookup_value, is_abbreviation;
int32 unicode; int zscii;
unsigned char *text_in;
+ if (p_limit >= 0) {
+ ensure_memory_list_available(&translated_text_memlist, p_limit);
+ }
+
/* For STRCTX_ABBREV, the string being translated is itself an
abbreviation string, so it can't make use of abbreviations. Set
the is_abbreviation flag to indicate this.
The compiler has historically set this flag for the Lowstring
directive as well -- the in_low_memory and is_abbreviation flag were
always the same. I am preserving that convention. */
- int is_abbreviation = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
+ is_abbreviation = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING);
- /* Cast the input and output streams to unsigned char: text_out_pc will
+ /* Cast the input and output streams to unsigned char: text_out_pos will
advance as bytes of Z-coded text are written, but text_in doesn't */
text_in = (unsigned char *) s_text;
- text_out_pc = (unsigned char *) p;
- text_out_limit = (unsigned char *) p_limit;
+ text_out_pos = 0;
+ text_out_limit = p_limit;
text_out_overflow = FALSE;
/* Remember the Z-chars total so that later we can subtract to find the
&& (!is_abbreviation))
make_abbrevs_lookup();
- /* If we're storing the whole game text to memory, then add this text */
+ /* If we're storing the whole game text to memory, then add this text.
+ We will put two newlines between each text and four at the very end.
+ (The optimise code does a lot of sloppy text[i+2], so the extra
+ two newlines past all_text_top are necessary.) */
if ((!is_abbreviation) && (store_the_text))
- { no_chars_transcribed += strlen(s_text)+2;
- if (no_chars_transcribed >= MAX_TRANSCRIPT_SIZE)
- memoryerror("MAX_TRANSCRIPT_SIZE", MAX_TRANSCRIPT_SIZE);
- sprintf(all_text_top, "%s\n\n", s_text);
- all_text_top += strlen(all_text_top);
+ { int addlen = strlen(s_text);
+ ensure_memory_list_available(&all_text_memlist, all_text_top+addlen+5);
+ sprintf(all_text+all_text_top, "%s\n\n\n\n", s_text);
+ /* Advance past two newlines. */
+ all_text_top += (addlen+2);
}
if (transcript_switch) {
}
}
+ /* Computing the optimal way to parse strings to insert abbreviations with dynamic programming */
+ /* (ref: R.A. Wagner , "Common phrases and minimum-space text storage", Commun. ACM, 16 (3) (1973)) */
+ /* We compute this optimal way here; it's stored in abbreviations_optimal_parse_schedule */
+ if (economy_switch)
+ {
+ uchar *q, c;
+ int l, min_score, from;
+ int text_in_length;
+
+ text_in_length = strlen( (char*) text_in);
+ ensure_memory_list_available(&abbreviations_optimal_parse_schedule_memlist, text_in_length);
+ ensure_memory_list_available(&abbreviations_optimal_parse_scores_memlist, text_in_length+1);
+
+ abbreviations_optimal_parse_scores[text_in_length] = 0;
+ for(j=text_in_length-1; j>=0; j--)
+ { /* Initial values: empty schedule, score = just write the letter without abbreviating. */
+ abbreviations_optimal_parse_schedule[j] = -1;
+ min_score = zchar_weight(text_in[j]) + abbreviations_optimal_parse_scores[j+1];
+ /* If there's an abbreviation starting with that letter... */
+ if ( (from = abbrevs_lookup[text_in[j]]) != -1)
+ {
+ c = text_in[j];
+ /* Loop on all abbreviations starting with what is in c. */
+ for (k=from, q=(uchar *)abbreviations_at+from*MAX_ABBREV_LENGTH;
+ (k<no_abbreviations)&&(c==q[0]); k++, q+=MAX_ABBREV_LENGTH)
+ {
+ /* Let's compare; we also keep track of the length of the abbreviation. */
+ for (l=1; q[l]!=0; l++)
+ { if (text_in[j+l]!=q[l]) {goto NotMatched;}
+ }
+ /* We have a match (length l), but is it smaller in size? */
+ if (min_score > 2 + abbreviations_optimal_parse_scores[j+l])
+ { /* It is indeed smaller, so let's write it down in our schedule. */
+ min_score = 2 + abbreviations_optimal_parse_scores[j+l];
+ abbreviations_optimal_parse_schedule[j] = k;
+ }
+ NotMatched: ;
+ }
+ }
+ /* We gave it our best, this is the smallest we got. */
+ abbreviations_optimal_parse_scores[j] = min_score;
+ }
+ }
+
+
+
if (!glulx_mode) {
/* The empty string of Z-text is illegal, since it can't carry an end
}
}
- /* Try abbreviations if the economy switch set */
-
- if ((economy_switch) && (!is_abbreviation)
- && ((k=abbrevs_lookup[text_in[i]])!=-1))
- { if ((j=try_abbreviations_from(text_in, i, k))!=-1)
- { /* abbreviations run from MAX_DYNAMIC_STRINGS to 96 */
- j += MAX_DYNAMIC_STRINGS;
- write_z_char_z(j/32+1); write_z_char_z(j%32);
- }
+ /* Try abbreviations if the economy switch set. */
+ /* Look at the abbreviation schedule to see if we should abbreviate here. */
+ /* Note: Just because the schedule has something doesn't mean we should abbreviate there; */
+ /* sometimes you abbreviate before because it's better. If we have already replaced the */
+ /* char by a '1', it means we're in the middle of an abbreviation; don't try to abbreviate then. */
+ if ((economy_switch) && (!is_abbreviation) && text_in[i] != 1 &&
+ ((j = abbreviations_optimal_parse_schedule[i]) != -1))
+ {
+ /* Fill with 1s, which will get ignored by everyone else. */
+ uchar *p = (uchar *)abbreviations_at+j*MAX_ABBREV_LENGTH;
+ for (k=0; p[k]!=0; k++) text_in[i+k]=1;
+ /* Actually write the abbreviation in the story file. */
+ abbreviations[j].freq++;
+ /* Abbreviations run from MAX_DYNAMIC_STRINGS to 96. */
+ j += MAX_DYNAMIC_STRINGS;
+ write_z_char_z(j/32+1); write_z_char_z(j%32);
}
+
/* If Unicode switch set, use text_to_unicode to perform UTF-8
decoding */
/* '@' is the escape character in Inform string notation: the various
possibilities are:
- (printing only)
@@decimalnumber : write this ZSCII char (0 to 1023)
- @twodigits : write the abbreviation string with this
- decimal number
-
- (any string context)
+ @twodigits or : write the abbreviation string with this
+ @(digits) decimal number
+ @(symbol) : write the abbreviation string with this
+ (constant) value
@accentcode : this accented character: e.g.,
for @'e write an E-acute
@{...} : this Unicode char (in hex) */
if (text_in[i]=='@')
{ if (text_in[i+1]=='@')
{
- /* @@... */
+ /* @@... (ascii value) */
i+=2; j=atoi((char *) (text_in+i));
switch(j)
}
while (isdigit(text_in[i])) i++; i--;
}
+ else if (text_in[i+1]=='(')
+ {
+ /* @(...) (dynamic string) */
+ char dsymbol[MAX_IDENTIFIER_LENGTH+1];
+ int len = 0, digits = 0;
+ i += 2;
+ /* This accepts "12xyz" as a symbol, which it really isn't,
+ but that just means it won't be found. */
+ while ((text_in[i] == '_' || isalnum(text_in[i])) && len < MAX_IDENTIFIER_LENGTH) {
+ char ch = text_in[i++];
+ if (isdigit(ch)) digits++;
+ dsymbol[len++] = ch;
+ }
+ dsymbol[len] = '\0';
+ j = -1;
+ /* We would like to parse dsymbol as *either* a decimal
+ number or a constant symbol. */
+ if (text_in[i] != ')' || len == 0) {
+ error("'@(...)' abbreviation must contain a symbol");
+ }
+ else if (digits == len) {
+ /* all digits; parse as decimal */
+ j = atoi(dsymbol);
+ }
+ else {
+ int sym = symbol_index(dsymbol, -1);
+ if ((symbols[sym].flags & UNKNOWN_SFLAG) || symbols[sym].type != CONSTANT_T || symbols[sym].marker) {
+ error_named("'@(...)' abbreviation expected a known constant value, but contained", dsymbol);
+ }
+ else {
+ symbols[sym].flags |= USED_SFLAG;
+ j = symbols[sym].value;
+ }
+ }
+ if (!glulx_mode && j >= 96) {
+ error_max_dynamic_strings(j);
+ j = -1;
+ }
+ if (j >= MAX_DYNAMIC_STRINGS) {
+ error_max_dynamic_strings(j);
+ j = -1;
+ }
+ if (j >= 0) {
+ write_z_char_z(j/32+1); write_z_char_z(j%32);
+ }
+ else {
+ write_z_char_z(' '); /* error fallback */
+ }
+ }
else if (isdigit(text_in[i+1])!=0)
{ int d1, d2;
else
{
j = d1*10 + d2;
- if (!glulx_mode && j >= 96)
- { error("Z-machine dynamic strings are limited to 96");
- j = 0;
+ if (!glulx_mode && j >= 96) {
+ error_max_dynamic_strings(j);
+ j = -1;
}
if (j >= MAX_DYNAMIC_STRINGS) {
- memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
- j = 0;
+ /* Shouldn't get here with two digits */
+ error_max_dynamic_strings(j);
+ j = -1;
}
i+=2;
- write_z_char_z(j/32+1); write_z_char_z(j%32);
+ if (j >= 0) {
+ write_z_char_z(j/32+1); write_z_char_z(j%32);
+ }
+ else {
+ write_z_char_z(' '); /* error fallback */
+ }
}
}
else
/* Flush the Z-characters output buffer and set the "end" bit */
end_z_chars();
-
}
else {
write_z_char_g(j);
while (isdigit(text_in[i])) i++; i--;
}
+ else if (text_in[i+1]=='(') {
+ char dsymbol[MAX_IDENTIFIER_LENGTH+1];
+ int len = 0, digits = 0;
+ i += 2;
+ /* This accepts "12xyz" as a symbol, which it really isn't,
+ but that just means it won't be found. */
+ while ((text_in[i] == '_' || isalnum(text_in[i])) && len < MAX_IDENTIFIER_LENGTH) {
+ char ch = text_in[i++];
+ if (isdigit(ch)) digits++;
+ dsymbol[len++] = ch;
+ }
+ dsymbol[len] = '\0';
+ j = -1;
+ /* We would like to parse dsymbol as *either* a decimal
+ number or a constant symbol. */
+ if (text_in[i] != ')' || len == 0) {
+ error("'@(...)' abbreviation must contain a symbol");
+ }
+ else if (digits == len) {
+ /* all digits; parse as decimal */
+ j = atoi(dsymbol);
+ }
+ else {
+ int sym = symbol_index(dsymbol, -1);
+ if ((symbols[sym].flags & UNKNOWN_SFLAG) || symbols[sym].type != CONSTANT_T || symbols[sym].marker) {
+ error_named("'@(...)' abbreviation expected a known constant value, but contained", dsymbol);
+ }
+ else {
+ symbols[sym].flags |= USED_SFLAG;
+ j = symbols[sym].value;
+ }
+ }
+ if (j >= MAX_DYNAMIC_STRINGS) {
+ error_max_dynamic_strings(j);
+ j = -1;
+ }
+ if (j+1 >= no_dynamic_strings)
+ no_dynamic_strings = j+1;
+ if (j >= 0) {
+ write_z_char_g('@');
+ write_z_char_g('D');
+ write_z_char_g('A' + ((j >>12) & 0x0F));
+ write_z_char_g('A' + ((j >> 8) & 0x0F));
+ write_z_char_g('A' + ((j >> 4) & 0x0F));
+ write_z_char_g('A' + ((j ) & 0x0F));
+ }
+ else {
+ write_z_char_g(' '); /* error fallback */
+ }
+ }
else if (isdigit(text_in[i+1])) {
int d1, d2;
d1 = character_digit_value[text_in[i+1]];
i += 2;
j = d1*10 + d2;
if (j >= MAX_DYNAMIC_STRINGS) {
- memoryerror("MAX_DYNAMIC_STRINGS", MAX_DYNAMIC_STRINGS);
- j = 0;
+ error_max_dynamic_strings(j);
+ j = -1;
}
if (j+1 >= no_dynamic_strings)
no_dynamic_strings = j+1;
- write_z_char_g('@');
- write_z_char_g('D');
- write_z_char_g('A' + ((j >>12) & 0x0F));
- write_z_char_g('A' + ((j >> 8) & 0x0F));
- write_z_char_g('A' + ((j >> 4) & 0x0F));
- write_z_char_g('A' + ((j ) & 0x0F));
+ if (j >= 0) {
+ write_z_char_g('@');
+ write_z_char_g('D');
+ write_z_char_g('A' + ((j >>12) & 0x0F));
+ write_z_char_g('A' + ((j >> 8) & 0x0F));
+ write_z_char_g('A' + ((j >> 4) & 0x0F));
+ write_z_char_g('A' + ((j ) & 0x0F));
+ }
+ else {
+ write_z_char_g(' '); /* error fallback */
+ }
}
}
else {
}
}
write_z_char_g(0);
+ zchars_trans_in_last_string=total_zchars_trans-zchars_trans_in_last_string;
}
if (text_out_overflow)
- return NULL;
+ return -1;
else
- return((uchar *) text_out_pc);
+ return text_out_pos;
}
static int unicode_entity_index(int32 unicode)
{
- unicode_usage_t *uptr;
int j;
int buck = unicode % UNICODE_HASH_BUCKETS;
- for (uptr = unicode_usage_hash[buck]; uptr; uptr=uptr->next) {
- if (uptr->ch == unicode)
+ for (j = unicode_usage_hash[buck]; j >= 0; j=unicode_usage_entries[j].next) {
+ if (unicode_usage_entries[j].ch == unicode)
break;
}
- if (uptr) {
- j = (uptr - unicode_usage_entries);
- }
- else {
- if (no_unicode_chars >= MAX_UNICODE_CHARS) {
- memoryerror("MAX_UNICODE_CHARS", MAX_UNICODE_CHARS);
- j = 0;
- }
- else {
- j = no_unicode_chars;
- no_unicode_chars++;
- uptr = unicode_usage_entries + j;
- uptr->ch = unicode;
- uptr->next = unicode_usage_hash[buck];
- unicode_usage_hash[buck] = uptr;
- }
+ if (j < 0) {
+ ensure_memory_list_available(&unicode_usage_entries_memlist, no_unicode_chars+1);
+ j = no_unicode_chars++;
+ unicode_usage_entries[j].ch = unicode;
+ unicode_usage_entries[j].next = unicode_usage_hash[buck];
+ unicode_usage_hash[buck] = j;
}
return j;
int jx;
int ch;
int32 ix;
+ int max_char_set;
huffbitlist_t bits;
if (compression_switch) {
+ max_char_set = 257 + no_abbreviations + no_dynamic_strings + no_unicode_chars;
+
+ huff_entities = my_calloc(sizeof(huffentity_t), max_char_set*2+1,
+ "huffman entities");
+ hufflist = my_calloc(sizeof(huffentity_t *), max_char_set,
+ "huffman node list");
/* How many entities have we currently got? Well, 256 plus the
string-terminator plus Unicode chars plus abbrevations plus
huff_dynam_start = entities;
entities += no_dynamic_strings;
- if (entities > MAX_CHARACTER_SET)
- memoryerror("MAX_CHARACTER_SET",MAX_CHARACTER_SET);
+ if (entities > max_char_set)
+ compiler_error("Too many entities for max_char_set");
/* Characters */
for (jx=0; jx<256; jx++) {
no_huff_entities = 257;
huff_unicode_start = 257;
huff_abbrev_start = 257;
- huff_dynam_start = 257+MAX_ABBREVS;
+ huff_dynam_start = 257+no_abbreviations;
compression_table_size = 0;
}
- if (temporary_files_switch) {
- fclose(Temp1_fp);
- Temp1_fp=fopen(Temp1_Name,"rb");
- if (Temp1_fp==NULL)
- fatalerror("I/O failure: couldn't reopen temporary file 1");
- }
-
if (compression_switch) {
for (lx=0, ix=0; lx<no_strings; lx++) {
int done=FALSE;
int32 escapeval=0;
while (!done) {
- if (temporary_files_switch)
- ch = fgetc(Temp1_fp);
- else
- ch = read_byte_from_memory_block(&static_strings_area, ix);
+ ch = static_strings_area[ix];
ix++;
if (ix > static_strings_extent || ch < 0)
compiler_error("Read too much not-yet-compressed text.");
without actually doing the compression. */
compression_string_size = 0;
- if (temporary_files_switch) {
- fseek(Temp1_fp, 0, SEEK_SET);
- }
-
- if (no_strings >= MAX_NUM_STATIC_STRINGS)
- memoryerror("MAX_NUM_STATIC_STRINGS", MAX_NUM_STATIC_STRINGS);
+ ensure_memory_list_available(&compressed_offsets_memlist, no_strings);
for (lx=0, ix=0; lx<no_strings; lx++) {
int escapelen=0, escapetype=0;
compressed_offsets[lx] = compression_table_size + compression_string_size;
compression_string_size++; /* for the type byte */
while (!done) {
- if (temporary_files_switch)
- ch = fgetc(Temp1_fp);
- else
- ch = read_byte_from_memory_block(&static_strings_area, ix);
+ ch = static_strings_area[ix];
ix++;
if (ix > static_strings_extent || ch < 0)
compiler_error("Read too much not-yet-compressed text.");
/* for compatibility with previous releases. */
/* ------------------------------------------------------------------------- */
+/* The complete game text. */
+static char *opttext;
+static int32 opttextlen;
+
typedef struct tlb_s
{ char text[4];
int32 intab, occurrences;
} tlb;
-static tlb *tlbtab;
+static tlb *tlbtab; /* Three-letter blocks (allocated up to no_occs) */
+static memory_list tlbtab_memlist;
static int32 no_occs;
static int32 *grandtable;
int32 location;
char text[MAX_ABBREV_LENGTH];
} optab;
-static optab *bestyet, *bestyet2;
+static int32 MAX_BESTYET;
+static optab *bestyet; /* High-score entries (up to MAX_BESTYET used/allocated) */
+static optab *bestyet2; /* The selected entries (up to selected used; allocated to MAX_ABBREVS) */
static int pass_no;
-static char *sub_buffer;
-
static void optimise_pass(void)
-{ int32 i; int t1, t2;
+{
+ TIMEVALUE t1, t2;
+ float duration;
+ int32 i;
int32 j, j2, k, nl, matches, noflags, score, min, minat=0, x, scrabble, c;
- for (i=0; i<256; i++) bestyet[i].length=0;
+ for (i=0; i<MAX_BESTYET; i++) bestyet[i].length=0;
for (i=0; i<no_occs; i++)
{ if ((*(tlbtab[i].text)!=(int) '\n')&&(tlbtab[i].occurrences!=0))
{
if (i%((**g_pm_hndl).linespercheck) == 0)
{ ProcessEvents (&g_proc);
if (g_proc != true)
- { free_arrays();
- if (store_the_text)
- my_free(&all_text,"transcription text");
+ { ao_free_arrays();
longjmp (g_fallback, 1);
}
}
#endif
- printf("Pass %d, %4ld/%ld '%s' (%ld occurrences) ",
- pass_no, (long int) i, (long int) no_occs, tlbtab[i].text,
- (long int) tlbtab[i].occurrences);
- t1=(int) (time(0));
+ if (optabbrevs_trace_setting >= 2) {
+ printf("Pass %d, %4ld/%ld '%s' (%ld occurrences) ",
+ pass_no, (long int) i, (long int) no_occs, tlbtab[i].text,
+ (long int) tlbtab[i].occurrences);
+ }
+ TIMEVALUE_NOW(&t1);
for (j=0; j<tlbtab[i].occurrences; j++)
{ for (j2=0; j2<tlbtab[i].occurrences; j2++) grandflags[j2]=1;
nl=2; noflags=tlbtab[i].occurrences;
- while ((noflags>=2)&&(nl<=62))
+ while ((noflags>=2)&&(nl<MAX_ABBREV_LENGTH-1))
{ nl++;
for (j2=0; j2<nl; j2++)
- if (all_text[grandtable[tlbtab[i].intab+j]+j2]=='\n')
+ if (opttext[grandtable[tlbtab[i].intab+j]+j2]=='\n')
goto FinishEarly;
matches=0;
for (j2=j; j2<tlbtab[i].occurrences; j2++)
{ x=grandtable[tlbtab[i].intab+j2]
- grandtable[tlbtab[i].intab+j];
if (((x>-nl)&&(x<nl))
- || (memcmp(all_text+grandtable[tlbtab[i].intab+j],
- all_text+grandtable[tlbtab[i].intab+j2],
+ || (memcmp(opttext+grandtable[tlbtab[i].intab+j],
+ opttext+grandtable[tlbtab[i].intab+j2],
nl)!=0))
{ grandflags[j2]=0; noflags--; }
else matches++;
scrabble=0;
for (k=0; k<nl; k++)
{ scrabble++;
- c=all_text[grandtable[tlbtab[i].intab+j+k]];
+ c=opttext[grandtable[tlbtab[i].intab+j+k]];
if (c!=(int) ' ')
{ if (iso_to_alphabet_grid[c]<0)
scrabble+=2;
}
score=(matches-1)*(scrabble-2);
min=score;
- for (j2=0; j2<256; j2++)
+ for (j2=0; j2<MAX_BESTYET; j2++)
{ if ((nl==bestyet[j2].length)
- && (memcmp(all_text+bestyet[j2].location,
- all_text+grandtable[tlbtab[i].intab+j],
+ && (memcmp(opttext+bestyet[j2].location,
+ opttext+grandtable[tlbtab[i].intab+j],
nl)==0))
- { j2=256; min=score; }
+ { j2=MAX_BESTYET; min=score; }
else
{ if (bestyet[j2].score<min)
{ min=bestyet[j2].score; minat=j2;
bestyet[minat].length=nl;
bestyet[minat].location=grandtable[tlbtab[i].intab+j];
bestyet[minat].popularity=matches;
- for (j2=0; j2<nl; j2++) sub_buffer[j2]=
- all_text[bestyet[minat].location+j2];
- sub_buffer[nl]=0;
}
}
FinishEarly: ;
}
- t2=((int) time(0)) - t1;
- printf(" (%d seconds)\n",t2);
+ if (optabbrevs_trace_setting >= 2) {
+ TIMEVALUE_NOW(&t2);
+ duration = TIMEVALUE_DIFFERENCE(&t1, &t2);
+ printf(" (%.4f seconds)\n", duration);
+ }
}
}
}
return(0);
}
-#define MAX_TLBS 8000
-
extern void optimise_abbreviations(void)
-{ int32 i, j, t, max=0, MAX_GTABLE;
+{ int32 i, j, tcount, max=0, MAX_GTABLE;
int32 j2, selected, available, maxat=0, nl;
- tlb test;
+ if (opttext == NULL)
+ return;
+
+ /* We insist that the first two abbreviations will be ". " and ", ". */
+ if (MAX_ABBREVS < 2)
+ return;
+
+ /* Note that it's safe to access opttext[opttextlen+2]. There are
+ two newlines and a null beyond opttextlen. */
+
printf("Beginning calculation of optimal abbreviations...\n");
pass_no = 0;
- tlbtab=my_calloc(sizeof(tlb), MAX_TLBS, "tlb table"); no_occs=0;
- sub_buffer=my_calloc(sizeof(char), 4000, "sub_buffer");
- for (i=0; i<MAX_TLBS; i++) tlbtab[i].occurrences=0;
- bestyet=my_calloc(sizeof(optab), 256, "bestyet");
- bestyet2=my_calloc(sizeof(optab), 64, "bestyet2");
+ initialise_memory_list(&tlbtab_memlist,
+ sizeof(tlb), 1000, (void**)&tlbtab,
+ "three-letter-blocks buffer");
+
+ no_occs=0;
+
+ /* Not sure what the optimal size is for MAX_BESTYET. The original code always created 64 abbreviations and used MAX_BESTYET=256. I'm guessing that 4*MAX_ABBREVS is reasonable. */
+ MAX_BESTYET = 4 * MAX_ABBREVS;
+
+ bestyet=my_calloc(sizeof(optab), MAX_BESTYET, "bestyet");
+ bestyet2=my_calloc(sizeof(optab), MAX_ABBREVS, "bestyet2");
bestyet2[0].text[0]='.';
bestyet2[0].text[1]=' ';
bestyet2[1].text[1]=' ';
bestyet2[1].text[2]=0;
- for (i=0; all_text+i<all_text_top; i++)
+ selected=2;
+
+ for (i=0; i<opttextlen; i++)
{
- if ((all_text[i]=='.') && (all_text[i+1]==' ') && (all_text[i+2]==' '))
- { all_text[i]='\n'; all_text[i+1]='\n'; all_text[i+2]='\n';
+ if ((opttext[i]=='.') && (opttext[i+1]==' ') && (opttext[i+2]==' '))
+ { opttext[i]='\n'; opttext[i+1]='\n'; opttext[i+2]='\n';
bestyet2[0].popularity++;
}
- if ((all_text[i]=='.') && (all_text[i+1]==' '))
- { all_text[i]='\n'; all_text[i+1]='\n';
+ if ((opttext[i]=='.') && (opttext[i+1]==' '))
+ { opttext[i]='\n'; opttext[i+1]='\n';
bestyet2[0].popularity++;
}
- if ((all_text[i]==',') && (all_text[i+1]==' '))
- { all_text[i]='\n'; all_text[i+1]='\n';
+ if ((opttext[i]==',') && (opttext[i+1]==' '))
+ { opttext[i]='\n'; opttext[i+1]='\n';
bestyet2[1].popularity++;
}
}
- MAX_GTABLE=subtract_pointers(all_text_top,all_text)+1;
+ MAX_GTABLE=opttextlen+1;
grandtable=my_calloc(4*sizeof(int32), MAX_GTABLE/4, "grandtable");
- for (i=0, t=0; all_text+i<all_text_top; i++)
- { test.text[0]=all_text[i];
- test.text[1]=all_text[i+1];
- test.text[2]=all_text[i+2];
+ for (i=0, tcount=0; i<opttextlen; i++)
+ {
+ tlb test;
+ test.text[0]=opttext[i];
+ test.text[1]=opttext[i+1];
+ test.text[2]=opttext[i+2];
test.text[3]=0;
if ((test.text[0]=='\n')||(test.text[1]=='\n')||(test.text[2]=='\n'))
goto DontKeep;
- for (j=0; j<no_occs; j++)
+ for (j=0; j<no_occs; j++) {
if (strcmp(test.text,tlbtab[j].text)==0)
goto DontKeep;
+ }
test.occurrences=0;
- for (j=i+3; all_text+j<all_text_top; j++)
+ test.intab=0;
+ for (j=i+3; j<opttextlen; j++)
{
#ifdef MAC_FACE
if (j%((**g_pm_hndl).linespercheck) == 0)
{ ProcessEvents (&g_proc);
if (g_proc != true)
- { free_arrays();
- if (store_the_text)
- my_free(&all_text,"transcription text");
+ { ao_free_arrays();
longjmp (g_fallback, 1);
}
}
#endif
- if ((all_text[i]==all_text[j])
- && (all_text[i+1]==all_text[j+1])
- && (all_text[i+2]==all_text[j+2]))
- { grandtable[t+test.occurrences]=j;
+ if ((opttext[i]==opttext[j])
+ && (opttext[i+1]==opttext[j+1])
+ && (opttext[i+2]==opttext[j+2]))
+ { grandtable[tcount+test.occurrences]=j;
test.occurrences++;
- if (t+test.occurrences==MAX_GTABLE)
+ if (tcount+test.occurrences==MAX_GTABLE)
{ printf("All %ld cross-references used\n",
(long int) MAX_GTABLE);
goto Built;
}
}
if (test.occurrences>=2)
- { tlbtab[no_occs]=test;
- tlbtab[no_occs].intab=t; t+=tlbtab[no_occs].occurrences;
+ {
+ ensure_memory_list_available(&tlbtab_memlist, no_occs+1);
+ tlbtab[no_occs]=test;
+ tlbtab[no_occs].intab=tcount;
+ tcount += tlbtab[no_occs].occurrences;
if (max<tlbtab[no_occs].occurrences)
max=tlbtab[no_occs].occurrences;
no_occs++;
- if (no_occs==MAX_TLBS)
- { printf("All %d three-letter-blocks used\n",
- MAX_TLBS);
- goto Built;
- }
}
DontKeep: ;
}
grandflags=my_calloc(sizeof(int), max, "grandflags");
- printf("Cross-reference table (%ld entries) built...\n",
- (long int) no_occs);
+ if (optabbrevs_trace_setting >= 1) {
+ printf("Cross-reference table (%ld entries) built...\n",
+ (long int) no_occs);
+ }
/* for (i=0; i<no_occs; i++)
printf("%4d %4d '%s' %d\n",i,tlbtab[i].intab,tlbtab[i].text,
tlbtab[i].occurrences);
*/
- for (i=0; i<64; i++) bestyet2[i].length=0; selected=2;
- available=256;
- while ((available>0)&&(selected<64))
- { printf("Pass %d\n", ++pass_no);
-
+ for (i=0; i<MAX_ABBREVS; i++) bestyet2[i].length=0;
+ available=MAX_BESTYET;
+ while ((available>0)&&(selected<MAX_ABBREVS))
+ {
+ pass_no++;
+ if (optabbrevs_trace_setting >= 1) {
+ printf("Pass %d\n", pass_no);
+ }
+
optimise_pass();
available=0;
- for (i=0; i<256; i++)
+ for (i=0; i<MAX_BESTYET; i++)
if (bestyet[i].score!=0)
{ available++;
nl=bestyet[i].length;
for (j2=0; j2<nl; j2++) bestyet[i].text[j2]=
- all_text[bestyet[i].location+j2];
+ opttext[bestyet[i].location+j2];
bestyet[i].text[nl]=0;
}
/* printf("End of pass results:\n");
printf("\nno score freq string\n");
- for (i=0; i<256; i++)
+ for (i=0; i<MAX_BESTYET; i++)
if (bestyet[i].score>0)
printf("%02d: %4d %4d '%s'\n", i, bestyet[i].score,
bestyet[i].popularity, bestyet[i].text);
do
{ max=0;
- for (i=0; i<256; i++)
+ for (i=0; i<MAX_BESTYET; i++)
if (max<bestyet[i].score)
{ max=bestyet[i].score;
maxat=i;
}
if (max>0)
- { bestyet2[selected++]=bestyet[maxat];
-
- printf(
- "Selection %2ld: '%s' (repeated %ld times, scoring %ld)\n",
- (long int) selected,bestyet[maxat].text,
- (long int) bestyet[maxat].popularity,
- (long int) bestyet[maxat].score);
+ {
+ char testtext[4];
+ bestyet2[selected++]=bestyet[maxat];
+
+ if (optabbrevs_trace_setting >= 1) {
+ printf(
+ "Selection %2ld: '%s' (repeated %ld times, scoring %ld)\n",
+ (long int) selected,bestyet[maxat].text,
+ (long int) bestyet[maxat].popularity,
+ (long int) bestyet[maxat].score);
+ }
- test.text[0]=bestyet[maxat].text[0];
- test.text[1]=bestyet[maxat].text[1];
- test.text[2]=bestyet[maxat].text[2];
- test.text[3]=0;
+ testtext[0]=bestyet[maxat].text[0];
+ testtext[1]=bestyet[maxat].text[1];
+ testtext[2]=bestyet[maxat].text[2];
+ testtext[3]=0;
for (i=0; i<no_occs; i++)
- if (strcmp(test.text,tlbtab[i].text)==0)
+ if (strcmp(testtext,tlbtab[i].text)==0)
break;
for (j=0; j<tlbtab[i].occurrences; j++)
{ if (memcmp(bestyet[maxat].text,
- all_text+grandtable[tlbtab[i].intab+j],
+ opttext+grandtable[tlbtab[i].intab+j],
bestyet[maxat].length)==0)
{ for (j2=0; j2<bestyet[maxat].length; j2++)
- all_text[grandtable[tlbtab[i].intab+j]+j2]='\n';
+ opttext[grandtable[tlbtab[i].intab+j]+j2]='\n';
}
}
- for (i=0; i<256; i++)
+ for (i=0; i<MAX_BESTYET; i++)
if ((bestyet[i].score>0)&&
(any_overlap(bestyet[maxat].text,bestyet[i].text)==1))
{ bestyet[i].score=0;
bestyet[i].text); */
}
}
- } while ((max>0)&&(available>0)&&(selected<64));
+ } while ((max>0)&&(available>0)&&(selected<MAX_ABBREVS));
}
printf("\nChosen abbreviations (in Inform syntax):\n\n");
/* <Z-coded text> <flags> <verbnumber> <adjectivenumber> */
/* 4 or 6 bytes byte byte byte */
/* */
-/* For Glulx, the form is instead: (But see below about Unicode-valued */
-/* dictionaries and my heinie.) */
+/* For Glulx, the form is instead: (See below about Unicode-valued */
+/* dictionaries and DICT_WORD_BYTES.) */
/* */
/* <tag> <plain text> <flags> <verbnumber> <adjectivenumber> */
-/* $60 DICT_WORD_SIZE short short short */
+/* $60 DICT_WORD_BYTES short short short */
/* */
/* These records are stored in "accession order" (i.e. in order of their */
/* first being received by these routines) and only alphabetically sorted */
/* fields. (The high bytes are $DICT_WORD_SIZE+1/3/5.) */
/* ------------------------------------------------------------------------- */
-uchar *dictionary, /* (These two pointers are externally
+uchar *dictionary; /* (These two variables are externally
used only in "tables.c" when
building the story-file) */
- *dictionary_top; /* Pointer to next free record */
+static memory_list dictionary_memlist;
+int32 dictionary_top; /* Position of the next free record
+ in dictionary (i.e., the current
+ number of bytes) */
int dict_entries; /* Total number of records entered */
/* ------------------------------------------------------------------------- */
-/* dict_word is a typedef for a struct of 6 unsigned chars (defined in */
-/* "header.h"): it holds the (4 or) 6 bytes of Z-coded text of a word. */
+/* dict_word was originally a typedef for a struct of 6 unsigned chars. */
+/* It held the (4 or) 6 bytes of Z-coded text of a word. */
/* Usefully, because the PAD character 5 is < all alphabetic characters, */
/* alphabetic order corresponds to numeric order. For this reason, the */
/* dict_word is called the "sort code" of the original text word. */
/* */
-/* ###- In modifying the compiler, I've found it easier to discard the */
+/* In modifying the compiler for Glulx, I found it easier to discard the */
/* typedef, and operate directly on uchar arrays of length DICT_WORD_SIZE. */
/* In Z-code, DICT_WORD_SIZE will be 6, so the Z-code compiler will work */
/* as before. In Glulx, it can be any value up to MAX_DICT_WORD_SIZE. */
/* (That limit is defined as 40 in the header; it exists only for a few */
/* static buffers, and can be increased without using significant memory.) */
/* */
-/* ###- Well, that certainly bit me on the butt, didn't it. In further */
+/* ...Well, that certainly bit me on the butt, didn't it. In further */
/* modifying the compiler to generate a Unicode dictionary, I have to */
/* store four-byte values in the uchar array. This is handled by making */
/* the array size DICT_WORD_BYTES (which is DICT_WORD_SIZE*DICT_CHAR_SIZE).*/
char colour; /* The colour of the branch to the parent */
} dict_tree_node;
-static dict_tree_node *dtree;
+static dict_tree_node *dtree; /* Allocated to dict_entries */
+static memory_list dtree_memlist;
+
+static uchar *dict_sort_codes; /* Allocated to dict_entries*DICT_WORD_BYTES */
+static memory_list dict_sort_codes_memlist;
-int *final_dict_order;
-static uchar *dict_sort_codes;
+int *final_dict_order; /* Allocated at sort_dictionary() time */
static void dictionary_begin_pass(void)
{
/* Glulx has a 4-byte header instead. */
if (!glulx_mode)
- dictionary_top=dictionary+7;
+ dictionary_top = 7;
else
- dictionary_top=dictionary+4;
+ dictionary_top = 4;
+ ensure_memory_list_available(&dictionary_memlist, dictionary_top);
+
root = VACANT;
dict_entries = 0;
}
extern void sort_dictionary(void)
{ int i;
+
+ final_dict_order = my_calloc(sizeof(int), dict_entries, "final dictionary ordering table");
+
if (module_switch)
{ for (i=0; i<dict_entries; i++)
final_dict_order[i] = i;
if (n==0)
{
if (!glulx_mode) {
- p = dictionary+7 + at*(3+res) + res;
- p[0]=(p[0])|x; p[1]=(p[1])|y; p[2]=(p[2])|z;
+ p = dictionary+7 + at*DICT_ENTRY_BYTE_LENGTH + res;
+ p[0]=(p[0])|x; p[1]=(p[1])|y;
+ if (!ZCODE_LESS_DICT_DATA)
+ p[2]=(p[2])|z;
if (x & 128) p[0] = (p[0])|number_and_case;
}
else {
CreateEntry:
- if (dict_entries==MAX_DICT_ENTRIES)
- memoryerror("MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
+ ensure_memory_list_available(&dtree_memlist, dict_entries+1);
+ ensure_memory_list_available(&dict_sort_codes_memlist, (dict_entries+1)*DICT_WORD_BYTES);
dtree[dict_entries].branch[0] = VACANT;
dtree[dict_entries].branch[1] = VACANT;
if (!glulx_mode) {
- p = dictionary + (3+res)*dict_entries + 7;
+ ensure_memory_list_available(&dictionary_memlist, dictionary_top + DICT_ENTRY_BYTE_LENGTH);
+ p = dictionary + DICT_ENTRY_BYTE_LENGTH*dict_entries + 7;
/* So copy in the 4 (or 6) bytes of Z-coded text and the 3 data
bytes */
p[2]=prepared_sort[2]; p[3]=prepared_sort[3];
if (version_number > 3)
{ p[4]=prepared_sort[4]; p[5]=prepared_sort[5]; }
- p[res]=x; p[res+1]=y; p[res+2]=z;
+ p[res]=x; p[res+1]=y;
+ if (!ZCODE_LESS_DICT_DATA) p[res+2]=z;
if (x & 128) p[res] = (p[res])|number_and_case;
- dictionary_top += res+3;
+ dictionary_top += DICT_ENTRY_BYTE_LENGTH;
}
else {
int i;
+ ensure_memory_list_available(&dictionary_memlist, dictionary_top + DICT_ENTRY_BYTE_LENGTH);
p = dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*dict_entries;
p[0] = 0x60; /* type byte -- dict word */
if (i!=0)
{
if (!glulx_mode) {
- p=dictionary+7+(i-1)*(3+res)+res;
+ p=dictionary+7+(i-1)*DICT_ENTRY_BYTE_LENGTH+res;
p[1]=to;
}
else {
encoded_word[7] = 8*(((int) p[4])&0x3) + (((int) p[5])&0xe0)/32;
encoded_word[8] = ((int) p[5])&0x1f;
}
+ else
+ {
+ encoded_word[6] = encoded_word[7] = encoded_word[8] = 0;
+ }
shift = 0; cc = 0;
for (i=0; i< ((version_number==3)?6:9); i++)
results[cc] = 0;
}
-static void recursively_show_z(int node)
+/* Print a dictionary word to stdout.
+ (This assumes that d_show_buf is null.)
+ */
+void print_dict_word(int node)
+{
+ uchar *p;
+ int cprinted;
+
+ if (!glulx_mode) {
+ char textual_form[32];
+ p = (uchar *)dictionary + 7 + DICT_ENTRY_BYTE_LENGTH*node;
+
+ word_to_ascii(p, textual_form);
+
+ for (cprinted = 0; textual_form[cprinted]!=0; cprinted++)
+ show_char(textual_form[cprinted]);
+ }
+ else {
+ p = (uchar *)dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*node;
+
+ for (cprinted = 0; cprinted<DICT_WORD_SIZE; cprinted++)
+ {
+ uint32 ch;
+ if (DICT_CHAR_SIZE == 1)
+ ch = p[1+cprinted];
+ else
+ ch = (p[4*cprinted+4] << 24) + (p[4*cprinted+5] << 16) + (p[4*cprinted+6] << 8) + (p[4*cprinted+7]);
+ if (!ch)
+ break;
+ show_uchar(ch);
+ }
+ }
+}
+
+static void recursively_show_z(int node, int level)
{ int i, cprinted, flags; uchar *p;
char textual_form[32];
int res = (version_number == 3)?4:6; /* byte length of encoded text */
if (dtree[node].branch[0] != VACANT)
- recursively_show_z(dtree[node].branch[0]);
+ recursively_show_z(dtree[node].branch[0], level);
- p = (uchar *)dictionary + 7 + (3+res)*node;
+ p = (uchar *)dictionary + 7 + DICT_ENTRY_BYTE_LENGTH*node;
word_to_ascii(p, textual_form);
for (; cprinted < 4 + ((version_number==3)?6:9); cprinted++)
show_char(' ');
- if (d_show_buf == NULL)
- { for (i=0; i<3+res; i++) printf("%02x ",p[i]);
+ /* The level-1 info can only be printfed (d_show_buf must be null). */
+ if (d_show_buf == NULL && level >= 1)
+ {
+ if (level >= 2) {
+ for (i=0; i<DICT_ENTRY_BYTE_LENGTH; i++) printf("%02x ",p[i]);
+ }
flags = (int) p[res];
if (flags & 128)
}
if (dtree[node].branch[1] != VACANT)
- recursively_show_z(dtree[node].branch[1]);
+ recursively_show_z(dtree[node].branch[1], level);
}
-static void recursively_show_g(int node)
+static void recursively_show_g(int node, int level)
{ int i, cprinted;
uchar *p;
if (dtree[node].branch[0] != VACANT)
- recursively_show_g(dtree[node].branch[0]);
+ recursively_show_g(dtree[node].branch[0], level);
p = (uchar *)dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*node;
for (; cprinted<DICT_WORD_SIZE+4; cprinted++)
show_char(' ');
- if (d_show_buf == NULL)
- { for (i=0; i<DICT_ENTRY_BYTE_LENGTH; i++) printf("%02x ",p[i]);
- int flagpos = (DICT_CHAR_SIZE == 1) ? (DICT_WORD_SIZE+1) : (DICT_WORD_BYTES+4);
+ /* The level-1 info can only be printfed (d_show_buf must be null). */
+ if (d_show_buf == NULL && level >= 1)
+ { int flagpos = (DICT_CHAR_SIZE == 1) ? (DICT_WORD_SIZE+1) : (DICT_WORD_BYTES+4);
int flags = (p[flagpos+0] << 8) | (p[flagpos+1]);
int verbnum = (p[flagpos+2] << 8) | (p[flagpos+3]);
+ if (level >= 2) {
+ for (i=0; i<DICT_ENTRY_BYTE_LENGTH; i++) printf("%02x ",p[i]);
+ }
if (flags & 128)
{ printf("noun ");
if (flags & 4) printf("p"); else printf(" ");
}
if (dtree[node].branch[1] != VACANT)
- recursively_show_g(dtree[node].branch[1]);
+ recursively_show_g(dtree[node].branch[1], level);
}
static void show_alphabet(int i)
printf("\n");
}
-extern void show_dictionary(void)
-{ printf("Dictionary contains %d entries:\n",dict_entries);
+extern void show_dictionary(int level)
+{
+ /* Level 0: show words only. Level 1: show words and flags.
+ Level 2: also show bytes.*/
+ printf("Dictionary contains %d entries:\n",dict_entries);
if (dict_entries != 0)
{ d_show_len = 0; d_show_buf = NULL;
if (!glulx_mode)
- recursively_show_z(root);
+ recursively_show_z(root, level);
else
- recursively_show_g(root);
+ recursively_show_g(root, level);
}
if (!glulx_mode)
{
if (dict_entries != 0)
{
if (!glulx_mode)
- recursively_show_z(root);
+ recursively_show_z(root, 0);
else
- recursively_show_g(root);
+ recursively_show_g(root, 0);
}
if (d_show_len != 0) write_to_transcript_file(d_show_buf, STRCTX_DICT);
extern void init_text_vars(void)
{ int j;
+
+ opttext = NULL;
+ opttextlen = 0;
bestyet = NULL;
bestyet2 = NULL;
tlbtab = NULL;
grandtable = NULL;
grandflags = NULL;
- no_chars_transcribed = 0;
+
+ all_text = NULL;
for (j=0; j<256; j++) abbrevs_lookup[j] = -1;
total_zchars_trans = 0;
+ dictionary = NULL;
+ dictionary_top = 0;
dtree = NULL;
final_dict_order = NULL;
dict_sort_codes = NULL;
dict_entries=0;
- initialise_memory_block(&static_strings_area);
+ static_strings_area = NULL;
+ abbreviations_optimal_parse_schedule = NULL;
+ abbreviations_optimal_parse_scores = NULL;
+
+ compressed_offsets = NULL;
+ huff_entities = NULL;
+ hufflist = NULL;
+ unicode_usage_entries = NULL;
}
extern void text_begin_pass(void)
{ abbrevs_lookup_table_made = FALSE;
no_abbreviations=0;
total_chars_trans=0; total_bytes_trans=0;
- if (store_the_text) all_text_top=all_text;
+ all_text_top=0;
dictionary_begin_pass();
- low_strings_top = low_strings;
+ low_strings_top = 0;
static_strings_extent = 0;
no_strings = 0;
/* Note: for allocation and deallocation of all_the_text, see inform.c */
extern void text_allocate_arrays(void)
-{ abbreviations_at = my_malloc(MAX_ABBREVS*MAX_ABBREV_LENGTH,
- "abbreviations");
- abbrev_values = my_calloc(sizeof(int), MAX_ABBREVS, "abbrev values");
- abbrev_quality = my_calloc(sizeof(int), MAX_ABBREVS, "abbrev quality");
- abbrev_freqs = my_calloc(sizeof(int), MAX_ABBREVS, "abbrev freqs");
+{
+ int ix;
- dtree = my_calloc(sizeof(dict_tree_node), MAX_DICT_ENTRIES,
- "red-black tree for dictionary");
- final_dict_order = my_calloc(sizeof(int), MAX_DICT_ENTRIES,
- "final dictionary ordering table");
- dict_sort_codes = my_calloc(DICT_WORD_BYTES, MAX_DICT_ENTRIES,
- "dictionary sort codes");
+ initialise_memory_list(&translated_text_memlist,
+ sizeof(uchar), 8000, (void**)&translated_text,
+ "translated text holding area");
+
+ initialise_memory_list(&all_text_memlist,
+ sizeof(char), 0, (void**)&all_text,
+ "transcription text for optimise");
+
+ initialise_memory_list(&static_strings_area_memlist,
+ sizeof(uchar), 128, (void**)&static_strings_area,
+ "static strings area");
+
+ initialise_memory_list(&abbreviations_at_memlist,
+ MAX_ABBREV_LENGTH, 64, (void**)&abbreviations_at,
+ "abbreviation text");
- if (!glulx_mode)
- dictionary = my_malloc(9*MAX_DICT_ENTRIES+7,
- "dictionary");
- else
- dictionary = my_malloc(DICT_ENTRY_BYTE_LENGTH*MAX_DICT_ENTRIES+4,
- "dictionary");
+ initialise_memory_list(&abbreviations_memlist,
+ sizeof(abbreviation), 64, (void**)&abbreviations,
+ "abbreviations");
- strings_holding_area
- = my_malloc(MAX_STATIC_STRINGS,"static strings holding area");
- low_strings = my_malloc(MAX_LOW_STRINGS,"low (abbreviation) strings");
+ initialise_memory_list(&abbreviations_optimal_parse_schedule_memlist,
+ sizeof(int), 0, (void**)&abbreviations_optimal_parse_schedule,
+ "abbreviations optimal parse schedule");
+ initialise_memory_list(&abbreviations_optimal_parse_scores_memlist,
+ sizeof(int), 0, (void**)&abbreviations_optimal_parse_scores,
+ "abbreviations optimal parse scores");
+
+ initialise_memory_list(&dtree_memlist,
+ sizeof(dict_tree_node), 1500, (void**)&dtree,
+ "red-black tree for dictionary");
+ initialise_memory_list(&dict_sort_codes_memlist,
+ sizeof(uchar), 1500*DICT_WORD_BYTES, (void**)&dict_sort_codes,
+ "dictionary sort codes");
+
+ final_dict_order = NULL; /* will be allocated at sort_dictionary() time */
+
+ /* The exact size will be 7+7*num for z3, 7+9*num for z4+,
+ 4+DICT_ENTRY_BYTE_LENGTH*num for Glulx. But this is just an initial
+ allocation; we don't have to be precise. */
+ initialise_memory_list(&dictionary_memlist,
+ sizeof(uchar), 1000*DICT_ENTRY_BYTE_LENGTH, (void**)&dictionary,
+ "dictionary");
+
+ initialise_memory_list(&low_strings_memlist,
+ sizeof(uchar), 1024, (void**)&low_strings,
+ "low (abbreviation) strings");
d_show_buf = NULL;
d_show_size = 0;
compression_table_size = 0;
compressed_offsets = NULL;
- MAX_CHARACTER_SET = 0;
+ initialise_memory_list(&unicode_usage_entries_memlist,
+ sizeof(unicode_usage_t), 0, (void**)&unicode_usage_entries,
+ "unicode entity entries");
- if (glulx_mode) {
- if (compression_switch) {
- int ix;
- MAX_CHARACTER_SET = 257 + MAX_ABBREVS + MAX_DYNAMIC_STRINGS
- + MAX_UNICODE_CHARS;
- huff_entities = my_calloc(sizeof(huffentity_t), MAX_CHARACTER_SET*2+1,
- "huffman entities");
- hufflist = my_calloc(sizeof(huffentity_t *), MAX_CHARACTER_SET,
- "huffman node list");
- unicode_usage_entries = my_calloc(sizeof(unicode_usage_t),
- MAX_UNICODE_CHARS, "unicode entity entries");
- for (ix=0; ix<UNICODE_HASH_BUCKETS; ix++)
- unicode_usage_hash[ix] = NULL;
- }
- compressed_offsets = my_calloc(sizeof(int32), MAX_NUM_STATIC_STRINGS,
+ /* hufflist and huff_entities will be allocated at compress_game_text() time. */
+
+ /* This hash table is only used in Glulx */
+ for (ix=0; ix<UNICODE_HASH_BUCKETS; ix++)
+ unicode_usage_hash[ix] = -1;
+
+ initialise_memory_list(&compressed_offsets_memlist,
+ sizeof(int32), 0, (void**)&compressed_offsets,
"static strings index table");
- }
+}
+
+extern void extract_all_text()
+{
+ /* optimise_abbreviations() is called after free_arrays(). Therefore,
+ we need to preserve the text transcript where it will not be
+ freed up. We do this by copying the pointer to opttext. */
+ opttext = all_text;
+ opttextlen = all_text_top;
+
+ /* Re-init all_text_memlist. This causes it to forget all about the
+ old pointer. Deallocating it in text_free_arrays() will be a no-op. */
+ initialise_memory_list(&all_text_memlist,
+ sizeof(char), 0, (void**)&all_text,
+ "dummy transcription text");
}
extern void text_free_arrays(void)
{
- my_free(&strings_holding_area, "static strings holding area");
- my_free(&low_strings, "low (abbreviation) strings");
- my_free(&abbreviations_at, "abbreviations");
- my_free(&abbrev_values, "abbrev values");
- my_free(&abbrev_quality, "abbrev quality");
- my_free(&abbrev_freqs, "abbrev freqs");
-
- my_free(&dtree, "red-black tree for dictionary");
+ deallocate_memory_list(&translated_text_memlist);
+
+ deallocate_memory_list(&all_text_memlist);
+
+ deallocate_memory_list(&low_strings_memlist);
+ deallocate_memory_list(&abbreviations_at_memlist);
+ deallocate_memory_list(&abbreviations_memlist);
+
+ deallocate_memory_list(&abbreviations_optimal_parse_schedule_memlist);
+ deallocate_memory_list(&abbreviations_optimal_parse_scores_memlist);
+
+ deallocate_memory_list(&dtree_memlist);
+ deallocate_memory_list(&dict_sort_codes_memlist);
my_free(&final_dict_order, "final dictionary ordering table");
- my_free(&dict_sort_codes, "dictionary sort codes");
- my_free(&dictionary,"dictionary");
+ deallocate_memory_list(&dictionary_memlist);
- my_free(&compressed_offsets, "static strings index table");
+ deallocate_memory_list(&compressed_offsets_memlist);
my_free(&hufflist, "huffman node list");
my_free(&huff_entities, "huffman entities");
- my_free(&unicode_usage_entries, "unicode entity entities");
+
+ deallocate_memory_list(&unicode_usage_entries_memlist);
- deallocate_memory_block(&static_strings_area);
+ deallocate_memory_list(&static_strings_area_memlist);
}
extern void ao_free_arrays(void)
-{ my_free (&tlbtab,"tlb table");
- my_free (&sub_buffer,"sub_buffer");
+{
+ /* Called only after optimise_abbreviations() runs. */
+
+ my_free (&opttext,"stashed transcript for optimisation");
my_free (&bestyet,"bestyet");
my_free (&bestyet2,"bestyet2");
my_free (&grandtable,"grandtable");
my_free (&grandflags,"grandflags");
+
+ deallocate_memory_list(&tlbtab_memlist);
+
+ /* This was re-inited, so we should re-deallocate it. */
+ deallocate_memory_list(&all_text_memlist);
}
/* ========================================================================= */
/* by the compiler (e.g. DefArt) which the program doesn't */
/* provide */
/* */
-/* 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 */
/* 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/ */
/* */
/* ------------------------------------------------------------------------- */
compiled from the veneer? */
static debug_locations null_debug_locations =
- { { 0, 0, 0, 0, 0, 0, 0 }, NULL, 0 };
+ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, NULL, 0 };
extern void compile_initial_routine(void)
{
(since the interpreter begins execution with an empty stack frame):
and it must "quit" rather than "return".
+ (Pedantically, in Z-code 1-5, this is not a routine at all. It's
+ a sequence of opcodes which ends with "quit". The one-byte
+ header generated by assemble_routine_header() is a dummy.)
+
In order not to impose these restrictions on "Main", we compile a
trivial routine consisting of a call to "Main" followed by "quit". */
assign_symbol(j,
assemble_routine_header(0, FALSE, "Main__", FALSE, j),
ROUTINE_T);
- sflags[j] |= SYSTEM_SFLAG + USED_SFLAG;
- if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+ symbols[j].flags |= SYSTEM_SFLAG + USED_SFLAG;
+ if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
if (!glulx_mode) {
return(AO);
}
+extern char *veneer_routine_name(int code)
+{
+ if (code < 0 || code >= VENEER_ROUTINES) {
+ return "???";
+ }
+ if (!glulx_mode) {
+ return VRs_z[code].name;
+ }
+ else {
+ return VRs_g[code].name;
+ }
+}
+
static void compile_symbol_table_routine(void)
{ int32 j, nl, arrays_l, routines_l, constants_l;
assembly_operand AO, AO2, AO3;
/* Assign local var names for the benefit of the debugging information
- file. */
- local_variable_texts[0] = "dummy1";
- local_variable_texts[1] = "dummy2";
+ file. (We don't set local_variable.keywords because we're not
+ going to be parsing any code.) */
+ strcpy(local_variable_names[0].text, "dummy1");
+ strcpy(local_variable_names[1].text, "dummy2");
veneer_mode = TRUE; j = symbol_index("Symb__Tab", -1);
assign_symbol(j,
assemble_routine_header(2, FALSE, "Symb__Tab", FALSE, j),
ROUTINE_T);
- sflags[j] |= SYSTEM_SFLAG + USED_SFLAG;
- if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+ symbols[j].flags |= SYSTEM_SFLAG + USED_SFLAG;
+ if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
if (!glulx_mode) {
if (define_INFIX_switch == FALSE)
{ assemblez_0(rfalse_zc);
- variable_usage[1] = TRUE;
- variable_usage[2] = TRUE;
+ variables[1].usage = TRUE;
+ variables[2].usage = TRUE;
assemble_routine_end(FALSE, null_debug_locations);
veneer_mode = FALSE;
return;
nl = next_label++;
sequence_point_follows = FALSE;
assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
- AO3.value = array_sizes[j];
+ AO3.value = arrays[j].size;
AO3.marker = 0;
assemblez_store(temp_var2, AO3);
- AO3.value = array_types[j];
- if (sflags[array_symbols[j]] & (INSF_SFLAG+SYSTEM_SFLAG))
+ AO3.value = arrays[j].type;
+ if (symbols[arrays[j].symbol].flags & (INSF_SFLAG+SYSTEM_SFLAG))
AO3.value = AO3.value + 16;
AO3.marker = 0;
assemblez_store(temp_var3, AO3);
- AO3.value = svals[array_symbols[j]];
- AO3.marker = (!array_locs[j] ? ARRAY_MV : STATIC_ARRAY_MV);
+ AO3.value = symbols[arrays[j].symbol].value;
+ AO3.marker = (!arrays[j].loc ? ARRAY_MV : STATIC_ARRAY_MV);
assemblez_1(ret_zc, AO3);
assemble_label_no(nl);
}
sequence_point_follows = FALSE;
assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
AO3.value = 0;
- if (sflags[named_routine_symbols[j]]
+ if (symbols[named_routine_symbols[j]].flags
& (INSF_SFLAG+SYSTEM_SFLAG)) AO3.value = 16;
AO3.marker = 0;
assemblez_store(temp_var3, AO3);
- AO3.value = svals[named_routine_symbols[j]];
+ AO3.value = symbols[named_routine_symbols[j]].value;
AO3.marker = IROUTINE_MV;
assemblez_1(ret_zc, AO3);
assemble_label_no(nl);
assemble_label_no(constants_l);
for (j=0, no_named_constants=0; j<no_symbols; j++)
- { if (((stypes[j] == OBJECT_T) || (stypes[j] == CLASS_T)
- || (stypes[j] == CONSTANT_T))
- && ((sflags[j] & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
+ { if (((symbols[j].type == OBJECT_T) || (symbols[j].type == CLASS_T)
+ || (symbols[j].type == CONSTANT_T))
+ && ((symbols[j].flags & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
{ AO2.value = no_named_constants++;
if (AO2.value<256) AO2.type = SHORT_CONSTANT_OT;
else AO2.type = LONG_CONSTANT_OT;
sequence_point_follows = FALSE;
assemblez_2_branch(je_zc, AO, AO2, nl, FALSE);
AO3.value = 0;
- if (stypes[j] == OBJECT_T) AO3.value = 2;
- if (stypes[j] == CLASS_T) AO3.value = 1;
- if (sflags[j] & (INSF_SFLAG+SYSTEM_SFLAG))
+ if (symbols[j].type == OBJECT_T) AO3.value = 2;
+ if (symbols[j].type == CLASS_T) AO3.value = 1;
+ if (symbols[j].flags & (INSF_SFLAG+SYSTEM_SFLAG))
AO3.value = AO3.value + 16;
AO3.marker = 0;
assemblez_store(temp_var3, AO3);
sequence_point_follows = FALSE;
assemblez_0(rfalse_zc);
- variable_usage[1] = TRUE;
- variable_usage[2] = TRUE;
+ variables[1].usage = TRUE;
+ variables[2].usage = TRUE;
assemble_routine_end(FALSE, null_debug_locations);
veneer_mode = FALSE;
}
if (define_INFIX_switch == FALSE)
{ assembleg_1(return_gc, zero_operand);
- variable_usage[1] = TRUE;
- variable_usage[2] = TRUE;
+ variables[1].usage = TRUE;
+ variables[2].usage = TRUE;
assemble_routine_end(FALSE, null_debug_locations);
veneer_mode = FALSE;
return;
for (i=0; i<VENEER_ROUTINES; i++)
{ if (veneer_routine_needs_compilation[i] == VR_CALLED)
{ j = symbol_index(VRs[i].name, -1);
- if (sflags[j] & UNKNOWN_SFLAG)
+ if (symbols[j].flags & UNKNOWN_SFLAG)
{ veneer_mode = TRUE;
strcpy(veneer_source_area, VRs[i].source1);
strcat(veneer_source_area, VRs[i].source2);
VRs[i].name, TRUE, j),
ROUTINE_T);
veneer_mode = FALSE;
- if (trace_fns_setting==3) sflags[j] |= STAR_SFLAG;
+ if (trace_fns_setting==3) symbols[j].flags |= STAR_SFLAG;
}
else
- { if (stypes[j] != ROUTINE_T)
+ { if (symbols[j].type != ROUTINE_T)
error_named("The following name is reserved by Inform for its \
own use as a routine name; you can use it as a routine name yourself (to \
override the standard definition) but cannot use it for anything else:",
VRs[i].name);
else
- sflags[j] |= USED_SFLAG;
+ symbols[j].flags |= USED_SFLAG;
}
- veneer_routine_address[i] = svals[j];
+ veneer_routine_address[i] = symbols[j].value;
veneer_routine_needs_compilation[i] = VR_COMPILED;
try_veneer_again = TRUE;
}
/* "verbs" : Manages actions and grammar tables; parses the directives */
/* Verb and Extend. */
/* */
-/* 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 */
/* ------------------------------------------------------------------------- */
/* Array defined below: */
/* */
-/* int32 action_byte_offset[n] The (byte) offset in the Z-machine */
-/* code area of the ...Sub routine */
-/* for action n. (NB: This is left */
-/* blank until the end of the */
-/* compilation pass.) */
-/* int32 action_symbol[n] The symbol table index of the n-th */
-/* action's name. */
+/* actioninfo actions[n] Symbol table index and byte offset */
+/* of the ...Sub routine */
/* ------------------------------------------------------------------------- */
int no_actions, /* Number of actions made so far */
/* The format of this list is a sequence of variable-length records: */
/* */
/* Byte offset to start of next record (1 byte) */
-/* Inform verb number this word corresponds to (1 byte) */
+/* Inform verb number this word corresponds to (2 bytes) */
/* The English verb-word (reduced to lower case), null-terminated */
/* ------------------------------------------------------------------------- */
-static char *English_verb_list, /* First byte of first record */
- *English_verb_list_top; /* Next byte free for new record */
+static char *English_verb_list; /* Allocated to English_verb_list_size */
+static memory_list English_verb_list_memlist;
-static int English_verb_list_size; /* Size of the list in bytes
- (redundant but convenient) */
+static int English_verb_list_size; /* Size of the list in bytes */
-/* Maximum synonyms in a single Verb/Extend directive */
-#define MAX_VERB_SYNONYMS (32)
+static char *English_verbs_given; /* Allocated to verbs_given_pos
+ (Used only within make_verb()) */
+static memory_list English_verbs_given_memlist;
/* ------------------------------------------------------------------------- */
/* Arrays used by this file */
/* ------------------------------------------------------------------------- */
- verbt *Inform_verbs;
- uchar *grammar_lines;
+ verbt *Inform_verbs; /* Allocated up to no_Inform_verbs */
+ static memory_list Inform_verbs_memlist;
+ uchar *grammar_lines; /* Allocated to grammar_lines_top */
+ static memory_list grammar_lines_memlist;
int32 grammar_lines_top;
int no_grammar_lines, no_grammar_tokens;
- int32 *action_byte_offset,
- *action_symbol,
- *grammar_token_routine,
- *adjectives;
- static uchar *adjective_sort_code;
+ actioninfo *actions; /* Allocated to no_actions */
+ memory_list actions_memlist;
+ int32 *grammar_token_routine; /* Allocated to no_grammar_token_routines */
+ static memory_list grammar_token_routine_memlist;
+
+ int32 *adjectives; /* Allocated to no_adjectives */
+ static memory_list adjectives_memlist;
+
+ static uchar *adjective_sort_code; /* Allocated to no_adjectives*DICT_WORD_BYTES */
+ static memory_list adjective_sort_code_memlist;
/* ------------------------------------------------------------------------- */
/* Tracing for compiler maintenance */
/* ------------------------------------------------------------------------- */
+static char *find_verb_by_number(int num);
+
+static void list_grammar_line_v1(int mark)
+{
+ int action, actsym;
+ int ix, len;
+ char *str;
+
+ /* There is no GV1 for Glulx. */
+ if (glulx_mode)
+ return;
+
+ action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ mark += 2;
+
+ printf(" *");
+ while (grammar_lines[mark] != 15) {
+ uchar tok = grammar_lines[mark];
+ mark += 3;
+
+ switch (tok) {
+ case 0:
+ printf(" noun");
+ break;
+ case 1:
+ printf(" held");
+ break;
+ case 2:
+ printf(" multi");
+ break;
+ case 3:
+ printf(" multiheld");
+ break;
+ case 4:
+ printf(" multiexcept");
+ break;
+ case 5:
+ printf(" multiinside");
+ break;
+ case 6:
+ printf(" creature");
+ break;
+ case 7:
+ printf(" special");
+ break;
+ case 8:
+ printf(" number");
+ break;
+ default:
+ if (tok >= 16 && tok < 48) {
+ printf(" noun=%d", tok-16);
+ }
+ else if (tok >= 48 && tok < 80) {
+ printf(" routine=%d", tok-48);
+ }
+ else if (tok >= 80 && tok < 128) {
+ printf(" scope=%d", tok-80);
+ }
+ else if (tok >= 128 && tok < 160) {
+ printf(" attr=%d", tok-128);
+ }
+ else if (tok >= 160) {
+ printf(" prep=%d", tok);
+ }
+ else {
+ printf(" ???");
+ }
+ }
+ }
+
+ printf(" -> ");
+ actsym = actions[action].symbol;
+ str = (symbols[actsym].name);
+ len = strlen(str) - 3; /* remove "__A" */
+ for (ix=0; ix<len; ix++) putchar(str[ix]);
+ printf("\n");
+}
+
+static void list_grammar_line_v2(int mark)
+{
+ int action, flags, actsym;
+ int ix, len;
+ char *str;
+
+ if (!glulx_mode) {
+ action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ flags = (action & 0x400);
+ action &= 0x3FF;
+ mark += 2;
+ }
+ else {
+ action = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ mark += 2;
+ flags = grammar_lines[mark++];
+ }
+
+ printf(" *");
+ while (grammar_lines[mark] != 15) {
+ int toktype, tokdat, tokalt;
+ if (!glulx_mode) {
+ toktype = grammar_lines[mark] & 0x0F;
+ tokalt = (grammar_lines[mark] >> 4) & 0x03;
+ mark += 1;
+ tokdat = (grammar_lines[mark] << 8) | (grammar_lines[mark+1]);
+ mark += 2;
+ }
+ else {
+ toktype = grammar_lines[mark] & 0x0F;
+ tokalt = (grammar_lines[mark] >> 4) & 0x03;
+ mark += 1;
+ tokdat = (grammar_lines[mark] << 24) | (grammar_lines[mark+1] << 16) | (grammar_lines[mark+2] << 8) | (grammar_lines[mark+3]);
+ mark += 4;
+ }
+
+ if (tokalt == 3 || tokalt == 1)
+ printf(" /");
+
+ switch (toktype) {
+ case 1:
+ switch (tokdat) {
+ case 0: printf(" noun"); break;
+ case 1: printf(" held"); break;
+ case 2: printf(" multi"); break;
+ case 3: printf(" multiheld"); break;
+ case 4: printf(" multiexcept"); break;
+ case 5: printf(" multiinside"); break;
+ case 6: printf(" creature"); break;
+ case 7: printf(" special"); break;
+ case 8: printf(" number"); break;
+ case 9: printf(" topic"); break;
+ default: printf(" ???"); break;
+ }
+ break;
+ case 2:
+ printf(" '");
+ print_dict_word(tokdat);
+ printf("'");
+ break;
+ case 3:
+ printf(" noun=%d", tokdat);
+ break;
+ case 4:
+ printf(" attr=%d", tokdat);
+ break;
+ case 5:
+ printf(" scope=%d", tokdat);
+ break;
+ case 6:
+ printf(" routine=%d", tokdat);
+ break;
+ default:
+ printf(" ???%d:%d", toktype, tokdat);
+ break;
+ }
+ }
+ printf(" -> ");
+ actsym = actions[action].symbol;
+ str = (symbols[actsym].name);
+ len = strlen(str) - 3; /* remove "__A" */
+ for (ix=0; ix<len; ix++) putchar(str[ix]);
+ if (flags) printf(" (reversed)");
+ printf("\n");
+}
+
extern void list_verb_table(void)
-{ int i;
- for (i=0; i<no_Inform_verbs; i++)
- printf("Verb %2d has %d lines\n", i, Inform_verbs[i].lines);
+{
+ int verb, lx;
+ printf("Grammar table: %d verbs\n", no_Inform_verbs);
+ for (verb=0; verb<no_Inform_verbs; verb++) {
+ char *verbword = find_verb_by_number(verb);
+ printf("Verb '%s'\n", verbword);
+ for (lx=0; lx<Inform_verbs[verb].lines; lx++) {
+ int mark = Inform_verbs[verb].l[lx];
+ switch (grammar_version_number) {
+ case 1:
+ list_grammar_line_v1(mark);
+ break;
+ case 2:
+ list_grammar_line_v2(mark);
+ break;
+ }
+ }
+ }
}
/* ------------------------------------------------------------------------- */
by using make_action above, or the Fake_Action directive, or by
the linker). At present just a hook for some tracing code. */
- if (printprops_switch)
+ if (printactions_switch)
printf("Action '%s' is numbered %d\n",b,c);
}
snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", token_text);
i = symbol_index(action_sub, -1);
- if (!(sflags[i] & UNKNOWN_SFLAG))
+ if (!(symbols[i].flags & UNKNOWN_SFLAG))
{ discard_token_location(beginning_debug_location);
/* The user didn't know they were defining FOO__A, but they were and it's a problem. */
- ebf_symbol_error("new fake action name", action_sub, typename(stypes[i]), slines[i]);
+ ebf_symbol_error("new fake action name", action_sub, typename(symbols[i].type), symbols[i].line);
panic_mode_error_recovery(); return;
}
if (debugfile_switch)
{ debug_file_printf("<fake-action>");
debug_file_printf("<identifier>##%s</identifier>", token_text);
- debug_file_printf("<value>%d</value>", svals[i]);
+ debug_file_printf("<value>%d</value>", symbols[i].value);
get_next_token();
write_debug_locations
(get_token_location_end(beginning_debug_location));
snprintf(action_sub, MAX_IDENTIFIER_LENGTH+4, "%s__A", name);
j = symbol_index(action_sub, -1);
- if (stypes[j] == FAKE_ACTION_T)
+ if (symbols[j].type == FAKE_ACTION_T)
{ INITAO(&AO);
- AO.value = svals[j];
+ AO.value = symbols[j].value;
if (!glulx_mode)
AO.type = LONG_CONSTANT_OT;
else
set_constant_ot(&AO);
- sflags[j] |= USED_SFLAG;
+ symbols[j].flags |= USED_SFLAG;
return AO;
}
- if (sflags[j] & UNKNOWN_SFLAG)
+ if (symbols[j].flags & UNKNOWN_SFLAG)
{
- if (no_actions>=MAX_ACTIONS) memoryerror("MAX_ACTIONS",MAX_ACTIONS);
+ ensure_memory_list_available(&actions_memlist, no_actions+1);
new_action(name, no_actions);
- action_symbol[no_actions] = j;
+ actions[no_actions].symbol = j;
+ actions[no_actions].byte_offset = 0; /* fill in later */
assign_symbol(j, no_actions++, CONSTANT_T);
- sflags[j] |= ACTION_SFLAG;
+ symbols[j].flags |= ACTION_SFLAG;
}
- sflags[j] |= USED_SFLAG;
+ symbols[j].flags |= USED_SFLAG;
INITAO(&AO);
- AO.value = svals[j];
+ AO.value = symbols[j].value;
AO.marker = ACTION_MV;
if (!glulx_mode) {
AO.type = (module_switch)?LONG_CONSTANT_OT:SHORT_CONSTANT_OT;
- if (svals[j] >= 256) AO.type = LONG_CONSTANT_OT;
+ if (symbols[j].value >= 256) AO.type = LONG_CONSTANT_OT;
}
else {
AO.type = CONSTANT_OT;
char action_sub[MAX_IDENTIFIER_LENGTH+4];
if (module_switch)
- for (i=0; i<no_actions; i++) action_byte_offset[i] = 0;
+ for (i=0; i<no_actions; i++) actions[i].byte_offset = 0;
else
for (i=0; i<no_actions; i++)
- { strcpy(action_name, (char *) symbs[action_symbol[i]]);
+ { strcpy(action_name, symbols[actions[i].symbol].name);
action_name[strlen(action_name) - 3] = '\0'; /* remove "__A" */
strcpy(action_sub, action_name);
strcat(action_sub, "Sub");
j = symbol_index(action_sub, -1);
- if (sflags[j] & UNKNOWN_SFLAG)
+ if (symbols[j].flags & UNKNOWN_SFLAG)
{
- error_named_at("No ...Sub action routine found for action:", action_name, slines[action_symbol[i]]);
+ error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
}
else
- if (stypes[j] != ROUTINE_T)
+ if (symbols[j].type != ROUTINE_T)
{
- error_named_at("No ...Sub action routine found for action:", action_name, slines[action_symbol[i]]);
- error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, slines[j]);
+ error_named_at("No ...Sub action routine found for action:", action_name, symbols[actions[i].symbol].line);
+ error_named_at("-- ...Sub symbol found, but not a routine:", action_sub, symbols[j].line);
}
else
- { action_byte_offset[i] = svals[j];
- sflags[j] |= USED_SFLAG;
+ { actions[i].byte_offset = symbols[j].value;
+ symbols[j].flags |= USED_SFLAG;
}
}
}
int i;
uchar new_sort_code[MAX_DICT_WORD_BYTES];
- if (no_adjectives >= MAX_ADJECTIVES)
- memoryerror("MAX_ADJECTIVES", MAX_ADJECTIVES);
+ if (no_adjectives >= 255) {
+ error("Grammar version 1 cannot support more than 255 prepositions");
+ return 0;
+ }
+ if (ZCODE_LESS_DICT_DATA && !glulx_mode) {
+ /* We need to use #dict_par3 for the preposition number. */
+ error("Grammar version 1 cannot be used with ZCODE_LESS_DICT_DATA");
+ return 0;
+ }
+ ensure_memory_list_available(&adjectives_memlist, no_adjectives+1);
+ ensure_memory_list_available(&adjective_sort_code_memlist, (no_adjectives+1) * DICT_WORD_BYTES);
dictionary_prepare(English_word, new_sort_code);
for (i=0; i<no_adjectives; i++)
if (grammar_token_routine[l] == routine_address)
return l;
- grammar_token_routine[l] = routine_address;
+ ensure_memory_list_available(&grammar_token_routine_memlist, no_grammar_token_routines+1);
+
+ grammar_token_routine[no_grammar_token_routines] = routine_address;
return(no_grammar_token_routines++);
}
char *p;
p=English_verb_list;
- while (p < English_verb_list_top)
+ while (p < English_verb_list+English_verb_list_size)
{ if (strcmp(English_verb, p+3) == 0)
{ if (new_number)
{ p[1] = (*new_number)/256;
return(-1);
}
+static char *find_verb_by_number(int num)
+{
+ /* Find the English verb string with the given verb number. */
+ char *p;
+ p=English_verb_list;
+ while (p < English_verb_list+English_verb_list_size)
+ {
+ int val = (p[1] << 8) | p[2];
+ if (val == num) {
+ return p+3;
+ }
+ p=p+(uchar)p[0];
+ }
+ return "???";
+}
+
static void register_verb(char *English_verb, int number)
{
/* Registers a new English verb as referring to the given Inform-verb
number. (See comments above for format of the list.) */
+ char *top;
int entrysize;
if (find_or_renumber_verb(English_verb, NULL) != -1)
entrysize = strlen(English_verb)+4;
if (entrysize > MAX_VERB_WORD_SIZE+4)
error_numbered("Verb word is too long -- max length is", MAX_VERB_WORD_SIZE);
+ ensure_memory_list_available(&English_verb_list_memlist, English_verb_list_size + entrysize);
+ top = English_verb_list + English_verb_list_size;
English_verb_list_size += entrysize;
- if (English_verb_list_size >= MAX_VERBSPACE)
- memoryerror("MAX_VERBSPACE", MAX_VERBSPACE);
-
- English_verb_list_top[0] = entrysize;
- English_verb_list_top[1] = number/256;
- English_verb_list_top[2] = number%256;
- strcpy(English_verb_list_top+3, English_verb);
- English_verb_list_top += entrysize;
+
+ top[0] = entrysize;
+ top[1] = number/256;
+ top[2] = number%256;
+ strcpy(top+3, English_verb);
}
static int get_verb(void)
/* Grammar lines for Verb/Extend directives. */
/* ------------------------------------------------------------------------- */
+static void ensure_grammar_lines_available(int verbnum, int num)
+{
+ /* Note that the size field always starts positive. */
+ if (num > Inform_verbs[verbnum].size) {
+ int newsize = 2*num+4;
+ my_realloc(&Inform_verbs[verbnum].l, sizeof(int) * Inform_verbs[verbnum].size, sizeof(int) * newsize, "grammar lines for one verb");
+ Inform_verbs[verbnum].size = newsize;
+ }
+}
+
static int grammar_line(int verbnum, int line)
{
- /* Parse a grammar line, to be written into grammar_lines[mark] onward.
+ /* Parse a grammar line, to be written into grammar_lines[] starting
+ at grammar_lines_top. grammar_lines_top is left at the end
+ of the new line.
+
+ This stores the line position in Inform_verbs[verbnum].l[line].
+ (It does not increment Inform_verbs[verbnum].lines; the caller
+ must do that.)
Syntax: * <token1> ... <token-n> -> <action>
return FALSE;
}
- /* Have we run out of lines or token space? */
-
- if (line >= MAX_LINES_PER_VERB)
- { discard_token_location(beginning_debug_location);
- error("Too many lines of grammar for verb. This maximum is built \
-into Inform, so suggest rewriting grammar using general parsing routines");
- return(FALSE);
- }
-
- /* Internally, a line can be up to 3*32 + 1 + 2 = 99 bytes long */
- /* In Glulx, that's 5*32 + 4 = 164 bytes */
-
mark = grammar_lines_top;
- if (!glulx_mode) {
- if (mark + 100 >= MAX_LINESPACE)
- { discard_token_location(beginning_debug_location);
- memoryerror("MAX_LINESPACE", MAX_LINESPACE);
- }
- }
- else {
- if (mark + 165 >= MAX_LINESPACE)
- { discard_token_location(beginning_debug_location);
- memoryerror("MAX_LINESPACE", MAX_LINESPACE);
- }
- }
+ ensure_grammar_lines_available(verbnum, line+1);
Inform_verbs[verbnum].l[line] = mark;
if (!glulx_mode) {
mark = mark + 3;
TOKEN_SIZE = 5;
}
+ ensure_memory_list_available(&grammar_lines_memlist, mark);
grammar_token = 0; last_was_slash = TRUE; slash_mode = FALSE;
no_grammar_lines++;
get_next_token();
if ((token_type != SYMBOL_TT)
- || (stypes[token_value] != ROUTINE_T))
+ || (symbols[token_value].type != ROUTINE_T))
{ discard_token_location(beginning_debug_location);
ebf_error("routine name after 'noun='", token_text);
panic_mode_error_recovery();
}
if (grammar_version_number == 1)
bytecode
- = 16 + make_parsing_routine(svals[token_value]);
+ = 16 + make_parsing_routine(symbols[token_value].value);
else
{ bytecode = 0x83;
- wordcode = svals[token_value];
+ wordcode = symbols[token_value].value;
}
- sflags[token_value] |= USED_SFLAG;
+ symbols[token_value].flags |= USED_SFLAG;
}
else
{ put_token_back();
get_next_token();
if ((token_type != SYMBOL_TT)
- || (stypes[token_value] != ROUTINE_T))
+ || (symbols[token_value].type != ROUTINE_T))
{ discard_token_location(beginning_debug_location);
ebf_error("routine name after 'scope='", token_text);
panic_mode_error_recovery();
if (grammar_version_number == 1)
bytecode = 80 +
- make_parsing_routine(svals[token_value]);
- else { bytecode = 0x85; wordcode = svals[token_value]; }
- sflags[token_value] |= USED_SFLAG;
+ make_parsing_routine(symbols[token_value].value);
+ else { bytecode = 0x85; wordcode = symbols[token_value].value; }
+ symbols[token_value].flags |= USED_SFLAG;
}
else if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
{ discard_token_location(beginning_debug_location);
else { /* <attribute> or <general-parsing-routine> tokens */
if ((token_type != SYMBOL_TT)
- || ((stypes[token_value] != ATTRIBUTE_T)
- && (stypes[token_value] != ROUTINE_T)))
+ || ((symbols[token_value].type != ATTRIBUTE_T)
+ && (symbols[token_value].type != ROUTINE_T)))
{ discard_token_location(beginning_debug_location);
error_named("No such grammar token as", token_text);
panic_mode_error_recovery();
return FALSE;
}
- if (stypes[token_value]==ATTRIBUTE_T)
+ if (symbols[token_value].type==ATTRIBUTE_T)
{ if (grammar_version_number == 1)
- bytecode = 128 + svals[token_value];
- else { bytecode = 4; wordcode = svals[token_value]; }
+ bytecode = 128 + symbols[token_value].value;
+ else { bytecode = 4; wordcode = symbols[token_value].value; }
}
else
{ if (grammar_version_number == 1)
bytecode = 48 +
- make_parsing_routine(svals[token_value]);
- else { bytecode = 0x86; wordcode = svals[token_value]; }
+ make_parsing_routine(symbols[token_value].value);
+ else { bytecode = 0x86; wordcode = symbols[token_value].value; }
}
- sflags[token_value] |= USED_SFLAG;
+ symbols[token_value].flags |= USED_SFLAG;
}
grammar_token++; no_grammar_tokens++;
error("'/' can only be applied to prepositions");
bytecode |= 0x10;
}
+ ensure_memory_list_available(&grammar_lines_memlist, mark+5);
grammar_lines[mark++] = bytecode;
if (!glulx_mode) {
grammar_lines[mark++] = wordcode/256;
} while (TRUE);
+ ensure_memory_list_available(&grammar_lines_memlist, mark+1);
grammar_lines[mark++] = 15;
grammar_lines_top = mark;
debug_file_printf("</table-entry>");
}
+ ensure_memory_list_available(&grammar_lines_memlist, mark+3);
if (!glulx_mode) {
if (reverse_action)
j = j + 0x400;
int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE;
- char *English_verbs_given[MAX_VERB_SYNONYMS];
- int no_given = 0, i;
+ int no_given = 0, verbs_given_pos = 0;
+ int i, pos;
directive_keywords.enabled = TRUE;
while ((token_type == DQ_TT) || (token_type == SQ_TT))
{
- if (no_given >= MAX_VERB_SYNONYMS) {
- error("Too many synonyms in a Verb directive.");
- panic_mode_error_recovery(); return;
- }
- English_verbs_given[no_given++] = token_text;
+ int len = strlen(token_text) + 1;
+ ensure_memory_list_available(&English_verbs_given_memlist, verbs_given_pos + len);
+ strcpy(English_verbs_given+verbs_given_pos, token_text);
+ verbs_given_pos += len;
+ no_given++;
get_next_token();
}
ebf_error("';' after English verb", token_text);
}
else
- { Inform_verb = no_Inform_verbs;
- if (no_Inform_verbs == MAX_VERBS)
- memoryerror("MAX_VERBS",MAX_VERBS);
+ { verb_equals_form = FALSE;
+ if (!glulx_mode && no_Inform_verbs >= 255) {
+ error("Z-code is limited to 255 verbs.");
+ panic_mode_error_recovery(); return;
+ }
+ ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
+ Inform_verb = no_Inform_verbs;
+ Inform_verbs[no_Inform_verbs].lines = 0;
+ Inform_verbs[no_Inform_verbs].size = 4;
+ Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
}
- for (i=0; i<no_given; i++)
- { dictionary_add(English_verbs_given[i],
+ for (i=0, pos=0; i<no_given; i++) {
+ char *wd = English_verbs_given+pos;
+ dictionary_add(wd,
0x41 + ((meta_verb_flag)?0x02:0x00),
(glulx_mode)?(0xffff-Inform_verb):(0xff-Inform_verb), 0);
- register_verb(English_verbs_given[i], Inform_verb);
+ register_verb(wd, Inform_verb);
+ pos += (strlen(wd) + 1);
}
if (!verb_equals_form)
get_next_token();
if ((token_type == DIR_KEYWORD_TT) && (token_value == ONLY_DK))
- { l = -1;
- if (no_Inform_verbs == MAX_VERBS)
- memoryerror("MAX_VERBS", MAX_VERBS);
+ {
+ if (!glulx_mode && no_Inform_verbs >= 255) {
+ error("Z-code is limited to 255 verbs.");
+ panic_mode_error_recovery(); return;
+ }
+ ensure_memory_list_available(&Inform_verbs_memlist, no_Inform_verbs+1);
+ l = -1;
while (get_next_token(),
((token_type == DQ_TT) || (token_type == SQ_TT)))
{ Inform_verb = get_verb();
/* Copy the old Inform-verb into a new one which the list of
English-verbs given have had their dictionary entries modified
to point to */
+ /* (We are copying entry Inform_verb to no_Inform_verbs here.) */
- Inform_verbs[no_Inform_verbs] = Inform_verbs[Inform_verb];
+ l = Inform_verbs[Inform_verb].lines; /* number of lines to copy */
+
+ Inform_verbs[no_Inform_verbs].lines = l;
+ Inform_verbs[no_Inform_verbs].size = l+4;
+ Inform_verbs[no_Inform_verbs].l = my_malloc(sizeof(int) * Inform_verbs[no_Inform_verbs].size, "grammar lines for one verb");
+ for (k=0; k<l; k++)
+ Inform_verbs[no_Inform_verbs].l[k] = Inform_verbs[Inform_verb].l[k];
Inform_verb = no_Inform_verbs++;
}
else
lines = 0;
if (extend_mode == EXTEND_LAST) lines=l;
do
- { if (extend_mode == EXTEND_FIRST)
+ {
+ if (extend_mode == EXTEND_FIRST) {
+ ensure_grammar_lines_available(Inform_verb, l+lines+1);
for (k=l; k>0; k--)
Inform_verbs[Inform_verb].l[k+lines]
= Inform_verbs[Inform_verb].l[k-1+lines];
+ }
} while (grammar_line(Inform_verb, lines++));
if (extend_mode == EXTEND_FIRST)
- { Inform_verbs[Inform_verb].lines = l+lines-1;
- for (k=0; k<l; k++)
+ {
+ ensure_grammar_lines_available(Inform_verb, l+lines+1);
+ Inform_verbs[Inform_verb].lines = l+lines-1;
+ for (k=0; k<l; k++) {
Inform_verbs[Inform_verb].l[k+lines-1]
= Inform_verbs[Inform_verb].l[k+lines];
+ }
}
else Inform_verbs[Inform_verb].lines = --lines;
English_verb_list_size = 0;
Inform_verbs = NULL;
- action_byte_offset = NULL;
+ actions = NULL;
+ grammar_lines = NULL;
grammar_token_routine = NULL;
adjectives = NULL;
adjective_sort_code = NULL;
English_verb_list = NULL;
+ English_verbs_given = NULL;
if (!glulx_mode)
grammar_version_number = 1;
extern void verbs_allocate_arrays(void)
{
- Inform_verbs = my_calloc(sizeof(verbt), MAX_VERBS, "verbs");
- grammar_lines = my_malloc(MAX_LINESPACE, "grammar lines");
- action_byte_offset = my_calloc(sizeof(int32), MAX_ACTIONS, "actions");
- action_symbol = my_calloc(sizeof(int32), MAX_ACTIONS,
- "action symbols");
- grammar_token_routine = my_calloc(sizeof(int32), MAX_ACTIONS,
- "grammar token routines");
- adjectives = my_calloc(sizeof(int32), MAX_ADJECTIVES,
- "adjectives");
- adjective_sort_code = my_calloc(DICT_WORD_BYTES, MAX_ADJECTIVES,
- "adjective sort codes");
-
- English_verb_list = my_malloc(MAX_VERBSPACE, "register of verbs");
- English_verb_list_top = English_verb_list;
+ initialise_memory_list(&Inform_verbs_memlist,
+ sizeof(verbt), 128, (void**)&Inform_verbs,
+ "verbs");
+
+ initialise_memory_list(&grammar_lines_memlist,
+ sizeof(uchar), 4000, (void**)&grammar_lines,
+ "grammar lines");
+
+ initialise_memory_list(&actions_memlist,
+ sizeof(actioninfo), 128, (void**)&actions,
+ "actions");
+
+ initialise_memory_list(&grammar_token_routine_memlist,
+ sizeof(int32), 50, (void**)&grammar_token_routine,
+ "grammar token routines");
+
+ initialise_memory_list(&adjectives_memlist,
+ sizeof(int32), 50, (void**)&adjectives,
+ "adjectives");
+ initialise_memory_list(&adjective_sort_code_memlist,
+ sizeof(uchar), 50*DICT_WORD_BYTES, (void**)&adjective_sort_code,
+ "adjective sort codes");
+
+ initialise_memory_list(&English_verb_list_memlist,
+ sizeof(char), 2048, (void**)&English_verb_list,
+ "register of verbs");
+
+ initialise_memory_list(&English_verbs_given_memlist,
+ sizeof(char), 80, (void**)&English_verbs_given,
+ "verb words within a single definition");
}
extern void verbs_free_arrays(void)
{
- my_free(&Inform_verbs, "verbs");
- my_free(&grammar_lines, "grammar lines");
- my_free(&action_byte_offset, "actions");
- my_free(&action_symbol, "action symbols");
- my_free(&grammar_token_routine, "grammar token routines");
- my_free(&adjectives, "adjectives");
- my_free(&adjective_sort_code, "adjective sort codes");
- my_free(&English_verb_list, "register of verbs");
+ int ix;
+ for (ix=0; ix<no_Inform_verbs; ix++)
+ {
+ my_free(&Inform_verbs[ix].l, "grammar lines for one verb");
+ }
+ deallocate_memory_list(&Inform_verbs_memlist);
+ deallocate_memory_list(&grammar_lines_memlist);
+ deallocate_memory_list(&actions_memlist);
+ deallocate_memory_list(&grammar_token_routine_memlist);
+ deallocate_memory_list(&adjectives_memlist);
+ deallocate_memory_list(&adjective_sort_code_memlist);
+ deallocate_memory_list(&English_verb_list_memlist);
+ deallocate_memory_list(&English_verbs_given_memlist);
}
/* ========================================================================= */