/* ------------------------------------------------------------------------- */
/* "tables" : Maintains tables of dictionary, objects, actions, */
/* grammar and global variables; */
/* and constructs the tables part of the story file */
/* */
/* Part of Inform release 5 */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
int no_attributes, no_properties, no_globals, no_fake_actions=0;
int dict_entries;
int release_number=1, statusline_flag=0;
int time_set=0;
char time_given[7];
int globals_size, properties_size;
int32 prop_defaults[64];
int prop_longflag[64];
int prop_additive[64];
char *properties_table;
int max_no_objects=0;
int resobj_flag = 0;
static int no_verbs=0, no_actions=0, no_adjectives=0,
no_objects=0, no_classes=0, classes_size=0;
static int fp_no_actions=0;
static int embedded_routine = 0;
static fpropt full_object;
/* ------------------------------------------------------------------------- */
/* Arrays used by this file */
/* ------------------------------------------------------------------------- */
#ifndef ALLOCATE_BIG_ARRAYS
static verbt vs[MAX_VERBS];
static objectt objects[MAX_OBJECTS];
static int table_init[MAX_STATIC_DATA];
static int32 actions[MAX_ACTIONS],
preactions[MAX_ACTIONS],
adjectives[MAX_ADJECTIVES];
static dict_word adjcomps[MAX_ADJECTIVES];
static int32 gvalues[240];
static int dict_places_list[MAX_DICT_ENTRIES],
dict_places_back[MAX_DICT_ENTRIES],
dict_places_inverse[MAX_DICT_ENTRIES];
static dict_word dict_sorts[MAX_DICT_ENTRIES];
static zip class_pointer[MAX_CLASS_TABLE_SIZE];
static int classes_here[MAX_CLASSES];
static int32 *classes_at[MAX_CLASSES];
#else
static verbt *vs;
static objectt *objects;
static int *table_init;
static int32 *actions,
*preactions,
*adjectives;
static dict_word *adjcomps;
static int32 *gvalues;
static int *dict_places_list,
*dict_places_back,
*dict_places_inverse;
static dict_word *dict_sorts;
static int *classes_here;
static int32 **classes_at;
static zip *class_pointer;
#endif
/* ------------------------------------------------------------------------- */
/* A routine using an unusual ANSI library function: */
/* */
/* write_serialnumber writes today's date in the form YYMMDD as a string */
/* (as can be seen, the VAX doesn't know it) */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* Dictionary table builder */
/* The dictionary is, so to speak, thumb-indexed: the beginning of each */
/* letter in the double-linked-list is marked. Experiments with */
/* increasing the number of markers (to the first two letters, say) result */
/* in extra bureaucracy which cancels out any speed gain. */
/* ------------------------------------------------------------------------- */
#define NUMBER_DICT_MARKERS 26
static int total_dict_entries;
static dict_word letter_keys[NUMBER_DICT_MARKERS];
static int letter_starts[NUMBER_DICT_MARKERS];
static int start_list;
static dict_word prepared_sort;
static int initial_letter;
static void dictionary_begin_pass(void)
{ int i, j;
dict_p=dictionary+7;
total_dict_entries=dict_entries; dict_entries=0;
if (pass_number==1)
{ start_list=0; dict_places_list[0]= -2; dict_places_back[0]= -1;
for (i=0; i<NUMBER_DICT_MARKERS; i++)
{ letter_keys[i].b[0]=0xff;
letter_starts[i]= -1;
}
}
else
{ for (j=start_list, i=0; i<total_dict_entries; i++)
{ dict_places_inverse[j]=i; j=dict_places_list[j]; }
}
}
static int compare_sorts(dict_word d1, dict_word d2)
{ int i;
for (i=0; i<6; i++) if (d1.b[i]!=d2.b[i]) return(d1.b[i]-d2.b[i]);
/* since memcmp(d1.b, d2.b, 6); doesn't work in the Unix port - ? */
return(0);
}
static dict_word dictionary_prepare(char *dword)
{ int i, j, k, wd[10]; int32 tot;
for (i=0, j=0; (i<9)&&(dword[j]!=0); i++, j++)
{ k=(int) dword[j];
if (k==(int) '\'')
obsolete_warning("use the ^ character for an apostrophe \
in a dictionary word, e.g. 'peter^s'");
if (k==(int) '^') k=(int) '\'';
k=chars_lookup[k];
if ((k>=26)&&(k<2*26)) k=k-26;
if ((k/26)!=0) wd[i++]=3+(k/26);
wd[i]=6+(k%26);
}
for (; i<9; i++) wd[i]=5;
InV3 { wd[6]=5; wd[7]=5; wd[8]=5;
if ((wd[5]==3)||(wd[5]==4)) wd[5]=5;
}
InV5 { if ((wd[8]==3)||(wd[8]==4)) wd[8]=5; }
initial_letter = wd[0]-6;
if (initial_letter<0)
{ error("Dictionary words must begin with a letter of the alphabet");
initial_letter=0;
}
/* Note... this doesn't depend on A to Z being contiguous in the
machine's character set */
extern int dictionary_find(char *dword, int scope)
{ int32 j, j2, k, jlim;
dict_word i;
i=dictionary_prepare(dword);
if (scope==1) jlim=dict_entries; else jlim=total_dict_entries;
if (pass_number==1)
{ for (j=0; j<jlim; j++)
if (compare_sorts(i,dict_sorts[j])==0) return((int) j+1);
return(0);
}
if ((k=letter_starts[initial_letter])==-1) return(0);
j=initial_letter+1;
while ((j<NUMBER_DICT_MARKERS)&&((j2=letter_starts[j])==-1)) j++;
if (j==NUMBER_DICT_MARKERS) { j2= -2; }
while (k!=j2)
{
if ((compare_sorts(i,dict_sorts[k])==0)&&(k<jlim))
return(dict_places_inverse[k]+1);
k=dict_places_list[k];
}
return(0);
}
static void dictionary_set_verb_number(char *dword, int to)
{ int i; zip *p;
int res=((version_number==3)?4:6);
i=dictionary_find(dword,1);
if (i!=0)
{ p=dictionary+7+(i-1)*(3+res)+res; p[1]=to;
}
}
extern int dictionary_add(char *dword, int x, int y, int z)
{ int off, i, k, l; zip *p; dict_word pcomp, qcomp;
int res=((version_number==3)?4:6);
if (dict_entries==MAX_DICT_ENTRIES)
{ memoryerror("MAX_DICT_ENTRIES",MAX_DICT_ENTRIES); }
i=dictionary_find(dword,1);
if (i!=0)
{ p=dictionary+7+(i-1)*(3+res)+res;
p[0]=(p[0])|x; p[1]=(p[1])|y; p[2]=(p[2])|z;
return(dictionary_offset+7+(3+res)*(i-1));
}
if (pass_number==1) i=dict_entries;
else { i=dict_places_inverse[dict_entries]; }
static int make_action(int32 addr)
{ int i;
if (no_actions>=MAX_ACTIONS)
memoryerror("MAX_ACTIONS",MAX_ACTIONS);
for (i=0; i<no_actions; i++) if (actions[i]==addr) return(i);
actions[no_actions]=addr; preactions[no_actions]= -1;
return(no_actions++);
}
extern int find_action(int32 addr)
{ int i;
for (i=0; i<fp_no_actions; i++) if (actions[i]==addr) return(i);
if (pass_number==2)
error("Action given in constant does not exist");
return(0);
}
extern void new_action(char *b, int c)
{ if ((printprops_mode==0)||(pass_number==2)) return;
printf("Action '%s' is numbered %d\n",b,c);
}
/* ------------------------------------------------------------------------- */
/* Parsing the grammar table, and making new adjectives and verbs */
/* (see the documentation for what the verb table it makes looks like) */
/* ------------------------------------------------------------------------- */
static int make_adjective(char *c)
{ int i; dict_word acomp;
acomp=dictionary_prepare(c);
for (i=0; i<no_adjectives; i++)
{ if (compare_sorts(acomp,adjcomps[i])==0) return(0xff-i);
}
adjectives[no_adjectives]=dictionary_add(c,8,0,0xff-no_adjectives);
adjcomps[no_adjectives]=acomp;
return(0xff-no_adjectives++);
}
static int find_verb(char *verb)
{ char *p;
p=verblist;
while (p<verblist_p)
{ if (strcmp(verb, p+2)==0) return(p[1]);
p=p+p[0];
}
return(-1);
}
static int verbspace_consumed = 0;
static void register_verb(char *verb, int number)
{ if (find_verb(verb)>=0)
{ error_named("Two different verb definitions refer to", verb);
return;
}
verbspace_consumed += strlen(verb)+3;
if (verbspace_consumed >= MAX_VERBSPACE)
memoryerror("MAX_VERBSPACE",MAX_VERBSPACE);
strcpy(verblist_p+2,verb);
verblist_p[1]=number;
verblist_p[0]=3+strlen(verb);
verblist_p += verblist_p[0];
}
static int32 parsing_routines[64];
static int no_prs;
static int debug_acts_writ[256];
static int action_exists[256];
static int grammar_line(int verbnum, int line, int i, char *b)
{ int j, l, flag=0; int32 k;
int vargs, vtokens, vinsert;
if (line>=MAX_LINES_PER_VERB)
{ error("Too many lines of grammar for verb: increase \
#define MAX_LINES_PER_VERB"); return(0); }
word(b,i++); flag=2;
if (b[0]==0) return(0);
if (strcmp(b,"*")!=0)
{ error_named("'*' divider expected, but found",b); return(0); }
vtokens=1; vargs=0; for (j=0; j<8; j++) vs[verbnum].l[line].e[j]=0;
do
{ word(b,i++);
if (b[0]==0) { error("'->' clause missing"); return(0); }
if (strcmp(b,"->")==0) break;
if (b[0]=='\"')
{ textword(b,i-1); vinsert=make_adjective(b);
}
else On_("noun") { vargs++; vinsert=0; }
else On_("held") { vargs++; vinsert=1; }
else On_("multi") { vargs++; vinsert=2; }
else On_("multiheld") { vargs++; vinsert=3; }
else On_("multiexcept") { vargs++; vinsert=4; }
else On_("multiinside") { vargs++; vinsert=5; }
else On_("creature") { vargs++; vinsert=6; }
else On_("special") { vargs++; vinsert=7; }
else On_("number") { vargs++; vinsert=8; }
else On_("scope")
{ word(b,i++);
if (strcmp(b,"=")!=0)
{ error_named("Expected '=' after 'scope' but found",b);
return(0);
}
word(b,i++);
j=find_symbol(b);
if ((j<0) || (stypes[j]!=1))
{ error_named(
"Expected routine after 'scope=' but found",b);
return(0);
}
for (l=0; (l<no_prs)
&& parsing_routines[l]!=svals[j]; l++) ;
parsing_routines[l]=svals[j]; if (l==no_prs) no_prs++;
vargs++; vinsert=l+80;
}
else On_("=")
{ if ((vtokens==0)||(vs[verbnum].l[line].e[vtokens-1]!=0))
{ error("'=' is only legal here as 'noun=Routine'");
return(0);
}
word(b,i++);
j=find_symbol(b);
if ((j<0) || (stypes[j]!=1))
{ error_named(
"Expected routine after 'noun=' but found", b);
return(0);
}
vtokens--;
for (l=0; (l<no_prs)
&& parsing_routines[l]!=svals[j]; l++) ;
parsing_routines[l]=svals[j]; if (l==no_prs) no_prs++;
vinsert=l+16;
}
else
{ j=find_symbol(b);
if ((j<0) || ((stypes[j]!=7)&&(stypes[j]!=1)))
{ error_named("No such token as",b); return(0); }
if (stypes[j]==7)
{ vargs++; vinsert=svals[j]+128;
}
else
{ vargs++;
for (l=0; (l<no_prs)
&& parsing_routines[l]!=svals[j]; l++) ;
parsing_routines[l]=svals[j]; if (l==no_prs) no_prs++;
vinsert=l+48;
}
}
vs[verbnum].l[line].e[vtokens]=vinsert;
vtokens++;
} while (1==1);
word(b,i++);
j=strlen(b)-3;
if ((j<0)||(b[j]!='S')||(b[j+1]!='u')||(b[j+2]!='b'))
sprintf(b+j+3,"Sub");
j=find_symbol(b);
if ((j==-1)&&(pass_number==2))
{ error_named("No such action routine as",b);
return(0);
}
if (j==-1) k=0;
else
{ if (stypes[j]!=1) { error_named("Not an action:",b); return(0); }
k=svals[j];
}
vs[verbnum].l[line].e[0]=vargs;
vs[verbnum].l[line].e[7]=make_action(k);
j=find_action(k);
if (action_exists[j]==0)
{ action_exists[j]=1; new_action(b,j);
}
if ((debugging_file==1)&&(k!=0)
&&(debug_acts_writ[j]==0))
{ debug_pass=2;
b[strlen(b)-3]=0;
write_debug_byte(8); write_debug_byte(j);
write_debug_string(b);
debug_pass=1;
if (pass_number==2) debug_acts_writ[j]=1;
}
return(i);
}
static int get_verb(char *b, int wn)
{ int j;
textword(b,wn); j=find_verb(b);
if (j==-1)
error_named("There is no previous grammar for the verb", b);
return(j);
}
extern void make_verb(char *b)
{ int i, i2, x=-1, flag=0;
int lines=0;
i=2;
word(b,i);
On_("meta") { i++; flag=2; }
i2=i;
do word(b,i2++); while (b[0]=='\"');
if (b[0]=='=') x=get_verb(b,i2++);
else
{ x=no_verbs;
if (no_verbs==MAX_VERBS)
memoryerror("MAX_VERBS",MAX_VERBS);
}
do
{ word(b,i);
if (b[0]!='\"') break;
textword(b,i++);
dictionary_add(b,0x41+flag,0xff-x,0);
if (pass_number==1) register_verb(b,x);
} while (1==1);
if (x!=no_verbs)
{ word(b,i2);
if (b[0]!=0)
error_named("Expected end of command but found",b);
return;
}
do
{ i=grammar_line(no_verbs, lines++,i,b);
} while (i!=0);
vs[no_verbs].lines=--lines;
no_verbs++;
}
extern void extend_verb(char *b)
{ int i, j, k, l, lines, mode;
word(b,2);
if (strcmp(b,"only")==0)
{ i=3; l=-1;
if (no_verbs==MAX_VERBS)
memoryerror("MAX_VERBS",MAX_VERBS);
do
{ j=get_verb(b,i++);
if (j==-1) return;
if ((l!=-1) && (j!=l) && (pass_number==1))
{ warning_named("Verb disagrees with previous verbs", b);
}
l=j;
dictionary_set_verb_number(b,0xff-no_verbs);
word(b,i);
} while (b[0]=='\"');
vs[no_verbs]=vs[j];
j=no_verbs++;
}
else { j=get_verb(b,2); if (j==-1) return; i=3; }
word(b,i); mode=3;
if (strcmp(b,"*")!=0)
{ mode=0;
if (strcmp(b,"replace")==0) mode=1;
if (strcmp(b,"first")==0) mode=2;
if (strcmp(b,"last")==0) mode=3;
if (mode==0)
{ error_named(
"Expected 'replace', 'last' or 'first' but found",b);
mode=3;
}
i++;
}
l=vs[j].lines; if (mode<=2) lines=0; else lines=l;
do
{ if (mode==2)
for (k=l; k>0; k--)
vs[j].l[k+lines]=vs[j].l[k-1+lines];
i=grammar_line(j, lines++,i,b);
} while (i!=0);
if (mode==2)
{ vs[j].lines = l+lines-1;
for (k=0; k<l; k++)
vs[j].l[k+lines-1]=vs[j].l[k+lines];
}
else vs[j].lines=--lines;
}
/* ------------------------------------------------------------------------- */
/* Object manufacture. Note that property lists are not kept for each */
/* object, only written in game-file format and then forgotten; but the */
/* object tree structure so far, is kept */
/* ------------------------------------------------------------------------- */
static int class_flag;
static int no_c_here;
static int properties(int w)
{ int i, k, x, y, pnw, flag=0; int32 j;
do
{ pnw=w;
word(sub_buffer,w++);
if (sub_buffer[0]==0) return(w-1);
/* if (strcmp(sub_buffer,",")==0) return(w-1); */
if (strcmp(sub_buffer,"has")==0) return(w-1);
if (strcmp(sub_buffer,"class")==0) return(w-1);
i=find_symbol(sub_buffer);
if (i==-1)
{ error_named("No such property as",sub_buffer);
return(w);
}
if (stypes[i]!=12)
{ error_named("Not a property:",sub_buffer);
return(w);
}
i=svals[i];
x=full_object.l++;
full_object.pp[x].num=i;
y=0;
do
{ word(sub_buffer,w++);
if (strcmp(sub_buffer,",")==0) break;
if (strcmp(sub_buffer,"has")==0) { w--; break; }
if (strcmp(sub_buffer,"class")==0) { w--; break; }
if (sub_buffer[0]==0) break;
if (strcmp(sub_buffer,"[")==0)
{ flag=1;
sprintf(sub_buffer,"Mb__%d",embedded_routine);
}
if ((i==1)&&(sub_buffer[0]=='\"'))
{ textword(sub_buffer,w-1);
j=dictionary_add(sub_buffer,0x80,0,0);
}
else
{ if ((pass_number==2)&&(y!=0))
{ k=find_symbol(sub_buffer);
if ((k!=-1)&&(stypes[k]==12))
{ warning_named(
"Missing ','? Property data seems to contain the property name",
sub_buffer);
}
}
j=constant_value(sub_buffer);
if (j==0)
{ if (prop_defaults[i]>=256) j=0x1000;
}
}
if ((j>=256)||(prop_longflag[i]==1))
full_object.pp[x].p[y++]=j/256;
full_object.pp[x].p[y++]=j%256;
} while (flag==0);
if (y==0) { full_object.pp[x].p[y++]=0;
full_object.pp[x].p[y++]=0;
}
full_object.pp[x].l=y;
InV3
{ if (y>8)
{ word(sub_buffer, pnw);
if (pass_number==2)
warning_named("Standard-game limit of 8 bytes per property exceeded \
(use Advanced to get 64), so truncating property", sub_buffer);
full_object.pp[x].l=8;
}
}
} while (flag==0);
sprintf(buffer,"[ Mb__%d",embedded_routine++);
do
{ word(sub_buffer,w++);
sprintf(buffer+strlen(buffer)," %s",sub_buffer);
} while (sub_buffer[0]!=0);
stack_line(buffer);
return(-1);
}
static int attributes(int w)
{ int i, negate_flag;
do
{ word(sub_buffer,w++);
if (sub_buffer[0]==0) return(w-1);
if ((strcmp(sub_buffer,"with")==0)
|| (strcmp(sub_buffer,",")==0)
|| (strcmp(sub_buffer,"class")==0)) return(w-1);
if (sub_buffer[0]=='~')
{ negate_flag=1; i=find_symbol(sub_buffer+1); }
else
{ negate_flag=0; i=find_symbol(sub_buffer); }
if ((i==-1)||(stypes[i]!=7))
{ error_named("No such attribute as",sub_buffer); return(w); }
i=svals[i];
if (negate_flag==0)
full_object.atts[i/8] =
full_object.atts[i/8] | (1 << (7-i%8));
else
full_object.atts[i/8] =
full_object.atts[i/8] & ~(1 << (7-i%8));
} while (1==1);
return(0);
}
static int classes(int w)
{ int i; zip *p;
do
{ word(sub_buffer,w++);
if (sub_buffer[0]==0) return(w-1);
if ((strcmp(sub_buffer,",")==0)
|| (strcmp(sub_buffer,"with")==0)
|| (strcmp(sub_buffer,"has")==0)) return(w-1);
i=find_symbol(sub_buffer);
if ((i==-1)||(stypes[i]!=13))
{ error_named("No such class as",sub_buffer); return(w); }
classes_here[no_c_here++]=svals[i];
/* printf("Inheriting attrs from %d\n",svals[i]); */
p=(zip *)classes_at[svals[i]-1];
for (i=0; i<6; i++) full_object.atts[i] |= p[i];
/* for (i=0; i<6; i++) printf("Data %d %x\n",i,p[i]); */
} while (1==1);
return(0);
}
static int write_properties(zip *p, char *shortname)
{ int i, l, j, k, count, number; zip *tmp; zip *from;
int32 props=0;
if (class_flag==0)
{ for (i=0;i<6;i++)
objects[no_objects].atts[i]=full_object.atts[i];
tmp=translate_text(p+1,shortname);
props=subtract_pointers(tmp,p);
p[0]=(props-1)/2;
}
else
{ p=class_pointer+classes_size;
classes_at[no_classes]=(int32 *) p;
/* printf("Class data at %08x\n",p); */
for (i=0;i<6;i++) p[i]=full_object.atts[i];
p+=6;
}
for (l=0; l<no_c_here; l++)
{ j=0; from=6+(zip *)classes_at[classes_here[l]-1];
/* printf("Inheriting from %d at %08x\n",classes_here[l],from); */
/* for (j=0; j<32; j++) printf("%02x ",from[j]); printf("\n"); j=0; */
for (l=((version_number==3)?31:63); l>0; l--)
{ for (j=0; j<full_object.l; j++)
{ if (full_object.pp[j].num == l)
{ count=full_object.pp[j].l; number=full_object.pp[j].num;
InV3
{ p[props++] = number + (count - 1)*32;
}
InV5
{ switch(count)
{ case 1:
p[props++] = number; break;
case 2:
p[props++] = number + 0x40; break;
default:
p[props++] = number + 0x80;
p[props++] = count + 0x80;
break;
}
}
for (k=0; k<full_object.pp[j].l; k++)
{ p[props++]=full_object.pp[j].p[k];
}
}
}
}
p[props]=0; props++;
if (class_flag==1)
{
classes_size+=props+6;
if (classes_size >= MAX_CLASS_TABLE_SIZE)
memoryerror("MAX_CLASS_TABLE_SIZE",MAX_CLASS_TABLE_SIZE);
}
else
{
properties_size+=props;
if (properties_size >= MAX_PROP_TABLE_SIZE)
memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
}
return(props);
}
static char shortname_buffer[256];
extern void finish_object(void)
{ int j;
if (class_flag == 0)
{ j=objects[no_objects].propsize;
objects[no_objects].propsize=
write_properties((zip *) (properties_table+properties_size),
shortname_buffer);
if (pass_number==2)
{ if (j != objects[no_objects].propsize)
{ error("Object has altered in memory usage between passes: \
perhaps an attempt to use a routine name as value of a small property");
}
}
no_objects++;
if (pass_number==1) max_no_objects++;
}
else { write_properties(NULL,NULL); no_classes++; }
if (debugging_file==1)
{ write_present_linenum();
}
}
extern void resume_object(char *b, int j)
{ int flag=0, commas=0;
if (j==1)
{ word(b,1); flag=1;
if ((strcmp(b,"has")==0)
|| (strcmp(b,",")==0)
|| (strcmp(b,"class")==0)
|| (strcmp(b,"with")==0)) flag=0;
}
do
{ RO_Comma:
if (flag==0)
{ word(b,j++);
if (b[0]==0)
{ if (commas>0)
error("Object/class definition finishes with ','");
break;
}
}
if (strcmp(b,",")==0) { commas++; goto RO_Comma; }
if (commas>1)
error("Two commas ',' in a row in object/class definition");
commas=0;
if ((flag==1)||(strcmp(b,"with")==0))
{ j=properties(j);
if (j==-1) { resobj_flag=1; return; }
}
else if (strcmp(b,"has")==0) j=attributes(j);
else if (strcmp(b,"class")==0) j=classes(j);
else error_named("Expected 'with', 'has' or \
'class' in object/class definition but found",b);
flag=0;
} while (1==1);
finish_object();
}
extern void make_object(char *b, int nearby_flag)
{ int i, j, k, non=0, later, subof;
if (no_objects==MAX_OBJECTS)
memoryerror("MAX_OBJECTS", MAX_OBJECTS);
class_flag = 0; no_c_here=0;
word(b,2);
if (b[0]=='\"')
{ textword(b,2);
error_named(
"Expected an (internal) name for object, but found the string", b);
sprintf(b,"failedobj");
}
new_symbol(b,no_objects+1,9);
if (debugging_file==1)
{ write_debug_byte(3);
write_debug_byte((no_objects+1)/256);
write_debug_byte((no_objects+1)%256);
write_debug_linenum(); write_debug_string(b);
}
do
{ word(b,3+non);
if (b[0]!='\"')
{ new_symbol(b,no_objects+1,9); non++;
obsolete_warning("an object should only have one internal name");
}
} while (b[0]!='\"');
later=non+5;
if (nearby_flag==0)
{ word(b,4+non);
subof=0;
if ((b[0]==0)
|| (strcmp(b,",")==0)
|| (strcmp(b,"with")==0)
|| (strcmp(b,"has")==0)
|| (strcmp(b,"class")==0)) later--;
else
{ i=find_symbol(b);
if (i<0)
{ error_named("An object must be defined \
after the one which contains it: (so far) there is no such object as",b);
return;
}
if (stypes[i]!=9)
{ error_named("Not an object:",b); return; }
subof=svals[i];
}
near_obj=no_objects+1;
}
else
{ subof=near_obj; later--;
}
full_object.atts[0]=0;
full_object.atts[1]=0;
full_object.atts[2]=0;
full_object.atts[3]=0;
full_object.atts[4]=0;
full_object.atts[5]=0;
objects[no_objects].parent=subof;
objects[no_objects].next=0;
objects[no_objects].child=0;
full_object.l=0;
if (subof>0)
{ j=subof-1; k=objects[j].child;
if (k==0)
{ objects[j].child=no_objects+1; }
else
{ while(objects[k-1].next!=0) { k=objects[k-1].next; }
objects[k-1].next=no_objects+1;
}
}
/* ------------------------------------------------------------------------- */
/* Making and initialising variables and arrays */
/* ------------------------------------------------------------------------- */
#define NON_VALUE (int32)0x100000L
extern void check_globals(void)
{ int i;
for (i=0;i<no_globals;i++)
if (gvalues[i]==NON_VALUE)
{ error("An initialised global variable was defined only in Pass 1");
return;
}
}
static int multiplier;
static int32 table_posn;
static int array_base;
int doing_table_mode;
static void finish_array(int32 i)
{ doing_table_mode=0;
if ((pass_number==1)&&(array_base!=globals_size))
{ if (multiplier==2)
{ table_init[array_base] = i/256;
table_init[array_base+1] = i%256;
}
else
{ if (i>=256)
error("A 'string' array can have at most 256 entries");
table_init[array_base] = i;
}
}
globals_size+=i*multiplier;
}
static void array_entry(int32 i, int32 j, char *b)
{ if (globals_size+i*multiplier >= MAX_STATIC_DATA)
memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
if (multiplier==1)
{ table_init[globals_size+i]=j;
if ((pass_number==2)&&(j>=256))
warning_named("Array entry too large for a byte:",b);
}
else
{ table_init[globals_size+2*i]=j/256;
table_init[globals_size+2*i+1]=j%256;
}
}
extern void assemble_table(char *b, int from)
{ int32 j; int i;
for (i=from;1==1;i++)
{ word(b,i); if (b[0]==0) return;
if (strcmp(b,"]")==0)
{ finish_array(table_posn);
return;
}
if (strcmp(b,"[")==0)
{ stack_line("]");
error("Expected ']' but found '['"); return;
}
j=constant_value(b);
array_entry(table_posn++, j, b);
}
return;
}
extern void make_global(char *b, int array_flag)
{ int32 i, j; int array_type, data_type, one_word;
word(b,2);
if (array_flag==0)
{ if (no_globals==235)
{ error("All 235 global variables already declared");
return;
}
if (pass_number==1)
{ new_symbol(b,no_globals,2);
if (debugging_file==1)
{ write_debug_byte(4); write_debug_byte(no_globals);
write_debug_string(b);
}
}
else
{ i=find_symbol(b);
no_globals=svals[i];
}
gvalues[no_globals]=0; no_globals++;
}
else
{ IfPass2
{ j=find_symbol(b);
svals[j]=variables_offset+globals_size;
}
else new_symbol(b,0x800+globals_size,8);
}
word(b,3);
if (b[0]==0)
{ if (array_flag==1) error("Missing array definition");
return;
}
if ((pass_number==1) && (array_flag==0))
gvalues[no_globals-1]=NON_VALUE;
if ((strcmp(b,"=")==0) && (array_flag==0))
{ word(b,4); i=constant_value(b);
if (pass_number==2) gvalues[no_globals-1]=i;
return;
}
if ((pass_number==2) && (array_flag==0))
gvalues[no_globals-1]=globals_size+variables_offset;
array_type=0; data_type=-1;
if ((array_flag==0)&&(strcmp(b,"data")==0)) { data_type=0; }
else if ((array_flag==0)&&(strcmp(b,"initial")==0)) { data_type=1; }
else if ((array_flag==0)&&(strcmp(b,"initstr")==0)) { data_type=2; }
else if (strcmp(b,"->")==0) array_type=0;
else if (strcmp(b,"-->")==0) array_type=1;
else if (strcmp(b,"string")==0) array_type=2;
else if (strcmp(b,"table")==0) array_type=3;
else { if (array_flag==0)
error_named("Expected '=', '->', '-->', 'string' or 'table' but found",b);
else
error_named("Expected '->', '-->', 'string' or 'table' but found",b);
return;
}
multiplier=1; if ((array_type==1) || (array_type==3)) multiplier=2;
word(b,5);
one_word=0; if (b[0]==0) one_word=1;
word(b,4);
if (b[0]==0) { error("Missing array definition"); return; }
switch(data_type)
{ case -1:
if (b[0]=='[') data_type=3;
else
{ if (one_word==1)
{ if (b[0]=='\"') data_type=2; else data_type=0;
}
else data_type=1;
}
break;
case 0: obsolete_warning("use '->' instead of 'data'"); break;
case 1: obsolete_warning("use '->' instead of 'initial'"); break;
case 2: obsolete_warning("use '->' instead of 'initstr'"); break;
}
array_base=globals_size;
if ((array_type==2) || (array_type==3)) globals_size+=multiplier;
switch(data_type)
{ case 0:
word(b,4); j=constant_value(b);
for (i=0; i<j; i++) array_entry(i, 0, b);
break;
case 1:
i=0;
do
{ word(b,4+i); if (b[0]==0) break;
if ((strcmp(b,"]")==0) || (strcmp(b,"[")==0))
{ error_named("Misplaced ",b); return; }
j=constant_value(b);
array_entry(i, j, b);
i++;
} while (1==1);
break;
case 2:
textword(b,4);
for (i=0; b[i]!=0; i++) array_entry(i, b[i], b);
break;
case 3:
doing_table_mode=1; table_posn=0;
if (one_word==0) assemble_table(b,5);
return;
}
finish_array(i);
}
/* ------------------------------------------------------------------------- */
/* Construct story file up as far as code area */
/* (see documentation for description of what goes on here) */
/* ------------------------------------------------------------------------- */