objects.c 86 KB

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