| /* ------------------------------------------------------------------------- */ | |
| /* "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 */ | |
| /* */ | |
| /* ------------------------------------------------------------------------- */ | |
| 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 */ | |
| /* ------------------------------------------------------------------------- */ | |
| 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]; | |
| 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; | |
| static char *verblist; | |
| static char *verblist_p; | |
| extern void tables_allocate_arrays(void) | |
| { | |
| vs = my_calloc(sizeof(verbt), MAX_VERBS, "verbs"); | |
| objects = my_calloc(sizeof(objectt), MAX_OBJECTS, "objects"); | |
| table_init = my_calloc(sizeof(int), MAX_STATIC_DATA, "static data"); | |
| actions = my_calloc(sizeof(int32), MAX_ACTIONS, "actions"); | |
| preactions = my_calloc(sizeof(int32), MAX_ACTIONS, "preactions"); | |
| adjectives = my_calloc(sizeof(int32), MAX_ADJECTIVES, "adjectives"); | |
| adjcomps = my_calloc(sizeof(dict_word), MAX_ADJECTIVES, "adj comps"); | |
| gvalues = my_calloc(sizeof(int32), 240, "global values"); | |
| dict_places_list = my_calloc(sizeof(int), MAX_DICT_ENTRIES, | |
| "dictionary places list"); | |
| dict_places_back = my_calloc(sizeof(int), MAX_DICT_ENTRIES, | |
| "dictionary places back"); | |
| dict_places_inverse = my_calloc(sizeof(int), MAX_DICT_ENTRIES, | |
| "inverse of dictionary places"); | |
| dict_sorts = my_calloc(sizeof(dict_word), MAX_DICT_ENTRIES, | |
| "dictionary sort codes"); | |
| class_pointer = my_malloc(MAX_CLASS_TABLE_SIZE, "class table"); | |
| classes_here = my_calloc(sizeof(int), MAX_CLASSES, | |
| "inherited classes list"); | |
| classes_at = my_calloc(sizeof(int32), MAX_CLASSES, | |
| "pointers to classes"); | |
| verblist = my_malloc(MAX_VERBSPACE, "register of verbs"); | |
| verblist_p = verblist; | |
| } | |
| extern void tables_free_arrays(void) | |
| { | |
| my_free(&vs, "verbs"); | |
| my_free(&objects, "objects"); | |
| my_free(&table_init, "static data"); | |
| my_free(&actions, "actions"); | |
| my_free(&preactions, "preactions"); | |
| my_free(&adjectives, "adjectives"); | |
| my_free(&adjcomps, "adj comps"); | |
| my_free(&gvalues, "global values"); | |
| my_free(&dict_places_list, "dictionary places list"); | |
| my_free(&dict_places_back, "dictionary places back"); | |
| my_free(&dict_places_inverse, "inverse of dictionary places"); | |
| my_free(&dict_sorts, "dictionary sort codes"); | |
| my_free(&class_pointer,"class table"); | |
| my_free(&classes_here, "inherited classes list"); | |
| my_free(&classes_at, "pointers to classes"); | |
| my_free(&verblist,"register of verbs"); | |
| } | |
| /* ------------------------------------------------------------------------- */ | |
| /* 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) */ | |
| /* ------------------------------------------------------------------------- */ | |
| static void write_serialnumber(char *buffer) | |
| { time_t tt; tt=time(0); | |
| if (time_set==0) | |
| sprintf(buffer,"940000"); | |
| strftime(buffer,10,"%y%m%d",localtime(&tt)); | |
| else | |
| sprintf(buffer,"%06s",time_given); | |
| } | |
| /* ------------------------------------------------------------------------- */ | |
| /* 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. */ | |
| /* ------------------------------------------------------------------------- */ | |
| 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 */ | |
| tot = wd[2] + wd[1]*(1<<5) + wd[0]*(1<<10); | |
| prepared_sort.b[1]=tot%0x100; | |
| prepared_sort.b[0]=(tot/0x100)%0x100; | |
| tot = wd[5] + wd[4]*(1<<5) + wd[3]*(1<<10); | |
| prepared_sort.b[3]=tot%0x100; | |
| prepared_sort.b[2]=(tot/0x100)%0x100; | |
| tot = wd[8] + wd[7]*(1<<5) + wd[6]*(1<<10); | |
| prepared_sort.b[5]=tot%0x100; | |
| prepared_sort.b[4]=(tot/0x100)%0x100; | |
| InV3 { prepared_sort.b[2]+=0x80; } | |
| InV5 { prepared_sort.b[4]+=0x80; } | |
| return(prepared_sort); | |
| } | |
| 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 show_letter(int code) | |
| { | |
| if (code<6) { printf("."); return; } | |
| printf("%c",(alphabet[0])[code-6]); | |
| } | |
| extern void show_dictionary(void) | |
| { int i, j; char *p; | |
| int res=((version_number==3)?4:6); | |
| printf("Dictionary contains %d entries:\n",dict_entries); | |
| for (i=0; i<dict_entries; i++) | |
| { p=(char *)dictionary+7+(3+res)*i; | |
| if (dict_entries==0) | |
| printf("Entry %03d (%03d > %03d) at %04x: ", | |
| i,dict_places_back[i],dict_places_list[i], | |
| dictionary_offset+7+(3+res)*i); | |
| else | |
| printf("Entry %03d at %04x: ",i,dictionary_offset+7+(3+res)*i); | |
| show_letter( (((int) p[0])&0x7c)/4 ); | |
| show_letter( 8*(((int) p[0])&0x3) + (((int) p[1])&0xe0)/32 ); | |
| show_letter( ((int) p[1])&0x1f ); | |
| show_letter( (((int) p[2])&0x7c)/4 ); | |
| show_letter( 8*(((int) p[2])&0x3) + (((int) p[3])&0xe0)/32 ); | |
| show_letter( ((int) p[3])&0x1f ); | |
| printf(" "); | |
| for (j=0; j<3+res; j++) printf("%02x ",p[j]); | |
| printf("\n"); | |
| } | |
| } | |
| 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]; } | |
| off=(3+res)*i+7; | |
| p=dictionary+off; | |
| p[0]=prepared_sort.b[0]; p[1]=prepared_sort.b[1]; | |
| p[2]=prepared_sort.b[2]; p[3]=prepared_sort.b[3]; | |
| InV5 { p[4]=prepared_sort.b[4]; p[5]=prepared_sort.b[5]; } | |
| p[res]=x; p[res+1]=y; p[res+2]=z; | |
| if (pass_number==1) | |
| { pcomp=prepared_sort; | |
| if (dict_entries==0) | |
| { dict_places_list[0]= -2; dict_places_list[1]= -1; | |
| goto PlaceFound; | |
| } | |
| l=initial_letter; do { k=letter_starts[l--]; } while ((l>=0)&&(k==-1)); | |
| if (k==-1) k=start_list; | |
| for (; k!=-2; k=dict_places_list[k]) | |
| { qcomp=dict_sorts[k]; | |
| if (compare_sorts(pcomp,qcomp)<0) | |
| { l=dict_places_back[k]; | |
| if (l==-1) | |
| { dict_places_list[dict_entries]=start_list; | |
| dict_places_back[dict_entries]= -1; | |
| dict_places_back[k]=dict_entries; | |
| start_list=dict_entries; goto PlaceFound; | |
| } | |
| dict_places_list[l]=dict_entries; | |
| dict_places_back[k]=dict_entries; | |
| dict_places_list[dict_entries]=k; | |
| dict_places_back[dict_entries]=l; | |
| goto PlaceFound; | |
| } | |
| l=k; | |
| } | |
| dict_places_list[l]=dict_entries; | |
| dict_places_back[dict_entries]=l; | |
| dict_places_list[dict_entries]= -2; | |
| PlaceFound: dict_sorts[dict_entries]=pcomp; | |
| if (compare_sorts(pcomp,letter_keys[initial_letter])<0) | |
| { letter_keys[initial_letter]=pcomp; | |
| letter_starts[initial_letter]=dict_entries; | |
| } | |
| } | |
| dict_entries++; dict_p+=res+3; | |
| /* show_dictionary(); */ | |
| return(dictionary_offset+off); | |
| } | |
| extern void list_object_tree(void) | |
| { int i; | |
| printf("obj par nxt chl Object tree:\n"); | |
| for (i=0; i<no_objects; i++) | |
| printf("%3d %3d %3d %3d\n", | |
| i+1,objects[i].parent,objects[i].next, objects[i].child); | |
| } | |
| extern void list_verb_table(void) | |
| { int i, j, k; | |
| for (i=0; i<no_verbs; i++) | |
| { printf("Verb entry %2d [%d]\n",i,vs[i].lines); | |
| for (j=0; j<vs[i].lines; j++) | |
| { for (k=0; k<8; k++) printf("%03d ",vs[i].l[j].e[k]); | |
| printf("\n"); | |
| } | |
| } | |
| } | |
| /* ------------------------------------------------------------------------- */ | |
| /* Keep track of actions */ | |
| /* ------------------------------------------------------------------------- */ | |
| 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; */ | |
| while (from[j]!=0) | |
| { InV3 | |
| { number=from[j]%32; count=1+from[j++]/32; | |
| } | |
| InV5 | |
| { number=from[j]%64; count=1+from[j++]/64; | |
| if (count>2) count=from[j++]%64; | |
| } | |
| /* printf("Inheriting no %d count %d\n",number,count); */ | |
| for (k=0; k<full_object.l; k++) | |
| { if (full_object.pp[k].num == number) | |
| { if ((number==1) || (prop_additive[number]!=0)) | |
| { /* printf("Appending %d\n",number); */ | |
| for (i=full_object.pp[k].l; | |
| i<full_object.pp[k].l+count; i++) | |
| full_object.pp[k].p[i]=from[j++]; | |
| full_object.pp[k].l += count; | |
| } | |
| else | |
| { j+=count; | |
| /* printf("Ignoring %d\n",number); */ | |
| } | |
| goto DunInheriting; | |
| } | |
| } | |
| k=full_object.l++; | |
| full_object.pp[k].num = number; | |
| full_object.pp[k].l = count; | |
| for (i=0; i<count; i++) | |
| full_object.pp[k].p[i]=from[j++]; | |
| /* printf("Creating %d\n",number); */ | |
| DunInheriting: ; | |
| } | |
| } | |
| 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_class(char *b) | |
| { class_flag = 1; no_c_here=0; | |
| if (no_classes==MAX_CLASSES) | |
| memoryerror("MAX_CLASSES", MAX_CLASSES); | |
| word(b,2); new_symbol(b,no_classes+1,13); | |
| if (debugging_file==1) | |
| { write_debug_byte(2); write_debug_linenum(); | |
| write_debug_string(b); | |
| } | |
| full_object.l=0; | |
| 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; | |
| resume_object(b,3); | |
| } | |
| static int near_obj; | |
| 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; | |
| } | |
| } | |
| textword(b,3+non); | |
| if ((listobjects_mode==1) && ((pass_number==2)||(bothpasses_mode==1))) | |
| printf("%3d \"%s\"\n",no_objects+1,b); | |
| strcpy(shortname_buffer,b); | |
| resume_object(b, later); | |
| } | |
| /* ------------------------------------------------------------------------- */ | |
| /* Making and initialising variables and arrays */ | |
| /* ------------------------------------------------------------------------- */ | |
| 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) */ | |
| /* ------------------------------------------------------------------------- */ | |
| static void percentage(char *name, int32 x, int32 total) | |
| { printf(" %-20s %2d.%d%%\n",name,x*100/total,(x*1000/total)%10); | |
| } | |
| static int alloc_done_flag=0; | |
| static char *version_name(int v) | |
| { switch(v) | |
| { case 3: return "Standard"; | |
| case 4: return "Plus"; | |
| case 5: return "Advanced"; | |
| case 6: return "graphical"; | |
| } | |
| return "extended format"; | |
| } | |
| extern void construct_storyfile(void) | |
| { char *p; unsigned char *u; int32 i, j, k; int32 excess; | |
| int32 syns, objs, props, vars, parse, code, strs, dict, nparse, | |
| actshere, preactshere; | |
| int32 synsat, glpat, objat, propat, parsat; | |
| int32 code_length, strings_length, alloc_size; | |
| int32 limit; | |
| int extend_offset; | |
| if (alloc_done_flag==0) | |
| { alloc_done_flag=1; | |
| alloc_size=0x4000 + subtract_pointers(dict_p,dictionary); | |
| for (i=0; i<no_objects; i++) alloc_size+=objects[i].propsize; | |
| output_p=my_malloc(alloc_size, "output buffer"); | |
| } | |
| p=(char *)output_p; u=(unsigned char *) p; | |
| for (i=0; i<=0x3f; i++) p[i]=0; | |
| p[0]=actual_version; p[1]=statusline_flag*2; | |
| p[2]=(release_number/256); p[3]=(release_number%256); | |
| p[16]=0; p[17]=0; | |
| write_serialnumber(buffer); | |
| for (i=0; i<6; i++) p[18+i]=buffer[i]; | |
| syns=0x40; | |
| u[syns]=0x80; p[syns+1]=0; syns+=2; | |
| for (i=0; i+low_strings<low_strings_p; syns++, i++) | |
| p[0x42+i]=low_strings[i]; | |
| p[24]=syns/256; p[25]=syns%256; synsat=syns; | |
| for (i=0; i<3*32; i++) | |
| { p[syns++]=0; p[syns++]=0x20; | |
| } | |
| for (i=0; i<no_abbrevs; i++) | |
| { j=abbrev_values[i]; | |
| p[synsat+64+2*i]=j/256; | |
| p[synsat+65+2*i]=j%256; | |
| } | |
| objs=syns; | |
| p[10]=objs/256; p[11]=objs%256; glpat=objs; | |
| p[objs]=0; p[objs+1]=0; | |
| for (i=2; i< ((version_number==3)?32:64); i++) | |
| { p[objs+2*i-2]=prop_defaults[i]/256; | |
| p[objs+2*i-1]=prop_defaults[i]%256; | |
| } | |
| objs+=2*i-2; | |
| props=objs+((version_number==3)?9:14)*no_objects; | |
| objat=objs; propat=props; | |
| for (i=0; i<properties_size; i++) | |
| p[props+i]=properties_table[i]; | |
| for (i=0; i<no_objects; i++) | |
| { | |
| InV3 | |
| { p[objs]=objects[i].atts[0]; | |
| p[objs+1]=objects[i].atts[1]; | |
| p[objs+2]=objects[i].atts[2]; | |
| p[objs+3]=objects[i].atts[3]; | |
| p[objs+4]=objects[i].parent; | |
| p[objs+5]=objects[i].next; | |
| p[objs+6]=objects[i].child; | |
| p[objs+7]=props/256; | |
| p[objs+8]=props%256; | |
| objs+=9; | |
| } | |
| InV5 | |
| { p[objs]=objects[i].atts[0]; | |
| p[objs+1]=objects[i].atts[1]; | |
| p[objs+2]=objects[i].atts[2]; | |
| p[objs+3]=objects[i].atts[3]; | |
| p[objs+4]=objects[i].atts[4]; | |
| p[objs+5]=objects[i].atts[5]; | |
| p[objs+6]=(objects[i].parent)/256; | |
| p[objs+7]=(objects[i].parent)%256; | |
| p[objs+8]=(objects[i].next)/256; | |
| p[objs+9]=(objects[i].next)%256; | |
| p[objs+10]=(objects[i].child)/256; | |
| p[objs+11]=(objects[i].child)%256; | |
| p[objs+12]=props/256; | |
| p[objs+13]=props%256; | |
| objs+=14; | |
| } | |
| props+=objects[i].propsize; | |
| } | |
| vars=props; | |
| p[12]=(vars/256); p[13]=(vars%256); | |
| for (i=vars; i<vars+globals_size; i++) p[i]=table_init[i-vars]; | |
| for (i=0; i<240; i++) | |
| { j=gvalues[i]; | |
| p[vars+i*2] = j/256; | |
| p[vars+i*2+1] = j%256; | |
| } | |
| parse=vars+globals_size; | |
| p[14]=(parse/256); p[15]=(parse%256); parsat=parse; | |
| nparse=parse+no_verbs*2; | |
| for (i=0; i<no_verbs; i++) | |
| { p[parse]=(nparse/256); p[parse+1]=(nparse%256); | |
| parse+=2; | |
| p[nparse]=vs[i].lines; nparse++; | |
| for (j=0; j<vs[i].lines; j++) | |
| { for (k=0; k<8; k++) p[nparse+k]=vs[i].l[j].e[k]; | |
| nparse+=8; | |
| } | |
| } | |
| actshere=nparse; nparse+=2*no_actions; | |
| preactshere=nparse; nparse+=2*no_actions; | |
| p[nparse]=0; p[nparse+1]=no_adjectives; nparse+=2; | |
| dict=nparse+4*no_adjectives; | |
| adjectives_offset=nparse; | |
| for (i=0; i<no_adjectives; i++) | |
| { j=adjectives[no_adjectives-i-1]; | |
| p[nparse]=j/256; p[nparse+1]=j%256; p[nparse+2]=0; | |
| p[nparse+3]=(256-no_adjectives+i); nparse+=4; | |
| } | |
| dictionary[0]=3; dictionary[1]='.'; dictionary[2]=','; dictionary[3]='"'; | |
| dictionary[4]=(version_number==3)?7:9; | |
| dictionary[5]=(dict_entries/256); dictionary[6]=(dict_entries%256); | |
| p[8]=(dict/256); p[9]=(dict%256); | |
| for (i=0; i+dictionary<dict_p; i++) p[dict+i]=dictionary[i]; | |
| code=dict+i; | |
| while ((code%scale_factor) != 0) p[code++]=0; | |
| p[4]=(code/256); p[5]=(code%256); | |
| p[6]=((code+1)/256); p[7]=((code+1)%256); | |
| Write_Code_At = code; | |
| code_length=subtract_pointers(zcode_p,zcode); | |
| strs=code+code_length; | |
| while ((strs%scale_factor) != 0) strs++; | |
| Write_Strings_At = strs; | |
| strings_length=subtract_pointers(strings_p,strings); | |
| Out_Size=strs+strings_length; | |
| if (actual_version==3) | |
| { excess=Out_Size-((int32) 0x20000L); limit=128; } | |
| if ((actual_version==4)||(actual_version==5)) | |
| { excess=Out_Size-((int32) 0x40000L); limit=256; } | |
| if ((actual_version==6)||(actual_version==8)) | |
| { excess=Out_Size-((int32) 0x80000L); limit=512; } | |
| if (actual_version==7) { excess=0; limit=320; } | |
| if (excess>0) | |
| { sprintf(buffer, | |
| "Story file exceeds version-%d limit (%dK) by %d bytes", | |
| version_number, limit, excess); | |
| fatalerror(buffer); | |
| } | |
| extend_offset=256; | |
| if (no_objects+5 > extend_offset) extend_offset=no_objects+5; | |
| if (extend_memory_map==1) code_offset = extend_offset*scale_factor; | |
| else code_offset = code; | |
| if (extend_memory_map==1) | |
| strings_offset = code_offset + (strs-code); | |
| else strings_offset = strs; | |
| dictionary_offset = dict; | |
| variables_offset = vars; | |
| actions_offset = actshere; | |
| preactions_offset = preactshere; | |
| j=Out_Size/scale_factor; | |
| p[26]=j/256; p[27]=j%256; p[28]=0; p[29]=0; | |
| for (i=0; i<no_actions; i++) | |
| { j=(actions[i]+code_offset)/scale_factor; | |
| p[actshere+i*2]=j/256; p[actshere+i*2+1]=j%256; | |
| if (i<no_prs) j=(parsing_routines[i]+code_offset)/scale_factor; | |
| else if (preactions[i]==-1) j=0; | |
| else j=(preactions[i]+code_offset)/scale_factor; | |
| p[preactshere+i*2]=j/256; p[preactshere+i*2+1]=j%256; | |
| } | |
| if (extend_memory_map==1) | |
| { j=Write_Code_At/scale_factor - extend_offset; | |
| p[40]=j/256; p[41]=j%256; | |
| j=Write_Code_At/scale_factor - extend_offset; | |
| p[42]=j/256; p[43]=j%256; | |
| } | |
| /* From here on, it's all reportage: construction is finished */ | |
| if (statistics_mode==1) | |
| { int32 k_long, rate; char *k_str=""; | |
| k_long=(Out_Size/1024); | |
| if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; } | |
| else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; } | |
| rate=total_bytes_trans*1000/total_chars_trans; | |
| if ((pass_number==2)||(bothpasses_mode==1)) | |
| { printf("Input %d lines (%d statements, %d chars)", | |
| total_source_line,internal_line,marker_in_file); | |
| if (total_files_read > 1) { printf(" from %d files", | |
| total_files_read); } | |
| printf( | |
| "\nVersion %d (%s) story file\n\ | |
| %4d objects (maximum %3d) %4d dictionary entries (maximum %d)\n\ | |
| %4d attributes (maximum %2d) %4d properties (maximum %2d)\n\ | |
| %4d adjectives (maximum 240) %4d verbs (maximum %d)\n\ | |
| %4d actions (maximum %3d) %4d abbreviations (maximum %d)\n", | |
| actual_version, version_name(actual_version), | |
| no_objects, ((version_number==3)?255:(MAX_OBJECTS-1)), | |
| dict_entries, MAX_DICT_ENTRIES, | |
| no_attributes, ((version_number==3)?32:48), | |
| no_properties-2, ((version_number==3)?30:62), | |
| no_adjectives, | |
| no_verbs, MAX_VERBS, | |
| no_actions, MAX_ACTIONS, | |
| no_abbrevs, MAX_ABBREVS); | |
| printf( | |
| "%4d globals (maximum 240) %4d variable space (maximum %d)\n\ | |
| %4d symbols (maximum %4d) %4d routines (maximum %d)\n\ | |
| %4d classes (maximum %2d) %4d fake actions (unlimited)\n\ | |
| %4ld characters of text (compressed to %ld bytes, rate 0.%3ld)\n\ | |
| Output story file is %3ld%sK long (maximum %ldK)\n", | |
| no_globals, | |
| globals_size, MAX_STATIC_DATA, | |
| no_symbols, MAX_SYMBOLS, | |
| no_routines, MAX_ROUTINES, | |
| no_classes, MAX_CLASSES, | |
| no_fake_actions, | |
| (long int) total_chars_trans, | |
| (long int) total_bytes_trans, | |
| (long int) rate, | |
| (long int) k_long, k_str, (long int) limit); | |
| } | |
| } | |
| if ((debugging_file==1)&&(pass_number==2)) | |
| { debug_pass=2; | |
| write_debug_byte(13); | |
| write_debug_address(vars+480); | |
| write_debug_address(parsat); | |
| write_debug_address(dict); | |
| write_debug_address(code); | |
| write_debug_address(strs); | |
| debug_pass=1; | |
| } | |
| if (offsets_mode==1) | |
| { if ((pass_number==2)||(bothpasses_mode==1)) | |
| { printf( | |
| "\nOffsets in story file:\n\ | |
| %05lx Synonyms %05lx Defaults %05lx Objects %05lx Properties\n\ | |
| %05lx Variables %05lx Parse table %05lx Actions %05lx Preactions\n\ | |
| %05lx Adjectives %05lx Dictionary %05lx Code %05lx Strings\n\n", | |
| (long int) synsat, (long int) glpat, (long int) objat, (long int) propat, | |
| (long int) vars, (long int) parsat, (long int) actshere, | |
| (long int) preactshere, (long int) adjectives_offset, (long int) dict, | |
| (long int) code, (long int) strs); | |
| } | |
| } | |
| if (memory_map_mode==1) | |
| { if ((pass_number==2)||(bothpasses_mode==1)) | |
| { | |
| printf("Dynamic +---------------------+ 00000\n"); | |
| printf("memory | header |\n"); | |
| printf(" +---------------------+ 00040\n"); | |
| printf(" | synonym strings |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", (long int) synsat); | |
| printf(" | synonym table |\n"); | |
| printf(" +---------------------+ %05lx\n", (long int) glpat); | |
| printf(" | property defaults |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", (long int) objat); | |
| printf(" | objects |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", (long int) propat); | |
| printf(" | object short names |\n"); | |
| printf(" | and properties |\n"); | |
| printf(" +---------------------+ %05lx\n", (long int) vars); | |
| printf(" | global variables |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", ((long int) vars)+480L); | |
| printf(" | arrays |\n"); | |
| printf(" +=====================+ %05lx\n", (long int) parsat); | |
| printf("Static | grammar table |\n"); | |
| printf("cached + - - - - - - - - - - + %05lx\n", (long int) actshere); | |
| printf("data | actions |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", (long int) preactshere); | |
| printf(" | preactions |\n"); | |
| printf(" + - - - - - - - - - - + %05lx\n", | |
| (long int) adjectives_offset); | |
| printf(" | adjectives |\n"); | |
| printf(" +---------------------+ %05lx\n", (long int) dict); | |
| printf(" | dictionary |\n"); | |
| printf(" +---------------------+ %05lx\n", (long int) code); | |
| printf("Static | Z-code |\n"); | |
| printf("paged +---------------------+ %05lx\n", (long int) strs); | |
| printf("data | strings |\n"); | |
| printf(" +---------------------+ %05lx\n", (long int) Out_Size); | |
| } | |
| } | |
| if (percentages_mode==1) | |
| { if ((pass_number==2)||(bothpasses_mode==1)) | |
| { printf("Approximate percentage breakdown of story file:\n"); | |
| percentage("Z-code",code_length,Out_Size); | |
| percentage("Static strings",strings_length,Out_Size); | |
| percentage("Dictionary",code-dict,Out_Size); | |
| percentage("Objects",vars-glpat,Out_Size); | |
| percentage("Globals",parsat-vars,Out_Size); | |
| percentage("Parsing tables",dict-parsat,Out_Size); | |
| percentage("Header and synonyms",glpat,Out_Size); | |
| percentage("Total of save area",parsat,Out_Size); | |
| percentage("Total of text",total_bytes_trans,Out_Size); | |
| } | |
| } | |
| if (frequencies_mode==1) | |
| { if ((pass_number==2)||(bothpasses_mode==1)) | |
| { printf("How frequently abbreviations were used, and roughly\n"); | |
| printf("how many bytes they saved: ('_' denotes spaces)\n"); | |
| for (i=0; i<no_abbrevs; i++) | |
| { sprintf(sub_buffer, | |
| (char *)abbreviations_at+i*MAX_ABBREV_LENGTH); | |
| for (j=0; sub_buffer[j]!=0; j++) | |
| if (sub_buffer[j]==' ') sub_buffer[j]='_'; | |
| printf("%10s %5d/%5d ",sub_buffer,abbrev_freqs[i], | |
| 2*((abbrev_freqs[i]-1)*abbrev_quality[i])/3); | |
| if ((i%3)==2) printf("\n"); | |
| } | |
| if ((i%3)!=0) printf("\n"); | |
| if (no_abbrevs==0) printf("None were declared.\n"); | |
| } | |
| } | |
| if (((statistics_mode==1)||(economy_mode==1))&&(pass_number==2)) | |
| { printf("Essential size %ld bytes: %ld remaining\n", | |
| (long int) Out_Size, | |
| (long int) (((long int) (limit*1024L)) - ((long int) Out_Size))); | |
| } | |
| } | |
| /* ------------------------------------------------------------------------- */ | |
| /* Begin pass */ | |
| /* ------------------------------------------------------------------------- */ | |
| extern void tables_begin_pass(void) | |
| { int i; | |
| for (i=0; i<256; i++) debug_acts_writ[i]=0; | |
| dictionary_begin_pass(); | |
| properties_size=0; classes_size=0; | |
| no_objects=0; no_classes=0; embedded_routine=0; | |
| no_verbs=0; fp_no_actions=no_actions; no_actions=0; no_adjectives=0; | |
| no_properties=2; no_attributes=0; no_fake_actions=0; | |
| no_globals=0; globals_size=0x1e0; | |
| no_prs=0; | |
| objects[0].parent=0; objects[0].child=0; objects[0].next=0; | |
| doing_table_mode = 0; | |
| } | |
| extern void init_tables_vars(void) | |
| { | |
| no_fake_actions = 0; | |
| release_number = 1; | |
| statusline_flag = 0; | |
| max_no_objects = 0; | |
| resobj_flag = 0; | |
| no_verbs = 0; | |
| no_actions = 0; | |
| no_adjectives = 0; | |
| no_objects = 0; | |
| no_classes = 0; | |
| classes_size = 0; | |
| fp_no_actions = 0; | |
| embedded_routine = 0; | |
| verbspace_consumed = 0; | |
| alloc_done_flag = 0; | |
| vs = NULL; | |
| objects = NULL; | |
| table_init = NULL; | |
| actions = NULL; | |
| preactions = NULL; | |
| adjectives = NULL; | |
| adjcomps = NULL; | |
| gvalues = NULL; | |
| dict_places_list = NULL; | |
| dict_places_back = NULL; | |
| dict_places_inverse = NULL; | |
| dict_sorts = NULL; | |
| class_pointer = NULL; | |
| classes_here = NULL; | |
| classes_at = NULL; | |
| verblist = NULL; | |
| output_p = NULL; | |
| } | |
Xet Storage Details
- Size:
- 56.6 kB
- Xet hash:
- b25fad21bdeccea143dfc91d0de6d0dc934d6a78be06d576779e0b031dd55a87
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.