1 /* ------------------------------------------------------------------------- */
2 /* "veneer" : Compiling the run-time "veneer" of any routines invoked */
3 /* by the compiler (e.g. DefArt) which the program doesn't */
6 /* Part of Inform 6.33 */
7 /* copyright (c) Graham Nelson 1993 - 2014 */
9 /* ------------------------------------------------------------------------- */
13 int veneer_mode
; /* Is the code currently being
14 compiled from the veneer? */
16 static debug_locations null_debug_locations
=
17 { { 0, 0, 0, 0, 0, 0, 0 }, NULL
, 0 };
19 extern void compile_initial_routine(void)
21 /* The first routine present in memory in any Inform game, beginning
22 at the code area start position, always has 0 local variables
23 (since the interpreter begins execution with an empty stack frame):
24 and it must "quit" rather than "return".
26 In order not to impose these restrictions on "Main", we compile a
27 trivial routine consisting of a call to "Main" followed by "quit". */
32 j
= symbol_index("Main__", -1);
34 assemble_routine_header(0, FALSE
, "Main__", FALSE
, j
),
36 sflags
[j
] |= SYSTEM_SFLAG
+ USED_SFLAG
;
37 if (trace_fns_setting
==3) sflags
[j
] |= STAR_SFLAG
;
41 AO
.value
= 0; AO
.type
= LONG_CONSTANT_OT
; AO
.marker
= MAIN_MV
;
43 sequence_point_follows
= FALSE
;
45 if (version_number
> 3)
46 assemblez_1_to(call_vs_zc
, AO
, temp_var1
);
48 assemblez_1_to(call_zc
, AO
, temp_var1
);
55 AO
.value
= 0; AO
.type
= CONSTANT_OT
; AO
.marker
= MAIN_MV
;
57 sequence_point_follows
= FALSE
;
59 assembleg_3(call_gc
, AO
, zero_operand
, zero_operand
);
60 assembleg_1(return_gc
, zero_operand
);
64 assemble_routine_end(FALSE
, null_debug_locations
);
67 /* ------------------------------------------------------------------------- */
68 /* The rest of the veneer is applied at the end of the pass, as required. */
69 /* ------------------------------------------------------------------------- */
71 static int veneer_routine_needs_compilation
[VENEER_ROUTINES
];
72 int32 veneer_routine_address
[VENEER_ROUTINES
];
73 static int veneer_symbols_base
;
79 typedef struct VeneerRoutine_s
89 static char *veneer_source_area
;
91 static VeneerRoutine VRs_z
[VENEER_ROUTINES
] =
93 /* Box__Routine: the only veneer routine used in the implementation of
94 an actual statement ("box", of course), written in a
95 hybrid of Inform and assembly language. Note the
96 transcription of the box text to the transcript
97 output stream (-1, or $ffff). */
100 "maxw table n w w2 line lc t;\
115 { @set_cursor line w;\
117 @set_cursor line w2;\
119 if (t~=0) print (string) t;\
128 @output_stream $ffff;\
133 if (w ~= 0) print (string) w;\
145 /* This batch of routines is expected to be defined (rather better) by
146 the Inform library: these minimal forms here are provided to prevent
147 tiny non-library-using programs from failing to compile when certain
148 legal syntaxes (such as <<Action a b>>;) are used. */
151 "a b c d; print \"Action <\", a, \" \", b, \" \", c;\
152 if (d) print \", \", d; print \">^\";\
153 ]", "", "", "", "", ""
156 "obj; print \"the \", obj; ]", "", "", "", "", ""
159 "obj; print \"a \", obj; ]", "", "", "", "", ""
162 "obj; print \"The \", obj; ]", "", "", "", "", ""
165 "obj; print \"A \", obj; ]", "", "", "", "", ""
168 "obj; switch(metaclass(obj))\
169 { 0: print \"nothing\";\
170 Object: @print_obj obj;\
171 Class: print \"class \"; @print_obj obj;\
172 Routine: print \"(routine at \", obj, \")\";\
173 String: print \"(string at \", obj, \")\";\
174 } ]", "", "", "", "", ""
177 "obj; print obj; ]", "", "", "", "", ""
182 { cla = #classes_table-->(prop & $ff);\
183 print (name) cla, \"::\";\
184 if ((prop & $8000) == 0) prop = (prop & $3f00)/$100;\
186 { prop = (prop & $7f00)/$100;\
188 while ((i-->0 ~= 0) && (prop>0))\
192 prop = (i-->0) & $7fff;\
195 "p = #identifiers_table;\
197 if (prop<=0 || prop>=size || p-->prop==0)\
198 print \"<number \", prop, \">\";\
199 else print (string) p-->prop;\
203 /* The remaining routines make up the run-time half of the object
204 orientation system, and need never be present for Inform 5 programs. */
207 /* WV__Pr: write a value to the property for the given
208 object having the given identifier */
211 "obj identifier value x;\
212 x = obj..&identifier;\
213 if (x==0) { RT__Err(\"write to\", obj, identifier); return; }\
215 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,value);\
216 #ifnot; #ifdef DEBUG;\
217 if (debug_flag & 15) RT__TrPS(obj,identifier,value);\
220 ]", "", "", "", "", ""
223 /* RV__Pr: read a value from the property for the given
224 object having the given identifier */
228 x = obj..&identifier;\
230 { if (identifier >= 1 && identifier < 64 && obj.#identifier <= 2)\
231 return obj.identifier;\
232 RT__Err(\"read\", obj, identifier); return; }\
233 if (obj..#identifier > 2) RT__Err(\"read\", obj, identifier, 2);\
235 ]", "", "", "", "", ""
237 { /* CA__Pr: call, that is, print-or-run-or-read, a property:
238 this exactly implements obj..prop(...). Note that
239 classes (members of Class) have 5 built-in properties
240 inherited from Class: create, recreate, destroy,
241 remaining and copy. Implementing these here prevents
242 the need for a full metaclass inheritance scheme. */
245 "obj id a b c d e f x y z s s2 n m;\
246 if (obj < 1 || obj > #largest_object-255)\
247 { switch(Z__Region(obj))\
248 { 2: if (id == call)\
249 { s = sender; sender = self; self = obj;\
250 #ifdef action;sw__var=action;#endif;\
251 x = indirect(obj, a, b, c, d, e, f);\
252 self = sender; sender = s; return x; }\
254 "3: if (id == print) { @print_paddr obj; rtrue; }\
255 if (id == print_to_array)\
256 { @output_stream 3 a; @print_paddr obj; @output_stream -3;\
262 @check_arg_count 3 ?~A__x;y++;@check_arg_count 4 ?~A__x;y++;\
263 @check_arg_count 5 ?~A__x;y++;@check_arg_count 6 ?~A__x;y++;\
264 @check_arg_count 7 ?~A__x;y++;@check_arg_count 8 ?~A__x;y++;.A__x;",
265 "#ifdef INFIX;if (obj has infix__watching) n=1;#endif;\
266 #ifdef DEBUG;if (debug_flag & 1 ~= 0) n=1;#endif;\
268 #ifdef DEBUG;n=debug_flag & 1; debug_flag=debug_flag-n;#endif;\
269 print \"[ ~\", (name) obj, \"~.\", (property) id, \"(\";\
270 switch(y) { 1: print a; 2: print a,\",\",b; 3: print a,\",\",b,\",\",c;\
271 4: print a,\",\",b,\",\",c,\",\",d;\
272 5: print a,\",\",b,\",\",c,\",\",d,\",\",e;\
273 6: print a,\",\",b,\",\",c,\",\",d,\",\",e,\",\",f; }\
275 #ifdef DEBUG;debug_flag = debug_flag + n;#endif;\
277 "if (id > 0 && id < 64)\
278 { x = obj.&id; if (x==0) { x=$000a-->0 + 2*(id-1); n=2; }\
281 { if (id>=64 && id<69 && obj in Class)\
282 return Cl__Ms(obj,id,y,a,b,c,d);\
284 if (x == 0) { .Call__Error;\
285 RT__Err(\"send message\", obj, id); return; }\
287 if (id&$C000==$4000)\
288 switch (n&$C0) { 0: n=1; $40: n=2; $80: n=n&$3F; }\
291 { if (x-->m==$ffff) rfalse;\
292 switch(Z__Region(x-->m))\
293 { 2: s = sender; sender = self; self = obj; s2 = sw__var;\
295 if (id==life) sw__var=reason_code; else sw__var=action;\
297 switch(y) { 0: z = indirect(x-->m); 1: z = indirect(x-->m, a);\
298 2: z = indirect(x-->m, a, b); 3: z = indirect(x-->m, a, b, c);",
299 "4: z = indirect(x-->m, a, b, c, d); 5:z = indirect(x-->m, a, b, c, d, e);\
300 6: z = indirect(x-->m, a, b, c, d, e, f); }\
301 self = sender; sender = s; sw__var = s2;\
302 if (z ~= 0) return z;\
303 3: print_ret (string) x-->m;\
304 default: return x-->m;\
311 /* IB__Pr: ++(individual property) */
315 x = obj..&identifier;\
316 if (x==0) { RT__Err(\"increment\", obj, identifier); return; }\
318 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)+1);\
319 #ifnot; #ifdef DEBUG;\
320 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)+1);\
323 ]", "", "", "", "", ""
326 /* IA__Pr: (individual property)++ */
330 x = obj..&identifier;\
331 if (x==0) { RT__Err(\"increment\", obj, identifier); return; }\
333 if (obj has infix__watching || (debug_flag & 15))\
334 RT__TrPS(obj,identifier,(x-->0)+1);\
335 #ifnot; #ifdef DEBUG;\
336 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)+1);\
339 ]", "", "", "", "", ""
342 /* DB__Pr: --(individual property) */
346 x = obj..&identifier;\
347 if (x==0) { RT__Err(\"decrement\", obj, identifier); return; }\
349 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)-1);\
350 #ifnot; #ifdef DEBUG;\
351 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)-1);\
354 ]", "", "", "", "", ""
357 /* DA__Pr: (individual property)-- */
361 x = obj..&identifier;\
362 if (x==0) { RT__Err(\"decrement\", obj, identifier); return; }\
364 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)-1);\
365 #ifnot; #ifdef DEBUG;\
366 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)-1);\
369 ]", "", "", "", "", ""
372 /* RA__Pr: read the address of a property value for a given object,
373 returning 0 if it doesn't provide this individual
377 "obj identifier i otherid cla;\
379 if (identifier<64 && identifier>0) return obj.&identifier;\
380 if (identifier & $8000 ~= 0)\
381 { cla = #classes_table-->(identifier & $ff);\
382 if (cla.&3 == 0) rfalse;\
383 if (~~(obj ofclass cla)) rfalse;\
384 identifier = (identifier & $7f00) / $100;\
386 while (identifier>0)\
392 "if (identifier & $4000 ~= 0)\
393 { cla = #classes_table-->(identifier & $ff);\
394 identifier = (identifier & $3f00) / $100;\
395 if (~~(obj ofclass cla)) rfalse; i=0-->5;\
396 if (cla == 2) return i+2*identifier-2;\
397 i = 0-->((i+124+cla*14)/2);\
398 i = CP__Tab(i + 2*(0->i) + 1, -1)+6;\
399 return CP__Tab(i, identifier);\
401 if (obj.&3 == 0) rfalse;\
403 { if (identifier<64 || identifier>=72) rfalse;\
406 otherid = identifier | $8000;\
409 { if (i-->0 == identifier or otherid)\
417 /* RL__Pr: read the property length of an individual property value,
418 returning 0 if it isn't provided by the given object */
422 if (identifier<64 && identifier>0) return obj.#identifier;\
423 x = obj..&identifier;\
425 if (identifier&$C000==$4000)\
426 switch (((x-1)->0)&$C0)\
427 { 0: return 1; $40: return 2; $80: return ((x-1)->0)&$3F; }\
429 ]", "", "", "", "", ""
432 /* RA__Sc: implement the "superclass" (::) operator,
433 returning an identifier */
436 "cla identifier otherid i j k;\
437 if (cla notin 1 && cla > 4)\
438 { RT__Err(\"be a '::' superclass\", cla, -1); rfalse; }\
439 if (self ofclass cla) otherid = identifier | $8000;\
440 for (j=0: #classes_table-->j ~= 0: j++)\
441 { if (cla==#classes_table-->j)\
442 { if (identifier < 64) return $4000 + identifier*$100 + j;\
443 if (cla.&3 == 0) break;\
446 { if (i-->0 == identifier or otherid)\
447 return $8000 + k*$100 + j;\
454 RT__Err(\"make use of\", cla, identifier);\
459 /* OP__Pr: test whether or not given object provides individual
460 property with the given identifier code */
464 if (obj<1 || obj > (#largest_object-255))\
465 { if (identifier ~= print or print_to_array or call) rfalse;\
466 switch(Z__Region(obj))\
467 { 2: if (identifier == call) rtrue;\
468 3: if (identifier == print or print_to_array) rtrue;\
473 { if (obj.&identifier ~= 0) rtrue;\
476 if (obj..&identifier ~= 0) rtrue;\
477 if (identifier<72 && obj in 1) rtrue;\
482 /* OC__Cl: test whether or not given object is of the given class */
486 if (obj<1 || obj > (#largest_object-255))\
487 { if (cla ~= 3 or 4) rfalse;\
488 if (Z__Region(obj) == cla-1) rtrue;\
493 if (obj in 1) rtrue;\
495 } else if (cla == 2) {\
497 if (obj in 1) rfalse;\
499 } else if (cla == 3 or 4) {\
502 "if (cla notin 1) { RT__Err(\"apply 'ofclass' for\", cla, -1);rfalse;}\
503 @get_prop_addr obj 2 -> a;\
505 @get_prop_len a -> n;\
506 for (j=0: j<n/2: j++)\
507 { if (a-->j == cla) rtrue;\
512 { /* Copy__Primitive: routine to "deep copy" objects */
515 "o1 o2 a1 a2 n m l size identifier;\
517 { if (o2 has n) give o1 n;\
520 for (n=1:n<64:n++) if (n~=2 or 3)\
521 { a1 = o1.&n; a2 = o2.&n; size = o1.#n;\
522 if (a1~=0 && a2~=0 && size==o2.#n)\
523 { for (m=0:m<size:m++) a1->m=a2->m;\
526 "if (o1.&3 == 0 || o2.&3 == 0) return;\
527 for (n=o2.3: n-->0 ~= 0: n = n + size + 3)\
528 { identifier = n-->0;\
530 for (m=o1.3: m-->0 ~= 0: m = m + m->2 + 3)\
531 if ((identifier & $7fff == (m-->0) & $7fff) && size==m->2)\
532 for (l=3: l<size+3: l++) m->l = n->l;\
536 { /* RT__Err: for run-time errors occurring in the above: e.g.,
537 an attempt to write to a non-existent individual
541 "crime obj id size p q;\
542 print \"^[** Programming error: \";\
543 if (crime<0) jump RErr;\
544 if (crime==1) { print \"class \"; @print_obj obj;\
545 \": 'create' can have 0 to 3 parameters only **]\";}\
546 if (crime == 32) \"objectloop broken because the object \",\
547 (name) obj, \" was moved while the loop passed through it **]\";\
548 if (crime == 33) \"tried to print (char) \", obj,\
549 \", which is not a valid ZSCII character code for output **]\";\
550 if (crime == 34) \"tried to print (address) on something not the \",\
551 \"byte address of a string **]\";\
552 if (crime == 35) \"tried to print (string) on something not a \",\
554 if (crime == 36) \"tried to print (object) on something not an \",\
555 \"object or class **]\";",
556 "if (crime < 32) { print \"tried to \";\
557 if (crime >= 28) { if (crime==28 or 29) print \"read from \";\
558 else print \"write to \";\
559 if (crime==29 or 31) print \"-\"; print \"->\", obj,\
560 \" in the\"; switch(size&7){0,1:q=0; 2:print \" string\";\
561 q=1; 3:print \" table\";q=1; 4:print \" buffer\";q=WORDSIZE;} \
562 if(size&16) print\" (->)\"; if(size&8) print\" (-->)\";\
563 \" array ~\", (string) #array_names_offset-->p,\
564 \"~, which has entries \", q, \" up to \",id,\" **]\"; }\
565 if (crime >= 24 && crime <=27) { if (crime<=25) print \"read\";\
566 else print \"write\"; print \" outside memory using \";\
567 switch(crime) { 24,26:\"-> **]\"; 25,27:\"--> **]\"; } }\
568 if (crime < 4) print \"test \"; else\
569 if (crime < 12 || crime > 20) print \"find the \"; else\
570 if (crime < 14) print \"use \";\
571 if (crime==20) \"divide by zero **]\"; print \"~\";\
573 2: print \"in~ or ~notin\"; 3: print \"has~ or ~hasnt\";\
574 4: print \"parent\"; 5: print \"eldest\"; 6: print \"child\";\
575 7: print \"younger\"; 8: print \"sibling\"; 9: print \"children\";\
576 10: print \"youngest\"; 11: print \"elder\";\
577 12: print \"objectloop\"; 13: print \"}~ at end of ~objectloop\";\
578 14: \"give~ an attribute to \", (name) obj, \" **]\";\
579 15: \"remove~ \", (name) obj, \" **]\";",
580 "16,17,18: print \"move~ \", (name) obj, \" to \", (name) id;\
581 if (crime==18) { print \", which would make a loop: \",(name) obj;\
582 p=id; if (p==obj) p=obj;\
583 else do { print \" in \", (name) p; p=parent(p);} until (p==obj);\
584 \" in \", (name) p, \" **]\"; }\
585 \" **]\"; 19: \"give~ or test ~has~ or ~hasnt~ with a non-attribute"\
586 " on the object \",(name) obj,\" **]\";\
587 21: print \".&\"; 22: print \".#\"; 23: print \".\"; }\
588 \"~ of \", (name) obj, \" **]\"; }",
589 ".RErr; if (obj>=0 && obj<=(#largest_object-255)) {\
590 if (obj && obj in Class) print \"class \";\
591 if (obj) @print_obj obj;else print \"nothing\";print\" \";}\
592 print \"(object number \", obj, \") \";\
593 if (id<0) print \"is not of class \", (name) -id;",
594 "else if (size) print \"has a property \", (property) id,\
595 \", but it is longer than 2 bytes so you cannot use ~.~\";\
597 { print \" has no property \", (property) id;\
598 p = #identifiers_table;\
600 if (id<0 || id>=size)\
601 print \" (and nor has any other object)\";\
603 print \" to \", (string) crime, \" **]^\";\
606 { /* Z__Region: Determines whether a value is:
610 0 none of the above */
614 if (addr==0 or -1) rfalse;\
616 #IfV5; #iftrue (#version_number == 6) || (#version_number == 7);\
617 @log_shift addr $FFFF -> top; #Endif; #Endif;\
618 if (Unsigned__Compare(top, $001A-->0) >= 0) rfalse;\
619 if (addr>=1 && addr<=(#largest_object-255)) rtrue;\
620 #iftrue #oddeven_packing;\
621 @test addr 1 ?~NotString;\
622 if (Unsigned__Compare(addr, #strings_offset)<0) rfalse;\
625 if (Unsigned__Compare(addr, #code_offset)<0) rfalse;\
628 if (Unsigned__Compare(addr, #strings_offset)>=0) return 3;\
629 if (Unsigned__Compare(addr, #code_offset)>=0) return 2;\
632 ]", "", "", "", "", ""
634 { /* Unsigned__Compare: returns 1 if x>y, 0 if x=y, -1 if x<y */
639 if (x<0 && y>=0) return 1;\
640 if (x>=0 && y<0) return -1;\
641 u = x&$7fff; v= y&$7fff;\
644 ]", "", "", "", "", ""
646 { /* Meta__class: returns the metaclass of an object */
650 switch(Z__Region(obj))\
651 { 2: return Routine;\
653 1: if (obj in 1 || obj <= 4) return Class;\
657 ]", "", "", "", "", ""
659 { /* CP__Tab: searches a common property table for the given
660 identifier, thus imitating the get_prop_addr opcode.
661 Returns 0 if not provided, except:
662 if the identifier supplied is -1, then returns
663 the address of the first byte after the table. */
667 while ((n=0->x) ~= 0)\
668 { if (n & $80) { x++; l = (0->x) & $3f; }\
669 else { if (n & $40) l=2; else l=1; }\
671 if ((n & $3f) == id) return x;\
674 if (id<0) return x+1; rfalse; ]", "", "", "", "", ""
676 { /* Cl__Ms: the five message-receiving properties of Classes */
679 "obj id y a b c d x;\
682 if (children(obj)<=1) rfalse; x=child(obj);\
683 remove x; if (x provides create) { if (y==0) x..create();\
684 if (y==1) x..create(a); if (y==2) x..create(a,b);\
685 if (y>3) RT__Err(1,obj); if (y>=3) x..create(a,b,c);}\
688 if (~~(a ofclass obj))\
689 { RT__Err(\"recreate\", a, -obj); rfalse; }\
690 Copy__Primitive(a, child(obj));\
691 if (a provides create) { if (y==1) a..create();\
692 if (y==2) a..create(b); if (y==3) a..create(b,c);\
693 if (y>4) RT__Err(1,obj); if (y>=4) a..create(b,c,d);\
696 if (~~(a ofclass obj))\
697 { RT__Err(\"destroy\", a, -obj); rfalse; }\
698 if (a provides destroy) a..destroy();\
699 Copy__Primitive(a, child(obj));\
700 move a to obj; rfalse;\
702 return children(obj)-1;",
704 if (~~(a ofclass obj))\
705 { RT__Err(\"copy\", a, -obj); rfalse; }\
706 if (~~(b ofclass obj))\
707 { RT__Err(\"copy\", b, -obj); rfalse; }\
708 Copy__Primitive(a, b); rfalse;\
712 { /* RT__ChT: check at run-time that a proposed object move is legal
713 cause error and do nothing if not; otherwise move */
717 if (obj1<5 || obj1>(#largest_object-255) || obj1 in 1)\
718 return RT__Err(16,obj1,obj2);\
719 if (obj2<5 || obj2>(#largest_object-255) || obj2 in 1)\
720 return RT__Err(17,obj1,obj2);",
721 "x=obj2; while (x~=0) { if (x==obj1) return RT__Err(18,obj1,obj2); \
724 if (obj1 has infix__watching\
725 || obj2 has infix__watching || (debug_flag & 15))\
726 print \"[Moving \", (name) obj1, \" to \", (name) obj2, \"]^\";\
727 #ifnot; #ifdef DEBUG;\
728 if (debug_flag & 15)\
729 print \"[Moving \", (name) obj1, \" to \", (name) obj2, \"]^\";\
731 @insert_obj obj1 obj2; ]", "", "", "", ""
733 { /* RT__ChR: check at run-time that a proposed object remove is legal
734 cause error and do nothing if not; otherwise remove */
738 if (obj1<5 || obj1>(#largest_object-255) || obj1 in 1)\
739 return RT__Err(15,obj1);",
741 if (obj1 has infix__watching || (debug_flag & 15))\
742 print \"[Removing \", (name) obj1, \"]^\";\
743 #ifnot; #ifdef DEBUG;\
744 if (debug_flag & 15)\
745 print \"[Removing \", (name) obj1, \"]^\";\
747 @remove_obj obj1; ]", "", "", "", ""
749 { /* RT__ChG: check at run-time that a proposed attr give is legal
750 cause error and do nothing if not; otherwise give */
754 if (obj1<5 || obj1>(#largest_object-255) || obj1 in 1)\
755 return RT__Err(14,obj1); if (a<0 || a>=48) return RT__Err(19,obj1);\
756 if (obj1 has a) return;",
758 if (a ~= workflag && (obj1 has infix__watching || (debug_flag & 15)))\
759 print \"[Giving \", (name) obj1, \" \", (DebugAttribute) a, \"]^\";\
760 #ifnot; #ifdef DEBUG;\
761 if (a ~= workflag && debug_flag & 15)\
762 print \"[Giving \", (name) obj1, \" \", (DebugAttribute) a, \"]^\";\
764 @set_attr obj1 a; ]", "", "", "", ""
766 { /* RT__ChGt: check at run-time that a proposed attr give ~ is legal
767 cause error and do nothing if not; otherwise give */
771 if (obj1<5 || obj1>(#largest_object-255) || obj1 in 1)\
772 return RT__Err(14,obj1); if (a<0 || a>=48) return RT__Err(19,obj1);\
773 if (obj1 hasnt a) return;",
775 if (a ~= workflag && (obj1 has infix__watching || (debug_flag & 15)))\
776 print \"[Giving \",(name) obj1,\" @@126\", (DebugAttribute) a, \"]^\";\
777 #ifnot; #ifdef DEBUG;\
778 if (a ~= workflag && debug_flag & 15)\
779 print \"[Giving \",(name) obj1,\" @@126\", (DebugAttribute) a, \"]^\";\
781 @clear_attr obj1 a; ]", "", "", "", ""
783 { /* RT__ChPS: check at run-time that a proposed property set is legal
784 cause error and do nothing if not; otherwise make it */
788 if (obj<5 || obj>(#largest_object-255) || obj in 1 || obj.&prop==0 || (size=obj.#prop)>2 )\
789 return RT__Err(\"set\", obj, prop, size);\
790 @put_prop obj prop val;",
792 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,prop,val);\
793 #ifnot; #ifdef DEBUG;\
794 if (debug_flag & 15) RT__TrPS(obj,prop,val);\
796 return val; ]", "", "", "", ""
798 { /* RT__ChPR: check at run-time that a proposed property read is legal
799 cause error and return 0 if not; otherwise read it */
803 if (obj<5 || obj>(#largest_object-255) || (size=obj.#prop)>2)\
804 {RT__Err(\"read\", obj, prop, size); obj=2;}\
805 @get_prop obj prop -> val;",
806 "return val; ]", "", "", "", ""
808 { /* RT__TrPS: trace property settings */
812 print \"[Setting \",(name) obj,\".\",(property) prop,\
813 \" to \",val,\"]^\"; ]",
816 { /* RT__ChLDB: check at run-time that it's safe to load a byte
817 and return the byte */
821 a=base+offset;if (Unsigned__Compare(a,#readable_memory_offset)>=0)\
822 return RT__Err(24);",
823 "@loadb base offset -> val;return val; ]", "", "", "", ""
825 { /* RT__ChLDW: check at run-time that it's safe to load a word
826 and return the word */
830 a=base+2*offset;if (Unsigned__Compare(a,#readable_memory_offset)>=0)\
831 return RT__Err(25);",
832 "@loadw base offset -> val;return val; ]", "", "", "", ""
834 { /* RT__ChSTB: check at run-time that it's safe to store a byte
838 "base offset val a f;\
840 if (Unsigned__Compare(a,#array__start)>=0\
841 && Unsigned__Compare(a,#array__end)<0) f=1; else\
842 if (Unsigned__Compare(a,#cpv__start)>=0\
843 && Unsigned__Compare(a,#cpv__end)<0) f=1; else\
844 if (Unsigned__Compare(a,#ipv__start)>=0\
845 && Unsigned__Compare(a,#ipv__end)<0) f=1; else\
847 if (f==0) return RT__Err(26);",
848 "@storeb base offset val; ]", "", "", "", ""
850 { /* RT__ChSTW: check at run-time that it's safe to store a word
854 "base offset val a f;\
856 if (Unsigned__Compare(a,#array__start)>=0\
857 && Unsigned__Compare(a,#array__end)<0) f=1; else\
858 if (Unsigned__Compare(a,#cpv__start)>=0\
859 && Unsigned__Compare(a,#cpv__end)<0) f=1; else\
860 if (Unsigned__Compare(a,#ipv__start)>=0\
861 && Unsigned__Compare(a,#ipv__end)<0) f=1; else\
863 if (f==0) return RT__Err(27);",
864 "@storew base offset val; ]", "", "", "", ""
866 { /* RT__ChPrintC: check at run-time that it's safe to print (char)
871 if (c==0 or 9 or 11 or 13) fl=1;\
872 if (c>=32 && c<=126) fl=1; if (c>=155 && c<=251) fl=1;\
873 if (fl==0) return RT__Err(33,c);",
874 "@print_char c; ]", "", "", "", ""
876 { /* RT__ChPrintA: check at run-time that it's safe to print (address)
881 if (Unsigned__Compare(a, #readable_memory_offset)>=0)\
882 return RT__Err(34);",
883 "@print_addr a; ]", "", "", "", ""
885 { /* RT__ChPrintS: check at run-time that it's safe to print (string)
890 if (Z__Region(a)~=3) return RT__Err(35);",
891 "@print_paddr a; ]", "", "", "", ""
893 { /* RT__ChPrintO: check at run-time that it's safe to print (object)
898 if (Z__Region(a)~=1) return RT__Err(36);",
899 "@print_obj a; ]", "", "", "", ""
903 static VeneerRoutine VRs_g
[VENEER_ROUTINES
] =
906 /* Box__Routine: Display the given array of text as a box quote.
907 This is a very simple implementation; the library should provide
914 for (ix=0 : ix<arr-->0 : ix++) {\
915 print (string) arr-->(ix+1);\
919 ]", "", "", "", "", ""
922 /* This batch of routines is expected to be defined (rather better) by
923 the Inform library: these minimal forms here are provided to prevent
924 tiny non-library-using programs from failing to compile when certain
925 legal syntaxes (such as <<Action a b>>;) are used. */
928 "a b c d; print \"Action <\", a, \" \", b, \" \", c;\
929 if (d) print \", \", d; print \">^\";\
930 ]", "", "", "", "", ""
933 "obj; print \"the \", obj; ]", "", "", "", "", ""
936 "obj; print \"a \", obj; ]", "", "", "", "", ""
939 "obj; print \"The \", obj; ]", "", "", "", "", ""
942 "obj; print \"A \", obj; ]", "", "", "", "", ""
945 "obj q; switch(metaclass(obj))\
946 { 0: print \"nothing\";\
947 Object: q = obj-->GOBJFIELD_NAME; @streamstr q;\
948 Class: print \"class \"; q = obj-->GOBJFIELD_NAME; @streamstr q;\
949 Routine: print \"(routine at \", obj, \")\";\
950 String: print \"(string at \", obj, \")\";\
951 } ]", "", "", "", "", ""
954 "obj; print obj; ]", "", "", "", "", ""
957 /* Print__PName: Print the name of a property.
960 "prop ptab cla maxcom minind maxind str;\
961 if (prop & $FFFF0000) {\
962 cla = #classes_table-->(prop & $FFFF);\
963 print (name) cla, \"::\";\
964 @ushiftr prop 16 prop;\
966 ptab = #identifiers_table;\
968 minind = INDIV_PROP_START;\
969 maxind = minind + ptab-->3;\
971 if (prop >= 0 && prop < maxcom) {\
972 str = (ptab-->0)-->prop;\
974 else if (prop >= minind && prop < maxind) {\
975 str = (ptab-->2)-->(prop-minind);\
980 print \"<number \", prop, \">\";\
981 ]", "", "", "", "", ""
984 /* The remaining routines make up the run-time half of the object
985 orientation system, and need never be present for Inform 5 programs. */
988 /* WV__Pr: Write a value to the property for the given object.
994 RT__Err(\"write\", obj, id);\
999 ]", "", "", "", "", ""
1003 /* RV__Pr: Read a value to the property for the given object.
1009 if (id > 0 && id < INDIV_PROP_START) {\
1010 return #cpv__start-->id;\
1012 RT__Err(\"read\", obj, id);\
1016 ]", "", "", "", "", ""
1019 /* CA__Pr: Call, that is, print-or-run-or-read, a property:
1020 this exactly implements obj..prop(...). Note that
1021 classes (members of Class) have 5 built-in properties
1022 inherited from Class: create, recreate, destroy,
1023 remaining and copy. Implementing these here prevents
1024 the need for a full metaclass inheritance scheme.
1027 "_vararg_count obj id zr s s2 z addr len m val;\
1030 _vararg_count = _vararg_count - 2;\
1031 zr = Z__Region(obj);\
1034 s = sender; sender = self; self = obj;\
1035 #ifdef action; sw__var=action; #endif;\
1036 @call obj _vararg_count z;\
1037 self = sender; sender = s;\
1044 @streamstr obj; rtrue;\
1046 if (id == print_to_array) {\
1047 if (_vararg_count >= 2) {\
1052 RT__Err(37); rfalse;\
1055 s = glk($0043, m+4, len-4, 1, 0);",
1060 @copy $ffffffff sp;\
1074 #ifdef DEBUG;#ifdef InformLibrary;\
1075 if (debug_flag & 1 ~= 0) {\
1077 print \"[ ~\", (name) obj, \"~.\", (property) id, \"(\";\
1078 @stkcopy _vararg_count;\
1079 for (val=0 : val < _vararg_count : val++) {\
1080 if (val) print \", \";\
1087 if (obj in Class) {\
1090 return Cl__Ms(obj, id);\
1094 return Cl__Ms(obj, id, m, val);\
1095 create, destroy, recreate:\
1096 m = _vararg_count+2;\
1099 @call Cl__Ms m val;\
1105 if (id > 0 && id < INDIV_PROP_START) {\
1106 addr = #cpv__start + 4*id;\
1116 for (m=0 : 4*m<len : m++) {\
1118 if (val == -1) rfalse;\
1119 switch (Z__Region(val)) {\
1121 s = sender; sender = self; self = obj; s2 = sw__var;\
1123 if (id==life) sw__var=reason_code; else sw__var=action;\
1125 " @stkcopy _vararg_count;\
1126 @call val _vararg_count z;\
1127 self = sender; sender = s; sw__var = s2;\
1128 if (z ~= 0) return z;\
1139 RT__Err(\"send message\", obj, id);\
1144 /* IB__Pr: ++(individual property) */
1148 x = obj.&identifier;\
1149 if (x==0) { RT__Err(\"increment\", obj, identifier); return; }\
1151 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)+1);\
1152 #ifnot; #ifdef DEBUG;\
1153 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)+1);\
1156 ]", "", "", "", "", ""
1159 /* IA__Pr: (individual property)++ */
1163 x = obj.&identifier;\
1164 if (x==0) { RT__Err(\"increment\", obj, identifier); return; }\
1166 if (obj has infix__watching || (debug_flag & 15))\
1167 RT__TrPS(obj,identifier,(x-->0)+1);\
1168 #ifnot; #ifdef DEBUG;\
1169 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)+1);\
1172 ]", "", "", "", "", ""
1175 /* DB__Pr: --(individual property) */
1179 x = obj.&identifier;\
1180 if (x==0) { RT__Err(\"decrement\", obj, identifier); return; }\
1182 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)-1);\
1183 #ifnot; #ifdef DEBUG;\
1184 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)-1);\
1187 ]", "", "", "", "", ""
1190 /* DA__Pr: (individual property)-- */
1194 x = obj.&identifier;\
1195 if (x==0) { RT__Err(\"decrement\", obj, identifier); return; }\
1197 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,identifier,(x-->0)-1);\
1198 #ifnot; #ifdef DEBUG;\
1199 if (debug_flag & 15) RT__TrPS(obj,identifier,(x-->0)-1);\
1202 ]", "", "", "", "", ""
1205 /* RA__Pr: Read the property address of a given property value.
1206 Returns zero if it isn't provided by the object. This
1207 understands all the same concerns as RL__Pr().
1210 "obj id cla prop ix;\
1211 if (id & $FFFF0000) {\
1212 cla = #classes_table-->(id & $FFFF);\
1213 if (~~(obj ofclass cla)) return 0;\
1217 prop = CP__Tab(obj, id);\
1218 if (prop==0) return 0;\
1219 if (obj in Class && cla == 0) {\
1220 if (id < INDIV_PROP_START || id >= INDIV_PROP_START+8)\
1224 @aloadbit prop 72 ix;\
1228 ]", "", "", "", "", ""
1232 /* RL__Pr: Read the property length of a given property value.
1233 Returns zero if it isn't provided by the object. This understands
1234 inherited values (of the form class::prop) as well as simple
1235 property ids and the special metaclass methods. It also knows
1236 that private properties can only be read if (self == obj).
1239 "obj id cla prop ix;\
1240 if (id & $FFFF0000) {\
1241 cla = #classes_table-->(id & $FFFF);\
1242 if (~~(obj ofclass cla)) return 0;\
1246 prop = CP__Tab(obj, id);\
1247 if (prop==0) return 0;\
1248 if (obj in Class && cla == 0) {\
1249 if (id < INDIV_PROP_START || id >= INDIV_PROP_START+8)\
1253 @aloadbit prop 72 ix;\
1257 return WORDSIZE * ix;\
1258 ]", "", "", "", "", ""
1261 /* RA__Sc: Implement the \"superclass\" (::) operator. This
1262 returns an compound property identifier, which is a
1267 if ((cla notin Class) && (cla ~= Class or String or Routine or Object)) {\
1268 RT__Err(\"be a '::' superclass\", cla, -1);\
1271 for (j=0 : #classes_table-->j ~= 0 : j++) {\
1272 if (cla == #classes_table-->j) {\
1273 return (id * $10000 + j);\
1276 RT__Err(\"make use of\", cla, id);\
1278 ]", "", "", "", "", ""
1282 /* OP__Pr: Test whether the given object provides the given property.
1283 This winds up calling RA__Pr().
1287 zr = Z__Region(obj);\
1289 if (id == print or print_to_array) rtrue;\
1293 if (id == call) rtrue;\
1296 if (zr ~= 1) rfalse;\
1297 if (id >= INDIV_PROP_START && id < INDIV_PROP_START+8) {\
1298 if (obj in Class) rtrue;\
1303 ]", "", "", "", "", ""
1306 /* OC__Cl: Test whether the given object is of the given class.
1307 (implements the OfClass operator.)
1310 "obj cla zr jx inlist inlistlen;\
1311 zr = Z__Region(obj);\
1313 if (cla == String) rtrue;\
1317 if (cla == Routine) rtrue;\
1320 if (zr ~= 1) rfalse;\
1321 if (cla == Class) {\
1323 || obj == Class or String or Routine or Object)\
1327 if (cla == Object) {\
1329 || obj == Class or String or Routine or Object)\
1333 if (cla == String or Routine) rfalse;\
1334 if (cla notin Class) {\
1335 RT__Err(\"apply 'ofclass' for\", cla, -1);\
1339 if (inlist == 0) rfalse;\
1340 inlistlen = (obj.#2) / WORDSIZE;\
1341 for (jx=0 : jx<inlistlen : jx++) {\
1342 if (inlist-->jx == cla) rtrue;\
1345 ]", "", "", "", "", ""
1349 /* Copy__Primitive: Routine to \"deep copy\" objects.
1352 "o1 o2 p1 p2 pcount i j propid proplen val pa1 pa2;\
1353 for (i=1 : i<=NUM_ATTR_BYTES : i++) {\
1356 p2 = o2-->GOBJFIELD_PROPTAB;\
1359 for (i=0 : i<pcount : i++) {\
1360 @aloads p2 0 propid;\
1361 @aloads p2 1 proplen;\
1362 p1 = CP__Tab(o1, propid);\
1365 if (proplen == val) {\
1370 for (j=0 : j<proplen : j++)\
1376 ]", "", "", "", "", ""
1378 { /* RT__Err: for run-time errors occurring in the above: e.g.,
1379 an attempt to write to a non-existent individual
1383 "crime obj id size p q;\
1384 print \"^[** Programming error: \";\
1385 if (crime<0) jump RErr;\
1386 if (crime==1) { print \"class \"; q = obj-->GOBJFIELD_NAME; @streamstr q;\
1387 \": 'create' can have 0 to 3 parameters only **]\";}\
1388 if (crime == 40) \"tried to change printing variable \",\
1389 obj, \"; must be 0 to \", #dynam_string_table-->0-1, \" **]\";\
1390 if (crime == 32) \"objectloop broken because the object \",\
1391 (name) obj, \" was moved while the loop passed through it **]\";\
1392 if (crime == 33) \"tried to print (char) \", obj,\
1393 \", which is not a valid Glk character code for output **]\";\
1394 if (crime == 34) \"tried to print (address) on something not the \",\
1395 \"address of a dict word **]\";\
1396 if (crime == 35) \"tried to print (string) on something not a \",\
1398 if (crime == 36) \"tried to print (object) on something not an \",\
1399 \"object or class **]\";\
1400 if (crime == 37) \"tried to call Glulx print_to_array with only \",\
1401 \"one argument **]\";",
1402 "if (crime < 32) { print \"tried to \";\
1403 if (crime >= 28) { if (crime==28 or 29) print \"read from \";\
1404 else print \"write to \";\
1405 if (crime==29 or 31) print \"-\"; print \"->\", obj,\
1406 \" in the\"; switch(size&7){0,1:q=0; 2:print \" string\";\
1407 q=1; 3:print \" table\";q=1; 4:print \" buffer\";q=WORDSIZE;} \
1408 if(size&16) print\" (->)\"; if(size&8) print\" (-->)\";\
1409 \" array ~\", (string) #array_names_offset-->(p+1),\
1410 \"~, which has entries \", q, \" up to \",id,\" **]\"; }\
1411 if (crime >= 24 && crime <=27) { if (crime<=25) print \"read\";\
1412 else print \"write\"; print \" outside memory using \";\
1413 switch(crime) { 24,26:\"-> **]\"; 25,27:\"--> **]\"; } }\
1414 if (crime < 4) print \"test \"; else\
1415 if (crime < 12 || crime > 20) print \"find the \"; else\
1416 if (crime < 14) print \"use \";\
1417 if (crime==20) \"divide by zero **]\"; print \"~\";\
1419 2: print \"in~ or ~notin\"; 3: print \"has~ or ~hasnt\";\
1420 4: print \"parent\"; 5: print \"eldest\"; 6: print \"child\";\
1421 7: print \"younger\"; 8: print \"sibling\"; 9: print \"children\";\
1422 10: print \"youngest\"; 11: print \"elder\";\
1423 12: print \"objectloop\"; 13: print \"}~ at end of ~objectloop\";\
1424 14: \"give~ an attribute to \", (name) obj, \" **]\";\
1425 15: \"remove~ \", (name) obj, \" **]\";",
1426 "16,17,18: print \"move~ \", (name) obj, \" to \", (name) id;\
1427 if (crime==18) { print \", which would make a loop: \",(name) obj;\
1428 p=id; if (p==obj) p=obj;\
1429 else do { print \" in \", (name) p; p=parent(p);} until (p==obj);\
1430 \" in \", (name) p, \" **]\"; }\
1431 \" **]\"; 19: \"give~ or test ~has~ or ~hasnt~ with a non-attribute"\
1432 " on the object \",(name) obj,\" **]\";\
1433 21: print \".&\"; 22: print \".#\"; 23: print \".\"; }\
1434 \"~ of \", (name) obj, \" **]\"; }",
1435 ".RErr; if (obj==0 || obj->0>=$70 && obj->0<=$7F) {\
1436 if (obj && obj in Class) print \"class \";\
1437 if (obj) print (object) obj;else print \"nothing\";print\" \";}\
1438 print \"(object number \", obj, \") \";\
1439 if (id<0) print \"is not of class \", (name) -id;",
1441 { print \" has no property \", (property) id;\
1442 p = #identifiers_table;\
1443 size = INDIV_PROP_START + p-->3;\
1444 if (id<0 || id>=size)\
1445 print \" (and nor has any other object)\";\
1447 print \" to \", (string) crime, \" **]^\";\
1451 /* Z__Region: Determines whether a value is:
1459 if (addr<36) rfalse;\
1460 @getmemsize endmem;\
1461 @jgeu addr endmem?outrange;\
1463 if (tb >= $E0) return 3;\
1464 if (tb >= $C0) return 2;\
1465 if (tb >= $70 && tb <= $7F && addr >= (0-->2)) return 1;\
1468 ]", "", "", "", "", ""
1470 { /* Unsigned__Compare: returns 1 if x>y, 0 if x=y, -1 if x<y */
1472 "Unsigned__Compare",
1481 ]", "", "", "", "", ""
1483 { /* Meta__class: returns the metaclass of an object */
1487 switch(Z__Region(obj))\
1488 { 2: return Routine;\
1490 1: if (obj in Class\
1491 || obj == Class or String or Routine or Object)\
1496 ]", "", "", "", "", ""
1500 /* CP__Tab: Search a property table for the given identifier.
1501 The definition here is a bit different from the Z-code veneer.
1502 This just searches the property table of obj for an entry with
1503 the given identifier. It return the address of the property
1504 entry, or 0 if nothing found. (Remember that the value returned
1505 is not the address of the property *data*; it's the structure
1506 which contains the address/length/flags.)
1509 "obj id otab max res;\
1510 if (Z__Region(obj)~=1) {RT__Err(23, obj); rfalse;}\
1511 otab = obj-->GOBJFIELD_PROPTAB;\
1512 if (otab == 0) return 0;\
1515 @binarysearch id 2 otab 10 max 0 0 res;\
1517 ]", "", "", "", "", ""
1521 /* Cl__Ms: Implements the five message-receiving properties of
1525 "_vararg_count obj id a b x y;\
1528 _vararg_count = _vararg_count - 2;\
1531 if (children(obj) <= 1) rfalse;\
1534 if (x provides create) {\
1537 y = _vararg_count + 2;\
1544 if (~~(a ofclass obj)) {\
1545 RT__Err(\"recreate\", a, -obj);\
1548 if (a provides destroy)\
1550 Copy__Primitive(a, child(obj));\
1551 if (a provides create) {\
1554 y = _vararg_count + 2;\
1561 if (~~(a ofclass obj)) {\
1562 RT__Err(\"destroy\", a, -obj);\
1565 if (a provides destroy)\
1567 Copy__Primitive(a, child(obj));\
1571 return children(obj)-1;\
1575 _vararg_count = _vararg_count - 2;\
1576 if (~~(a ofclass obj)) {\
1577 RT__Err(\"copy\", a, -obj);\
1580 if (~~(b ofclass obj)) {\
1581 RT__Err(\"copy\", b, -obj);\
1584 Copy__Primitive(a, b);\
1587 ]", "", "", "", "", ""
1590 /* RT__ChT: Check at run-time that a proposed object move is legal.
1591 Cause error and do nothing if not; otherwise move
1595 if (obj1==0 || Z__Region(obj1)~=1\
1596 || (obj1 == Class or String or Routine or Object) || obj1 in Class)\
1597 return RT__Err(16, obj1, obj2);\
1598 if (obj2==0 || Z__Region(obj2)~=1\
1599 || (obj2 == Class or String or Routine or Object) || obj2 in Class)\
1600 return RT__Err(17, obj1, obj2);\
1603 if (ix==obj1) return RT__Err(18, obj1, obj2);\
1607 if (obj1 has infix__watching\
1608 || obj2 has infix__watching || (debug_flag & 15))\
1609 print \"[Moving \", (name) obj1, \" to \", (name) obj2, \"]^\";\
1610 #ifnot; #ifdef DEBUG;\
1611 if (debug_flag & 15)\
1612 print \"[Moving \", (name) obj1, \" to \", (name) obj2, \"]^\";\
1614 OB__Move(obj1, obj2);\
1615 ]", "", "", "", "", ""
1618 /* RT__ChR: Check at run-time that a proposed object remove is legal.
1619 Cause error and do nothing if not; otherwise remove
1623 if (obj1==0 || Z__Region(obj1)~=1\
1624 || (obj1 == Class or String or Routine or Object) || obj1 in Class)\
1625 return RT__Err(15, obj1);\
1627 if (obj1 has infix__watching || (debug_flag & 15))\
1628 print \"[Removing \", (name) obj1, \"]^\";\
1629 #ifnot; #ifdef DEBUG;\
1630 if (debug_flag & 15)\
1631 print \"[Removing \", (name) obj1, \"]^\";\
1634 ]", "", "", "", "", ""
1636 { /* RT__ChG: check at run-time that a proposed attr give is legal
1637 cause error and do nothing if not; otherwise give */
1641 if (Z__Region(obj1) ~= 1) return RT__Err(14,obj1);\
1642 if (obj1 in Class || obj1 == Class or String or Routine or Object)\
1643 return RT__Err(14,obj1);\
1644 if (a<0 || a>=NUM_ATTR_BYTES*8) return RT__Err(19,obj1);\
1645 if (obj1 has a) return;",
1647 if (a ~= workflag && (obj1 has infix__watching || (debug_flag & 15)))\
1648 print \"[Giving \", (name) obj1, \" \", (DebugAttribute) a, \"]^\";\
1649 #ifnot; #ifdef DEBUG;\
1650 if (a ~= workflag && debug_flag & 15)\
1651 print \"[Giving \", (name) obj1, \" \", (DebugAttribute) a, \"]^\";\
1653 give obj1 a; ]", "", "", "", ""
1655 { /* RT__ChGt: check at run-time that a proposed attr give ~ is legal
1656 cause error and do nothing if not; otherwise give */
1660 if (Z__Region(obj1) ~= 1) return RT__Err(14,obj1);\
1661 if (obj1 in Class || obj1 == Class or String or Routine or Object)\
1662 return RT__Err(14,obj1);\
1663 if (a<0 || a>=NUM_ATTR_BYTES*8) return RT__Err(19,obj1);\
1664 if (obj1 hasnt a) return;",
1666 if (a ~= workflag && (obj1 has infix__watching || (debug_flag & 15)))\
1667 print \"[Giving \",(name) obj1,\" @@126\", (DebugAttribute) a, \"]^\";\
1668 #ifnot; #ifdef DEBUG;\
1669 if (a ~= workflag && debug_flag & 15)\
1670 print \"[Giving \",(name) obj1,\" @@126\", (DebugAttribute) a, \"]^\";\
1672 give obj1 ~a; ]", "", "", "", ""
1675 /* RT__ChPS: Check at run-time that a proposed property set is legal.
1676 Cause error and do nothing if not; otherwise make it.
1680 if (obj==0 || Z__Region(obj)~=1\
1681 || (obj == Class or String or Routine or Object) || obj in Class)\
1682 return RT__Err(\"set\", obj, prop);\
1683 res = WV__Pr(obj, prop, val);\
1685 if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,prop,val);\
1686 #ifnot; #ifdef DEBUG;\
1687 if (debug_flag & 15) RT__TrPS(obj,prop,val);\
1690 ]", "", "", "", "", ""
1692 { /* RT__ChPR: check at run-time that a proposed property read is legal.
1693 cause error and return 0 if not; otherwise read it */
1696 if (obj==0 or Class or String or Routine or Object || Z_Region(obj)~=1 )\
1697 {RT__Err(\"read\", obj, prop); obj=2;}\
1698 val = RV__Pr(obj, prop);",
1699 "return val; ]", "", "", "", ""
1701 { /* RT__TrPS: trace property settings */
1705 print \"[Setting \",(name) obj,\".\",(property) prop,\
1706 \" to \",val,\"]^\"; ]",
1710 /* RT__ChLDB: Check at run-time that it's safe to load a byte
1711 and return the byte.
1714 "base offset a b val;\
1717 if (Unsigned__Compare(a, b) >= 0)\
1718 return RT__Err(24);\
1719 @aloadb base offset val;\
1721 ]", "", "", "", "", ""
1725 /* RT__ChLDW: Check at run-time that it's safe to load a word
1729 "base offset a b val;\
1730 a=base+WORDSIZE*offset;\
1732 if (Unsigned__Compare(a, b) >= 0)\
1733 return RT__Err(25);\
1734 @aload base offset val;\
1736 ]", "", "", "", "", ""
1740 /* RT__ChSTB: Check at run-time that it's safe to store a byte
1744 "base offset val a b;\
1747 if (Unsigned__Compare(a, b) >= 0) jump ChSTB_Fail;\
1749 if (Unsigned__Compare(a, b) < 0) jump ChSTB_Fail;\
1750 @astoreb base offset val;\
1753 return RT__Err(26);\
1754 ]", "", "", "", "", ""
1758 /* RT__ChSTW: Check at run-time that it's safe to store a word
1762 "base offset val a b;\
1763 a=base+WORDSIZE*offset;\
1765 if (Unsigned__Compare(a, b) >= 0) jump ChSTW_Fail;\
1767 if (Unsigned__Compare(a, b) < 0) jump ChSTW_Fail;\
1768 @astore base offset val;\
1771 return RT__Err(27);\
1772 ]", "", "", "", "", ""
1776 /* RT__ChPrintC: Check at run-time that it's safe to print (char)
1781 if (c<10 || (c>10 && c<32) || (c>126 && c<160))\
1782 return RT__Err(33,c);\
1787 ]", "", "", "", "", ""
1790 /* RT__ChPrintA: Check at run-time that it's safe to print (address)
1796 return RT__Err(34);\
1797 @getmemsize endmem;\
1798 if (Unsigned__Compare(addr, endmem) >= 0)\
1799 return RT__Err(34);\
1800 if (addr->0 ~= $60)\
1801 return RT__Err(34);\
1803 ]", "", "", "", "", ""
1806 /* Check at run-time that it's safe to print (string) and do so.
1810 if (Z__Region(str) ~= 3)\
1811 return RT__Err(35);\
1813 ]", "", "", "", "", ""
1816 /* Check at run-time that it's safe to print (object) and do so.
1820 if (Z__Region(obj) ~= 1)\
1821 return RT__Err(36);\
1822 @aload obj GOBJFIELD_NAME sp; @streamstr sp;\
1823 ]", "", "", "", "", ""
1826 /* OB__Move: Move an object within the object tree. This does no
1827 more error checking than the Z-code \"move\" opcode.
1830 "obj dest par chi sib;\
1831 par = obj-->GOBJFIELD_PARENT;\
1833 chi = par-->GOBJFIELD_CHILD;\
1835 par-->GOBJFIELD_CHILD = obj-->GOBJFIELD_SIBLING;\
1839 sib = chi-->GOBJFIELD_SIBLING;\
1844 chi-->GOBJFIELD_SIBLING = obj-->GOBJFIELD_SIBLING;\
1847 obj-->GOBJFIELD_SIBLING = dest-->GOBJFIELD_CHILD;\
1848 obj-->GOBJFIELD_PARENT = dest;\
1849 dest-->GOBJFIELD_CHILD = obj;\
1851 ]", "", "", "", "", ""
1855 /* OB__Remove: Remove an object from the tree. This does no
1856 more error checking than the Z-code \"remove\" opcode.
1860 par = obj-->GOBJFIELD_PARENT;\
1863 chi = par-->GOBJFIELD_CHILD;\
1865 par-->GOBJFIELD_CHILD = obj-->GOBJFIELD_SIBLING;\
1869 sib = chi-->GOBJFIELD_SIBLING;\
1874 chi-->GOBJFIELD_SIBLING = obj-->GOBJFIELD_SIBLING;\
1876 obj-->GOBJFIELD_SIBLING = 0;\
1877 obj-->GOBJFIELD_PARENT = 0;\
1879 ]", "", "", "", "", ""
1883 /* Print__Addr: Handle the print (address) statement. In Glulx,
1884 this behaves differently than on the Z-machine; it can *only*
1885 print dictionary words.
1889 if (addr->0 ~= $60) {\
1890 print \"(\", addr, \": not dict word)\";\
1893 for (ix=1 : ix <= DICT_WORD_SIZE : ix++) {\
1894 #ifndef DICT_IS_UNICODE;\
1899 if (ch == 0) return;\
1902 ]", "", "", "", "", ""
1906 /* Glk__Wrap: This is a wrapper for the @glk opcode. It just passes
1907 all its arguments into the Glk dispatcher, and returns the Glk
1911 "_vararg_count callid retval;\
1913 _vararg_count = _vararg_count - 1;\
1914 @glk callid _vararg_count retval;\
1916 ]", "", "", "", "", ""
1920 /* Dynam__String: Set dynamic string (printing variable) num to the
1921 given val, which can be any string or function.
1925 if (num < 0 || num >= #dynam_string_table-->0)\
1926 return RT__Err(40, num);\
1927 (#dynam_string_table)-->(num+1) = val;\
1928 ]", "", "", "", "", ""
1934 static void mark_as_needed_z(int code
)
1937 if (veneer_routine_needs_compilation
[code
] == VR_UNUSED
)
1938 { veneer_routine_needs_compilation
[code
] = VR_CALLED
;
1939 /* Here each routine must mark every veneer routine it explicitly
1943 mark_as_needed_z(RT__TrPS_VR
);
1944 mark_as_needed_z(RT__Err_VR
);
1947 mark_as_needed_z(RT__Err_VR
);
1950 mark_as_needed_z(Z__Region_VR
);
1951 mark_as_needed_z(Cl__Ms_VR
);
1952 mark_as_needed_z(RT__Err_VR
);
1958 mark_as_needed_z(RT__Err_VR
);
1959 mark_as_needed_z(RT__TrPS_VR
);
1962 mark_as_needed_z(CP__Tab_VR
);
1965 mark_as_needed_z(RT__Err_VR
);
1968 mark_as_needed_z(Z__Region_VR
);
1971 mark_as_needed_z(Z__Region_VR
);
1972 mark_as_needed_z(RT__Err_VR
);
1975 mark_as_needed_z(Unsigned__Compare_VR
);
1978 mark_as_needed_z(Z__Region_VR
);
1981 mark_as_needed_z(RT__Err_VR
);
1982 mark_as_needed_z(Copy__Primitive_VR
);
1989 mark_as_needed_z(RT__Err_VR
);
1992 mark_as_needed_z(RT__Err_VR
);
1993 mark_as_needed_z(RT__TrPS_VR
);
1999 mark_as_needed_z(Unsigned__Compare_VR
);
2000 mark_as_needed_z(RT__Err_VR
);
2002 case RT__ChPrintC_VR
:
2003 mark_as_needed_z(RT__Err_VR
);
2005 case RT__ChPrintA_VR
:
2006 mark_as_needed_z(Unsigned__Compare_VR
);
2007 mark_as_needed_z(RT__Err_VR
);
2009 case RT__ChPrintS_VR
:
2010 case RT__ChPrintO_VR
:
2011 mark_as_needed_z(RT__Err_VR
);
2012 mark_as_needed_z(Z__Region_VR
);
2018 static void mark_as_needed_g(int code
)
2021 if (veneer_routine_needs_compilation
[code
] == VR_UNUSED
)
2022 { veneer_routine_needs_compilation
[code
] = VR_CALLED
;
2023 /* Here each routine must mark every veneer routine it explicitly
2027 case PrintShortName_VR
:
2028 mark_as_needed_g(Metaclass_VR
);
2030 case Print__Pname_VR
:
2031 mark_as_needed_g(PrintShortName_VR
);
2034 mark_as_needed_g(RA__Pr_VR
);
2035 mark_as_needed_g(RT__TrPS_VR
);
2036 mark_as_needed_g(RT__Err_VR
);
2039 mark_as_needed_g(RA__Pr_VR
);
2040 mark_as_needed_g(RT__Err_VR
);
2043 mark_as_needed_g(RA__Pr_VR
);
2044 mark_as_needed_g(RL__Pr_VR
);
2045 mark_as_needed_g(PrintShortName_VR
);
2046 mark_as_needed_g(Print__Pname_VR
);
2047 mark_as_needed_g(Z__Region_VR
);
2048 mark_as_needed_g(Cl__Ms_VR
);
2049 mark_as_needed_g(Glk__Wrap_VR
);
2050 mark_as_needed_g(RT__Err_VR
);
2056 mark_as_needed_g(RT__Err_VR
);
2057 mark_as_needed_g(RT__TrPS_VR
);
2060 mark_as_needed_g(OC__Cl_VR
);
2061 mark_as_needed_g(CP__Tab_VR
);
2064 mark_as_needed_g(OC__Cl_VR
);
2065 mark_as_needed_g(CP__Tab_VR
);
2068 mark_as_needed_g(OC__Cl_VR
);
2069 mark_as_needed_g(RT__Err_VR
);
2072 mark_as_needed_g(RA__Pr_VR
);
2073 mark_as_needed_g(Z__Region_VR
);
2076 mark_as_needed_g(RA__Pr_VR
);
2077 mark_as_needed_g(RL__Pr_VR
);
2078 mark_as_needed_g(Z__Region_VR
);
2079 mark_as_needed_g(RT__Err_VR
);
2081 case Copy__Primitive_VR
:
2082 mark_as_needed_g(CP__Tab_VR
);
2085 mark_as_needed_g(Unsigned__Compare_VR
);
2089 mark_as_needed_g(Z__Region_VR
);
2092 mark_as_needed_g(OC__Cl_VR
);
2093 mark_as_needed_g(OP__Pr_VR
);
2094 mark_as_needed_g(RT__Err_VR
);
2095 mark_as_needed_g(Copy__Primitive_VR
);
2096 mark_as_needed_g(OB__Remove_VR
);
2097 mark_as_needed_g(OB__Move_VR
);
2101 mark_as_needed_g(RT__Err_VR
);
2104 mark_as_needed_g(RT__Err_VR
);
2105 mark_as_needed_g(Z__Region_VR
);
2106 mark_as_needed_g(OB__Remove_VR
);
2109 mark_as_needed_g(RT__Err_VR
);
2110 mark_as_needed_g(Z__Region_VR
);
2111 mark_as_needed_g(OB__Move_VR
);
2114 mark_as_needed_g(RT__Err_VR
);
2115 mark_as_needed_g(RT__TrPS_VR
);
2116 mark_as_needed_g(WV__Pr_VR
);
2119 mark_as_needed_g(RT__Err_VR
);
2120 mark_as_needed_g(RV__Pr_VR
); return;
2125 mark_as_needed_g(Unsigned__Compare_VR
);
2126 mark_as_needed_g(RT__Err_VR
);
2128 case RT__ChPrintC_VR
:
2129 mark_as_needed_g(RT__Err_VR
);
2131 case RT__ChPrintA_VR
:
2132 mark_as_needed_g(Unsigned__Compare_VR
);
2133 mark_as_needed_g(RT__Err_VR
);
2134 mark_as_needed_g(Print__Addr_VR
);
2136 case RT__ChPrintS_VR
:
2137 case RT__ChPrintO_VR
:
2138 mark_as_needed_g(RT__Err_VR
);
2139 mark_as_needed_g(Z__Region_VR
);
2141 case Print__Addr_VR
:
2142 mark_as_needed_g(RT__Err_VR
);
2144 case Dynam__String_VR
:
2145 mark_as_needed_g(RT__Err_VR
);
2151 extern assembly_operand
veneer_routine(int code
)
2152 { assembly_operand AO
;
2154 AO
.type
= LONG_CONSTANT_OT
;
2155 AO
.marker
= VROUTINE_MV
;
2157 mark_as_needed_z(code
);
2160 AO
.type
= CONSTANT_OT
;
2161 AO
.marker
= VROUTINE_MV
;
2163 mark_as_needed_g(code
);
2168 static void compile_symbol_table_routine(void)
2169 { int32 j
, nl
, arrays_l
, routines_l
, constants_l
;
2170 assembly_operand AO
, AO2
, AO3
;
2172 /* Assign local var names for the benefit of the debugging information
2174 local_variable_texts
[0] = "dummy1";
2175 local_variable_texts
[1] = "dummy2";
2177 veneer_mode
= TRUE
; j
= symbol_index("Symb__Tab", -1);
2179 assemble_routine_header(2, FALSE
, "Symb__Tab", FALSE
, j
),
2181 sflags
[j
] |= SYSTEM_SFLAG
+ USED_SFLAG
;
2182 if (trace_fns_setting
==3) sflags
[j
] |= STAR_SFLAG
;
2186 if (define_INFIX_switch
== FALSE
)
2187 { assemblez_0(rfalse_zc
);
2188 variable_usage
[1] = TRUE
;
2189 variable_usage
[2] = TRUE
;
2190 assemble_routine_end(FALSE
, null_debug_locations
);
2191 veneer_mode
= FALSE
;
2195 AO
.value
= 1; AO
.type
= VARIABLE_OT
; AO
.marker
= 0;
2196 AO2
.type
= SHORT_CONSTANT_OT
; AO2
.marker
= 0;
2197 AO3
.type
= LONG_CONSTANT_OT
; AO3
.marker
= 0;
2199 arrays_l
= next_label
++;
2200 routines_l
= next_label
++;
2201 constants_l
= next_label
++;
2203 sequence_point_follows
= FALSE
;
2205 assemblez_2_branch(je_zc
, AO
, AO2
, arrays_l
, TRUE
);
2206 sequence_point_follows
= FALSE
;
2208 assemblez_2_branch(je_zc
, AO
, AO2
, routines_l
, TRUE
);
2209 sequence_point_follows
= FALSE
;
2211 assemblez_2_branch(je_zc
, AO
, AO2
, constants_l
, TRUE
);
2212 sequence_point_follows
= FALSE
;
2213 assemblez_0(rtrue_zc
);
2215 assemble_label_no(arrays_l
);
2217 for (j
=0; j
<no_arrays
; j
++)
2219 if (AO2
.value
<256) AO2
.type
= SHORT_CONSTANT_OT
;
2220 else AO2
.type
= LONG_CONSTANT_OT
;
2222 sequence_point_follows
= FALSE
;
2223 assemblez_2_branch(je_zc
, AO
, AO2
, nl
, FALSE
);
2224 AO3
.value
= array_sizes
[j
];
2226 assemblez_store(temp_var2
, AO3
);
2227 AO3
.value
= array_types
[j
];
2228 if (sflags
[array_symbols
[j
]] & (INSF_SFLAG
+SYSTEM_SFLAG
))
2229 AO3
.value
= AO3
.value
+ 16;
2231 assemblez_store(temp_var3
, AO3
);
2232 AO3
.value
= svals
[array_symbols
[j
]];
2233 AO3
.marker
= ARRAY_MV
;
2234 assemblez_1(ret_zc
, AO3
);
2235 assemble_label_no(nl
);
2238 sequence_point_follows
= FALSE
;
2239 assemblez_0(rtrue_zc
);
2240 assemble_label_no(routines_l
);
2241 for (j
=0; j
<no_named_routines
; j
++)
2243 if (AO2
.value
<256) AO2
.type
= SHORT_CONSTANT_OT
;
2244 else AO2
.type
= LONG_CONSTANT_OT
;
2246 sequence_point_follows
= FALSE
;
2247 assemblez_2_branch(je_zc
, AO
, AO2
, nl
, FALSE
);
2249 if (sflags
[named_routine_symbols
[j
]]
2250 & (INSF_SFLAG
+SYSTEM_SFLAG
)) AO3
.value
= 16;
2252 assemblez_store(temp_var3
, AO3
);
2253 AO3
.value
= svals
[named_routine_symbols
[j
]];
2254 AO3
.marker
= IROUTINE_MV
;
2255 assemblez_1(ret_zc
, AO3
);
2256 assemble_label_no(nl
);
2258 sequence_point_follows
= FALSE
;
2259 assemblez_0(rtrue_zc
);
2261 assemble_label_no(constants_l
);
2262 for (j
=0, no_named_constants
=0; j
<no_symbols
; j
++)
2263 { if (((stypes
[j
] == OBJECT_T
) || (stypes
[j
] == CLASS_T
)
2264 || (stypes
[j
] == CONSTANT_T
))
2265 && ((sflags
[j
] & (UNKNOWN_SFLAG
+ACTION_SFLAG
))==0))
2266 { AO2
.value
= no_named_constants
++;
2267 if (AO2
.value
<256) AO2
.type
= SHORT_CONSTANT_OT
;
2268 else AO2
.type
= LONG_CONSTANT_OT
;
2270 sequence_point_follows
= FALSE
;
2271 assemblez_2_branch(je_zc
, AO
, AO2
, nl
, FALSE
);
2273 if (stypes
[j
] == OBJECT_T
) AO3
.value
= 2;
2274 if (stypes
[j
] == CLASS_T
) AO3
.value
= 1;
2275 if (sflags
[j
] & (INSF_SFLAG
+SYSTEM_SFLAG
))
2276 AO3
.value
= AO3
.value
+ 16;
2278 assemblez_store(temp_var3
, AO3
);
2280 AO3
.marker
= SYMBOL_MV
;
2281 assemblez_1(ret_zc
, AO3
);
2282 assemble_label_no(nl
);
2285 no_named_constants
= 0; AO3
.marker
= 0;
2287 sequence_point_follows
= FALSE
;
2288 assemblez_0(rfalse_zc
);
2289 variable_usage
[1] = TRUE
;
2290 variable_usage
[2] = TRUE
;
2291 assemble_routine_end(FALSE
, null_debug_locations
);
2292 veneer_mode
= FALSE
;
2296 if (define_INFIX_switch
== FALSE
)
2297 { assembleg_1(return_gc
, zero_operand
);
2298 variable_usage
[1] = TRUE
;
2299 variable_usage
[2] = TRUE
;
2300 assemble_routine_end(FALSE
, null_debug_locations
);
2301 veneer_mode
= FALSE
;
2305 error("*** Infix symbol-table routine is not yet implemented. ***");
2309 extern void compile_veneer(void)
2310 { int i
, j
, try_veneer_again
;
2313 if (module_switch
) return;
2315 VRs
= (!glulx_mode
) ? VRs_z
: VRs_g
;
2317 /* Called at the end of the pass to insert as much of the veneer as is
2318 needed and not elsewhere compiled. */
2320 veneer_symbols_base
= no_symbols
;
2322 /* for (i=0; i<VENEER_ROUTINES; i++)
2323 printf("%s %d %d %d %d %d %d\n", VRs[i].name,
2324 strlen(VRs[i].source1), strlen(VRs[i].source2),
2325 strlen(VRs[i].source3), strlen(VRs[i].source4),
2326 strlen(VRs[i].source5), strlen(VRs[i].source6)); */
2328 try_veneer_again
= TRUE
;
2329 while (try_veneer_again
)
2330 { try_veneer_again
= FALSE
;
2331 for (i
=0; i
<VENEER_ROUTINES
; i
++)
2332 { if (veneer_routine_needs_compilation
[i
] == VR_CALLED
)
2333 { j
= symbol_index(VRs
[i
].name
, -1);
2334 if (sflags
[j
] & UNKNOWN_SFLAG
)
2335 { veneer_mode
= TRUE
;
2336 strcpy(veneer_source_area
, VRs
[i
].source1
);
2337 strcat(veneer_source_area
, VRs
[i
].source2
);
2338 strcat(veneer_source_area
, VRs
[i
].source3
);
2339 strcat(veneer_source_area
, VRs
[i
].source4
);
2340 strcat(veneer_source_area
, VRs
[i
].source5
);
2341 strcat(veneer_source_area
, VRs
[i
].source6
);
2343 parse_routine(veneer_source_area
, FALSE
,
2344 VRs
[i
].name
, TRUE
, j
),
2346 veneer_mode
= FALSE
;
2347 if (trace_fns_setting
==3) sflags
[j
] |= STAR_SFLAG
;
2350 { if (stypes
[j
] != ROUTINE_T
)
2351 error_named("The following name is reserved by Inform for its \
2352 own use as a routine name; you can use it as a routine name yourself (to \
2353 override the standard definition) but cannot use it for anything else:",
2356 sflags
[j
] |= USED_SFLAG
;
2358 veneer_routine_address
[i
] = svals
[j
];
2359 veneer_routine_needs_compilation
[i
] = VR_COMPILED
;
2360 try_veneer_again
= TRUE
;
2365 compile_symbol_table_routine();
2368 /* ========================================================================= */
2369 /* Data structure management routines */
2370 /* ------------------------------------------------------------------------- */
2372 extern void init_veneer_vars(void)
2376 extern void veneer_begin_pass(void)
2378 veneer_mode
= FALSE
;
2379 for (i
=0; i
<VENEER_ROUTINES
; i
++)
2380 { veneer_routine_needs_compilation
[i
] = VR_UNUSED
;
2381 veneer_routine_address
[i
] = 0;
2385 extern void veneer_allocate_arrays(void)
2386 { veneer_source_area
= my_malloc(16384, "veneer source code area");
2389 extern void veneer_free_arrays(void)
2390 { my_free(&veneer_source_area
, "veneer source code area");
2393 /* ========================================================================= */