1 /* ------------------------------------------------------------------------- */
2 /* "objects" : [1] the object-maker, which constructs objects and enters */
3 /* them into the tree, given a low-level specification; */
5 /* [2] the parser of Object/Nearby/Class directives, which */
6 /* checks syntax and translates such directives into */
7 /* specifications for the object-maker. */
9 /* Part of Inform 6.42 */
10 /* copyright (c) Graham Nelson 1993 - 2024 */
12 /* Inform is free software: you can redistribute it and/or modify */
13 /* it under the terms of the GNU General Public License as published by */
14 /* the Free Software Foundation, either version 3 of the License, or */
15 /* (at your option) any later version. */
17 /* Inform is distributed in the hope that it will be useful, */
18 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
19 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
20 /* GNU General Public License for more details. */
22 /* You should have received a copy of the GNU General Public License */
23 /* along with Inform. If not, see https://gnu.org/licenses/ */
25 /* ------------------------------------------------------------------------- */
29 /* ------------------------------------------------------------------------- */
31 /* ------------------------------------------------------------------------- */
33 int no_objects; /* Number of objects made so far */
35 static int no_embedded_routines; /* Used for naming routines which
36 are given as property values: these
37 are called EmbeddedRoutine__1, ... */
39 static fpropt full_object; /* "fpropt" is a typedef for a struct
40 containing an array to hold the
41 attribute and property values of
42 a single object. We only keep one
43 of these, for the current object
44 being made, and compile it into
45 Z-machine tables when each object
46 definition is complete, since
47 sizeof(fpropt) is about 6200 bytes */
48 static fproptg full_object_g; /* Equivalent for Glulx. This object
49 is very small, since the large arrays
50 are allocated dynamically as
53 static char *shortname_buffer; /* Text buffer to hold the short name
54 (which is read in first, but
55 written almost last) */
56 static memory_list shortname_buffer_memlist;
58 static int parent_of_this_obj;
60 static memory_list current_object_name; /* The name of the object currently
63 static int current_classname_symbol; /* The symbol index of the class
64 currently being defined.
65 For error-checking and printing
66 names of embedded routines only. */
68 static memory_list embedded_function_name; /* Temporary storage for inline
69 function name in property. */
71 /* ------------------------------------------------------------------------- */
73 /* ------------------------------------------------------------------------- */
74 /* Arrays defined below: */
76 /* classinfo class_info[] Object number and prop offset */
77 /* int classes_to_inherit_from[] The list of classes to inherit */
78 /* from as taken from the current */
79 /* Nearby/Object/Class definition */
80 /* ------------------------------------------------------------------------- */
82 int no_classes; /* Number of class defns made so far */
84 static int current_defn_is_class, /* TRUE if current Nearby/Object/Class
85 defn is in fact a Class definition */
86 no_classes_to_inherit_from; /* Number of classes in the list
87 of classes to inherit in the
88 current Nearby/Object/Class defn */
90 /* ------------------------------------------------------------------------- */
91 /* Making attributes and properties. */
92 /* ------------------------------------------------------------------------- */
94 int no_attributes, /* Number of attributes defined so far */
95 no_properties; /* Number of properties defined so far,
96 plus 1 (properties are numbered from
97 1 and Inform creates "name" and two
98 others itself, so the variable begins
99 the compilation pass set to 4) */
101 /* Print a PROPS trace line. The f flag is 0 for an attribute, 1 for
102 a common property, 2 for an individual property. */
103 static void trace_s(char *name, int32 number, int f)
105 if (!printprops_switch) return;
106 if (f == 0) stype = "Attr";
107 else if (f == 1) stype = "Prop";
108 else if (f == 2) stype = "Indiv";
109 printf("%-5s %02ld ", stype, (long int) number);
110 if (f != 1) printf(" ");
111 else printf("%s%s",(commonprops[number].is_long)?"L":" ",
112 (commonprops[number].is_additive)?"A":" ");
113 printf(" %-24s (%s)\n", name, current_location_text());
116 extern void make_attribute(void)
118 debug_location_beginning beginning_debug_location =
119 get_token_location_beginning();
122 if (no_attributes==((version_number==3)?32:48))
123 { discard_token_location(beginning_debug_location);
124 if (version_number==3)
125 error("All 32 attributes already declared (compile as Advanced \
126 game to get an extra 16)");
128 error("All 48 attributes already declared");
129 panic_mode_error_recovery();
135 if (no_attributes==NUM_ATTR_BYTES*8) {
136 discard_token_location(beginning_debug_location);
138 "All %d attributes already declared -- increase NUM_ATTR_BYTES to use \
141 panic_mode_error_recovery();
148 i = token_value; name = token_text;
149 /* We hold onto token_text through the end of this Property directive, which should be okay. */
150 if (token_type != SYMBOL_TT)
151 { discard_token_location(beginning_debug_location);
152 ebf_curtoken_error("new attribute name");
153 panic_mode_error_recovery();
157 if (!(symbols[i].flags & UNKNOWN_SFLAG))
158 { discard_token_location(beginning_debug_location);
159 ebf_symbol_error("new attribute name", token_text, typename(symbols[i].type), symbols[i].line);
160 panic_mode_error_recovery();
165 directive_keywords.enabled = TRUE;
167 directive_keywords.enabled = FALSE;
169 if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
171 if (!((token_type == SYMBOL_TT)
172 && (symbols[token_value].type == ATTRIBUTE_T)))
173 { discard_token_location(beginning_debug_location);
174 ebf_curtoken_error("an existing attribute name after 'alias'");
175 panic_mode_error_recovery();
179 assign_symbol(i, symbols[token_value].value, ATTRIBUTE_T);
180 symbols[token_value].flags |= ALIASED_SFLAG;
181 symbols[i].flags |= ALIASED_SFLAG;
184 { assign_symbol(i, no_attributes++, ATTRIBUTE_T);
188 if (debugfile_switch)
189 { debug_file_printf("<attribute>");
190 debug_file_printf("<identifier>%s</identifier>", name);
191 debug_file_printf("<value>%d</value>", symbols[i].value);
192 write_debug_locations(get_token_location_end(beginning_debug_location));
193 debug_file_printf("</attribute>");
196 trace_s(name, symbols[i].value, 0);
201 Property [long] [additive] name
202 Property [long] [additive] name alias oldname
203 Property [long] [additive] name defaultvalue
204 Property [long] individual name
206 extern void make_property(void)
207 { int32 default_value, i;
208 int keywords, prevkeywords;
211 int additive_flag, indiv_flag;
212 debug_location_beginning beginning_debug_location =
213 get_token_location_beginning();
215 /* The next bit is tricky. We want to accept any number of the keywords
216 "long", "additive", "individual" before the property name. But we
217 also want to accept "Property long" -- that's a legitimate
219 The solution is to keep track of which keywords we've seen in
220 a bitmask, and another for one token previous. That way we
221 can back up one token if there's no name visible. */
222 keywords = prevkeywords = 0;
224 { directive_keywords.enabled = TRUE;
226 if ((token_type == DIR_KEYWORD_TT) && (token_value == LONG_DK)) {
227 prevkeywords = keywords;
230 else if ((token_type == DIR_KEYWORD_TT) && (token_value == ADDITIVE_DK)) {
231 prevkeywords = keywords;
234 else if ((token_type == DIR_KEYWORD_TT) && (token_value == INDIVIDUAL_DK)) {
235 prevkeywords = keywords;
243 /* Re-parse the name with keywords turned off. (This allows us to
244 accept a property name like "table".) */
246 directive_keywords.enabled = FALSE;
249 if (token_type != SYMBOL_TT && keywords) {
250 /* This can't be a name. Try putting back the last keyword. */
251 keywords = prevkeywords;
257 additive_flag = indiv_flag = FALSE;
259 obsolete_warning("all properties are now automatically 'long'");
261 additive_flag = TRUE;
265 i = token_value; name = token_text;
266 /* We hold onto token_text through the end of this Property directive, which should be okay. */
267 if (token_type != SYMBOL_TT)
268 { discard_token_location(beginning_debug_location);
269 ebf_curtoken_error("new property name");
270 panic_mode_error_recovery();
274 if (!(symbols[i].flags & UNKNOWN_SFLAG))
275 { discard_token_location(beginning_debug_location);
276 ebf_symbol_error("new property name", token_text, typename(symbols[i].type), symbols[i].line);
277 panic_mode_error_recovery();
283 int this_identifier_number;
286 { error("'individual' incompatible with 'additive'");
287 panic_mode_error_recovery();
292 this_identifier_number = no_individual_properties++;
293 assign_symbol(i, this_identifier_number, INDIVIDUAL_PROPERTY_T);
294 if (debugfile_switch) {
295 debug_file_printf("<property>");
297 ("<identifier>%s</identifier>", name);
299 ("<value>%d</value>", this_identifier_number);
300 debug_file_printf("</property>");
302 trace_s(name, symbols[i].value, 2);
306 directive_keywords.enabled = TRUE;
308 directive_keywords.enabled = FALSE;
310 namelen = strlen(name);
311 if (namelen > 3 && strcmp(name+namelen-3, "_to") == 0) {
312 /* Direction common properties "n_to", etc are compared in some
313 libraries. They have STAR_SFLAG to tell us to skip a warning. */
314 symbols[i].flags |= STAR_SFLAG;
317 /* Now we might have "alias" or a default value (but not both). */
319 if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
320 { discard_token_location(beginning_debug_location);
322 { error("'alias' incompatible with 'additive'");
323 panic_mode_error_recovery();
328 if (!((token_type == SYMBOL_TT)
329 && (symbols[token_value].type == PROPERTY_T)))
330 { ebf_curtoken_error("an existing property name after 'alias'");
331 panic_mode_error_recovery();
336 assign_symbol(i, symbols[token_value].value, PROPERTY_T);
337 trace_s(name, symbols[i].value, 1);
338 symbols[token_value].flags |= ALIASED_SFLAG;
339 symbols[i].flags |= ALIASED_SFLAG;
343 /* We now know we're allocating a new common property. Make sure
346 if (no_properties==((version_number==3)?32:64))
347 { discard_token_location(beginning_debug_location);
348 /* The maximum listed here includes "name" but not the
349 unused zero value or the two hidden properties (class
350 inheritance and indiv table). */
351 if (version_number==3)
352 error("All 29 properties already declared (compile as \
353 Advanced game to get 32 more)");
355 error("All 61 properties already declared");
356 panic_mode_error_recovery();
362 if (no_properties==INDIV_PROP_START) {
363 discard_token_location(beginning_debug_location);
365 "All %d properties already declared (increase INDIV_PROP_START to get more)",
367 panic_mode_error_recovery();
376 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
378 assembly_operand AO = parse_expression(CONSTANT_CONTEXT);
379 default_value = AO.value;
381 backpatch_zmachine(AO.marker, PROP_DEFAULTS_ZA,
382 (no_properties-1) * WORDSIZE);
385 commonprops[no_properties].default_value = default_value;
386 commonprops[no_properties].is_long = TRUE;
387 commonprops[no_properties].is_additive = additive_flag;
389 assign_symbol(i, no_properties++, PROPERTY_T);
391 if (debugfile_switch)
392 { debug_file_printf("<property>");
393 debug_file_printf("<identifier>%s</identifier>", name);
394 debug_file_printf("<value>%d</value>", symbols[i].value);
395 write_debug_locations
396 (get_token_location_end(beginning_debug_location));
397 debug_file_printf("</property>");
400 trace_s(name, symbols[i].value, 1);
403 /* ------------------------------------------------------------------------- */
405 /* ------------------------------------------------------------------------- */
407 commonpropinfo *commonprops; /* Info about common properties
409 INDIV_PROP_START entries) */
411 uchar *properties_table; /* Holds the table of property values
412 (holding one block for each object
413 and coming immediately after the
414 object tree in Z-memory) */
415 memory_list properties_table_memlist;
416 int properties_table_size; /* Number of bytes in this table */
418 /* ------------------------------------------------------------------------- */
419 /* Individual properties */
421 /* Each new i.p. name is given a unique number. These numbers start from */
422 /* 72, since 0 is reserved as a null, 1 to 63 refer to common properties */
423 /* and 64 to 71 are kept for methods of the metaclass Class (for example, */
424 /* 64 is "create"). */
426 /* An object provides individual properties by having property 3 set to a */
427 /* non-zero value, which must be a byte address of a table in the form: */
429 /* <record-1> ... <record-n> 00 00 */
431 /* where a <record> looks like */
433 /* <identifier> <size> <up to 255 bytes of data> */
434 /* or <identifier + 0x8000> */
435 /* ----- 2 bytes ---------- 1 byte <size> number of bytes */
437 /* The <identifier> part is the number allocated to the name of what is */
438 /* being provided. The top bit of this word is set to indicate that */
439 /* although the individual property is being provided, it is provided */
440 /* only privately (so that it is inaccessible except to the object's own */
441 /* embedded routines). */
443 /* In Glulx: i-props are numbered from INDIV_PROP_START+8 up. And all */
444 /* properties, common and individual, are stored in the same table. */
445 /* ------------------------------------------------------------------------- */
447 int no_individual_properties; /* Actually equal to the next
448 identifier number to be allocated,
449 so this is initially 72 even though
450 none have been made yet. */
451 static int individual_prop_table_size; /* Size of the table of individual
452 properties so far for current obj */
453 uchar *individuals_table; /* Table of records, each being the
454 i.p. table for an object */
455 memory_list individuals_table_memlist;
456 int i_m; /* Write mark position in the above */
457 int individuals_length; /* Extent of individuals_table */
459 /* ------------------------------------------------------------------------- */
460 /* Arrays used by this file */
461 /* ------------------------------------------------------------------------- */
463 objecttz *objectsz; /* Allocated to no_objects; Z-code only */
464 memory_list objectsz_memlist;
465 objecttg *objectsg; /* Allocated to no_objects; Glulx only */
466 static memory_list objectsg_memlist;
467 uchar *objectatts; /* Allocated to no_objects; Glulx only */
468 static memory_list objectatts_memlist;
469 static int *classes_to_inherit_from; /* Allocated to no_classes_to_inherit_from */
470 static memory_list classes_to_inherit_from_memlist;
471 classinfo *class_info; /* Allocated up to no_classes */
472 memory_list class_info_memlist;
474 /* ------------------------------------------------------------------------- */
475 /* Tracing for compiler maintenance */
476 /* ------------------------------------------------------------------------- */
478 extern void list_object_tree(void)
480 printf("Object tree:\n");
481 printf("obj name par nxt chl:\n");
482 for (i=0; i<no_objects; i++) {
484 int sym = objectsz[i].symbol;
485 char *symname = ((sym > 0) ? symbols[sym].name : "...");
486 printf("%3d %-32s %3d %3d %3d\n",
488 objectsz[i].parent, objectsz[i].next, objectsz[i].child);
491 int sym = objectsg[i].symbol;
492 char *symname = ((sym > 0) ? symbols[sym].name : "...");
493 printf("%3d %-32s %3d %3d %3d\n",
495 objectsg[i].parent, objectsg[i].next, objectsg[i].child);
500 /* ------------------------------------------------------------------------- */
501 /* Object and class manufacture begins here. */
503 /* These definitions have headers (parsed far, far below) and a series */
504 /* of segments, introduced by keywords and optionally separated by commas. */
505 /* Each segment has its own parsing routine. Note that when errors are */
506 /* detected, parsing continues rather than being abandoned, which assists */
507 /* a little in "error recovery" (i.e. in stopping lots more errors being */
508 /* produced for essentially the same mistake). */
509 /* ------------------------------------------------------------------------- */
511 /* ========================================================================= */
512 /* [1] The object-maker: builds an object from a specification, viz.: */
515 /* shortname_buffer, */
516 /* parent_of_this_obj, */
517 /* current_defn_is_class (flag) */
518 /* classes_to_inherit_from[], no_classes_to_inherit_from, */
519 /* individual_prop_table_size (to date ) */
521 /* For efficiency's sake, the individual properties table has already been */
522 /* created (as far as possible, i.e., all except for inherited individual */
523 /* properties); unless the flag is clear, in which case the actual */
524 /* definition did not specify any individual properties. */
525 /* ========================================================================= */
526 /* Property inheritance from classes. */
527 /* ------------------------------------------------------------------------- */
529 static void property_inheritance_z(void)
531 /* Apply the property inheritance rules to full_object, which should
532 initially be complete (i.e., this routine takes place after the whole
533 Nearby/Object/Class definition has been parsed through).
535 On exit, full_object contains the final state of the properties to
538 int i, j, k, kmax, class, mark,
539 prop_number, prop_length, prop_in_current_defn;
540 uchar *class_prop_block;
544 for (class=0; class<no_classes_to_inherit_from; class++)
547 mark = class_info[classes_to_inherit_from[class] - 1].begins_at;
548 class_prop_block = (properties_table + mark);
550 while (class_prop_block[j]!=0)
551 { if (version_number == 3)
552 { prop_number = class_prop_block[j]%32;
553 prop_length = 1 + class_prop_block[j++]/32;
556 { prop_number = class_prop_block[j]%64;
557 prop_length = 1 + class_prop_block[j++]/64;
559 prop_length = class_prop_block[j++]%64;
562 /* So we now have property number prop_number present in the
563 property block for the class being read: its bytes are
565 class_prop_block[j, ..., j + prop_length - 1]
567 Question now is: is there already a value given in the
568 current definition under this property name? */
570 prop_in_current_defn = FALSE;
572 kmax = full_object.l;
574 fatalerror("More than 64 property entries in an object");
576 for (k=0; k<kmax; k++)
577 if (full_object.pp[k].num == prop_number)
578 { prop_in_current_defn = TRUE;
580 /* (Note that the built-in "name" property is additive) */
582 if ((prop_number==1) || (commonprops[prop_number].is_additive))
584 /* The additive case: we accumulate the class
585 property values onto the end of the full_object
588 for (i=full_object.pp[k].l;
589 i<full_object.pp[k].l+prop_length/2; i++)
592 { error("An additive property has inherited \
593 so many values that the list has overflowed the maximum 32 entries");
596 if ((version_number==3) && i >= 4)
597 { error("An additive property has inherited \
598 so many values that the list has overflowed the maximum 4 entries");
601 INITAOTV(&full_object.pp[k].ao[i], LONG_CONSTANT_OT, mark + j);
603 full_object.pp[k].ao[i].marker = INHERIT_MV;
605 full_object.pp[k].l += prop_length/2;
608 /* The ordinary case: the full_object property
609 values simply overrides the class definition,
610 so we skip over the values in the class table */
615 { int y, z, class_block_offset;
617 /* Property 3 holds the address of the table of
618 instance variables, so this is the case where
619 the object already has instance variables in its
620 own table but must inherit some more from the
623 class_block_offset = class_prop_block[j-2]*256
624 + class_prop_block[j-1];
626 z = class_block_offset;
627 while ((individuals_table[z]!=0)||(individuals_table[z+1]!=0))
628 { int already_present = FALSE, l;
629 for (l = full_object.pp[k].ao[0].value; l < i_m;
630 l = l + 3 + individuals_table[l + 2])
631 if (individuals_table[l] == individuals_table[z]
632 && individuals_table[l + 1] == individuals_table[z+1])
633 { already_present = TRUE; break;
635 if (already_present == FALSE)
637 ensure_memory_list_available(&individuals_table_memlist, i_m+3+individuals_table[z+2]);
638 individuals_table[i_m++] = individuals_table[z];
639 individuals_table[i_m++] = individuals_table[z+1];
640 individuals_table[i_m++] = individuals_table[z+2];
641 for (y=0;y < individuals_table[z+2]/2;y++)
642 { individuals_table[i_m++] = (z+3+y*2)/256;
643 individuals_table[i_m++] = (z+3+y*2)%256;
644 backpatch_zmachine(INHERIT_INDIV_MV,
645 INDIVIDUAL_PROP_ZA, i_m-2);
648 z += individuals_table[z+2] + 3;
650 individuals_length = i_m;
653 /* For efficiency we exit the loop now (this property
654 number has been dealt with) */
659 if (!prop_in_current_defn)
661 /* The case where the class defined a property which wasn't
662 defined at all in full_object: we copy out the data into
663 a new property added to full_object */
667 fatalerror("More than 64 property entries in an object");
668 full_object.pp[k].num = prop_number;
669 full_object.pp[k].l = prop_length/2;
670 for (i=0; i<prop_length/2; i++)
672 INITAOTV(&full_object.pp[k].ao[i], LONG_CONSTANT_OT, mark + j);
674 full_object.pp[k].ao[i].marker = INHERIT_MV;
678 { int y, z, class_block_offset;
680 /* Property 3 holds the address of the table of
681 instance variables, so this is the case where
682 the object had no instance variables of its own
683 but must inherit some more from the class */
685 if (individual_prop_table_size++ == 0)
686 { full_object.pp[k].num = 3;
687 full_object.pp[k].l = 1;
688 INITAOTV(&full_object.pp[k].ao[0], LONG_CONSTANT_OT, individuals_length);
689 full_object.pp[k].ao[0].marker = INDIVPT_MV;
690 i_m = individuals_length;
692 class_block_offset = class_prop_block[j-2]*256
693 + class_prop_block[j-1];
695 z = class_block_offset;
696 while ((individuals_table[z]!=0)||(individuals_table[z+1]!=0))
698 ensure_memory_list_available(&individuals_table_memlist, i_m+3+individuals_table[z+2]);
699 individuals_table[i_m++] = individuals_table[z];
700 individuals_table[i_m++] = individuals_table[z+1];
701 individuals_table[i_m++] = individuals_table[z+2];
702 for (y=0;y < individuals_table[z+2]/2;y++)
703 { individuals_table[i_m++] = (z+3+y*2)/256;
704 individuals_table[i_m++] = (z+3+y*2)%256;
705 backpatch_zmachine(INHERIT_INDIV_MV,
706 INDIVIDUAL_PROP_ZA, i_m-2);
708 z += individuals_table[z+2] + 3;
710 individuals_length = i_m;
716 if (individual_prop_table_size > 0)
718 ensure_memory_list_available(&individuals_table_memlist, i_m+2);
720 individuals_table[i_m++] = 0;
721 individuals_table[i_m++] = 0;
722 individuals_length += 2;
726 static void property_inheritance_g(void)
728 /* Apply the property inheritance rules to full_object, which should
729 initially be complete (i.e., this routine takes place after the whole
730 Nearby/Object/Class definition has been parsed through).
732 On exit, full_object contains the final state of the properties to
735 int i, j, k, class, num_props,
736 prop_number, prop_length, prop_flags, prop_in_current_defn;
737 int32 mark, prop_addr;
742 for (class=0; class<no_classes_to_inherit_from; class++) {
743 mark = class_info[classes_to_inherit_from[class] - 1].begins_at;
744 cpb = (properties_table + mark);
745 /* This now points to the compiled property-table for the class.
746 We'll have to go through and decompile it. (For our sins.) */
747 num_props = ReadInt32(cpb);
748 for (j=0; j<num_props; j++) {
750 prop_number = ReadInt16(pe);
752 prop_length = ReadInt16(pe);
754 prop_addr = ReadInt32(pe);
756 prop_flags = ReadInt16(pe);
759 /* So we now have property number prop_number present in the
760 property block for the class being read. Its bytes are
761 cpb[prop_addr ... prop_addr + prop_length - 1]
762 Question now is: is there already a value given in the
763 current definition under this property name? */
765 prop_in_current_defn = FALSE;
767 for (k=0; k<full_object_g.numprops; k++) {
768 if (full_object_g.props[k].num == prop_number) {
769 prop_in_current_defn = TRUE;
774 if (prop_in_current_defn) {
776 || (prop_number < INDIV_PROP_START
777 && commonprops[prop_number].is_additive)) {
778 /* The additive case: we accumulate the class
779 property values onto the end of the full_object
780 properties. Remember that k is still the index number
781 of the first prop-block matching our property number. */
783 if (full_object_g.props[k].continuation == 0) {
784 full_object_g.props[k].continuation = 1;
788 prevcont = full_object_g.props[k].continuation;
789 for (k++; k<full_object_g.numprops; k++) {
790 if (full_object_g.props[k].num == prop_number) {
791 prevcont = full_object_g.props[k].continuation;
795 k = full_object_g.numprops++;
796 ensure_memory_list_available(&full_object_g.props_memlist, k+1);
797 full_object_g.props[k].num = prop_number;
798 full_object_g.props[k].flags = 0;
799 full_object_g.props[k].datastart = full_object_g.propdatasize;
800 full_object_g.props[k].continuation = prevcont+1;
801 full_object_g.props[k].datalen = prop_length;
803 ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize + prop_length);
804 for (i=0; i<prop_length; i++) {
805 int ppos = full_object_g.propdatasize++;
806 INITAOTV(&full_object_g.propdata[ppos], CONSTANT_OT, prop_addr + 4*i);
807 full_object_g.propdata[ppos].marker = INHERIT_MV;
811 /* The ordinary case: the full_object_g property
812 values simply overrides the class definition,
813 so we skip over the values in the class table. */
817 /* The case where the class defined a property which wasn't
818 defined at all in full_object_g: we copy out the data into
819 a new property added to full_object_g. */
820 k = full_object_g.numprops++;
821 ensure_memory_list_available(&full_object_g.props_memlist, k+1);
822 full_object_g.props[k].num = prop_number;
823 full_object_g.props[k].flags = prop_flags;
824 full_object_g.props[k].datastart = full_object_g.propdatasize;
825 full_object_g.props[k].continuation = 0;
826 full_object_g.props[k].datalen = prop_length;
828 ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize + prop_length);
829 for (i=0; i<prop_length; i++) {
830 int ppos = full_object_g.propdatasize++;
831 INITAOTV(&full_object_g.propdata[ppos], CONSTANT_OT, prop_addr + 4*i);
832 full_object_g.propdata[ppos].marker = INHERIT_MV;
841 /* ------------------------------------------------------------------------- */
842 /* Construction of Z-machine-format property blocks. */
843 /* ------------------------------------------------------------------------- */
845 static int write_properties_between(int mark, int from, int to)
846 { int j, k, prop_number;
848 for (prop_number=to; prop_number>=from; prop_number--)
849 { for (j=0; j<full_object.l; j++)
850 { if ((full_object.pp[j].num == prop_number)
851 && (full_object.pp[j].l != 100))
853 int prop_length = 2*full_object.pp[j].l;
854 ensure_memory_list_available(&properties_table_memlist, mark+2+prop_length);
855 if (version_number == 3)
856 properties_table[mark++] = prop_number + (prop_length - 1)*32;
858 { switch(prop_length)
860 properties_table[mark++] = prop_number; break;
862 properties_table[mark++] = prop_number + 0x40; break;
864 properties_table[mark++] = prop_number + 0x80;
865 properties_table[mark++] = prop_length + 0x80; break;
869 for (k=0; k<full_object.pp[j].l; k++)
872 /* We catch this earlier, but we'll check again to avoid overflowing ao[] */
873 error("Too many values for Z-machine property");
876 if (full_object.pp[j].ao[k].marker != 0)
877 backpatch_zmachine(full_object.pp[j].ao[k].marker,
879 properties_table[mark++] = full_object.pp[j].ao[k].value/256;
880 properties_table[mark++] = full_object.pp[j].ao[k].value%256;
886 ensure_memory_list_available(&properties_table_memlist, mark+1);
887 properties_table[mark++]=0;
891 static int write_property_block_z(char *shortname)
893 /* Compile the (now complete) full_object properties into a
894 property-table block at "p" in Inform's memory.
895 "shortname" is the object's short name, if specified; otherwise
898 Return the number of bytes written to the block. */
900 int32 mark = properties_table_size, i;
902 /* printf("Object at %04x\n", mark); */
904 if (shortname != NULL)
906 /* The limit of 510 bytes, or 765 Z-characters, is a Z-spec limit. */
907 i = translate_text(510,shortname,STRCTX_OBJNAME);
909 error ("Short name of object exceeded 765 Z-characters");
912 ensure_memory_list_available(&properties_table_memlist, mark+1+i);
913 memcpy(properties_table + mark+1, translated_text, i);
914 properties_table[mark] = i/2;
917 if (current_defn_is_class)
918 { mark = write_properties_between(mark,3,3);
919 ensure_memory_list_available(&properties_table_memlist, mark+6);
921 properties_table[mark++] = full_object.atts[i];
922 ensure_memory_list_available(&class_info_memlist, no_classes+1);
923 class_info[no_classes++].begins_at = mark;
926 mark = write_properties_between(mark, 1, (version_number==3)?31:63);
928 i = mark - properties_table_size;
929 properties_table_size = mark;
934 static int gpropsort(void *ptr1, void *ptr2)
939 if (prop2->num == -1)
941 if (prop1->num == -1)
943 if (prop1->num < prop2->num)
945 if (prop1->num > prop2->num)
948 return (prop1->continuation - prop2->continuation);
951 static int32 write_property_block_g(void)
953 /* Compile the (now complete) full_object properties into a
954 property-table block at "p" in Inform's memory.
955 Return the number of bytes written to the block.
956 In Glulx, the shortname property isn't used here; it's already
957 been compiled into an ordinary string. */
960 int ix, jx, kx, totalprops;
961 int32 mark = properties_table_size;
964 if (current_defn_is_class) {
965 ensure_memory_list_available(&properties_table_memlist, mark+NUM_ATTR_BYTES);
966 for (i=0;i<NUM_ATTR_BYTES;i++)
967 properties_table[mark++] = full_object_g.atts[i];
968 ensure_memory_list_available(&class_info_memlist, no_classes+1);
969 class_info[no_classes++].begins_at = mark;
972 qsort(full_object_g.props, full_object_g.numprops, sizeof(propg),
973 (int (*)(const void *, const void *))(&gpropsort));
975 full_object_g.finalpropaddr = mark;
979 for (ix=0; ix<full_object_g.numprops; ix=jx) {
980 int propnum = full_object_g.props[ix].num;
984 jx<full_object_g.numprops && full_object_g.props[jx].num == propnum;
989 /* Write out the number of properties in this table. */
990 ensure_memory_list_available(&properties_table_memlist, mark+4);
991 WriteInt32(properties_table+mark, totalprops);
994 datamark = mark + 10*totalprops;
996 for (ix=0; ix<full_object_g.numprops; ix=jx) {
997 int propnum = full_object_g.props[ix].num;
998 int flags = full_object_g.props[ix].flags;
1000 int32 datamarkstart = datamark;
1004 jx<full_object_g.numprops && full_object_g.props[jx].num == propnum;
1006 int32 datastart = full_object_g.props[jx].datastart;
1007 ensure_memory_list_available(&properties_table_memlist, datamark+4*full_object_g.props[jx].datalen);
1008 for (kx=0; kx<full_object_g.props[jx].datalen; kx++) {
1009 int32 val = full_object_g.propdata[datastart+kx].value;
1010 WriteInt32(properties_table+datamark, val);
1011 if (full_object_g.propdata[datastart+kx].marker != 0)
1012 backpatch_zmachine(full_object_g.propdata[datastart+kx].marker,
1018 ensure_memory_list_available(&properties_table_memlist, mark+10);
1019 WriteInt16(properties_table+mark, propnum);
1021 WriteInt16(properties_table+mark, totallen);
1023 WriteInt32(properties_table+mark, datamarkstart);
1025 WriteInt16(properties_table+mark, flags);
1031 i = mark - properties_table_size;
1032 properties_table_size = mark;
1036 /* ------------------------------------------------------------------------- */
1037 /* The final stage in Nearby/Object/Class definition processing. */
1038 /* ------------------------------------------------------------------------- */
1040 static void manufacture_object_z(void)
1043 segment_markers.enabled = FALSE;
1044 directives.enabled = TRUE;
1046 ensure_memory_list_available(&objectsz_memlist, no_objects+1);
1048 objectsz[no_objects].symbol = full_object.symbol;
1050 property_inheritance_z();
1052 objectsz[no_objects].parent = parent_of_this_obj;
1053 objectsz[no_objects].next = 0;
1054 objectsz[no_objects].child = 0;
1056 if ((parent_of_this_obj > 0) && (parent_of_this_obj != 0x7fff))
1057 { i = objectsz[parent_of_this_obj-1].child;
1059 objectsz[parent_of_this_obj-1].child = no_objects + 1;
1061 { while(objectsz[i-1].next != 0) i = objectsz[i-1].next;
1062 objectsz[i-1].next = no_objects+1;
1066 /* The properties table consists simply of a sequence of property
1067 blocks, one for each object in order of definition, exactly as
1068 it will appear in the final Z-machine. */
1070 j = write_property_block_z(shortname_buffer);
1072 objectsz[no_objects].propsize = j;
1074 if (current_defn_is_class)
1075 for (i=0;i<6;i++) objectsz[no_objects].atts[i] = 0;
1078 objectsz[no_objects].atts[i] = full_object.atts[i];
1083 static void manufacture_object_g(void)
1086 segment_markers.enabled = FALSE;
1087 directives.enabled = TRUE;
1089 ensure_memory_list_available(&objectsg_memlist, no_objects+1);
1090 ensure_memory_list_available(&objectatts_memlist, no_objects+1);
1092 objectsg[no_objects].symbol = full_object_g.symbol;
1094 property_inheritance_g();
1096 objectsg[no_objects].parent = parent_of_this_obj;
1097 objectsg[no_objects].next = 0;
1098 objectsg[no_objects].child = 0;
1100 if ((parent_of_this_obj > 0) && (parent_of_this_obj != 0x7fffffff))
1101 { i = objectsg[parent_of_this_obj-1].child;
1103 objectsg[parent_of_this_obj-1].child = no_objects + 1;
1105 { while(objectsg[i-1].next != 0) i = objectsg[i-1].next;
1106 objectsg[i-1].next = no_objects+1;
1110 objectsg[no_objects].shortname = compile_string(shortname_buffer,
1113 /* The properties table consists simply of a sequence of property
1114 blocks, one for each object in order of definition, exactly as
1115 it will appear in the final machine image. */
1117 j = write_property_block_g();
1119 objectsg[no_objects].propaddr = full_object_g.finalpropaddr;
1121 objectsg[no_objects].propsize = j;
1123 if (current_defn_is_class)
1124 for (i=0;i<NUM_ATTR_BYTES;i++)
1125 objectatts[no_objects*NUM_ATTR_BYTES+i] = 0;
1127 for (i=0;i<NUM_ATTR_BYTES;i++)
1128 objectatts[no_objects*NUM_ATTR_BYTES+i] = full_object_g.atts[i];
1134 /* ========================================================================= */
1135 /* [2] The Object/Nearby/Class directives parser: translating the syntax */
1136 /* into object specifications and then triggering off the above. */
1137 /* ========================================================================= */
1138 /* Properties ("with" or "private") segment. */
1139 /* ------------------------------------------------------------------------- */
1141 static int *defined_this_segment;
1142 static long defined_this_segment_size; /* calloc size */
1145 static void ensure_defined_this_segment(int newsize)
1147 int oldsize = defined_this_segment_size;
1148 defined_this_segment_size = newsize;
1149 my_recalloc(&defined_this_segment, sizeof(int), oldsize,
1150 defined_this_segment_size, "defined this segment table");
1153 static void properties_segment_z(int this_segment)
1155 /* Parse through the "with" part of an object/class definition:
1157 <prop-1> <values...>, <prop-2> <values...>, ..., <prop-n> <values...>
1159 This routine also handles "private", with this_segment being equal
1160 to the token value for the introductory word ("private" or "with"). */
1163 int i, property_name_symbol, property_number=0, next_prop=0, length,
1164 individual_property, this_identifier_number;
1167 { get_next_token_with_directives();
1168 if ((token_type == SEGMENT_MARKER_TT)
1169 || (token_type == EOF_TT)
1170 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1171 { put_token_back(); return;
1174 if (token_type != SYMBOL_TT)
1175 { ebf_curtoken_error("property name");
1179 individual_property = (symbols[token_value].type != PROPERTY_T);
1181 if (individual_property)
1182 { if (symbols[token_value].flags & UNKNOWN_SFLAG)
1183 { this_identifier_number = no_individual_properties++;
1184 assign_symbol(token_value, this_identifier_number,
1185 INDIVIDUAL_PROPERTY_T);
1187 if (debugfile_switch)
1188 { debug_file_printf("<property>");
1190 ("<identifier>%s</identifier>", token_text);
1192 ("<value>%d</value>", this_identifier_number);
1193 debug_file_printf("</property>");
1196 trace_s(token_text, symbols[token_value].value, 2);
1199 { if (symbols[token_value].type==INDIVIDUAL_PROPERTY_T)
1200 this_identifier_number = symbols[token_value].value;
1202 { ebf_symbol_error("property name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
1207 if (def_t_s >= defined_this_segment_size)
1208 ensure_defined_this_segment(def_t_s*2);
1209 defined_this_segment[def_t_s++] = token_value;
1211 if (individual_prop_table_size++ == 0)
1213 int k=full_object.l++;
1215 fatalerror("More than 64 property entries in an object");
1216 full_object.pp[k].num = 3;
1217 full_object.pp[k].l = 1;
1218 INITAOTV(&full_object.pp[k].ao[0], LONG_CONSTANT_OT, individuals_length);
1219 full_object.pp[k].ao[0].marker = INDIVPT_MV;
1221 i_m = individuals_length;
1223 ensure_memory_list_available(&individuals_table_memlist, i_m+3);
1224 individuals_table[i_m] = this_identifier_number/256;
1225 if (this_segment == PRIVATE_SEGMENT)
1226 individuals_table[i_m] |= 0x80;
1227 individuals_table[i_m+1] = this_identifier_number%256;
1228 individuals_table[i_m+2] = 0;
1231 { if (symbols[token_value].flags & UNKNOWN_SFLAG)
1232 { error_named("No such property name as", token_text);
1235 if (this_segment == PRIVATE_SEGMENT)
1236 error_named("Property should be declared in 'with', \
1237 not 'private':", token_text);
1238 if (def_t_s >= defined_this_segment_size)
1239 ensure_defined_this_segment(def_t_s*2);
1240 defined_this_segment[def_t_s++] = token_value;
1241 property_number = symbols[token_value].value;
1243 next_prop=full_object.l++;
1244 if (next_prop >= 64)
1245 fatalerror("More than 64 property entries in an object");
1246 full_object.pp[next_prop].num = property_number;
1249 for (i=0; i<(def_t_s-1); i++)
1250 if (defined_this_segment[i] == token_value)
1251 { error_named("Property given twice in the same declaration:",
1252 symbols[token_value].name);
1255 if (symbols[defined_this_segment[i]].value == symbols[token_value].value)
1258 "Property given twice in the same declaration, because \
1259 the names \"%s\" and \"%s\" actually refer to the same property",
1260 symbols[defined_this_segment[i]].name,
1261 symbols[token_value].name);
1264 property_name_symbol = token_value;
1265 symbols[token_value].flags |= USED_SFLAG;
1269 { assembly_operand AO;
1270 get_next_token_with_directives();
1271 if ((token_type == EOF_TT)
1272 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1273 || ((token_type == SEP_TT) && (token_value == COMMA_SEP)))
1276 if (token_type == SEGMENT_MARKER_TT) { put_token_back(); break; }
1278 if ((!individual_property) && (property_number==1)
1279 && ((token_type != SQ_TT) || (strlen(token_text) <2 ))
1280 && (token_type != DQ_TT)
1282 warning ("'name' property should only contain dictionary words");
1284 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
1286 char *prefix, *sep, *sym;
1287 sym = symbols[property_name_symbol].name;
1288 if (current_defn_is_class)
1290 prefix = symbols[current_classname_symbol].name;
1295 prefix = current_object_name.data;
1298 ensure_memory_list_available(&embedded_function_name, strlen(prefix)+strlen(sep)+strlen(sym)+1);
1299 sprintf(embedded_function_name.data, "%s%s%s", prefix, sep, sym);
1301 /* parse_routine() releases lexer text! */
1302 AO.value = parse_routine(NULL, TRUE, embedded_function_name.data, FALSE, -1);
1303 AO.type = LONG_CONSTANT_OT;
1304 AO.marker = IROUTINE_MV;
1306 directives.enabled = FALSE;
1307 segment_markers.enabled = TRUE;
1309 statements.enabled = FALSE;
1310 misc_keywords.enabled = FALSE;
1311 local_variables.enabled = FALSE;
1312 system_functions.enabled = FALSE;
1313 conditions.enabled = FALSE;
1317 /* A special rule applies to values in double-quotes of the
1318 built-in property "name", which always has number 1: such
1319 property values are dictionary entries and not static
1322 if ((!individual_property) &&
1323 (property_number==1) && (token_type == DQ_TT))
1324 { AO.value = dictionary_add(token_text, 0x80, 0, 0);
1325 AO.type = LONG_CONSTANT_OT;
1326 AO.marker = DWORD_MV;
1331 if ((token_type == SYMBOL_TT)
1332 && (symbols[token_value].type==PROPERTY_T))
1334 /* This is not necessarily an error: it's possible
1335 to imagine a property whose value is a list
1336 of other properties to look up, but far more
1337 likely that a comma has been omitted in between
1338 two property blocks */
1341 "Missing ','? Property data seems to contain the property name",
1346 /* An ordinary value, then: */
1349 AO = parse_expression(ARRAY_CONTEXT);
1352 /* length is in bytes here, but we report the limit in words. */
1355 { error_named("Limit (of 32 values) exceeded for property",
1356 symbols[property_name_symbol].name);
1360 if ((version_number==3) && (!individual_property) && length == 8)
1361 { error_named("Limit (of 4 values) exceeded for property",
1362 symbols[property_name_symbol].name);
1366 if (individual_property)
1367 { if (AO.marker != 0)
1368 backpatch_zmachine(AO.marker, INDIVIDUAL_PROP_ZA,
1370 ensure_memory_list_available(&individuals_table_memlist, i_m+3+length+2);
1371 individuals_table[i_m+3+length++] = AO.value/256;
1372 individuals_table[i_m+3+length++] = AO.value%256;
1375 { full_object.pp[next_prop].ao[length/2] = AO;
1376 length = length + 2;
1381 /* People rarely do, but it is legal to declare a property without
1384 with name "fish", number, time_left;
1386 in which case the properties "number" and "time_left" are
1387 created as in effect variables and initialised to zero. */
1390 { if (individual_property)
1392 ensure_memory_list_available(&individuals_table_memlist, i_m+3+length+2);
1393 individuals_table[i_m+3+length++] = 0;
1394 individuals_table[i_m+3+length++] = 0;
1398 INITAOTV(&full_object.pp[next_prop].ao[0], LONG_CONSTANT_OT, 0);
1403 if (individual_property)
1405 ensure_memory_list_available(&individuals_table_memlist, individuals_length+length+3);
1406 individuals_table[i_m + 2] = length;
1407 individuals_length += length+3;
1408 i_m = individuals_length;
1411 full_object.pp[next_prop].l = length/2;
1413 if ((token_type == EOF_TT)
1414 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1415 { put_token_back(); return;
1422 static void properties_segment_g(int this_segment)
1424 /* Parse through the "with" part of an object/class definition:
1426 <prop-1> <values...>, <prop-2> <values...>, ..., <prop-n> <values...>
1428 This routine also handles "private", with this_segment being equal
1429 to the token value for the introductory word ("private" or "with"). */
1433 individual_property, this_identifier_number;
1434 int32 property_name_symbol, property_number, length;
1437 { get_next_token_with_directives();
1438 if ((token_type == SEGMENT_MARKER_TT)
1439 || (token_type == EOF_TT)
1440 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1441 { put_token_back(); return;
1444 if (token_type != SYMBOL_TT)
1445 { ebf_curtoken_error("property name");
1449 individual_property = (symbols[token_value].type != PROPERTY_T);
1451 if (individual_property)
1452 { if (symbols[token_value].flags & UNKNOWN_SFLAG)
1453 { this_identifier_number = no_individual_properties++;
1454 assign_symbol(token_value, this_identifier_number,
1455 INDIVIDUAL_PROPERTY_T);
1457 if (debugfile_switch)
1458 { debug_file_printf("<property>");
1460 ("<identifier>%s</identifier>", token_text);
1462 ("<value>%d</value>", this_identifier_number);
1463 debug_file_printf("</property>");
1466 trace_s(token_text, symbols[token_value].value, 2);
1469 { if (symbols[token_value].type==INDIVIDUAL_PROPERTY_T)
1470 this_identifier_number = symbols[token_value].value;
1472 { ebf_symbol_error("property name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
1477 if (def_t_s >= defined_this_segment_size)
1478 ensure_defined_this_segment(def_t_s*2);
1479 defined_this_segment[def_t_s++] = token_value;
1480 property_number = symbols[token_value].value;
1482 next_prop=full_object_g.numprops++;
1483 ensure_memory_list_available(&full_object_g.props_memlist, next_prop+1);
1484 full_object_g.props[next_prop].num = property_number;
1485 full_object_g.props[next_prop].flags =
1486 ((this_segment == PRIVATE_SEGMENT) ? 1 : 0);
1487 full_object_g.props[next_prop].datastart = full_object_g.propdatasize;
1488 full_object_g.props[next_prop].continuation = 0;
1489 full_object_g.props[next_prop].datalen = 0;
1492 { if (symbols[token_value].flags & UNKNOWN_SFLAG)
1493 { error_named("No such property name as", token_text);
1496 if (this_segment == PRIVATE_SEGMENT)
1497 error_named("Property should be declared in 'with', \
1498 not 'private':", token_text);
1500 if (def_t_s >= defined_this_segment_size)
1501 ensure_defined_this_segment(def_t_s*2);
1502 defined_this_segment[def_t_s++] = token_value;
1503 property_number = symbols[token_value].value;
1505 next_prop=full_object_g.numprops++;
1506 ensure_memory_list_available(&full_object_g.props_memlist, next_prop+1);
1507 full_object_g.props[next_prop].num = property_number;
1508 full_object_g.props[next_prop].flags = 0;
1509 full_object_g.props[next_prop].datastart = full_object_g.propdatasize;
1510 full_object_g.props[next_prop].continuation = 0;
1511 full_object_g.props[next_prop].datalen = 0;
1514 for (i=0; i<(def_t_s-1); i++)
1515 if (defined_this_segment[i] == token_value)
1516 { error_named("Property given twice in the same declaration:",
1517 symbols[token_value].name);
1520 if (symbols[defined_this_segment[i]].value == symbols[token_value].value)
1523 "Property given twice in the same declaration, because \
1524 the names \"%s\" and \"%s\" actually refer to the same property",
1525 symbols[defined_this_segment[i]].name,
1526 symbols[token_value].name);
1529 property_name_symbol = token_value;
1530 symbols[token_value].flags |= USED_SFLAG;
1534 { assembly_operand AO;
1535 get_next_token_with_directives();
1536 if ((token_type == EOF_TT)
1537 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1538 || ((token_type == SEP_TT) && (token_value == COMMA_SEP)))
1541 if (token_type == SEGMENT_MARKER_TT) { put_token_back(); break; }
1543 if ((!individual_property) && (property_number==1)
1544 && ((token_type != SQ_TT) || (strlen(token_text) <2 ))
1545 && (token_type != DQ_TT)
1547 warning ("'name' property should only contain dictionary words");
1549 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
1551 char *prefix, *sep, *sym;
1552 sym = symbols[property_name_symbol].name;
1553 if (current_defn_is_class)
1555 prefix = symbols[current_classname_symbol].name;
1560 prefix = current_object_name.data;
1563 ensure_memory_list_available(&embedded_function_name, strlen(prefix)+strlen(sep)+strlen(sym)+1);
1564 sprintf(embedded_function_name.data, "%s%s%s", prefix, sep, sym);
1566 INITAOT(&AO, CONSTANT_OT);
1567 /* parse_routine() releases lexer text! */
1568 AO.value = parse_routine(NULL, TRUE, embedded_function_name.data, FALSE, -1);
1569 AO.marker = IROUTINE_MV;
1571 directives.enabled = FALSE;
1572 segment_markers.enabled = TRUE;
1574 statements.enabled = FALSE;
1575 misc_keywords.enabled = FALSE;
1576 local_variables.enabled = FALSE;
1577 system_functions.enabled = FALSE;
1578 conditions.enabled = FALSE;
1582 /* A special rule applies to values in double-quotes of the
1583 built-in property "name", which always has number 1: such
1584 property values are dictionary entries and not static
1587 if ((!individual_property) &&
1588 (property_number==1) && (token_type == DQ_TT))
1589 { AO.value = dictionary_add(token_text, 0x80, 0, 0);
1590 AO.type = CONSTANT_OT;
1591 AO.marker = DWORD_MV;
1596 if ((token_type == SYMBOL_TT)
1597 && (symbols[token_value].type==PROPERTY_T))
1599 /* This is not necessarily an error: it's possible
1600 to imagine a property whose value is a list
1601 of other properties to look up, but far more
1602 likely that a comma has been omitted in between
1603 two property blocks */
1606 "Missing ','? Property data seems to contain the property name",
1611 /* An ordinary value, then: */
1614 AO = parse_expression(ARRAY_CONTEXT);
1617 if (length == 32768) /* VENEER_CONSTRAINT_ON_PROP_TABLE_SIZE? */
1618 { error_named("Limit (of 32768 values) exceeded for property",
1619 symbols[property_name_symbol].name);
1623 ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize+1);
1625 full_object_g.propdata[full_object_g.propdatasize++] = AO;
1630 /* People rarely do, but it is legal to declare a property without
1633 with name "fish", number, time_left;
1635 in which case the properties "number" and "time_left" are
1636 created as in effect variables and initialised to zero. */
1640 assembly_operand AO;
1641 INITAOTV(&AO, CONSTANT_OT, 0);
1642 ensure_memory_list_available(&full_object_g.propdata_memlist, full_object_g.propdatasize+1);
1643 full_object_g.propdata[full_object_g.propdatasize++] = AO;
1647 full_object_g.props[next_prop].datalen = length;
1649 if ((token_type == EOF_TT)
1650 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1651 { put_token_back(); return;
1657 static void properties_segment(int this_segment)
1660 properties_segment_z(this_segment);
1662 properties_segment_g(this_segment);
1665 /* ------------------------------------------------------------------------- */
1666 /* Attributes ("has") segment. */
1667 /* ------------------------------------------------------------------------- */
1669 static void attributes_segment(void)
1671 /* Parse through the "has" part of an object/class definition:
1673 [~]<attribute-1> [~]<attribute-2> ... [~]<attribute-n> */
1675 int attribute_number, truth_state, bitmask;
1678 { truth_state = TRUE;
1682 get_next_token_with_directives();
1683 if ((token_type == SEGMENT_MARKER_TT)
1684 || (token_type == EOF_TT)
1685 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1687 ebf_curtoken_error("attribute name after '~'");
1688 put_token_back(); return;
1690 if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) return;
1692 if ((token_type == SEP_TT) && (token_value == ARTNOT_SEP))
1693 { truth_state = !truth_state; goto ParseAttrN;
1696 if ((token_type != SYMBOL_TT)
1697 || (symbols[token_value].type != ATTRIBUTE_T))
1698 { ebf_curtoken_error("name of an already-declared attribute");
1702 attribute_number = symbols[token_value].value;
1703 symbols[token_value].flags |= USED_SFLAG;
1706 bitmask = (1 << (7-attribute_number%8));
1707 attrbyte = &(full_object.atts[attribute_number/8]);
1710 /* In Glulx, my prejudices rule, and therefore bits are numbered
1711 from least to most significant. This is the opposite of the
1712 way the Z-machine works. */
1713 bitmask = (1 << (attribute_number%8));
1714 attrbyte = &(full_object_g.atts[attribute_number/8]);
1718 *attrbyte |= bitmask; /* Set attribute bit */
1720 *attrbyte &= ~bitmask; /* Clear attribute bit */
1725 /* ------------------------------------------------------------------------- */
1726 /* Classes ("class") segment. */
1727 /* ------------------------------------------------------------------------- */
1729 static void add_class_to_inheritance_list(int class_number)
1733 /* The class number is actually the class's object number, which needs
1734 to be translated into its actual class number: */
1736 for (i=0;i<no_classes;i++)
1737 if (class_number == class_info[i].object_number)
1738 { class_number = i+1;
1742 /* Remember the inheritance list so that property inheritance can
1743 be sorted out later on, when the definition has been finished: */
1745 ensure_memory_list_available(&classes_to_inherit_from_memlist, no_classes_to_inherit_from+1);
1747 classes_to_inherit_from[no_classes_to_inherit_from++] = class_number;
1749 /* Inheriting attributes from the class at once: */
1754 |= properties_table[class_info[class_number-1].begins_at - 6 + i];
1757 for (i=0; i<NUM_ATTR_BYTES; i++)
1758 full_object_g.atts[i]
1759 |= properties_table[class_info[class_number-1].begins_at
1760 - NUM_ATTR_BYTES + i];
1764 static void classes_segment(void)
1766 /* Parse through the "class" part of an object/class definition:
1768 <class-1> ... <class-n> */
1771 { get_next_token_with_directives();
1772 if ((token_type == SEGMENT_MARKER_TT)
1773 || (token_type == EOF_TT)
1774 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1775 { put_token_back(); return;
1777 if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) return;
1779 if ((token_type != SYMBOL_TT)
1780 || (symbols[token_value].type != CLASS_T))
1781 { ebf_curtoken_error("name of an already-declared class");
1784 if (current_defn_is_class && token_value == current_classname_symbol)
1785 { error("A class cannot inherit from itself");
1789 symbols[token_value].flags |= USED_SFLAG;
1790 add_class_to_inheritance_list(symbols[token_value].value);
1794 /* ------------------------------------------------------------------------- */
1795 /* Parse the body of a Nearby/Object/Class definition. */
1796 /* ------------------------------------------------------------------------- */
1798 static void parse_body_of_definition(void)
1799 { int commas_in_row;
1804 { commas_in_row = -1;
1806 { get_next_token_with_directives(); commas_in_row++;
1807 } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
1809 if (commas_in_row>1)
1810 error("Two commas ',' in a row in object/class definition");
1812 if ((token_type == EOF_TT)
1813 || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1814 { if (commas_in_row > 0)
1815 error("Object/class definition finishes with ','");
1816 if (token_type == EOF_TT)
1817 error("Object/class definition incomplete (no ';') at end of file");
1821 if (token_type != SEGMENT_MARKER_TT)
1822 { error_named("Expected 'with', 'has' or 'class' in \
1823 object/class definition but found", token_text);
1828 { case WITH_SEGMENT:
1829 properties_segment(WITH_SEGMENT);
1831 case PRIVATE_SEGMENT:
1832 properties_segment(PRIVATE_SEGMENT);
1835 attributes_segment();
1846 /* ------------------------------------------------------------------------- */
1847 /* Class directives: */
1849 /* Class <name> <body of definition> */
1850 /* ------------------------------------------------------------------------- */
1852 static void initialise_full_object(void)
1856 full_object.symbol = 0;
1858 full_object.atts[0] = 0;
1859 full_object.atts[1] = 0;
1860 full_object.atts[2] = 0;
1861 full_object.atts[3] = 0;
1862 full_object.atts[4] = 0;
1863 full_object.atts[5] = 0;
1866 full_object_g.symbol = 0;
1867 full_object_g.numprops = 0;
1868 full_object_g.propdatasize = 0;
1869 for (i=0; i<NUM_ATTR_BYTES; i++)
1870 full_object_g.atts[i] = 0;
1874 extern void make_class(char * metaclass_name)
1875 { int n, duplicates_to_make = 0, class_number = no_objects+1,
1876 metaclass_flag = (metaclass_name != NULL);
1877 debug_location_beginning beginning_debug_location =
1878 get_token_location_beginning();
1880 current_defn_is_class = TRUE; no_classes_to_inherit_from = 0;
1881 individual_prop_table_size = 0;
1883 ensure_memory_list_available(&class_info_memlist, no_classes+1);
1885 if (no_classes==VENEER_CONSTRAINT_ON_CLASSES)
1886 fatalerror("Inform's maximum possible number of classes (whatever \
1887 amount of memory is allocated) has been reached. If this causes serious \
1888 inconvenience, please contact the maintainers.");
1890 directives.enabled = FALSE;
1893 { token_text = metaclass_name;
1894 token_value = symbol_index(token_text, -1, NULL);
1895 token_type = SYMBOL_TT;
1899 if (token_type != SYMBOL_TT)
1900 { discard_token_location(beginning_debug_location);
1901 ebf_curtoken_error("new class name");
1902 panic_mode_error_recovery();
1905 if (!(symbols[token_value].flags & UNKNOWN_SFLAG))
1906 { discard_token_location(beginning_debug_location);
1907 ebf_symbol_error("new class name", token_text, typename(symbols[token_value].type), symbols[token_value].line);
1908 panic_mode_error_recovery();
1913 /* Each class also creates a modest object representing itself: */
1915 ensure_memory_list_available(&shortname_buffer_memlist, strlen(token_text)+1);
1916 strcpy(shortname_buffer, token_text);
1918 assign_symbol(token_value, class_number, CLASS_T);
1919 current_classname_symbol = token_value;
1922 if (metaclass_flag) symbols[token_value].flags |= SYSTEM_SFLAG;
1925 /* In Glulx, metaclasses have to be backpatched too! So we can't
1926 mark it as "system", but we should mark it "used". */
1927 if (metaclass_flag) symbols[token_value].flags |= USED_SFLAG;
1930 /* "Class" (object 1) has no parent, whereas all other classes are
1931 the children of "Class". */
1933 if (metaclass_flag) parent_of_this_obj = 0;
1934 else parent_of_this_obj = 1;
1936 class_info[no_classes].object_number = class_number;
1937 class_info[no_classes].symbol = current_classname_symbol;
1938 class_info[no_classes].begins_at = 0;
1940 initialise_full_object();
1942 /* Give the class the (nameless in Inform syntax) "inheritance" property
1943 with value its own class number. (This therefore accumulates onto
1944 the inheritance property of any object inheriting from the class,
1945 since property 2 is always set to "additive" -- see below) */
1948 full_object.symbol = current_classname_symbol;
1950 full_object.pp[0].num = 2;
1951 full_object.pp[0].l = 1;
1952 INITAOTV(&full_object.pp[0].ao[0], LONG_CONSTANT_OT, no_objects + 1);
1953 full_object.pp[0].ao[0].marker = OBJECT_MV;
1956 full_object_g.symbol = current_classname_symbol;
1957 full_object_g.numprops = 1;
1958 ensure_memory_list_available(&full_object_g.props_memlist, 1);
1959 full_object_g.props[0].num = 2;
1960 full_object_g.props[0].flags = 0;
1961 full_object_g.props[0].datastart = 0;
1962 full_object_g.props[0].continuation = 0;
1963 full_object_g.props[0].datalen = 1;
1964 full_object_g.propdatasize = 1;
1965 ensure_memory_list_available(&full_object_g.propdata_memlist, 1);
1966 INITAOTV(&full_object_g.propdata[0], CONSTANT_OT, no_objects + 1);
1967 full_object_g.propdata[0].marker = OBJECT_MV;
1970 if (!metaclass_flag)
1972 if ((token_type == SEP_TT) && (token_value == OPENB_SEP))
1973 { assembly_operand AO;
1974 AO = parse_expression(CONSTANT_CONTEXT);
1976 { error("Duplicate-number not known at compile time");
1981 if ((n<0) || (n>10000))
1982 { error("The number of duplicates must be 0 to 10000");
1986 /* Make one extra duplicate, since the veneer routines need
1987 always to keep an undamaged prototype for the class in stock */
1989 duplicates_to_make = n + 1;
1991 match_close_bracket();
1992 } else put_token_back();
1994 /* Parse the body of the definition: */
1996 parse_body_of_definition();
1999 if (debugfile_switch)
2000 { debug_file_printf("<class>");
2001 debug_file_printf("<identifier>%s</identifier>", shortname_buffer);
2002 debug_file_printf("<class-number>%d</class-number>", no_classes);
2003 debug_file_printf("<value>");
2004 write_debug_object_backpatch(no_objects + 1);
2005 debug_file_printf("</value>");
2006 write_debug_locations
2007 (get_token_location_end(beginning_debug_location));
2008 debug_file_printf("</class>");
2012 manufacture_object_z();
2014 manufacture_object_g();
2016 if (individual_prop_table_size >= VENEER_CONSTRAINT_ON_IP_TABLE_SIZE)
2017 error("This class is too complex: it now carries too many properties. \
2018 You may be able to get round this by declaring some of its property names as \
2019 \"common properties\" using the 'Property' directive.");
2021 if (duplicates_to_make > 0)
2023 int namelen = strlen(shortname_buffer);
2024 char *duplicate_name = my_malloc(namelen+16, "temporary storage for object duplicate names");
2025 strcpy(duplicate_name, shortname_buffer);
2026 for (n=1; (duplicates_to_make--) > 0; n++)
2028 sprintf(duplicate_name+namelen, "_%d", n);
2029 make_object(FALSE, duplicate_name, class_number, class_number, -1);
2031 my_free(&duplicate_name, "temporary storage for object duplicate names");
2034 /* Finished building the class. */
2035 current_classname_symbol = 0;
2038 /* ------------------------------------------------------------------------- */
2039 /* Object/Nearby directives: */
2041 /* Object <name-1> ... <name-n> "short name" [parent] <body of def> */
2043 /* Nearby <name-1> ... <name-n> "short name" <body of definition> */
2044 /* ------------------------------------------------------------------------- */
2046 static int end_of_header(void)
2047 { if (((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
2048 || ((token_type == SEP_TT) && (token_value == COMMA_SEP))
2049 || (token_type == SEGMENT_MARKER_TT)) return TRUE;
2053 extern void make_object(int nearby_flag,
2054 char *textual_name, int specified_parent, int specified_class,
2057 /* Ordinarily this is called with nearby_flag TRUE for "Nearby",
2058 FALSE for "Object"; and textual_name NULL, specified_parent and
2059 specified_class both -1. The next three arguments are used when
2060 the routine is called for class duplicates manufacture (see above).
2061 The last is used to create instances of a particular class. */
2063 int i, tree_depth, internal_name_symbol = 0;
2064 debug_location_beginning beginning_debug_location =
2065 get_token_location_beginning();
2067 directives.enabled = FALSE;
2069 ensure_memory_list_available(¤t_object_name, 32);
2070 sprintf(current_object_name.data, "nameless_obj__%d", no_objects+1);
2072 current_defn_is_class = FALSE;
2074 no_classes_to_inherit_from=0;
2076 individual_prop_table_size = 0;
2078 if (nearby_flag) tree_depth=1; else tree_depth=0;
2080 if (specified_class != -1) goto HeaderPassed;
2084 /* Read past and count a sequence of "->"s, if any are present */
2086 if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
2088 error("The syntax '->' is only used as an alternative to 'Nearby'");
2090 while ((token_type == SEP_TT) && (token_value == ARROW_SEP))
2096 ensure_memory_list_available(&shortname_buffer_memlist, 2);
2097 sprintf(shortname_buffer, "?");
2099 segment_markers.enabled = TRUE;
2101 /* This first word is either an internal name, or a textual short name,
2102 or the end of the header part */
2104 if (end_of_header()) goto HeaderPassed;
2106 if (token_type == DQ_TT) textual_name = token_text;
2108 { if (token_type != SYMBOL_TT) {
2109 ebf_curtoken_error("name for new object or its textual short name");
2111 else if (!(symbols[token_value].flags & UNKNOWN_SFLAG)) {
2112 ebf_symbol_error("new object", token_text, typename(symbols[token_value].type), symbols[token_value].line);
2115 { internal_name_symbol = token_value;
2116 ensure_memory_list_available(¤t_object_name, strlen(token_text)+1);
2117 strcpy(current_object_name.data, token_text);
2121 /* The next word is either a parent object, or
2122 a textual short name, or the end of the header part */
2124 get_next_token_with_directives();
2125 if (end_of_header()) goto HeaderPassed;
2127 if (token_type == DQ_TT)
2128 { if (textual_name != NULL)
2129 error("Two textual short names given for only one object");
2131 textual_name = token_text;
2134 { if ((token_type != SYMBOL_TT)
2135 || (symbols[token_value].flags & UNKNOWN_SFLAG))
2136 { if (textual_name == NULL)
2137 ebf_curtoken_error("parent object or the object's textual short name");
2139 ebf_curtoken_error("parent object");
2141 else goto SpecParent;
2144 /* Finally, it's possible that there is still a parent object */
2147 if (end_of_header()) goto HeaderPassed;
2149 if (specified_parent != -1)
2150 ebf_curtoken_error("body of object definition");
2153 if ((symbols[token_value].type == OBJECT_T)
2154 || (symbols[token_value].type == CLASS_T))
2155 { specified_parent = symbols[token_value].value;
2156 symbols[token_value].flags |= USED_SFLAG;
2158 else ebf_curtoken_error("name of (the parent) object");
2161 /* Now it really has to be the body of the definition. */
2163 get_next_token_with_directives();
2164 if (end_of_header()) goto HeaderPassed;
2166 ebf_curtoken_error("body of object definition");
2169 if (specified_class == -1) put_token_back();
2171 if (internal_name_symbol > 0)
2172 assign_symbol(internal_name_symbol, no_objects + 1, OBJECT_T);
2174 if (textual_name == NULL)
2176 if (internal_name_symbol > 0) {
2177 ensure_memory_list_available(&shortname_buffer_memlist, strlen(symbols[internal_name_symbol].name)+4);
2178 sprintf(shortname_buffer, "(%s)",
2179 symbols[internal_name_symbol].name);
2182 ensure_memory_list_available(&shortname_buffer_memlist, 32);
2183 sprintf(shortname_buffer, "(%d)", no_objects+1);
2189 /* This check is only advisory. It's possible that a string of less than 765 characters will encode to more than 510 bytes. We'll double-check in write_property_block_z(). */
2190 if (strlen(textual_name)>765)
2191 error("Short name of object (in quotes) exceeded 765 Z-characters");
2192 ensure_memory_list_available(&shortname_buffer_memlist, 766);
2193 strncpy(shortname_buffer, textual_name, 765);
2196 ensure_memory_list_available(&shortname_buffer_memlist, strlen(textual_name)+1);
2197 strcpy(shortname_buffer, textual_name);
2201 if (specified_parent != -1)
2202 { if (tree_depth > 0)
2203 error("Use of '->' (or 'Nearby') clashes with giving a parent");
2204 parent_of_this_obj = specified_parent;
2207 { parent_of_this_obj = 0;
2210 /* We have to set the parent object to the most recently defined
2211 object at level (tree_depth - 1) in the tree.
2213 A complication is that objects are numbered 1, 2, ... in the
2214 Z-machine (and in the objects[].parent, etc., fields) but
2215 0, 1, 2, ... internally (and as indices to object[]). */
2217 for (i=no_objects-1; i>=0; i--)
2220 /* Metaclass or class objects cannot be '->' parents: */
2225 if (objectsz[i].parent == 1)
2227 while (objectsz[j].parent != 0)
2228 { j = objectsz[j].parent - 1; k++; }
2231 if (objectsg[i].parent == 1)
2233 while (objectsg[j].parent != 0)
2234 { j = objectsg[j].parent - 1; k++; }
2237 if (k == tree_depth - 1)
2238 { parent_of_this_obj = i+1;
2242 if (parent_of_this_obj == 0)
2243 { if (tree_depth == 1)
2244 error("'->' (or 'Nearby') fails because there is no previous object");
2246 error("'-> -> ...' fails because no previous object is deep enough");
2251 initialise_full_object();
2253 full_object.symbol = internal_name_symbol;
2255 full_object_g.symbol = internal_name_symbol;
2257 if (instance_of != -1) add_class_to_inheritance_list(instance_of);
2259 if (specified_class == -1) parse_body_of_definition();
2260 else add_class_to_inheritance_list(specified_class);
2262 if (debugfile_switch)
2263 { debug_file_printf("<object>");
2264 if (internal_name_symbol > 0)
2265 { debug_file_printf("<identifier>%s</identifier>",
2266 current_object_name.data);
2269 ("<identifier artificial=\"true\">%s</identifier>",
2270 current_object_name.data);
2272 debug_file_printf("<value>");
2273 write_debug_object_backpatch(no_objects + 1);
2274 debug_file_printf("</value>");
2275 write_debug_locations
2276 (get_token_location_end(beginning_debug_location));
2277 debug_file_printf("</object>");
2281 manufacture_object_z();
2283 manufacture_object_g();
2286 /* ========================================================================= */
2287 /* Data structure management routines */
2288 /* ------------------------------------------------------------------------- */
2290 extern void init_objects_vars(void)
2292 properties_table = NULL;
2293 individuals_table = NULL;
2295 shortname_buffer = NULL;
2300 classes_to_inherit_from = NULL;
2303 full_object_g.props = NULL;
2304 full_object_g.propdata = NULL;
2307 extern void objects_begin_pass(void)
2309 properties_table_size=0;
2311 /* The three predefined common properties: */
2312 /* (Entry 0 is not used.) */
2315 commonprops[1].default_value = 0;
2316 commonprops[1].is_long = TRUE;
2317 commonprops[1].is_additive = TRUE;
2319 /* class inheritance property */
2320 commonprops[2].default_value = 0;
2321 commonprops[2].is_long = TRUE;
2322 commonprops[2].is_additive = TRUE;
2324 /* instance variables table address */
2325 /* (This property is only meaningful in Z-code; in Glulx its entry is
2326 reserved but never used.) */
2327 commonprops[3].default_value = 0;
2328 commonprops[3].is_long = TRUE;
2329 commonprops[3].is_additive = FALSE;
2333 if (debugfile_switch)
2335 /* These two properties are not symbols, so they won't be emitted
2336 by emit_debug_information_for_predefined_symbol(). Do it
2338 debug_file_printf("<property>");
2340 ("<identifier artificial=\"true\">inheritance class</identifier>");
2341 debug_file_printf("<value>2</value>");
2342 debug_file_printf("</property>");
2343 debug_file_printf("<property>");
2345 ("<identifier artificial=\"true\">instance variables table address "
2346 "(Z-code)</identifier>");
2347 debug_file_printf("<value>3</value>");
2348 debug_file_printf("</property>");
2351 if (define_INFIX_switch) no_attributes = 1;
2352 else no_attributes = 0;
2355 /* Setting the info for object zero is probably a relic of very old code, but we do it. */
2357 ensure_memory_list_available(&objectsz_memlist, 1);
2358 objectsz[0].parent = 0; objectsz[0].child = 0; objectsz[0].next = 0;
2359 no_individual_properties=72;
2362 ensure_memory_list_available(&objectsg_memlist, 1);
2363 objectsg[0].parent = 0; objectsg[0].child = 0; objectsg[0].next = 0;
2364 no_individual_properties = INDIV_PROP_START+8;
2367 current_classname_symbol = 0;
2369 no_embedded_routines = 0;
2371 individuals_length=0;
2374 extern void objects_allocate_arrays(void)
2380 commonprops = my_calloc(sizeof(commonpropinfo), INDIV_PROP_START,
2381 "common property info");
2383 initialise_memory_list(&class_info_memlist,
2384 sizeof(classinfo), 64, (void**)&class_info,
2386 initialise_memory_list(&classes_to_inherit_from_memlist,
2387 sizeof(int), 64, (void**)&classes_to_inherit_from,
2388 "inherited classes list");
2390 initialise_memory_list(&properties_table_memlist,
2391 sizeof(uchar), 10000, (void**)&properties_table,
2392 "properties table");
2393 initialise_memory_list(&individuals_table_memlist,
2394 sizeof(uchar), 10000, (void**)&individuals_table,
2395 "individual properties table");
2397 defined_this_segment_size = 128;
2398 defined_this_segment = my_calloc(sizeof(int), defined_this_segment_size,
2399 "defined this segment table");
2401 initialise_memory_list(¤t_object_name,
2402 sizeof(char), 32, NULL,
2403 "object name currently being defined");
2404 initialise_memory_list(&shortname_buffer_memlist,
2405 sizeof(char), 768, (void**)&shortname_buffer,
2406 "textual name of object currently being defined");
2407 initialise_memory_list(&embedded_function_name,
2408 sizeof(char), 32, NULL,
2409 "temporary storage for inline function name");
2412 initialise_memory_list(&objectsz_memlist,
2413 sizeof(objecttz), 256, (void**)&objectsz,
2417 initialise_memory_list(&objectsg_memlist,
2418 sizeof(objecttg), 256, (void**)&objectsg,
2420 initialise_memory_list(&objectatts_memlist,
2421 NUM_ATTR_BYTES, 256, (void**)&objectatts,
2423 initialise_memory_list(&full_object_g.props_memlist,
2424 sizeof(propg), 64, (void**)&full_object_g.props,
2425 "object property list");
2426 initialise_memory_list(&full_object_g.propdata_memlist,
2427 sizeof(assembly_operand), 1024, (void**)&full_object_g.propdata,
2428 "object property data table");
2432 extern void objects_free_arrays(void)
2434 my_free(&commonprops, "common property info");
2436 deallocate_memory_list(¤t_object_name);
2437 deallocate_memory_list(&shortname_buffer_memlist);
2438 deallocate_memory_list(&embedded_function_name);
2439 deallocate_memory_list(&objectsz_memlist);
2440 deallocate_memory_list(&objectsg_memlist);
2441 deallocate_memory_list(&objectatts_memlist);
2442 deallocate_memory_list(&class_info_memlist);
2443 deallocate_memory_list(&classes_to_inherit_from_memlist);
2445 deallocate_memory_list(&properties_table_memlist);
2446 deallocate_memory_list(&individuals_table_memlist);
2448 my_free(&defined_this_segment,"defined this segment table");
2451 deallocate_memory_list(&full_object_g.props_memlist);
2452 deallocate_memory_list(&full_object_g.propdata_memlist);
2457 /* ========================================================================= */