~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to src/objects.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ------------------------------------------------------------------------- */
2
 
/*   "objects" :  [1] the object-maker, which constructs objects and enters  */
3
 
/*                    them into the tree, given a low-level specification;   */
4
 
/*                                                                           */
5
 
/*                [2] the parser of Object/Nearby/Class directives, which    */
6
 
/*                    checks syntax and translates such directives into      */
7
 
/*                    specifications for the object-maker.                   */
8
 
/*                                                                           */
9
 
/*   Part of Inform 6.30                                                     */
10
 
/*   copyright (c) Graham Nelson 1993 - 2004                                 */
11
 
/*                                                                           */
12
 
/* ------------------------------------------------------------------------- */
13
 
 
14
 
#include "header.h"
15
 
 
16
 
/* ------------------------------------------------------------------------- */
17
 
/*   Objects.                                                                */
18
 
/* ------------------------------------------------------------------------- */
19
 
 
20
 
int no_objects;                        /* Number of objects made so far      */
21
 
 
22
 
static int no_embedded_routines;       /* Used for naming routines which
23
 
                                          are given as property values: these
24
 
                                          are called EmbeddedRoutine__1, ... */
25
 
 
26
 
static fpropt full_object;             /* "fpropt" is a typedef for a struct
27
 
                                          containing an array to hold the
28
 
                                          attribute and property values of
29
 
                                          a single object.  We only keep one
30
 
                                          of these, for the current object
31
 
                                          being made, and compile it into
32
 
                                          Z-machine tables when each object
33
 
                                          definition is complete, since
34
 
                                          sizeof(fpropt) is about 6200 bytes */
35
 
static fproptg full_object_g;          /* Equivalent for Glulx. This object
36
 
                                          is very small, since the large arrays
37
 
                                          are allocated dynamically by the
38
 
                                          Glulx compiler                     */
39
 
static char shortname_buffer[766];     /* Text buffer to hold the short name
40
 
                                          (which is read in first, but
41
 
                                          written almost last)               */
42
 
static int parent_of_this_obj;
43
 
 
44
 
static char *classname_text, *objectname_text;
45
 
                                       /* For printing names of embedded
46
 
                                          routines only                      */
47
 
 
48
 
/* ------------------------------------------------------------------------- */
49
 
/*   Classes.                                                                */
50
 
/* ------------------------------------------------------------------------- */
51
 
/*   Arrays defined below:                                                   */
52
 
/*                                                                           */
53
 
/*    int32 class_begins_at[n]            offset of properties block for     */
54
 
/*                                        nth class (always an offset        */
55
 
/*                                        inside the properties_table)       */
56
 
/*    int   classes_to_inherit_from[]     The list of classes to inherit     */
57
 
/*                                        from as taken from the current     */
58
 
/*                                        Nearby/Object/Class definition     */
59
 
/*    int   class_object_numbers[n]       The number of the prototype-object */
60
 
/*                                        for the nth class                  */
61
 
/* ------------------------------------------------------------------------- */
62
 
 
63
 
int        no_classes;                 /* Number of class defns made so far  */
64
 
 
65
 
static int current_defn_is_class,      /* TRUE if current Nearby/Object/Class
66
 
                                          defn is in fact a Class definition */
67
 
           no_classes_to_inherit_from; /* Number of classes in the list
68
 
                                          of classes to inherit in the
69
 
                                          current Nearby/Object/Class defn   */
70
 
 
71
 
/* ------------------------------------------------------------------------- */
72
 
/*   Making attributes and properties.                                       */
73
 
/* ------------------------------------------------------------------------- */
74
 
 
75
 
int no_attributes,                 /* Number of attributes defined so far    */
76
 
    no_properties;                 /* Number of properties defined so far,
77
 
                                      plus 1 (properties are numbered from
78
 
                                      1 and Inform creates "name" and two
79
 
                                      others itself, so the variable begins
80
 
                                      the compilation pass set to 4)         */
81
 
 
82
 
static void trace_s(char *name, int32 number, int f)
83
 
{   if (!printprops_switch) return;
84
 
    printf("%s  %02ld  ",(f==0)?"Attr":"Prop",(long int) number);
85
 
    if (f==0) printf("  ");
86
 
    else      printf("%s%s",(prop_is_long[number])?"L":" ",
87
 
                            (prop_is_additive[number])?"A":" ");
88
 
    printf("  %s\n",name);
89
 
}
90
 
 
91
 
extern void make_attribute(void)
92
 
{   int i; char *name;
93
 
 
94
 
 if (!glulx_mode) { 
95
 
    if (no_attributes==((version_number==3)?32:48))
96
 
    {   if (version_number==3)
97
 
            error("All 32 attributes already declared (compile as Advanced \
98
 
game to get an extra 16)");
99
 
        else
100
 
            error("All 48 attributes already declared");
101
 
        panic_mode_error_recovery(); return;
102
 
    }
103
 
 }
104
 
 else {
105
 
    if (no_attributes==NUM_ATTR_BYTES*8) {
106
 
      error_numbered(
107
 
        "All attributes already declared -- increase NUM_ATTR_BYTES to use \
108
 
more than", 
109
 
        NUM_ATTR_BYTES*8);
110
 
      panic_mode_error_recovery(); 
111
 
      return;
112
 
    }
113
 
 }
114
 
 
115
 
    get_next_token();
116
 
    i = token_value; name = token_text;
117
 
    if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
118
 
    {   ebf_error("new attribute name", token_text);
119
 
        panic_mode_error_recovery(); return;
120
 
    }
121
 
 
122
 
    directive_keywords.enabled = TRUE;
123
 
    get_next_token();
124
 
    directive_keywords.enabled = FALSE;
125
 
 
126
 
    if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
127
 
    {   get_next_token();
128
 
        if (!((token_type == SYMBOL_TT)
129
 
              && (stypes[token_value] == ATTRIBUTE_T)))
130
 
        {   ebf_error("an existing attribute name after 'alias'",
131
 
                token_text); panic_mode_error_recovery(); return;
132
 
        }
133
 
        assign_symbol(i, svals[token_value], ATTRIBUTE_T);
134
 
        sflags[token_value] |= ALIASED_SFLAG;
135
 
        sflags[i] |= ALIASED_SFLAG;
136
 
    }
137
 
    else
138
 
    {   assign_symbol(i, no_attributes++, ATTRIBUTE_T);
139
 
        put_token_back();
140
 
    }
141
 
 
142
 
    trace_s(name, svals[i], 0);
143
 
    return;
144
 
}
145
 
 
146
 
extern void make_property(void)
147
 
{   int32 default_value, i;
148
 
    int additive_flag=FALSE; char *name;
149
 
    assembly_operand AO;
150
 
 
151
 
    if (!glulx_mode) {
152
 
        if (no_properties==((version_number==3)?32:64))
153
 
        {   if (version_number==3)
154
 
                error("All 30 properties already declared (compile as \
155
 
Advanced game to get an extra 62)");
156
 
            else
157
 
                error("All 62 properties already declared");
158
 
            panic_mode_error_recovery(); return;
159
 
        }
160
 
    }
161
 
    else {
162
 
        /* INDIV_PROP_START could be a memory setting */
163
 
        if (no_properties==INDIV_PROP_START) {
164
 
            error_numbered("All properties already declared -- max is",
165
 
                INDIV_PROP_START);
166
 
            panic_mode_error_recovery(); 
167
 
            return;
168
 
        }
169
 
    }
170
 
 
171
 
    do
172
 
    {   directive_keywords.enabled = TRUE;
173
 
        get_next_token();
174
 
        if ((token_type == DIR_KEYWORD_TT) && (token_value == LONG_DK))
175
 
            obsolete_warning("all properties are now automatically 'long'");
176
 
        else
177
 
        if ((token_type == DIR_KEYWORD_TT) && (token_value == ADDITIVE_DK))
178
 
            additive_flag = TRUE;
179
 
        else break;
180
 
    } while (TRUE);
181
 
 
182
 
    put_token_back();
183
 
    directive_keywords.enabled = FALSE;
184
 
    get_next_token();
185
 
 
186
 
    i = token_value; name = token_text;
187
 
    if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
188
 
    {   ebf_error("new property name", token_text);
189
 
        panic_mode_error_recovery(); return;
190
 
    }
191
 
 
192
 
    directive_keywords.enabled = TRUE;
193
 
    get_next_token();
194
 
    directive_keywords.enabled = FALSE;
195
 
 
196
 
    if (strcmp(name+strlen(name)-3, "_to") == 0) sflags[i] |= STAR_SFLAG;
197
 
 
198
 
    if ((token_type == DIR_KEYWORD_TT) && (token_value == ALIAS_DK))
199
 
    {   if (additive_flag)
200
 
        {   error("'alias' incompatible with 'additive'");
201
 
            panic_mode_error_recovery();
202
 
            return;
203
 
        }
204
 
        get_next_token();
205
 
        if (!((token_type == SYMBOL_TT)
206
 
            && (stypes[token_value] == PROPERTY_T)))
207
 
        {   ebf_error("an existing property name after 'alias'",
208
 
                token_text); panic_mode_error_recovery(); return;
209
 
        }
210
 
 
211
 
        assign_symbol(i, svals[token_value], PROPERTY_T);
212
 
        trace_s(name, svals[i], 1);
213
 
        sflags[token_value] |= ALIASED_SFLAG;
214
 
        sflags[i] |= ALIASED_SFLAG;
215
 
        return;
216
 
    }
217
 
 
218
 
    default_value = 0;
219
 
    put_token_back();
220
 
 
221
 
    if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
222
 
    {   AO = parse_expression(CONSTANT_CONTEXT);
223
 
        default_value = AO.value;
224
 
        if (AO.marker != 0)
225
 
            backpatch_zmachine(AO.marker, PROP_DEFAULTS_ZA, 
226
 
                (no_properties-1) * WORDSIZE);
227
 
    }
228
 
 
229
 
    prop_default_value[no_properties] = default_value;
230
 
    prop_is_long[no_properties] = TRUE;
231
 
    prop_is_additive[no_properties] = additive_flag;
232
 
 
233
 
    assign_symbol(i, no_properties++, PROPERTY_T);
234
 
    trace_s(name, svals[i], 1);
235
 
}
236
 
 
237
 
/* ------------------------------------------------------------------------- */
238
 
/*   Properties.                                                             */
239
 
/* ------------------------------------------------------------------------- */
240
 
 
241
 
int32 *prop_default_value;             /* Default values for properties      */
242
 
int   *prop_is_long,                   /* Property modifiers, TRUE or FALSE:
243
 
                                          "long" means "never write a 1-byte
244
 
                                          value to this property", and is an
245
 
                                          obsolete feature: since Inform 5
246
 
                                          all properties have been "long"    */
247
 
      *prop_is_additive;               /* "additive" means that values
248
 
                                          accumulate rather than erase each
249
 
                                          other during class inheritance     */
250
 
char *properties_table;                /* Holds the table of property values
251
 
                                          (holding one block for each object
252
 
                                          and coming immediately after the
253
 
                                          object tree in Z-memory)           */
254
 
int properties_table_size;             /* Number of bytes in this table      */
255
 
 
256
 
/* ------------------------------------------------------------------------- */
257
 
/*   Individual properties                                                   */
258
 
/*                                                                           */
259
 
/*   Each new i.p. name is given a unique number.  These numbers start from  */
260
 
/*   72, since 0 is reserved as a null, 1 to 63 refer to common properties   */
261
 
/*   and 64 to 71 are kept for methods of the metaclass Class (for example,  */
262
 
/*   64 is "create").                                                        */
263
 
/*                                                                           */
264
 
/*   An object provides individual properties by having property 3 set to a  */
265
 
/*   non-zero value, which must be a byte address of a table in the form:    */
266
 
/*                                                                           */
267
 
/*       <record-1> ... <record-n> 00 00                                     */
268
 
/*                                                                           */
269
 
/*   where a <record> looks like                                             */
270
 
/*                                                                           */
271
 
/*       <identifier>              <size>  <up to 255 bytes of data>         */
272
 
/*       or <identifier + 0x8000>                                            */
273
 
/*       ----- 2 bytes ----------  1 byte  <size> number of bytes            */
274
 
/*                                                                           */
275
 
/*   The <identifier> part is the number allocated to the name of what is    */
276
 
/*   being provided.  The top bit of this word is set to indicate that       */
277
 
/*   although the individual property is being provided, it is provided      */
278
 
/*   only privately (so that it is inaccessible except to the object's own   */
279
 
/*   embedded routines).                                                     */
280
 
/*                                                                           */
281
 
/*   In Glulx: i-props are numbered from INDIV_PROP_START+8 up. And all      */
282
 
/*   properties, common and individual, are stored in the same table.        */
283
 
/* ------------------------------------------------------------------------- */
284
 
 
285
 
       int no_individual_properties;   /* Actually equal to the next
286
 
                                          identifier number to be allocated,
287
 
                                          so this is initially 72 even though
288
 
                                          none have been made yet.           */
289
 
static int individual_prop_table_size; /* Size of the table of individual
290
 
                                          properties so far for current obj  */
291
 
       uchar *individuals_table;       /* Table of records, each being the
292
 
                                          i.p. table for an object           */
293
 
       int i_m;                        /* Write mark position in the above   */
294
 
       int individuals_length;         /* Extent of individuals_table        */
295
 
 
296
 
/* ------------------------------------------------------------------------- */
297
 
/*   Arrays used by this file                                                */
298
 
/* ------------------------------------------------------------------------- */
299
 
 
300
 
objecttz     *objectsz;                /* Z-code only                        */
301
 
objecttg     *objectsg;                /* Glulx only                         */
302
 
uchar        *objectatts;              /* Glulx only                         */
303
 
static int   *classes_to_inherit_from;
304
 
int          *class_object_numbers;
305
 
int32        *class_begins_at;
306
 
 
307
 
 
308
 
/* ------------------------------------------------------------------------- */
309
 
/*   Tracing for compiler maintenance                                        */
310
 
/* ------------------------------------------------------------------------- */
311
 
 
312
 
extern void list_object_tree(void)
313
 
{   int i;
314
 
    printf("obj   par nxt chl   Object tree:\n");
315
 
    for (i=0; i<no_objects; i++)
316
 
        printf("%3d   %3d %3d %3d\n",
317
 
            i+1,objectsz[i].parent,objectsz[i].next, objectsz[i].child);
318
 
}
319
 
 
320
 
/* ------------------------------------------------------------------------- */
321
 
/*   Object and class manufacture begins here.                               */
322
 
/*                                                                           */
323
 
/*   These definitions have headers (parsed far, far below) and a series     */
324
 
/*   of segments, introduced by keywords and optionally separated by commas. */
325
 
/*   Each segment has its own parsing routine.  Note that when errors are    */
326
 
/*   detected, parsing continues rather than being abandoned, which assists  */
327
 
/*   a little in "error recovery" (i.e. in stopping lots more errors being   */
328
 
/*   produced for essentially the same mistake).                             */
329
 
/* ------------------------------------------------------------------------- */
330
 
 
331
 
/* ========================================================================= */
332
 
/*   [1]  The object-maker: builds an object from a specification, viz.:     */
333
 
/*                                                                           */
334
 
/*           full_object,                                                    */
335
 
/*           shortname_buffer,                                               */
336
 
/*           parent_of_this_obj,                                             */
337
 
/*           current_defn_is_class (flag)                                    */
338
 
/*           classes_to_inherit_from[], no_classes_to_inherit_from,          */
339
 
/*           individual_prop_table_size (to date  )                          */
340
 
/*                                                                           */
341
 
/*   For efficiency's sake, the individual properties table has already been */
342
 
/*   created (as far as possible, i.e., all except for inherited individual  */
343
 
/*   properties); unless the flag is clear, in which case the actual         */
344
 
/*   definition did not specify any individual properties.                   */
345
 
/* ========================================================================= */
346
 
/*   Property inheritance from classes.                                      */
347
 
/* ------------------------------------------------------------------------- */
348
 
 
349
 
static void property_inheritance_z(void)
350
 
{
351
 
    /*  Apply the property inheritance rules to full_object, which should
352
 
        initially be complete (i.e., this routine takes place after the whole
353
 
        Nearby/Object/Class definition has been parsed through).
354
 
 
355
 
        On exit, full_object contains the final state of the properties to
356
 
        be written.                                                          */
357
 
 
358
 
    int i, j, k, kmax, class, mark,
359
 
        prop_number, prop_length, prop_in_current_defn;
360
 
    uchar *class_prop_block;
361
 
 
362
 
    ASSERT_ZCODE();
363
 
 
364
 
    for (class=0; class<no_classes_to_inherit_from; class++)
365
 
    {
366
 
        j=0;
367
 
        mark = class_begins_at[classes_to_inherit_from[class]-1];
368
 
        class_prop_block = (uchar *) (properties_table + mark);
369
 
 
370
 
        while (class_prop_block[j]!=0)
371
 
        {   if (version_number == 3)
372
 
            {   prop_number = class_prop_block[j]%32;
373
 
                prop_length = 1 + class_prop_block[j++]/32;
374
 
            }
375
 
            else
376
 
            {   prop_number = class_prop_block[j]%64;
377
 
                prop_length = 1 + class_prop_block[j++]/64;
378
 
                if (prop_length > 2)
379
 
                    prop_length = class_prop_block[j++]%64;
380
 
            }
381
 
 
382
 
            /*  So we now have property number prop_number present in the
383
 
                property block for the class being read: its bytes are
384
 
 
385
 
                class_prop_block[j, ..., j + prop_length - 1]
386
 
 
387
 
                Question now is: is there already a value given in the
388
 
                current definition under this property name?                 */
389
 
 
390
 
            prop_in_current_defn = FALSE;
391
 
 
392
 
            kmax = full_object.l;
393
 
 
394
 
            for (k=0; k<kmax; k++)
395
 
                if (full_object.pp[k].num == prop_number)
396
 
                {   prop_in_current_defn = TRUE;
397
 
 
398
 
                    /*  (Note that the built-in "name" property is additive) */
399
 
 
400
 
                    if ((prop_number==1) || (prop_is_additive[prop_number]))
401
 
                    {
402
 
                        /*  The additive case: we accumulate the class
403
 
                            property values onto the end of the full_object
404
 
                            property                                         */
405
 
 
406
 
                        for (i=full_object.pp[k].l;
407
 
                             i<full_object.pp[k].l+prop_length/2; i++)
408
 
                        {   if (i >= 32)
409
 
                            {   error("An additive property has inherited \
410
 
so many values that the list has overflowed the maximum 32 entries");
411
 
                                break;
412
 
                            }
413
 
                            full_object.pp[k].ao[i].value = mark + j;
414
 
                            j += 2;
415
 
                            full_object.pp[k].ao[i].marker = INHERIT_MV;
416
 
                            full_object.pp[k].ao[i].type = LONG_CONSTANT_OT;
417
 
                        }
418
 
                        full_object.pp[k].l += prop_length/2;
419
 
                    }
420
 
                    else
421
 
                        /*  The ordinary case: the full_object property
422
 
                            values simply overrides the class definition,
423
 
                            so we skip over the values in the class table    */
424
 
 
425
 
                        j+=prop_length;
426
 
 
427
 
                    if (prop_number==3)
428
 
                    {   int y, z, class_block_offset;
429
 
                        uchar *p;
430
 
 
431
 
                        /*  Property 3 holds the address of the table of
432
 
                            instance variables, so this is the case where
433
 
                            the object already has instance variables in its
434
 
                            own table but must inherit some more from the
435
 
                            class  */
436
 
 
437
 
                        if (individuals_length+64 > MAX_INDIV_PROP_TABLE_SIZE)
438
 
                            memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
439
 
                                        MAX_INDIV_PROP_TABLE_SIZE);
440
 
 
441
 
                        class_block_offset = class_prop_block[j-2]*256
442
 
                                             + class_prop_block[j-1];
443
 
 
444
 
                        p = individuals_table + class_block_offset;
445
 
                        z = class_block_offset;
446
 
                        while ((p[0]!=0)||(p[1]!=0))
447
 
                        {   int already_present = FALSE, l;
448
 
                            for (l = full_object.pp[k].ao[0].value; l < i_m;
449
 
                                 l = l + 3 + individuals_table[l + 2])
450
 
                                if (individuals_table[l] == p[0]
451
 
                                    && individuals_table[l + 1] == p[1])
452
 
                                {   already_present = TRUE; break;
453
 
                                }
454
 
                            if (already_present == FALSE)
455
 
                            {   if (module_switch)
456
 
                                    backpatch_zmachine(IDENT_MV,
457
 
                                        INDIVIDUAL_PROP_ZA, i_m);
458
 
                                individuals_table[i_m++] = p[0];
459
 
                                individuals_table[i_m++] = p[1];
460
 
                                individuals_table[i_m++] = p[2];
461
 
                                for (y=0;y < p[2]/2;y++)
462
 
                                {   individuals_table[i_m++] = (z+3+y*2)/256;
463
 
                                    individuals_table[i_m++] = (z+3+y*2)%256;
464
 
                                    backpatch_zmachine(INHERIT_INDIV_MV,
465
 
                                        INDIVIDUAL_PROP_ZA, i_m-2);
466
 
                                }
467
 
                            }
468
 
                            z += p[2] + 3;
469
 
                            p += p[2] + 3;
470
 
                        }
471
 
                        individuals_length = i_m;
472
 
                    }
473
 
 
474
 
                    /*  For efficiency we exit the loop now (this property
475
 
                        number has been dealt with)                          */
476
 
 
477
 
                    break;
478
 
                }
479
 
 
480
 
            if (!prop_in_current_defn)
481
 
            {
482
 
                /*  The case where the class defined a property which wasn't
483
 
                    defined at all in full_object: we copy out the data into
484
 
                    a new property added to full_object                      */
485
 
 
486
 
                k=full_object.l++;
487
 
                full_object.pp[k].num = prop_number;
488
 
                full_object.pp[k].l = prop_length/2;
489
 
                for (i=0; i<prop_length/2; i++)
490
 
                {   full_object.pp[k].ao[i].value = mark + j;
491
 
                    j+=2;
492
 
                    full_object.pp[k].ao[i].marker = INHERIT_MV;
493
 
                    full_object.pp[k].ao[i].type = LONG_CONSTANT_OT;
494
 
                }
495
 
 
496
 
                if (prop_number==3)
497
 
                {   int y, z, class_block_offset;
498
 
                    uchar *p;
499
 
 
500
 
                    /*  Property 3 holds the address of the table of
501
 
                        instance variables, so this is the case where
502
 
                        the object had no instance variables of its own
503
 
                        but must inherit some more from the class  */
504
 
 
505
 
                    if (individuals_length+64 > MAX_INDIV_PROP_TABLE_SIZE)
506
 
                        memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
507
 
                                    MAX_INDIV_PROP_TABLE_SIZE);
508
 
 
509
 
                    if (individual_prop_table_size++ == 0)
510
 
                    {   full_object.pp[k].num = 3;
511
 
                        full_object.pp[k].l = 1;
512
 
                        full_object.pp[k].ao[0].value
513
 
                            = individuals_length;
514
 
                        full_object.pp[k].ao[0].marker = INDIVPT_MV;
515
 
                        full_object.pp[k].ao[0].type = LONG_CONSTANT_OT;
516
 
                        i_m = individuals_length;
517
 
                    }
518
 
                    class_block_offset = class_prop_block[j-2]*256
519
 
                                         + class_prop_block[j-1];
520
 
 
521
 
                    p = individuals_table + class_block_offset;
522
 
                    z = class_block_offset;
523
 
                    while ((p[0]!=0)||(p[1]!=0))
524
 
                    {   if (module_switch)
525
 
                        backpatch_zmachine(IDENT_MV, INDIVIDUAL_PROP_ZA, i_m);
526
 
                        individuals_table[i_m++] = p[0];
527
 
                        individuals_table[i_m++] = p[1];
528
 
                        individuals_table[i_m++] = p[2];
529
 
                        for (y=0;y < p[2]/2;y++)
530
 
                        {   individuals_table[i_m++] = (z+3+y*2)/256;
531
 
                            individuals_table[i_m++] = (z+3+y*2)%256;
532
 
                            backpatch_zmachine(INHERIT_INDIV_MV,
533
 
                                INDIVIDUAL_PROP_ZA, i_m-2);
534
 
                        }
535
 
                        z += p[2] + 3;
536
 
                        p += p[2] + 3;
537
 
                    }
538
 
                    individuals_length = i_m;
539
 
                }
540
 
            }
541
 
        }
542
 
    }
543
 
 
544
 
    if (individual_prop_table_size > 0)
545
 
    {   individuals_table[i_m++] = 0;
546
 
        individuals_table[i_m++] = 0;
547
 
        individuals_length += 2;
548
 
    }
549
 
}
550
 
 
551
 
static void property_inheritance_g(void)
552
 
{
553
 
  /*  Apply the property inheritance rules to full_object, which should
554
 
      initially be complete (i.e., this routine takes place after the whole
555
 
      Nearby/Object/Class definition has been parsed through).
556
 
      
557
 
      On exit, full_object contains the final state of the properties to
558
 
      be written. */
559
 
 
560
 
  int i, j, k, class, num_props,
561
 
    prop_number, prop_length, prop_flags, prop_in_current_defn;
562
 
  int32 mark, prop_addr;
563
 
  uchar *cpb, *pe;
564
 
 
565
 
  ASSERT_GLULX();
566
 
 
567
 
  for (class=0; class<no_classes_to_inherit_from; class++) {
568
 
    mark = class_begins_at[classes_to_inherit_from[class]-1];
569
 
    cpb = (uchar *) (properties_table + mark);
570
 
    /* This now points to the compiled property-table for the class.
571
 
       We'll have to go through and decompile it. (For our sins.) */
572
 
    num_props = ReadInt32(cpb);
573
 
    for (j=0; j<num_props; j++) {
574
 
      pe = cpb + 4 + j*10;
575
 
      prop_number = ReadInt16(pe);
576
 
      pe += 2;
577
 
      prop_length = ReadInt16(pe);
578
 
      pe += 2;
579
 
      prop_addr = ReadInt32(pe);
580
 
      pe += 4;
581
 
      prop_flags = ReadInt16(pe);
582
 
      pe += 2;
583
 
 
584
 
      /*  So we now have property number prop_number present in the
585
 
          property block for the class being read. Its bytes are
586
 
          cpb[prop_addr ... prop_addr + prop_length - 1]
587
 
          Question now is: is there already a value given in the
588
 
          current definition under this property name? */
589
 
 
590
 
      prop_in_current_defn = FALSE;
591
 
 
592
 
      for (k=0; k<full_object_g.numprops; k++) {
593
 
        if (full_object_g.props[k].num == prop_number) {
594
 
          prop_in_current_defn = TRUE;
595
 
          break;
596
 
        }
597
 
      }
598
 
 
599
 
      if (prop_in_current_defn) {
600
 
        if ((prop_number==1)
601
 
          || (prop_number < INDIV_PROP_START 
602
 
            && prop_is_additive[prop_number])) {
603
 
          /*  The additive case: we accumulate the class
604
 
              property values onto the end of the full_object
605
 
              properties. Remember that k is still the index number
606
 
              of the first prop-block matching our property number. */
607
 
          int prevcont;
608
 
          if (full_object_g.props[k].continuation == 0) {
609
 
            full_object_g.props[k].continuation = 1;
610
 
            prevcont = 1;
611
 
          }
612
 
          else {
613
 
            prevcont = full_object_g.props[k].continuation;
614
 
            for (k++; k<full_object_g.numprops; k++) {
615
 
              if (full_object_g.props[k].num == prop_number) {
616
 
                prevcont = full_object_g.props[k].continuation;
617
 
              }
618
 
            }
619
 
          }
620
 
          k = full_object_g.numprops++;
621
 
          full_object_g.props[k].num = prop_number;
622
 
          full_object_g.props[k].flags = 0;
623
 
          full_object_g.props[k].datastart = full_object_g.propdatasize;
624
 
          full_object_g.props[k].continuation = prevcont+1;
625
 
          full_object_g.props[k].datalen = prop_length;
626
 
          if (full_object_g.propdatasize + prop_length 
627
 
            > MAX_OBJ_PROP_TABLE_SIZE) {
628
 
            error_numbered("Limit of property data exceeded for this object; \
629
 
MAX_OBJ_PROP_TABLE_SIZE is", MAX_OBJ_PROP_TABLE_SIZE);
630
 
            break;
631
 
          }
632
 
 
633
 
          for (i=0; i<prop_length; i++) {
634
 
            int ppos = full_object_g.propdatasize++;
635
 
            full_object_g.propdata[ppos].value = prop_addr + 4*i;
636
 
            full_object_g.propdata[ppos].marker = INHERIT_MV;
637
 
            full_object_g.propdata[ppos].type = CONSTANT_OT;
638
 
          }
639
 
        }
640
 
        else {
641
 
          /*  The ordinary case: the full_object_g property
642
 
              values simply overrides the class definition,
643
 
              so we skip over the values in the class table. */
644
 
        }
645
 
      }
646
 
          else {
647
 
            /*  The case where the class defined a property which wasn't
648
 
                defined at all in full_object_g: we copy out the data into
649
 
                a new property added to full_object_g. */
650
 
            k = full_object_g.numprops++;
651
 
            full_object_g.props[k].num = prop_number;
652
 
            full_object_g.props[k].flags = prop_flags;
653
 
            full_object_g.props[k].datastart = full_object_g.propdatasize;
654
 
            full_object_g.props[k].continuation = 0;
655
 
            full_object_g.props[k].datalen = prop_length;
656
 
            if (full_object_g.propdatasize + prop_length 
657
 
              > MAX_OBJ_PROP_TABLE_SIZE) {
658
 
              error_numbered("Limit of property data exceeded for this object; \
659
 
MAX_OBJ_PROP_TABLE_SIZE is", MAX_OBJ_PROP_TABLE_SIZE);
660
 
              break;
661
 
            }
662
 
 
663
 
            for (i=0; i<prop_length; i++) {
664
 
              int ppos = full_object_g.propdatasize++;
665
 
              full_object_g.propdata[ppos].value = prop_addr + 4*i;
666
 
              full_object_g.propdata[ppos].marker = INHERIT_MV; 
667
 
              full_object_g.propdata[ppos].type = CONSTANT_OT;
668
 
            }
669
 
          }
670
 
 
671
 
          if (full_object_g.numprops == MAX_OBJ_PROP_COUNT) {
672
 
            error_numbered("Limit of property entries exceeded for this \
673
 
object; MAX_OBJ_PROP_COUNT is", MAX_OBJ_PROP_COUNT);
674
 
            break;
675
 
          }
676
 
    }
677
 
  }
678
 
  
679
 
}
680
 
 
681
 
/* ------------------------------------------------------------------------- */
682
 
/*   Construction of Z-machine-format property blocks.                       */
683
 
/* ------------------------------------------------------------------------- */
684
 
 
685
 
static int write_properties_between(uchar *p, int mark, int from, int to)
686
 
{   int j, k, prop_number, prop_length;
687
 
    for (prop_number=to; prop_number>=from; prop_number--)
688
 
    {   for (j=0; j<full_object.l; j++)
689
 
        {   if ((full_object.pp[j].num == prop_number)
690
 
                && (full_object.pp[j].l != 100))
691
 
            {   prop_length = 2*full_object.pp[j].l;
692
 
                if (version_number == 3)
693
 
                    p[mark++] = prop_number + (prop_length - 1)*32;
694
 
                else
695
 
                {   switch(prop_length)
696
 
                    {   case 1:
697
 
                          p[mark++] = prop_number; break;
698
 
                        case 2:
699
 
                          p[mark++] = prop_number + 0x40; break;
700
 
                        default:
701
 
                          p[mark++] = prop_number + 0x80;
702
 
                          p[mark++] = prop_length + 0x80; break;
703
 
                    }
704
 
                }
705
 
 
706
 
                for (k=0; k<full_object.pp[j].l; k++)
707
 
                {   if (full_object.pp[j].ao[k].marker != 0)
708
 
                        backpatch_zmachine(full_object.pp[j].ao[k].marker,
709
 
                            PROP_ZA, mark);
710
 
                    p[mark++] = full_object.pp[j].ao[k].value/256;
711
 
                    p[mark++] = full_object.pp[j].ao[k].value%256;
712
 
                }
713
 
            }
714
 
        }
715
 
    }
716
 
 
717
 
    p[mark++]=0;
718
 
    return(mark);
719
 
}
720
 
 
721
 
static int write_property_block_z(char *shortname)
722
 
{
723
 
    /*  Compile the (now complete) full_object properties into a
724
 
        property-table block at "p" in Inform's memory.
725
 
        "shortname" is the object's short name, if specified; otherwise
726
 
        NULL.
727
 
 
728
 
        Return the number of bytes written to the block.                     */
729
 
 
730
 
    int32 mark = properties_table_size, i;
731
 
    uchar *p = (uchar *) properties_table;
732
 
 
733
 
    /* printf("Object at %04x\n", mark); */
734
 
 
735
 
    if (shortname != NULL)
736
 
    {   uchar *tmp = translate_text(p+mark+1,shortname);
737
 
        i = subtract_pointers(tmp,(p+mark+1));
738
 
        if (i>510) error ("Short name of object exceeded 765 Z-characters");
739
 
        p[mark] = i/2;
740
 
        mark += i+1;
741
 
    }
742
 
    if (current_defn_is_class)
743
 
    {   mark = write_properties_between(p,mark,3,3);
744
 
        for (i=0;i<6;i++)
745
 
            p[mark++] = full_object.atts[i];
746
 
        class_begins_at[no_classes++] = mark;
747
 
    }
748
 
 
749
 
    mark = write_properties_between(p, mark, 1, (version_number==3)?31:63);
750
 
 
751
 
    i = mark - properties_table_size;
752
 
    properties_table_size = mark;
753
 
 
754
 
    return(i);
755
 
}
756
 
 
757
 
static int gpropsort(void *ptr1, void *ptr2)
758
 
{
759
 
  propg *prop1 = ptr1;
760
 
  propg *prop2 = ptr2;
761
 
  
762
 
  if (prop2->num == -1)
763
 
    return -1;
764
 
  if (prop1->num == -1)
765
 
    return 1;
766
 
  if (prop1->num < prop2->num)
767
 
    return -1;
768
 
  if (prop1->num > prop2->num)
769
 
    return 1;
770
 
 
771
 
  return (prop1->continuation - prop2->continuation);
772
 
}
773
 
 
774
 
static int32 write_property_block_g(void)
775
 
{
776
 
  /*  Compile the (now complete) full_object properties into a
777
 
      property-table block at "p" in Inform's memory. 
778
 
      Return the number of bytes written to the block. 
779
 
      In Glulx, the shortname property isn't used here; it's already
780
 
      been compiled into an ordinary string. */
781
 
 
782
 
  int32 i;
783
 
  int ix, jx, kx, totalprops;
784
 
  int32 mark = properties_table_size;
785
 
  int32 datamark;
786
 
  uchar *p = (uchar *) properties_table;
787
 
 
788
 
  if (current_defn_is_class) {
789
 
    for (i=0;i<NUM_ATTR_BYTES;i++)
790
 
      p[mark++] = full_object_g.atts[i];
791
 
    class_begins_at[no_classes++] = mark;
792
 
  }
793
 
 
794
 
  qsort(full_object_g.props, full_object_g.numprops, sizeof(propg), 
795
 
    (int (*)(const void *, const void *))(&gpropsort));
796
 
 
797
 
  full_object_g.finalpropaddr = mark;
798
 
 
799
 
  totalprops = 0;
800
 
 
801
 
  for (ix=0; ix<full_object_g.numprops; ix=jx) {
802
 
    int propnum = full_object_g.props[ix].num;
803
 
    if (propnum == -1)
804
 
        break;
805
 
    for (jx=ix; 
806
 
        jx<full_object_g.numprops && full_object_g.props[jx].num == propnum;
807
 
        jx++);
808
 
    totalprops++;
809
 
  }
810
 
 
811
 
  /* Write out the number of properties in this table. */
812
 
  WriteInt32(p+mark, totalprops);
813
 
  mark += 4;
814
 
 
815
 
  datamark = mark + 10*totalprops;
816
 
 
817
 
  for (ix=0; ix<full_object_g.numprops; ix=jx) {
818
 
    int propnum = full_object_g.props[ix].num;
819
 
    int flags = full_object_g.props[ix].flags;
820
 
    int totallen = 0;
821
 
    int32 datamarkstart = datamark;
822
 
    if (propnum == -1)
823
 
      break;
824
 
    for (jx=ix; 
825
 
        jx<full_object_g.numprops && full_object_g.props[jx].num == propnum;
826
 
        jx++) {
827
 
      int32 datastart = full_object_g.props[jx].datastart;
828
 
      for (kx=0; kx<full_object_g.props[jx].datalen; kx++) {
829
 
        int32 val = full_object_g.propdata[datastart+kx].value;
830
 
        WriteInt32(p+datamark, val);
831
 
        if (full_object_g.propdata[datastart+kx].marker != 0)
832
 
          backpatch_zmachine(full_object_g.propdata[datastart+kx].marker,
833
 
            PROP_ZA, datamark);
834
 
        totallen++;
835
 
        datamark += 4;
836
 
      }
837
 
    }
838
 
    WriteInt16(p+mark, propnum);
839
 
    mark += 2;
840
 
    WriteInt16(p+mark, totallen);
841
 
    mark += 2;
842
 
    WriteInt32(p+mark, datamarkstart); 
843
 
    mark += 4;
844
 
    WriteInt16(p+mark, flags);
845
 
    mark += 2;
846
 
  }
847
 
 
848
 
  mark = datamark;
849
 
 
850
 
  i = mark - properties_table_size;
851
 
  properties_table_size = mark;
852
 
  return i;
853
 
}
854
 
 
855
 
/* ------------------------------------------------------------------------- */
856
 
/*   The final stage in Nearby/Object/Class definition processing.           */
857
 
/* ------------------------------------------------------------------------- */
858
 
 
859
 
static void manufacture_object_z(void)
860
 
{   int i, j;
861
 
 
862
 
    segment_markers.enabled = FALSE;
863
 
    directives.enabled = TRUE;
864
 
 
865
 
    property_inheritance_z();
866
 
 
867
 
    objectsz[no_objects].parent = parent_of_this_obj;
868
 
    objectsz[no_objects].next = 0;
869
 
    objectsz[no_objects].child = 0;
870
 
 
871
 
    if ((parent_of_this_obj > 0) && (parent_of_this_obj != 0x7fff))
872
 
    {   i = objectsz[parent_of_this_obj-1].child;
873
 
        if (i == 0)
874
 
            objectsz[parent_of_this_obj-1].child = no_objects + 1;
875
 
        else
876
 
        {   while(objectsz[i-1].next != 0) i = objectsz[i-1].next;
877
 
            objectsz[i-1].next = no_objects+1;
878
 
        }
879
 
    }
880
 
 
881
 
        /*  The properties table consists simply of a sequence of property
882
 
            blocks, one for each object in order of definition, exactly as
883
 
            it will appear in the final Z-machine.                           */
884
 
 
885
 
    j = write_property_block_z(shortname_buffer);
886
 
 
887
 
    objectsz[no_objects].propsize = j;
888
 
    if (properties_table_size >= MAX_PROP_TABLE_SIZE)
889
 
        memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
890
 
 
891
 
    if (current_defn_is_class)
892
 
        for (i=0;i<6;i++) objectsz[no_objects].atts[i] = 0;
893
 
    else
894
 
        for (i=0;i<6;i++)
895
 
            objectsz[no_objects].atts[i] = full_object.atts[i];
896
 
 
897
 
    no_objects++;
898
 
}
899
 
 
900
 
static void manufacture_object_g(void)
901
 
{   int32 i, j;
902
 
 
903
 
    segment_markers.enabled = FALSE;
904
 
    directives.enabled = TRUE;
905
 
 
906
 
    property_inheritance_g();
907
 
 
908
 
    objectsg[no_objects].parent = parent_of_this_obj;
909
 
    objectsg[no_objects].next = 0;
910
 
    objectsg[no_objects].child = 0;
911
 
 
912
 
    if ((parent_of_this_obj > 0) && (parent_of_this_obj != 0x7fffffff))
913
 
    {   i = objectsg[parent_of_this_obj-1].child;
914
 
        if (i == 0)
915
 
            objectsg[parent_of_this_obj-1].child = no_objects + 1;
916
 
        else
917
 
        {   while(objectsg[i-1].next != 0) i = objectsg[i-1].next;
918
 
            objectsg[i-1].next = no_objects+1;
919
 
        }
920
 
    }
921
 
 
922
 
    objectsg[no_objects].shortname = compile_string(shortname_buffer,
923
 
      FALSE, FALSE);
924
 
 
925
 
        /*  The properties table consists simply of a sequence of property
926
 
            blocks, one for each object in order of definition, exactly as
927
 
            it will appear in the final machine image.                      */
928
 
 
929
 
    j = write_property_block_g();
930
 
 
931
 
    objectsg[no_objects].propaddr = full_object_g.finalpropaddr;
932
 
 
933
 
    objectsg[no_objects].propsize = j;
934
 
    if (properties_table_size >= MAX_PROP_TABLE_SIZE)
935
 
        memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
936
 
 
937
 
    if (current_defn_is_class)
938
 
        for (i=0;i<NUM_ATTR_BYTES;i++) 
939
 
            objectatts[no_objects*NUM_ATTR_BYTES+i] = 0;
940
 
    else
941
 
        for (i=0;i<NUM_ATTR_BYTES;i++)
942
 
            objectatts[no_objects*NUM_ATTR_BYTES+i] = full_object_g.atts[i];
943
 
 
944
 
    no_objects++;
945
 
}
946
 
 
947
 
 
948
 
/* ========================================================================= */
949
 
/*   [2]  The Object/Nearby/Class directives parser: translating the syntax  */
950
 
/*        into object specifications and then triggering off the above.      */
951
 
/* ========================================================================= */
952
 
/*   Properties ("with" or "private") segment.                               */
953
 
/* ------------------------------------------------------------------------- */
954
 
 
955
 
static int defined_this_segment[128], def_t_s;
956
 
 
957
 
static void properties_segment_z(int this_segment)
958
 
{
959
 
    /*  Parse through the "with" part of an object/class definition:
960
 
 
961
 
        <prop-1> <values...>, <prop-2> <values...>, ..., <prop-n> <values...>
962
 
 
963
 
        This routine also handles "private", with this_segment being equal
964
 
        to the token value for the introductory word ("private" or "with").  */
965
 
 
966
 
 
967
 
    int   i, property_name_symbol, property_number, next_prop, length,
968
 
          individual_property, this_identifier_number;
969
 
 
970
 
    do
971
 
    {   get_next_token();
972
 
        if ((token_type == SEGMENT_MARKER_TT)
973
 
            || (token_type == EOF_TT)
974
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
975
 
        {   put_token_back(); return;
976
 
        }
977
 
 
978
 
        if (token_type != SYMBOL_TT)
979
 
        {   ebf_error("property name", token_text);
980
 
            return;
981
 
        }
982
 
 
983
 
        individual_property = (stypes[token_value] != PROPERTY_T);
984
 
 
985
 
        if (individual_property)
986
 
        {   if (sflags[token_value] & UNKNOWN_SFLAG)
987
 
            {   this_identifier_number = no_individual_properties++;
988
 
                assign_symbol(token_value, this_identifier_number,
989
 
                    INDIVIDUAL_PROPERTY_T);
990
 
            }
991
 
            else
992
 
            {   if (stypes[token_value]==INDIVIDUAL_PROPERTY_T)
993
 
                    this_identifier_number = svals[token_value];
994
 
                else
995
 
                {   char already_error[128];
996
 
                    sprintf(already_error,
997
 
                        "\"%s\" is a name already in use (with type %s) \
998
 
and may not be used as a property name too",
999
 
                        token_text, typename(stypes[token_value]));
1000
 
                    error(already_error);
1001
 
                    return;
1002
 
                }
1003
 
            }
1004
 
 
1005
 
            defined_this_segment[def_t_s++] = token_value;
1006
 
 
1007
 
            if (individual_prop_table_size++ == 0)
1008
 
            {   full_object.pp[full_object.l].num = 3;
1009
 
                full_object.pp[full_object.l].l = 1;
1010
 
                full_object.pp[full_object.l].ao[0].value
1011
 
                    = individuals_length;
1012
 
                full_object.pp[full_object.l].ao[0].type = LONG_CONSTANT_OT;
1013
 
                full_object.pp[full_object.l].ao[0].marker = INDIVPT_MV;
1014
 
 
1015
 
                i_m = individuals_length;
1016
 
                full_object.l++;
1017
 
            }
1018
 
            individuals_table[i_m] = this_identifier_number/256;
1019
 
            if (this_segment == PRIVATE_SEGMENT)
1020
 
                individuals_table[i_m] |= 0x80;
1021
 
            individuals_table[i_m+1] = this_identifier_number%256;
1022
 
            if (module_switch)
1023
 
                backpatch_zmachine(IDENT_MV, INDIVIDUAL_PROP_ZA, i_m);
1024
 
            individuals_table[i_m+2] = 0;
1025
 
        }
1026
 
        else
1027
 
        {   if (sflags[token_value] & UNKNOWN_SFLAG)
1028
 
            {   error_named("No such property name as", token_text);
1029
 
                return;
1030
 
            }
1031
 
            if (this_segment == PRIVATE_SEGMENT)
1032
 
                error_named("Property should be declared in 'with', \
1033
 
not 'private':", token_text);
1034
 
            defined_this_segment[def_t_s++] = token_value;
1035
 
            property_number = svals[token_value];
1036
 
 
1037
 
            next_prop=full_object.l++;
1038
 
            full_object.pp[next_prop].num = property_number;
1039
 
        }
1040
 
 
1041
 
        for (i=0; i<(def_t_s-1); i++)
1042
 
            if (defined_this_segment[i] == token_value)
1043
 
            {   error_named("Property given twice in the same declaration:",
1044
 
                    (char *) symbs[token_value]);
1045
 
            }
1046
 
            else
1047
 
            if (svals[defined_this_segment[i]] == svals[token_value])
1048
 
            {   char error_b[128];
1049
 
                sprintf(error_b,
1050
 
                    "Property given twice in the same declaration, because \
1051
 
the names '%s' and '%s' actually refer to the same property",
1052
 
                    (char *) symbs[defined_this_segment[i]],
1053
 
                    (char *) symbs[token_value]);
1054
 
                error(error_b);
1055
 
            }
1056
 
 
1057
 
        property_name_symbol = token_value;
1058
 
        sflags[token_value] |= USED_SFLAG;
1059
 
 
1060
 
        length=0;
1061
 
        do
1062
 
        {   assembly_operand AO;
1063
 
            get_next_token();
1064
 
            if ((token_type == EOF_TT)
1065
 
                || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1066
 
                || ((token_type == SEP_TT) && (token_value == COMMA_SEP)))
1067
 
                break;
1068
 
 
1069
 
            if (token_type == SEGMENT_MARKER_TT) { put_token_back(); break; }
1070
 
 
1071
 
            if ((!individual_property) && (property_number==1)
1072
 
                && ((token_type != SQ_TT) || (strlen(token_text) <2 )) 
1073
 
                && (token_type != DQ_TT)
1074
 
                )
1075
 
                warning ("'name' property should only contain dictionary words");
1076
 
 
1077
 
            if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
1078
 
            {   char embedded_name[80];
1079
 
                if (current_defn_is_class)
1080
 
                {   sprintf(embedded_name,
1081
 
                        "%s::%s", classname_text,
1082
 
                        (char *) symbs[property_name_symbol]);
1083
 
                }
1084
 
                else
1085
 
                {   sprintf(embedded_name,
1086
 
                        "%s.%s", objectname_text,
1087
 
                        (char *) symbs[property_name_symbol]);
1088
 
                }
1089
 
                AO.value = parse_routine(NULL, TRUE, embedded_name, FALSE, -1);
1090
 
                AO.type = LONG_CONSTANT_OT;
1091
 
                AO.marker = IROUTINE_MV;
1092
 
 
1093
 
                directives.enabled = FALSE;
1094
 
                segment_markers.enabled = TRUE;
1095
 
 
1096
 
                statements.enabled = FALSE;
1097
 
                misc_keywords.enabled = FALSE;
1098
 
                local_variables.enabled = FALSE;
1099
 
                system_functions.enabled = FALSE;
1100
 
                conditions.enabled = FALSE;
1101
 
            }
1102
 
            else
1103
 
 
1104
 
            /*  A special rule applies to values in double-quotes of the
1105
 
                built-in property "name", which always has number 1: such
1106
 
                property values are dictionary entries and not static
1107
 
                strings                                                      */
1108
 
 
1109
 
            if ((!individual_property) &&
1110
 
                (property_number==1) && (token_type == DQ_TT))
1111
 
            {   AO.value = dictionary_add(token_text, 0x80, 0, 0);
1112
 
                AO.type = LONG_CONSTANT_OT;
1113
 
                AO.marker = DWORD_MV;
1114
 
            }
1115
 
            else
1116
 
            {   if (length!=0)
1117
 
                {
1118
 
                    if ((token_type == SYMBOL_TT)
1119
 
                        && (stypes[token_value]==PROPERTY_T))
1120
 
                    {
1121
 
                        /*  This is not necessarily an error: it's possible
1122
 
                            to imagine a property whose value is a list
1123
 
                            of other properties to look up, but far more
1124
 
                            likely that a comma has been omitted in between
1125
 
                            two property blocks                              */
1126
 
 
1127
 
                        warning_named(
1128
 
               "Missing ','? Property data seems to contain the property name",
1129
 
                            token_text);
1130
 
                    }
1131
 
                }
1132
 
 
1133
 
                /*  An ordinary value, then:                                 */
1134
 
 
1135
 
                put_token_back();
1136
 
                AO = parse_expression(ARRAY_CONTEXT);
1137
 
            }
1138
 
 
1139
 
            if (length == 64)
1140
 
            {   error_named("Limit (of 32 values) exceeded for property",
1141
 
                    (char *) symbs[property_name_symbol]);
1142
 
                break;
1143
 
            }
1144
 
 
1145
 
            if (individual_property)
1146
 
            {   if (AO.marker != 0)
1147
 
                    backpatch_zmachine(AO.marker, INDIVIDUAL_PROP_ZA,
1148
 
                        i_m+3+length);
1149
 
                individuals_table[i_m+3+length++] = AO.value/256;
1150
 
                individuals_table[i_m+3+length++] = AO.value%256;
1151
 
            }
1152
 
            else
1153
 
            {   full_object.pp[next_prop].ao[length/2] = AO;
1154
 
                length = length + 2;
1155
 
            }
1156
 
 
1157
 
        } while (TRUE);
1158
 
 
1159
 
        /*  People rarely do, but it is legal to declare a property without
1160
 
            a value at all:
1161
 
 
1162
 
                with  name "fish", number, time_left;
1163
 
 
1164
 
            in which case the properties "number" and "time_left" are
1165
 
            created as in effect variables and initialised to zero.          */
1166
 
 
1167
 
        if (length == 0)
1168
 
        {   if (individual_property)
1169
 
            {   individuals_table[i_m+3+length++] = 0;
1170
 
                individuals_table[i_m+3+length++] = 0;
1171
 
            }
1172
 
            else
1173
 
            {   full_object.pp[next_prop].ao[0].value = 0;
1174
 
                full_object.pp[next_prop].ao[0].type  = LONG_CONSTANT_OT;
1175
 
                full_object.pp[next_prop].ao[0].marker = 0;
1176
 
                length = 2;
1177
 
            }
1178
 
        }
1179
 
 
1180
 
        if ((version_number==3) && (!individual_property))
1181
 
        {   if (length > 8)
1182
 
            {
1183
 
       warning_named("Version 3 limit of 4 values per property exceeded \
1184
 
(use -v5 to get 32), so truncating property",
1185
 
                    (char *) symbs[property_name_symbol]);
1186
 
                full_object.pp[next_prop].l=4;
1187
 
            }
1188
 
        }
1189
 
 
1190
 
        if (individual_property)
1191
 
        {   individuals_table[i_m + 2] = length;
1192
 
            individuals_length += length+3;
1193
 
            i_m = individuals_length;
1194
 
            if (individuals_length+64 > MAX_INDIV_PROP_TABLE_SIZE)
1195
 
                memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
1196
 
                    MAX_INDIV_PROP_TABLE_SIZE);
1197
 
        }
1198
 
        else
1199
 
            full_object.pp[next_prop].l = length/2;
1200
 
 
1201
 
        if ((token_type == EOF_TT)
1202
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1203
 
        {   put_token_back(); return;
1204
 
        }
1205
 
 
1206
 
    } while (TRUE);
1207
 
}
1208
 
 
1209
 
 
1210
 
static void properties_segment_g(int this_segment)
1211
 
{
1212
 
    /*  Parse through the "with" part of an object/class definition:
1213
 
 
1214
 
        <prop-1> <values...>, <prop-2> <values...>, ..., <prop-n> <values...>
1215
 
 
1216
 
        This routine also handles "private", with this_segment being equal
1217
 
        to the token value for the introductory word ("private" or "with").  */
1218
 
 
1219
 
 
1220
 
    int   i, next_prop,
1221
 
          individual_property, this_identifier_number;
1222
 
    int32 property_name_symbol, property_number, length;
1223
 
 
1224
 
    do
1225
 
    {   get_next_token();
1226
 
        if ((token_type == SEGMENT_MARKER_TT)
1227
 
            || (token_type == EOF_TT)
1228
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1229
 
        {   put_token_back(); return;
1230
 
        }
1231
 
 
1232
 
        if (token_type != SYMBOL_TT)
1233
 
        {   ebf_error("property name", token_text);
1234
 
            return;
1235
 
        }
1236
 
 
1237
 
        individual_property = (stypes[token_value] != PROPERTY_T);
1238
 
 
1239
 
        if (individual_property)
1240
 
        {   if (sflags[token_value] & UNKNOWN_SFLAG)
1241
 
            {   this_identifier_number = no_individual_properties++;
1242
 
                assign_symbol(token_value, this_identifier_number,
1243
 
                    INDIVIDUAL_PROPERTY_T);
1244
 
            }
1245
 
            else
1246
 
            {   if (stypes[token_value]==INDIVIDUAL_PROPERTY_T)
1247
 
                    this_identifier_number = svals[token_value];
1248
 
                else
1249
 
                {   char already_error[128];
1250
 
                    sprintf(already_error,
1251
 
                        "\"%s\" is a name already in use (with type %s) \
1252
 
and may not be used as a property name too",
1253
 
                        token_text, typename(stypes[token_value]));
1254
 
                    error(already_error);
1255
 
                    return;
1256
 
                }
1257
 
            }
1258
 
 
1259
 
            defined_this_segment[def_t_s++] = token_value;
1260
 
            property_number = svals[token_value];
1261
 
 
1262
 
            next_prop=full_object_g.numprops++;
1263
 
            full_object_g.props[next_prop].num = property_number;
1264
 
            full_object_g.props[next_prop].flags = 
1265
 
              ((this_segment == PRIVATE_SEGMENT) ? 1 : 0);
1266
 
            full_object_g.props[next_prop].datastart = full_object_g.propdatasize;
1267
 
            full_object_g.props[next_prop].continuation = 0;
1268
 
            full_object_g.props[next_prop].datalen = 0;
1269
 
        }
1270
 
        else
1271
 
        {   if (sflags[token_value] & UNKNOWN_SFLAG)
1272
 
            {   error_named("No such property name as", token_text);
1273
 
                return;
1274
 
            }
1275
 
            if (this_segment == PRIVATE_SEGMENT)
1276
 
                error_named("Property should be declared in 'with', \
1277
 
not 'private':", token_text);
1278
 
 
1279
 
            defined_this_segment[def_t_s++] = token_value;
1280
 
            property_number = svals[token_value];
1281
 
 
1282
 
            next_prop=full_object_g.numprops++;
1283
 
            full_object_g.props[next_prop].num = property_number;
1284
 
            full_object_g.props[next_prop].flags = 0;
1285
 
            full_object_g.props[next_prop].datastart = full_object_g.propdatasize;
1286
 
            full_object_g.props[next_prop].continuation = 0;
1287
 
            full_object_g.props[next_prop].datalen = 0;
1288
 
        }
1289
 
 
1290
 
        for (i=0; i<(def_t_s-1); i++)
1291
 
            if (defined_this_segment[i] == token_value)
1292
 
            {   error_named("Property given twice in the same declaration:",
1293
 
                    (char *) symbs[token_value]);
1294
 
            }
1295
 
            else
1296
 
            if (svals[defined_this_segment[i]] == svals[token_value])
1297
 
            {   char error_b[128];
1298
 
                sprintf(error_b,
1299
 
                    "Property given twice in the same declaration, because \
1300
 
the names '%s' and '%s' actually refer to the same property",
1301
 
                    (char *) symbs[defined_this_segment[i]],
1302
 
                    (char *) symbs[token_value]);
1303
 
                error(error_b);
1304
 
            }
1305
 
 
1306
 
        if (full_object_g.numprops == MAX_OBJ_PROP_COUNT) {
1307
 
          error_numbered("Limit of property entries exceeded for this \
1308
 
object; MAX_OBJ_PROP_COUNT is", MAX_OBJ_PROP_COUNT);
1309
 
          break;
1310
 
        }
1311
 
 
1312
 
        property_name_symbol = token_value;
1313
 
        sflags[token_value] |= USED_SFLAG;
1314
 
 
1315
 
        length=0;
1316
 
        do
1317
 
        {   assembly_operand AO;
1318
 
            get_next_token();
1319
 
            if ((token_type == EOF_TT)
1320
 
                || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1321
 
                || ((token_type == SEP_TT) && (token_value == COMMA_SEP)))
1322
 
                break;
1323
 
 
1324
 
            if (token_type == SEGMENT_MARKER_TT) { put_token_back(); break; }
1325
 
 
1326
 
            if ((!individual_property) && (property_number==1)
1327
 
                && (token_type != SQ_TT) && (token_type != DQ_TT)
1328
 
                )
1329
 
                warning ("'name' property should only contain dictionary words");
1330
 
 
1331
 
            if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
1332
 
            {   char embedded_name[80];
1333
 
                if (current_defn_is_class)
1334
 
                {   sprintf(embedded_name,
1335
 
                        "%s::%s", classname_text,
1336
 
                        (char *) symbs[property_name_symbol]);
1337
 
                }
1338
 
                else
1339
 
                {   sprintf(embedded_name,
1340
 
                        "%s.%s", objectname_text,
1341
 
                        (char *) symbs[property_name_symbol]);
1342
 
                }
1343
 
                AO.value = parse_routine(NULL, TRUE, embedded_name, FALSE, -1);
1344
 
                AO.type = CONSTANT_OT; 
1345
 
                AO.marker = IROUTINE_MV;
1346
 
 
1347
 
                directives.enabled = FALSE;
1348
 
                segment_markers.enabled = TRUE;
1349
 
 
1350
 
                statements.enabled = FALSE;
1351
 
                misc_keywords.enabled = FALSE;
1352
 
                local_variables.enabled = FALSE;
1353
 
                system_functions.enabled = FALSE;
1354
 
                conditions.enabled = FALSE;
1355
 
            }
1356
 
            else
1357
 
 
1358
 
            /*  A special rule applies to values in double-quotes of the
1359
 
                built-in property "name", which always has number 1: such
1360
 
                property values are dictionary entries and not static
1361
 
                strings                                                      */
1362
 
 
1363
 
            if ((!individual_property) &&
1364
 
                (property_number==1) && (token_type == DQ_TT))
1365
 
            {   AO.value = dictionary_add(token_text, 0x80, 0, 0);
1366
 
                AO.type = CONSTANT_OT; 
1367
 
                AO.marker = DWORD_MV;
1368
 
            }
1369
 
            else
1370
 
            {   if (length!=0)
1371
 
                {
1372
 
                    if ((token_type == SYMBOL_TT)
1373
 
                        && (stypes[token_value]==PROPERTY_T))
1374
 
                    {
1375
 
                        /*  This is not necessarily an error: it's possible
1376
 
                            to imagine a property whose value is a list
1377
 
                            of other properties to look up, but far more
1378
 
                            likely that a comma has been omitted in between
1379
 
                            two property blocks                              */
1380
 
 
1381
 
                        warning_named(
1382
 
               "Missing ','? Property data seems to contain the property name",
1383
 
                            token_text);
1384
 
                    }
1385
 
                }
1386
 
 
1387
 
                /*  An ordinary value, then:                                 */
1388
 
 
1389
 
                put_token_back();
1390
 
                AO = parse_expression(ARRAY_CONTEXT);
1391
 
            }
1392
 
 
1393
 
            if (length == 32768) /* VENEER_CONSTRAINT_ON_PROP_TABLE_SIZE? */
1394
 
            {   error_named("Limit (of 32768 values) exceeded for property",
1395
 
                    (char *) symbs[property_name_symbol]);
1396
 
                break;
1397
 
            }
1398
 
 
1399
 
            if (full_object_g.propdatasize >= MAX_OBJ_PROP_TABLE_SIZE) {
1400
 
              error_numbered("Limit of property data exceeded for this \
1401
 
object; MAX_OBJ_PROP_TABLE_SIZE is", MAX_OBJ_PROP_TABLE_SIZE);
1402
 
              break;
1403
 
            }
1404
 
 
1405
 
            full_object_g.propdata[full_object_g.propdatasize++] = AO;
1406
 
            length += 1;
1407
 
 
1408
 
        } while (TRUE);
1409
 
 
1410
 
        /*  People rarely do, but it is legal to declare a property without
1411
 
            a value at all:
1412
 
 
1413
 
                with  name "fish", number, time_left;
1414
 
 
1415
 
            in which case the properties "number" and "time_left" are
1416
 
            created as in effect variables and initialised to zero.          */
1417
 
 
1418
 
        if (length == 0)
1419
 
        {
1420
 
            assembly_operand AO;
1421
 
            AO.value = 0;
1422
 
            AO.type = CONSTANT_OT;
1423
 
            AO.marker = 0;
1424
 
            full_object_g.propdata[full_object_g.propdatasize++] = AO;
1425
 
            length += 1;
1426
 
        }
1427
 
 
1428
 
        full_object_g.props[next_prop].datalen = length;
1429
 
 
1430
 
        if ((token_type == EOF_TT)
1431
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1432
 
        {   put_token_back(); return;
1433
 
        }
1434
 
 
1435
 
    } while (TRUE);
1436
 
}
1437
 
 
1438
 
static void properties_segment(int this_segment)
1439
 
{
1440
 
  if (!glulx_mode)
1441
 
    properties_segment_z(this_segment);
1442
 
  else
1443
 
    properties_segment_g(this_segment);
1444
 
}
1445
 
 
1446
 
/* ------------------------------------------------------------------------- */
1447
 
/*   Attributes ("has") segment.                                             */
1448
 
/* ------------------------------------------------------------------------- */
1449
 
 
1450
 
static void attributes_segment(void)
1451
 
{
1452
 
    /*  Parse through the "has" part of an object/class definition:
1453
 
 
1454
 
        [~]<attribute-1> [~]<attribute-2> ... [~]<attribute-n>               */
1455
 
 
1456
 
    int attribute_number, truth_state, bitmask;
1457
 
    uchar *attrbyte;
1458
 
    do
1459
 
    {   truth_state = TRUE;
1460
 
 
1461
 
        ParseAttrN:
1462
 
 
1463
 
        get_next_token();
1464
 
        if ((token_type == SEGMENT_MARKER_TT)
1465
 
            || (token_type == EOF_TT)
1466
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1467
 
        {   if (!truth_state)
1468
 
                ebf_error("attribute name after '~'", token_text);
1469
 
            put_token_back(); return;
1470
 
        }
1471
 
        if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) return;
1472
 
 
1473
 
        if ((token_type == SEP_TT) && (token_value == ARTNOT_SEP))
1474
 
        {   truth_state = !truth_state; goto ParseAttrN;
1475
 
        }
1476
 
 
1477
 
        if ((token_type != SYMBOL_TT)
1478
 
            || (stypes[token_value] != ATTRIBUTE_T))
1479
 
        {   ebf_error("name of an already-declared attribute", token_text);
1480
 
            return;
1481
 
        }
1482
 
 
1483
 
        attribute_number = svals[token_value];
1484
 
        sflags[token_value] |= USED_SFLAG;
1485
 
 
1486
 
        if (!glulx_mode) {
1487
 
            bitmask = (1 << (7-attribute_number%8));
1488
 
            attrbyte = &(full_object.atts[attribute_number/8]);
1489
 
        }
1490
 
        else {
1491
 
            /* In Glulx, my prejudices rule, and therefore bits are numbered
1492
 
               from least to most significant. This is the opposite of the
1493
 
               way the Z-machine works. */
1494
 
            bitmask = (1 << (attribute_number%8));
1495
 
            attrbyte = &(full_object_g.atts[attribute_number/8]);
1496
 
        }
1497
 
 
1498
 
        if (truth_state)
1499
 
            *attrbyte |= bitmask;     /* Set attribute bit */
1500
 
        else
1501
 
            *attrbyte &= ~bitmask;    /* Clear attribute bit */
1502
 
 
1503
 
    } while (TRUE);
1504
 
}
1505
 
 
1506
 
/* ------------------------------------------------------------------------- */
1507
 
/*   Classes ("class") segment.                                              */
1508
 
/* ------------------------------------------------------------------------- */
1509
 
 
1510
 
static void add_class_to_inheritance_list(int class_number)
1511
 
{
1512
 
    int i;
1513
 
 
1514
 
    /*  The class number is actually the class's object number, which needs
1515
 
        to be translated into its actual class number:                       */
1516
 
 
1517
 
    for (i=0;i<no_classes;i++)
1518
 
        if (class_number == class_object_numbers[i])
1519
 
        {   class_number = i+1;
1520
 
            break;
1521
 
        }
1522
 
 
1523
 
    /*  Remember the inheritance list so that property inheritance can
1524
 
        be sorted out later on, when the definition has been finished:       */
1525
 
 
1526
 
    classes_to_inherit_from[no_classes_to_inherit_from++] = class_number;
1527
 
 
1528
 
    /*  Inheriting attributes from the class at once:                        */
1529
 
 
1530
 
    if (!glulx_mode) {
1531
 
        for (i=0; i<6; i++)
1532
 
            full_object.atts[i]
1533
 
                |= properties_table[class_begins_at[class_number-1] - 6 + i];
1534
 
    }
1535
 
    else {
1536
 
        for (i=0; i<NUM_ATTR_BYTES; i++)
1537
 
            full_object_g.atts[i]
1538
 
                |= properties_table[class_begins_at[class_number-1] 
1539
 
                    - NUM_ATTR_BYTES + i];
1540
 
    }
1541
 
}
1542
 
 
1543
 
static void classes_segment(void)
1544
 
{
1545
 
    /*  Parse through the "class" part of an object/class definition:
1546
 
 
1547
 
        <class-1> ... <class-n>                                              */
1548
 
 
1549
 
    do
1550
 
    {   get_next_token();
1551
 
        if ((token_type == SEGMENT_MARKER_TT)
1552
 
            || (token_type == EOF_TT)
1553
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1554
 
        {   put_token_back(); return;
1555
 
        }
1556
 
        if ((token_type == SEP_TT) && (token_value == COMMA_SEP)) return;
1557
 
 
1558
 
        if ((token_type != SYMBOL_TT)
1559
 
            || (stypes[token_value] != CLASS_T))
1560
 
        {   ebf_error("name of an already-declared class", token_text);
1561
 
            return;
1562
 
        }
1563
 
 
1564
 
        sflags[token_value] |= USED_SFLAG;
1565
 
        add_class_to_inheritance_list(svals[token_value]);
1566
 
    } while (TRUE);
1567
 
}
1568
 
 
1569
 
/* ------------------------------------------------------------------------- */
1570
 
/*   Parse the body of a Nearby/Object/Class definition.                     */
1571
 
/* ------------------------------------------------------------------------- */
1572
 
 
1573
 
static void parse_body_of_definition(void)
1574
 
{   int commas_in_row;
1575
 
 
1576
 
    def_t_s = 0;
1577
 
 
1578
 
    do
1579
 
    {   commas_in_row = -1;
1580
 
        do
1581
 
        {   get_next_token(); commas_in_row++;
1582
 
        } while ((token_type == SEP_TT) && (token_value == COMMA_SEP));
1583
 
 
1584
 
        if (commas_in_row>1)
1585
 
            error("Two commas ',' in a row in object/class definition");
1586
 
 
1587
 
        if ((token_type == EOF_TT)
1588
 
            || ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
1589
 
        {   if (commas_in_row > 0)
1590
 
                error("Object/class definition finishes with ','");
1591
 
            break;
1592
 
        }
1593
 
 
1594
 
        if (token_type != SEGMENT_MARKER_TT)
1595
 
        {   error_named("Expected 'with', 'has' or 'class' in \
1596
 
object/class definition but found", token_text);
1597
 
            break;
1598
 
        }
1599
 
        else
1600
 
        switch(token_value)
1601
 
        {   case WITH_SEGMENT:
1602
 
                properties_segment(WITH_SEGMENT);
1603
 
                break;
1604
 
            case PRIVATE_SEGMENT:
1605
 
                properties_segment(PRIVATE_SEGMENT);
1606
 
                break;
1607
 
            case HAS_SEGMENT:
1608
 
                attributes_segment();
1609
 
                break;
1610
 
            case CLASS_SEGMENT:
1611
 
                classes_segment();
1612
 
                break;
1613
 
        }
1614
 
 
1615
 
    } while (TRUE);
1616
 
 
1617
 
}
1618
 
 
1619
 
/* ------------------------------------------------------------------------- */
1620
 
/*   Class directives:                                                       */
1621
 
/*                                                                           */
1622
 
/*        Class <name>  <body of definition>                                 */
1623
 
/* ------------------------------------------------------------------------- */
1624
 
 
1625
 
static void initialise_full_object(void)
1626
 
{
1627
 
  int i;
1628
 
  if (!glulx_mode) {
1629
 
    full_object.l = 0;
1630
 
    full_object.atts[0] = 0;
1631
 
    full_object.atts[1] = 0;
1632
 
    full_object.atts[2] = 0;
1633
 
    full_object.atts[3] = 0;
1634
 
    full_object.atts[4] = 0;
1635
 
    full_object.atts[5] = 0;
1636
 
  }
1637
 
  else {
1638
 
    full_object_g.numprops = 0;
1639
 
    full_object_g.propdatasize = 0;
1640
 
    for (i=0; i<NUM_ATTR_BYTES; i++)
1641
 
      full_object_g.atts[i] = 0;
1642
 
  }
1643
 
}
1644
 
 
1645
 
extern void make_class(char * metaclass_name)
1646
 
{   int n, duplicates_to_make = 0, class_number = no_objects+1,
1647
 
        metaclass_flag = (metaclass_name != NULL);
1648
 
    char duplicate_name[128]; dbgl start_dbgl = token_line_ref;
1649
 
 
1650
 
    current_defn_is_class = TRUE; no_classes_to_inherit_from = 0;
1651
 
    individual_prop_table_size = 0;
1652
 
 
1653
 
    if (no_classes==MAX_CLASSES)
1654
 
        memoryerror("MAX_CLASSES", MAX_CLASSES);
1655
 
 
1656
 
    if (no_classes==VENEER_CONSTRAINT_ON_CLASSES)
1657
 
        fatalerror("Inform's maximum possible number of classes (whatever \
1658
 
amount of memory is allocated) has been reached. If this causes serious \
1659
 
inconvenience, please contact the author.");
1660
 
 
1661
 
    directives.enabled = FALSE;
1662
 
 
1663
 
    if (metaclass_flag)
1664
 
    {   token_text = metaclass_name;
1665
 
        token_value = symbol_index(token_text, -1);
1666
 
        token_type = SYMBOL_TT;
1667
 
    }
1668
 
    else
1669
 
    {   get_next_token();
1670
 
        if ((token_type != SYMBOL_TT)
1671
 
            || (!(sflags[token_value] & UNKNOWN_SFLAG)))
1672
 
        {   ebf_error("new class name", token_text);
1673
 
            panic_mode_error_recovery();
1674
 
            return;
1675
 
        }
1676
 
    }
1677
 
 
1678
 
    /*  Each class also creates a modest object representing itself:         */
1679
 
 
1680
 
    strcpy(shortname_buffer, token_text);
1681
 
 
1682
 
    assign_symbol(token_value, class_number, CLASS_T);
1683
 
    classname_text = (char *) symbs[token_value];
1684
 
 
1685
 
    if (!glulx_mode) {
1686
 
        if (metaclass_flag) sflags[token_value] |= SYSTEM_SFLAG;
1687
 
    }
1688
 
    else {
1689
 
        /*  In Glulx, metaclasses have to be backpatched too! So we can't 
1690
 
            mark it as "system", but we should mark it "used". */
1691
 
        if (metaclass_flag) sflags[token_value] |= USED_SFLAG;
1692
 
    }
1693
 
 
1694
 
    /*  "Class" (object 1) has no parent, whereas all other classes are
1695
 
        the children of "Class".  Since "Class" is not present in a module,
1696
 
        a special value is used which is corrected to 1 by the linker.       */
1697
 
 
1698
 
    if (metaclass_flag) parent_of_this_obj = 0;
1699
 
    else parent_of_this_obj = (module_switch)?MAXINTWORD:1;
1700
 
 
1701
 
    class_object_numbers[no_classes] = class_number;
1702
 
 
1703
 
    initialise_full_object();
1704
 
 
1705
 
    /*  Give the class the (nameless in Inform syntax) "inheritance" property
1706
 
        with value its own class number.  (This therefore accumulates onto
1707
 
        the inheritance property of any object inheriting from the class,
1708
 
        since property 2 is always set to "additive" -- see below)           */
1709
 
 
1710
 
    if (!glulx_mode) {
1711
 
      full_object.l = 1;
1712
 
      full_object.pp[0].num = 2;
1713
 
      full_object.pp[0].l = 1;
1714
 
      full_object.pp[0].ao[0].value  = no_objects + 1;
1715
 
      full_object.pp[0].ao[0].type   = LONG_CONSTANT_OT;
1716
 
      full_object.pp[0].ao[0].marker = OBJECT_MV;
1717
 
    }
1718
 
    else {
1719
 
      full_object_g.numprops = 1;
1720
 
      full_object_g.props[0].num = 2;
1721
 
      full_object_g.props[0].flags = 0;
1722
 
      full_object_g.props[0].datastart = 0;
1723
 
      full_object_g.props[0].continuation = 0;
1724
 
      full_object_g.props[0].datalen = 1;
1725
 
      full_object_g.propdatasize = 1;
1726
 
      full_object_g.propdata[0].value  = no_objects + 1;
1727
 
      full_object_g.propdata[0].type   = CONSTANT_OT;
1728
 
      full_object_g.propdata[0].marker = OBJECT_MV;
1729
 
    }
1730
 
 
1731
 
    if (!metaclass_flag)
1732
 
    {   get_next_token();
1733
 
        if ((token_type == SEP_TT) && (token_value == OPENB_SEP))
1734
 
        {   assembly_operand AO;
1735
 
            AO = parse_expression(CONSTANT_CONTEXT);
1736
 
            if (AO.marker != 0)
1737
 
            {   error("Duplicate-number not known at compile time");
1738
 
                n=0;
1739
 
            }
1740
 
            else
1741
 
                n = AO.value;
1742
 
            if ((n<0) || (n>10000))
1743
 
            {   error("The number of duplicates must be 0 to 10000");
1744
 
                n=0;
1745
 
            }
1746
 
 
1747
 
            /*  Make one extra duplicate, since the veneer routines need
1748
 
                always to keep an undamaged prototype for the class in stock */
1749
 
 
1750
 
            duplicates_to_make = n + 1;
1751
 
 
1752
 
            match_close_bracket();
1753
 
        } else put_token_back();
1754
 
 
1755
 
        /*  Parse the body of the definition:                                */
1756
 
 
1757
 
        parse_body_of_definition();
1758
 
    }
1759
 
 
1760
 
    if (debugfile_switch)
1761
 
    {   write_debug_byte(CLASS_DBR);
1762
 
        write_debug_string(shortname_buffer);
1763
 
        write_dbgl(start_dbgl);
1764
 
        write_dbgl(token_line_ref);
1765
 
    }
1766
 
 
1767
 
    if (!glulx_mode)
1768
 
      manufacture_object_z();
1769
 
    else
1770
 
      manufacture_object_g();
1771
 
 
1772
 
    if (individual_prop_table_size >= VENEER_CONSTRAINT_ON_IP_TABLE_SIZE)
1773
 
        error("This class is too complex: it now carries too many properties. \
1774
 
You may be able to get round this by declaring some of its property names as \
1775
 
\"common properties\" using the 'Property' directive.");
1776
 
 
1777
 
    if (duplicates_to_make > 0)
1778
 
    {   sprintf(duplicate_name, "%s_1", shortname_buffer);
1779
 
        for (n=1; (duplicates_to_make--) > 0; n++)
1780
 
        {   if (n>1)
1781
 
            {   int i = strlen(duplicate_name);
1782
 
                while (duplicate_name[i] != '_') i--;
1783
 
                sprintf(duplicate_name+i+1, "%d", n);
1784
 
            }
1785
 
            make_object(FALSE, duplicate_name, class_number, class_number, -1);
1786
 
        }
1787
 
    }
1788
 
}
1789
 
 
1790
 
/* ------------------------------------------------------------------------- */
1791
 
/*   Object/Nearby directives:                                               */
1792
 
/*                                                                           */
1793
 
/*       Object  <name-1> ... <name-n> "short name"  [parent]  <body of def> */
1794
 
/*                                                                           */
1795
 
/*       Nearby  <name-1> ... <name-n> "short name"  <body of definition>    */
1796
 
/* ------------------------------------------------------------------------- */
1797
 
 
1798
 
static int end_of_header(void)
1799
 
{   if (((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1800
 
        || ((token_type == SEP_TT) && (token_value == COMMA_SEP))
1801
 
        || (token_type == SEGMENT_MARKER_TT)) return TRUE;
1802
 
    return FALSE;
1803
 
}
1804
 
 
1805
 
extern void make_object(int nearby_flag,
1806
 
    char *textual_name, int specified_parent, int specified_class,
1807
 
    int instance_of)
1808
 
{
1809
 
    /*  Ordinarily this is called with nearby_flag TRUE for "Nearby",
1810
 
        FALSE for "Object"; and textual_name NULL, specified_parent and
1811
 
        specified_class both -1.  The next three arguments are used when
1812
 
        the routine is called for class duplicates manufacture (see above).
1813
 
        The last is used to create instances of a particular class.  */
1814
 
 
1815
 
    int i, tree_depth, internal_name_symbol = 0;
1816
 
    char internal_name[64];
1817
 
    dbgl start_dbgl = token_line_ref;
1818
 
 
1819
 
    directives.enabled = FALSE;
1820
 
 
1821
 
    if (no_objects==MAX_OBJECTS) memoryerror("MAX_OBJECTS", MAX_OBJECTS);
1822
 
 
1823
 
    sprintf(internal_name, "nameless_obj__%d", no_objects+1);
1824
 
    objectname_text = internal_name;
1825
 
 
1826
 
    current_defn_is_class = FALSE;
1827
 
 
1828
 
    no_classes_to_inherit_from=0;
1829
 
 
1830
 
    individual_prop_table_size = 0;
1831
 
 
1832
 
    if (nearby_flag) tree_depth=1; else tree_depth=0;
1833
 
 
1834
 
    if (specified_class != -1) goto HeaderPassed;
1835
 
 
1836
 
    get_next_token();
1837
 
 
1838
 
    /*  Read past and count a sequence of "->"s, if any are present          */
1839
 
 
1840
 
    if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
1841
 
    {   if (nearby_flag)
1842
 
          error("The syntax '->' is only used as an alternative to 'Nearby'");
1843
 
 
1844
 
        while ((token_type == SEP_TT) && (token_value == ARROW_SEP))
1845
 
        {   tree_depth++;
1846
 
            get_next_token();
1847
 
        }
1848
 
    }
1849
 
 
1850
 
    sprintf(shortname_buffer, "?");
1851
 
 
1852
 
    segment_markers.enabled = TRUE;
1853
 
 
1854
 
    /*  This first word is either an internal name, or a textual short name,
1855
 
        or the end of the header part                                        */
1856
 
 
1857
 
    if (end_of_header()) goto HeaderPassed;
1858
 
 
1859
 
    if (token_type == DQ_TT) textual_name = token_text;
1860
 
    else
1861
 
    {   if ((token_type != SYMBOL_TT)
1862
 
            || (!(sflags[token_value] & UNKNOWN_SFLAG)))
1863
 
            ebf_error("name for new object or its textual short name",
1864
 
                token_text);
1865
 
        else
1866
 
        {   internal_name_symbol = token_value;
1867
 
            strcpy(internal_name, token_text);
1868
 
        }
1869
 
    }
1870
 
 
1871
 
    /*  The next word is either a parent object, or
1872
 
        a textual short name, or the end of the header part                  */
1873
 
 
1874
 
    get_next_token();
1875
 
    if (end_of_header()) goto HeaderPassed;
1876
 
 
1877
 
    if (token_type == DQ_TT)
1878
 
    {   if (textual_name != NULL)
1879
 
            error("Two textual short names given for only one object");
1880
 
        else
1881
 
            textual_name = token_text;
1882
 
    }
1883
 
    else
1884
 
    {   if ((token_type != SYMBOL_TT)
1885
 
            || (sflags[token_value] & UNKNOWN_SFLAG))
1886
 
        {   if (textual_name == NULL)
1887
 
                ebf_error("parent object or the object's textual short name",
1888
 
                    token_text);
1889
 
            else
1890
 
                ebf_error("parent object", token_text);
1891
 
        }
1892
 
        else goto SpecParent;
1893
 
    }
1894
 
 
1895
 
    /*  Finally, it's possible that there is still a parent object           */
1896
 
 
1897
 
    get_next_token();
1898
 
    if (end_of_header()) goto HeaderPassed;
1899
 
 
1900
 
    if (specified_parent != -1)
1901
 
        ebf_error("body of object definition", token_text);
1902
 
    else
1903
 
    {   SpecParent:
1904
 
        if ((stypes[token_value] == OBJECT_T)
1905
 
            || (stypes[token_value] == CLASS_T))
1906
 
        {   specified_parent = svals[token_value];
1907
 
            sflags[token_value] |= USED_SFLAG;
1908
 
        }
1909
 
        else ebf_error("name of (the parent) object", token_text);
1910
 
    }
1911
 
 
1912
 
    /*  Now it really has to be the body of the definition.                  */
1913
 
 
1914
 
    get_next_token();
1915
 
    if (end_of_header()) goto HeaderPassed;
1916
 
 
1917
 
    ebf_error("body of object definition", token_text);
1918
 
 
1919
 
    HeaderPassed:
1920
 
    if (specified_class == -1) put_token_back();
1921
 
 
1922
 
    if (internal_name_symbol > 0)
1923
 
        assign_symbol(internal_name_symbol, no_objects + 1, OBJECT_T);
1924
 
 
1925
 
    if (listobjects_switch)
1926
 
        printf("%3d \"%s\"\n", no_objects+1,
1927
 
            (textual_name==NULL)?"(with no short name)":textual_name);
1928
 
    if (textual_name == NULL)
1929
 
    {   if (internal_name_symbol > 0)
1930
 
            sprintf(shortname_buffer, "(%s)",
1931
 
                (char *) symbs[internal_name_symbol]);
1932
 
        else
1933
 
            sprintf(shortname_buffer, "(%d)", no_objects+1);
1934
 
    }
1935
 
    else
1936
 
    {   if (strlen(textual_name)>765)
1937
 
            error("Short name of object (in quotes) exceeded 765 characters");
1938
 
        strncpy(shortname_buffer, textual_name, 765);
1939
 
    }
1940
 
 
1941
 
    if (specified_parent != -1)
1942
 
    {   if (tree_depth > 0)
1943
 
            error("Use of '->' (or 'Nearby') clashes with giving a parent");
1944
 
        parent_of_this_obj = specified_parent;
1945
 
    }
1946
 
    else
1947
 
    {   parent_of_this_obj = 0;
1948
 
        if (tree_depth>0)
1949
 
        {
1950
 
            /*  We have to set the parent object to the most recently defined
1951
 
                object at level (tree_depth - 1) in the tree.
1952
 
 
1953
 
                A complication is that objects are numbered 1, 2, ... in the
1954
 
                Z-machine (and in the objects[].parent, etc., fields) but
1955
 
                0, 1, 2, ... internally (and as indices to object[]).        */
1956
 
 
1957
 
            for (i=no_objects-1; i>=0; i--)
1958
 
            {   int j = i, k = 0;
1959
 
 
1960
 
                /*  Metaclass or class objects cannot be '->' parents:  */
1961
 
                if ((!module_switch) && (i<4))
1962
 
                    continue;
1963
 
 
1964
 
                if (!glulx_mode) {
1965
 
                    if (objectsz[i].parent == 1)
1966
 
                        continue;
1967
 
                    while (objectsz[j].parent != 0)
1968
 
                    {   j = objectsz[j].parent - 1; k++; }
1969
 
                }
1970
 
                else {
1971
 
                    if (objectsg[i].parent == 1)
1972
 
                        continue;
1973
 
                    while (objectsg[j].parent != 0)
1974
 
                    {   j = objectsg[j].parent - 1; k++; }
1975
 
                }
1976
 
 
1977
 
                if (k == tree_depth - 1)
1978
 
                {   parent_of_this_obj = i+1;
1979
 
                    break;
1980
 
                }
1981
 
            }
1982
 
            if (parent_of_this_obj == 0)
1983
 
            {   if (tree_depth == 1)
1984
 
    error("'->' (or 'Nearby') fails because there is no previous object");
1985
 
                else
1986
 
    error("'-> -> ...' fails because no previous object is deep enough");
1987
 
            }
1988
 
        }
1989
 
    }
1990
 
 
1991
 
    initialise_full_object();
1992
 
    if (instance_of != -1) add_class_to_inheritance_list(instance_of);
1993
 
 
1994
 
    if (specified_class == -1) parse_body_of_definition();
1995
 
    else add_class_to_inheritance_list(specified_class);
1996
 
 
1997
 
    if (debugfile_switch)
1998
 
    {   write_debug_byte(OBJECT_DBR);
1999
 
        write_debug_byte((no_objects+1)/256);
2000
 
        write_debug_byte((no_objects+1)%256);
2001
 
        write_debug_string(internal_name);
2002
 
        write_dbgl(start_dbgl);
2003
 
        write_dbgl(token_line_ref);
2004
 
    }
2005
 
 
2006
 
    if (!glulx_mode)
2007
 
      manufacture_object_z();
2008
 
    else
2009
 
      manufacture_object_g();
2010
 
}
2011
 
 
2012
 
/* ========================================================================= */
2013
 
/*   Data structure management routines                                      */
2014
 
/* ------------------------------------------------------------------------- */
2015
 
 
2016
 
extern void init_objects_vars(void)
2017
 
{
2018
 
    properties_table = NULL;
2019
 
    prop_is_long = NULL;
2020
 
    prop_is_additive = NULL;
2021
 
    prop_default_value = NULL;
2022
 
 
2023
 
    objectsz = NULL;
2024
 
    objectsg = NULL;
2025
 
    objectatts = NULL;
2026
 
    classes_to_inherit_from = NULL;
2027
 
    class_begins_at = NULL;
2028
 
}
2029
 
 
2030
 
extern void objects_begin_pass(void)
2031
 
{
2032
 
    properties_table_size=0;
2033
 
    prop_is_long[1] = TRUE; prop_is_additive[1] = TRUE;            /* "name" */
2034
 
    prop_is_long[2] = TRUE; prop_is_additive[2] = TRUE;  /* inheritance prop */
2035
 
    if (!glulx_mode)
2036
 
        prop_is_long[3] = TRUE; prop_is_additive[3] = FALSE;
2037
 
                                         /* instance variables table address */
2038
 
    no_properties = 4;
2039
 
 
2040
 
    if (define_INFIX_switch) no_attributes = 1;
2041
 
    else no_attributes = 0;
2042
 
 
2043
 
    no_objects = 0;
2044
 
    if (!glulx_mode) {
2045
 
        objectsz[0].parent = 0; objectsz[0].child = 0; objectsz[0].next = 0;
2046
 
        no_individual_properties=72;
2047
 
    }
2048
 
    else {
2049
 
        objectsg[0].parent = 0; objectsg[0].child = 0; objectsg[0].next = 0;
2050
 
        no_individual_properties = INDIV_PROP_START+8;
2051
 
    }
2052
 
    no_classes = 0;
2053
 
 
2054
 
    no_embedded_routines = 0;
2055
 
 
2056
 
    individuals_length=0;
2057
 
}
2058
 
 
2059
 
extern void objects_allocate_arrays(void)
2060
 
{
2061
 
    objectsz = NULL;
2062
 
    objectsg = NULL;
2063
 
    objectatts = NULL;
2064
 
 
2065
 
    prop_default_value    = my_calloc(sizeof(int32), INDIV_PROP_START,
2066
 
                                "property default values");
2067
 
    prop_is_long          = my_calloc(sizeof(int), INDIV_PROP_START,
2068
 
                                "property-is-long flags");
2069
 
    prop_is_additive      = my_calloc(sizeof(int), INDIV_PROP_START,
2070
 
                                "property-is-additive flags");
2071
 
 
2072
 
    classes_to_inherit_from = my_calloc(sizeof(int), MAX_CLASSES,
2073
 
                                "inherited classes list");
2074
 
    class_begins_at       = my_calloc(sizeof(int32), MAX_CLASSES,
2075
 
                                "pointers to classes");
2076
 
    class_object_numbers  = my_calloc(sizeof(int),     MAX_CLASSES,
2077
 
                                "class object numbers");
2078
 
 
2079
 
    properties_table      = my_malloc(MAX_PROP_TABLE_SIZE,"properties table");
2080
 
    individuals_table     = my_malloc(MAX_INDIV_PROP_TABLE_SIZE,
2081
 
                                "individual properties table");
2082
 
 
2083
 
    if (!glulx_mode) {
2084
 
      objectsz            = my_calloc(sizeof(objecttz), MAX_OBJECTS, 
2085
 
                                "z-objects");
2086
 
    }
2087
 
    else {
2088
 
      objectsg            = my_calloc(sizeof(objecttg), MAX_OBJECTS, 
2089
 
                                "g-objects");
2090
 
      objectatts          = my_calloc(NUM_ATTR_BYTES, MAX_OBJECTS, 
2091
 
                                "g-attributes");
2092
 
      full_object_g.props = my_calloc(sizeof(propg), MAX_OBJ_PROP_COUNT,
2093
 
                              "object property list");
2094
 
      full_object_g.propdata = my_calloc(sizeof(assembly_operand),
2095
 
                                 MAX_OBJ_PROP_TABLE_SIZE,
2096
 
                                 "object property data table");
2097
 
    }
2098
 
}
2099
 
 
2100
 
extern void objects_free_arrays(void)
2101
 
{
2102
 
    my_free(&prop_default_value, "property default values");
2103
 
    my_free(&prop_is_long,     "property-is-long flags");
2104
 
    my_free(&prop_is_additive, "property-is-additive flags");
2105
 
 
2106
 
    my_free(&objectsz,         "z-objects");
2107
 
    my_free(&objectsg,         "g-objects");
2108
 
    my_free(&objectatts,       "g-attributes");
2109
 
    my_free(&class_object_numbers,"class object numbers");
2110
 
    my_free(&classes_to_inherit_from, "inherited classes list");
2111
 
    my_free(&class_begins_at,  "pointers to classes");
2112
 
 
2113
 
    my_free(&properties_table, "properties table");
2114
 
    my_free(&individuals_table,"individual properties table");
2115
 
 
2116
 
    if (!glulx_mode) {
2117
 
        my_free(&full_object_g.props, "object property list");
2118
 
        my_free(&full_object_g.propdata, "object property data table");
2119
 
    }
2120
 
    
2121
 
}
2122
 
 
2123
 
/* ========================================================================= */