Added package with the documentation and the examples
[lwc.git] / vtbl.ch
blobe9f183f34dd5a4f524210e736090f5b256ff5c8b
1 //*******************************************
2 //      THIS FILE IS INCLUDED BY HIER.C
3 //*******************************************
5 /******************************************************************************
7         virtual table stuff.
8         virtual inheritance is what complicates things a lot
10 ******************************************************************************/
12 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
13 // virtual table structs
14 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
16 typedef struct vt_entry_t {
17         struct vt_entry_t *next;
18         Token *prototype, *xproto, *xargs;
19         Token entry_name;
20         typeID type;
21         bool isfunction, isconst;
22         Token fname;
23         typeID *arglist;
24         recID introduced_at;
25         Token *zpath;
26         int flagz;
27 } vt_entry;
29 typedef struct {
30         initID initTbl;
31         recID object;
32 } vt_init_entry;
34 typedef struct virtual_table {
35         recID appeared_at;
36         vt_entry *first_entry;
37         Token vtname;
38         bool inlined, constd, volatiled;
39         intnode *vu_tree;
40         vt_init_entry *vti;
41         int nvti, nvtalloc;
42         bool typeid;
43 } virtual_table;
45 // vti_entry.status
46 enum { VTI_STATUS_NI, VTI_STATUS_ND, VTI_STATUS_DD, VTI_STATUS_NU, VTI_STATUS_FINAL };
48 typedef struct vti_entry_t {
49         struct vti_entry_t *next;
50         vt_entry *vt_ent;
51         /* code, value: explained
52           - a virtual function has value and optionaly code.
53              the code is the virtuallity function definition.
54           - a virtual variable has no value and only code --> the init expression
55           - likewise for downcast data --> only code and no value   */
56         Token value;
57         Token *code;
58         int status;
59         bool cast_avoid_downcast;
60 } vti_entry;
62 typedef struct vt_initializer_t {
63         Token instance_name;
64         vtblID v_t_i;
65         bool open, unused;
66         bool exportdef;
67         recID rec;
69         vti_entry *first_entry;
70 } vt_initializer;
72 static virtual_table *VirtualTable;
73 static int nVTBL, nVTBLalloc;
75 static vt_initializer *VirtualInitializer;
76 static int nVTI, nVTIalloc;
78 #ifdef DEBUG
79 static void show_vt (recID r)
81         if (!structs [r].vtis)
82                 return;
83         PRINTF ("\n+++Virtual tables of ["COLS"%s"COLE"]:\n", expand (name_of_struct (r)));
84         int i;
85         for (i = 0; structs [r].vtis [i] != -1; i++) {
86                 PRINTF ("  --- Vtable %i:\n", i);
87                 vti_entry *v = VirtualInitializer [structs [r].vtis [i]].first_entry;
88                 for (;v;v = v->next) {
89                         PRINTF ("    + Entry ["COLS"%s"COLE"] value ["COLS"%s"COLE"] ["COLS"%i"COLE"\n",
90                                 expand (v->vt_ent->entry_name), v->value ? expand (v->value) : "-no value-",
91                                 v->status);
92                         if (!v->value) {
93                                 PRINTF ("      + "COLS"+ + >"COLE" constant expression ["COLS);
94                                 if (v->code) INTPRINT (v->code);
95                                 else PRINTF ("- no code -");
96                                 PRINTF (COLE"]\n");     
97                         }
98                 }
99         }
101 #endif
103 static vtblID new_virtual_table ()
105         if (nVTBL == nVTBLalloc)
106                 VirtualTable = (virtual_table*) realloc (VirtualTable,
107                          (nVTBLalloc += 50) * sizeof (virtual_table));
108         VirtualTable [nVTBL].first_entry = 0;
109         VirtualTable [nVTBL].vu_tree = 0;
110         VirtualTable [nVTBL].typeid = false;
111         VirtualTable [nVTBL].inlined = InlineAllVt;
112         VirtualTable [nVTBL].constd = ConstVtables;
113         VirtualTable [nVTBL].volatiled = !vtptrConst;
114         VirtualTable [nVTBL].nvti = VirtualTable [nVTBL].nvtalloc = 0;
115         VirtualTable [nVTBL].vti = 0;
116         return nVTBL++;
119 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
120 // unionify the virtual table so order
121 // of declaration not important.
122 // foreach new entry of the v-table,
123 // we store the hierarchy path in a
124 // way that can be expanded with unions
125 // afterwards in the generation of the
126 // v-table declaration.
127 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
129 #define PARMUL 10000
131 static void add_parent_child (vtblID vt, recID par, recID child)
133         int mval = par * PARMUL + child;
134         if (intfind (VirtualTable [vt].vu_tree, mval))
135                 return;
136         union ival i;
137         intadd (&VirtualTable [vt].vu_tree, mval, i);
140 /* Make Unionified path of virtual table entry */
141 static Token *vt_path (Token entn, recID root, recID node)
143         Token zpath [128];
144         int zpi, i=i;
145         ancestor *a;
146         recID r=r;
148         zpath [127] = -1;
149         zpath [zpi = 126] = entn;
151         while (node != root) {
152                 for (a = structs [node].ancestors; a->rec != -1; a++)
153                         if (a->path [1] == -1 && structs [r = a->rec].vtis)
154                                 for (i = 0; structs [r].vtis [i] != -1; i++)
155                                         if (VirtualTable [VirtualInitializer
156                                                  [structs [r].vtis [i]].v_t_i].appeared_at == root)
157                                                 goto dbreak;
158         dbreak:
159                 zpi -= 4;
160                 sintprintf (zpath + zpi, name_derrive_union, '.', name_derrive_memb (node), '.', NONULL);
161                 add_parent_child (VirtualInitializer [structs [r].vtis [i]].v_t_i, r, node);
162                 node = r;
163         }
165         return intdup (&zpath [zpi]);
168 static vt_entry *add_vt_entry (vtblID v, vt_entry *e)
170         vt_entry *ep = VirtualTable [v].first_entry;
172         /* make unionified path to vt entry */
173         e->zpath = vt_path (e->entry_name, VirtualTable [v].appeared_at, e->introduced_at);
175         if (!ep) VirtualTable [v].first_entry = e;
176         else {
177                 while (ep->next) ep = ep->next;
178                 ep->next = e;
179         }
180         return e;
183 static struct {
184         int n;
185         recID *vchild;
186 } get_child_r;
188 static void get_children_r (intnode *n, recID par)
190         int i = n->key;
191         if (i / PARMUL == par)
192                 get_child_r.vchild [get_child_r.n++] = i % PARMUL;
193         if (n->less) get_children_r (n->less, par);
194         if (n->more) get_children_r (n->more, par);
197 static void get_children (vtblID vt, recID par)
199         if (VirtualTable [vt].vu_tree)
200                 get_children_r (VirtualTable [vt].vu_tree, par);
203 static void declare_vtable_for (vtblID vt, recID r)
205         int n = 0, i, j;
206         vt_entry *ve;
207         vt_entry *ve_r [128];
208         recID children [32];
210         for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
211                 if (ve->introduced_at == r)
212                         ve_r [n++] = ve;
214         // bubble sort entries alphabetically
215         for (i = 0; i < n; i++)
216                 for (j = i + 1; j < n; j++)
217                         if (strcmp (expand (ve_r [i]->entry_name), expand (ve_r [j]->entry_name)) > 0)
218                                 ve = ve_r [i], ve_r [i] = ve_r [j], ve_r [j] = ve;
220         for (i = 0; i < n; i++)
221                 outprintf (STRUCTS, ISTR (ve_r [i]->prototype), ';', -1);
223         // now if derrived classes also use this virtual table
224         // for new entries, do the unionification thing
225         get_child_r.n = 0;
226         get_child_r.vchild = children;
227         get_children (vt, r);
228         if (!(n = get_child_r.n)) return;
230         outprintf (STRUCTS, RESERVED_union, '{', -1);
231         for (i = 0; i < n; i++) {
232                 outprintf (STRUCTS, RESERVED_struct, '{', -1);
233                 declare_vtable_for (vt, children [i]);
234                 outprintf (STRUCTS, '}', name_derrive_memb (children [i]), ';', -1);
235         }
236         outprintf (STRUCTS, '}', name_derrive_union, ';', -1);
239 static void declare_vtable (vtblID i)
241         outprintf (STRUCTS, RESERVED_struct,
242                    VirtualTable [i].vtname, '{', -1);
243         declare_vtable_for (i, VirtualTable [i].appeared_at);
244         outprintf (STRUCTS, '}', ';', -1);
247 static void export_virtual_table_declaration (recID r)
249         vtblID i;
251         if (structs [r].vtis) for (i = 0; i < nVTBL; i++)
252                 if (VirtualTable [i].appeared_at == r)
253                         declare_vtable (i);
256 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
257 // some more allocator/initializers
258 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
260 static initID new_v_t_initializer (recID obj)
262         if (nVTI == nVTIalloc)
263                 VirtualInitializer = (vt_initializer*) realloc (VirtualInitializer,
264                          (nVTIalloc += 50) * sizeof (vt_initializer));
266         VirtualInitializer [nVTI].first_entry = 0;
267         VirtualInitializer [nVTI].open = true;
268         VirtualInitializer [nVTI].unused = false;
269 //      VirtualInitializer [nVTI].exportdef = structs [obj].statik;
270         VirtualInitializer [nVTI].exportdef = false;
271         VirtualInitializer [nVTI].rec = obj;
273         return nVTI++;
276 static void add_initializer (vtblID vt, initID vi, recID obj)
278         virtual_table *vp = &VirtualTable [vt];
280         if (vp->nvti == vp->nvtalloc)
281                 vp->vti = (vt_init_entry*) realloc (vp->vti,
282                         (vp->nvtalloc += 20) * sizeof (vt_init_entry));
284         vp->vti [vp->nvti].initTbl = vi;
285         vp->vti [vp->nvti++].object = obj;
288 static void add_vti_entry (initID it, vti_entry *e)
290 #ifdef  DEBUG
291         if (debugflag.VIRTUALTABLES)
292                 PRINTF ("++Adding entry "COLS"%s"COLE" to initializer %i\n", expand (e->vt_ent->entry_name), it);
293 #endif
294         vti_entry *ep = VirtualInitializer [it].first_entry;
295         if (!ep)
296                 VirtualInitializer [it].first_entry = e;
297         else {
298                 while (ep->next) ep = ep->next;
299                 ep->next = e;
300         }
303 //---------------------------------------
304 // build the path to the virtual table
305 //---------------------------------------
307 static Token *pathto_vt (Token path [], initID i, bool const_path)
309         recID rd, ra;
311         rd = aliasclass (VirtualInitializer [i].rec);
312         ra = aliasclass (VirtualTable [VirtualInitializer [i].v_t_i].appeared_at);
314         if (rd == ra)
315                 sintprintf (path, RESERVED__v_p_t_r_, -1);
316         else {
317                 Token *p;
319                 bool v = is_ancestor (rd, ra, &p, const_path) == 2;
320                 sintprintf (path, ISTR (p), v ? POINTSAT : '.', RESERVED__v_p_t_r_, -1);
321         }
323         return path;
326 /* this is a path that helps us decide whether there is virtual base vti */
327 static Token *pathto_vt_virt (Token path[], initID i)
329         recID rd = VirtualInitializer [i].rec;
330         recID ra = VirtualTable [VirtualInitializer [i].v_t_i].appeared_at;
331         ancestor *a;
333         pathto_vt (path, i, false);
334         if ((a = structs [rd].ancestors) && ra != rd) {
335                 while (a->rec != ra) ++a;
336                 if (a->status == ASTATUS_VIRT2)
337                         path [intlen (path) - 2] = POINTSAT;
338         }
340         return path;
342 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 // best virtual table to add a new entry is the most
344 // recently created
345 // virtual tables reached through virtual inheritance
346 // dont count because we cannot ensure that the order of
347 // declarations will not matter.
348 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 static initID best_vti (recID r)
352         int i, j, rc = 1000;
353         initID ii, ir = -1;
354         Token pathto [128];
356         if (!structs [r].vtis)
357                 return -1;
359         for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
360                 pathto_vt_virt (pathto, ii);
361                 for (j = 0; pathto [j] != POINTSAT; j++)
362                         if (pathto [j] == -1) {
363                                 if (j < rc) {
364                                         rc = j;
365                                         ir = structs [r].vtis [i];
366                                 }
367                                 break;
368                         }
369         }
370         return ir;
373 static bool has_vtable (recID r)
375         if (!structs [r].vtis)
376                 return false;
377         int i, j;
378         initID ii;
379         Token pathto [128];
381         for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
382                 pathto_vt_virt (pathto, ii);
383                 for (j = 0; pathto [j] != POINTSAT; j++)
384                         if (pathto [j] == -1)
385                                 return true;
386         }
387         return false;
390 static inline bool vt_only (recID r)
392         return structs [r].firstmember || structs [r].ancestors || !has_vtable (r)
393                 || VirtualTable [VirtualInitializer [structs [r].vtis [0]].v_t_i].inlined;
395 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
396 // Inheritance of virtual tables
397 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
399 /* class <obj> inherits virtual initializer <iid> maybe by virtual inheritance */
400 static initID inherit_virtual_tbl (recID obj, initID iid)
402 #ifdef  DEBUG
403         if (debugflag.VIRTUALTABLES)
404                 PRINTF ("++Inherit virtual initializer %i in object %i(%s)\n", iid, obj, SNM(obj));
405 #endif
406         vtblID vt = VirtualInitializer [iid].v_t_i;
407         bool unused = VirtualInitializer [iid].unused;
409         initID ii = new_v_t_initializer (obj);
410         add_initializer (vt, ii, obj);
411         /* New initializer inherits values from parent */
412         vti_entry *vp, *vc;
413         for (vp = VirtualInitializer [iid].first_entry; vp; vp = vp->next) {
414                 vc = (vti_entry*) malloc (sizeof * vc);
415                 vc->next = 0;
416                 vc->vt_ent = vp->vt_ent;
417                 vc->value = vp->value;
418                 vc->code = vp->value && !unused ? 0 : vp->code;
419                 vc->status = (vp->status == VTI_STATUS_DD) ? VTI_STATUS_ND : vp->status;
420                 vc->cast_avoid_downcast = vp->cast_avoid_downcast;
421                 add_vti_entry (ii, vc);
422         }
423         /* once of these */
424         VirtualInitializer [ii].v_t_i = vt;
425         VirtualInitializer [ii].instance_name =
426                  name_instance (VirtualTable [vt].appeared_at, obj);
427         return ii;
430 static void collapse_virtuals (recID);
432 /* Inherit virtual table initializers from parents
433    Must be called after parents are set */
434 static void inherit_all_virtuales (recID obj)
436         int j, ti = 0;
437         recID p;
438         initID tmp [64];
439         ancestor *a = structs [obj].ancestors;
441         if (a) for (;(p = a->rec) != -1; a++)
442                 if (direct_ancest (a) && structs [p].vtis)
443                         for (j = 0; structs [p].vtis [j] != -1; j++)
444                                 tmp [ti++] = inherit_virtual_tbl (obj, structs [p].vtis [j]);
446         if (ti) {
447                 tmp [ti] = -1;
448                 structs [obj].vtis = intdup (tmp);
449                 collapse_virtuals (obj);
450         } else structs [obj].vtis = 0;
453 /* two initializers of the same virtual table
454    are actually initializing the same thing
455    because of virtual inheritance, or not ? */
456 static bool are_the_same (initID i1, initID i2)
458         int i, j;
459         Token p1 [128], p2 [128];
460         pathto_vt_virt (p1, i1), pathto_vt_virt (p2, i2);
462         for (i = 0; p1 [i] != -1; i++)
463                 if (p1 [i] == POINTSAT)
464                         for (j = 0; p2 [j] != -1; j++)
465                                 if (p2 [j] == p1 [i-1] && p2 [j + 1] == POINTSAT)
466                                         goto double_break;
467         return false; /* not */
468 double_break:;
469         vti_entry *v1 = VirtualInitializer [i1].first_entry;
470         vti_entry *v2 = VirtualInitializer [i2].first_entry;
472         /* do the combination of virtual tables.
473          * in the case of functions, there must be a unique final overrider.
474          * for virtual variables, currently, no, but the value wins
475          * for downcast offsets, always pick the v1 if both have.
476          *   the latter is probably impossible unless double virtual inh?
477          * 'final' wins non-final.
478          */
479         while (v1) {
480                 if (v1->status == VTI_STATUS_NI) {
481                         if (v2->status != VTI_STATUS_NI) copy: {
482                                 v1->value = v2->value;
483                                 v1->code = v2->code;
484                                 v1->status = v2->status;
485                         }
486                 } else if (v2->status != VTI_STATUS_NI) {
487                         if (v1->value == RESERVED_0) {
488                                 if (v2->value != RESERVED_0) {
489                                         v1->value = v2->value;
490                                         v1->code = v2->code;
491                                 }
492                         } else if (v1->value == 0) {
493                                 if (v1->code == 0 && v2->code != 0)
494                                         v1->code = v2->code;
495                         } else if (v2->value != RESERVED_0
496                                 && v2->value != v1->value) {
497                                         if (v2->status == VTI_STATUS_FINAL) {
498                                                 if (v2->status != v1->status)
499                                                         goto copy;
500                                                 else parse_error_ll ("final functions");
501                                         } else if (v1->status != VTI_STATUS_FINAL)
502                                                 v1->status = VTI_STATUS_NU;
503                         }
504                 }
505                 v1 = v1->next;
506                 v2 = v2->next;
507         }
508         VirtualInitializer [i2].unused = true;
509         return true;
513 /* collapse initializers of virtual base classes to a common one */
514 /* this is the whole point of virtual inheritance */
515 static void collapse_virtuals (recID r)
517         int en = 0;
518         int i, j;
519         initID *pa = structs [r].vtis;
521         for (i = 1; pa [i] != -1; i++) {
522                 vtblID vt = VirtualInitializer [pa [i]].v_t_i;
523                 Token in = VirtualInitializer [pa [i]].instance_name;
525                 for (j = 0; j < i; j++) {
526                         if (VirtualInitializer [pa [j]].instance_name == in)
527                                 VirtualInitializer [pa [i]].instance_name =
528                                         name_name_enumerate (in, en++);
529                         if (VirtualInitializer [pa [j]].v_t_i == vt)
530                                 if (are_the_same (pa [j], pa [i])) {
531                                         // disappear pa [i]
532                                         for (j = i; pa [j] != -1; j++)
533                                                 pa [j] = pa [j + 1];
534                                         i--;
535                                         break;
536                                 }
537                 }
538         }
540 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
541 // Virtual Functions
542 //  declarations of them...
543 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
545 static int lookup_virtual_f_ininit (initID i, Token n, typeID *va, Token **entn)
547         vtblID vi = VirtualInitializer [i].v_t_i;
548         vt_entry *ve;
550 #ifdef  DEBUG
551         if (debugflag.VIRTUALTABLES)
552                 PRINTF (" ++in virtual table %i, initializer %i\n", vi, i);
553 #endif
554         for (ve = VirtualTable [vi].first_entry; ve; ve = ve->next)
555                 if (ve->isfunction && ve->fname == n && arglist_compare (va, ve->arglist)) {
556                         vti_entry *vie;
557                         *entn = ve->zpath;
558                         for (vie = VirtualInitializer [i].first_entry; vie; vie = vie->next)
559                                 if (vie->vt_ent->entry_name == ve->entry_name)
560                                         if (vie->status == VTI_STATUS_NI) break;
561                                         else return vie->status; else;
562                 }
563         return VTI_STATUS_NI;
566 typedef struct {
567         int status;
568         initID iid;
569         Token *entn;
570 } vlookup;
572 static void lookup_virtual_f (recID r, Token n, typeID t, vlookup *v)
574 #ifdef  DEBUG
575         if (debugflag.VIRTUALTABLES)
576                 PRINTF ("++Looking for %s...\n", expand (n));
577 #endif
578         typeID *va = promoted_arglist_t (t);
579         int i = 0, ret;
580         Token *ent_ret;
582         v->status = VTI_STATUS_NI;
584         if (v->iid != -1)
585                 while (structs [r].vtis [i] != -1)
586                         if (structs [r].vtis [i++] == v->iid)
587                                 break;
589         for (; structs [r].vtis [i] != -1; i++)
590         if ((ret = lookup_virtual_f_ininit (structs [r].vtis [i], n, va, &ent_ret)) != VTI_STATUS_NI) {
591                 v->status = ret;
592                 v->iid = structs [r].vtis [i];
593                 v->entn = ent_ret;
594                 break;
595         }
596         free (va);
599 // 
600 // Force generation of virtual table with no entries at specific object
602 initID Here_virtualtable (OUTSTREAM o, recID r, bool inlined, bool constd, bool volatiled)
604 #ifdef  DEBUG
605         if (debugflag.VIRTUALTABLES)
606                 PRINTF ("++New virtual table introduced at class %s (%i)\n", SNM (r), r);
607 #endif
608         int i = 0;
610         if (structs [r].vtis)
611                 for (; structs [r].vtis [i] != -1; i++)
612                         if (VirtualTable [VirtualInitializer [structs [r].vtis [i]].v_t_i].
613                         appeared_at == r)
614                                 return -1;
616         //if (!inlined)
617                 add_variable_member (r, RESERVED__v_p_t_r_, typeID_voidP, 0, false, false);
618         vtblID vt = new_virtual_table ();
619         VirtualTable [vt].appeared_at = r;
620         VirtualTable [vt].vtname = name_virtual_table (r);
621         VirtualTable [vt].inlined = inlined;
622         VirtualTable [vt].constd = constd;
623         VirtualTable [vt].volatiled = volatiled;
624         outprintf (o, RESERVED_struct, VirtualTable [vt].vtname,
625                    CONST_IF (constd), STAR_IF (!inlined),
626                    CONST_IF (!inlined && !volatiled),
627 //                 !inlined && vtptrConst? RESERVED_const : BLANKT,
628                    RESERVED__v_p_t_r_, ';', -1);
629         initID vi = new_v_t_initializer (r);
630         VirtualInitializer [vi].v_t_i = vt;
631         VirtualInitializer [vi].instance_name = name_instance (r, r);
632         add_initializer (vt, vi, r);
633         structs [r].vtis = (initID*) realloc (structs [r].vtis, (i+2) * sizeof (int));
634         structs [r].vtis [i] = vi;
635         structs [r].vtis [i + 1] = -1;
636         structs [r].vt_inthis = true;
638         return vi;
641 // #.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#
642 /* Enter_virtual_function, may do 3 things:
643    1.  complain because virtual already has value
644    2.  set value to virtual slot (creating internal vf)
645    3.  create a new virtual table entry and set value
646  ********************************************************/
647 void Make_virtual_table (OUTSTREAM o, recID r, Token fname, typeID t)
649         if (!structs [r].vtis)
650                 Here_virtualtable (o, r, InlineAllVt, ConstVtables, !vtptrConst);
651         else {
652                 vlookup V = { .iid = -1 };
653                 lookup_virtual_f (r, fname, t, &V);
654                 if (V.status == VTI_STATUS_NI && !has_vtable (r))
655                 Here_virtualtable (o, r, InlineAllVt, ConstVtables, !vtptrConst);
656         }
659 static void New_virtual_function (vf_args*);
660 static void Override_virtual_function (vf_args*, vlookup*);
661 void Enter_virtual_function (vf_args *args)
663 #ifdef  DEBUG
664         if (debugflag.VIRTUALTABLES)
665         PRINTF ("\n++ENTER VIRTUAL: ["COLS"%s"COLE"] (%s)\n", expand (args->fname), SNM(args->r));
666 #endif
667         vlookup V = { .iid = -1 };
668         lookup_virtual_f (args->r, args->fname, args->ftype, &V);
670         // [3]
671         if (V.status == VTI_STATUS_NI)
672                 return New_virtual_function (args);
674         // [1]
675         if (V.status == VTI_STATUS_DD)
676                 parse_error_tok (args->fname, "Virtual function redefined?");
678         // [2]
679         while (V.status != VTI_STATUS_NI) {
680                 if (V.status == VTI_STATUS_FINAL)
681                         parse_error_tok (args->fname, "Virtual function has been declared final");
682                 Override_virtual_function (args, &V);
683                 lookup_virtual_f (args->r, args->fname, args->ftype, &V);
684         }
687 static void New_virtual_function (vf_args *args)
689         // [by convention, add it to the first virtual table if many]
690         vtblID vt = VirtualInitializer [best_vti (args->r)].v_t_i;
691         int i;
692         // + + + + new virtual table entry + + + +
693         vt_entry *ve = (vt_entry*) malloc (sizeof * ve);
694         *ve = (vt_entry) {
695                 .next = 0, .entry_name = name_virtual_slot (args->r, args->fname, args->ftype),
696                 .isfunction = true, .type = args->ftype, .fname = args->fname,
697                 .arglist = promoted_arglist_t (args->ftype), .introduced_at = args->r,
698                 .xproto = intdup (args->prototype), .xargs = intdup (args->argv),
699                 .flagz = args->flagz, .isconst = true
700                 /* XXX if final, give a nice warning */
701         };
702         // make pointer to function from function
703         {
704                 Token *fpt = mallocint (intlen (args->prototype) + 5);
705                 int i = 0, j = 0;
706                 while (args->prototype [i] != MARKER)
707                         fpt [j++] = args->prototype [i++];
708                 fpt [j++] = '(';
709                 fpt [j++] = '*';
710                 if (StdcallMembers)
711                         fpt [j++] = RESERVED_attr_stdcall;
712                 fpt [j++] = ve->entry_name; ++i;
713                 fpt [j++] = ')';
714                 while ((fpt [j++] = args->prototype [i++]) != -1);
715                 ve->prototype = fpt;
716         }
717         // add to virtual table slots. table may be empty.
718         add_vt_entry (vt, ve);
719         // + + + + in all other initializers this entry is NULL/NI + + + +
720         for (i = 0; i < VirtualTable [vt].nvti; i++) {
721                 vti_entry *vte = (vti_entry*) malloc (sizeof * vte);
722                 vte->next = 0;
723                 vte->vt_ent = ve;
724                 vte->code = 0;
725                 vte->cast_avoid_downcast = 0;
727                 if (VirtualTable [vt].vti [i].object != args->r) {
728                         vte->value = RESERVED_0;
729                         vte->status = VTI_STATUS_NI;
730                 } else {
731                         vte->value = args->fmemb ?: RESERVED_0;
732                         vte->status = VTI_STATUS_DD;
733                 }
734                 add_vti_entry (VirtualTable [vt].vti [i].initTbl, vte);
735         }
738 void add_struct_to_this (Token *p)
740         int i, j, k;
741         for (i = 0; p [i] != RESERVED_this; i++);
742         while (p [i] != '(') i--;
743         for (k = i; p [k] != -1; k++);
744         for (j = k++; j != i; )
745                 p [k--] = p [j--];
746         p [i+1] = RESERVED_struct;
749 static void Override_virtual_function (vf_args *args, vlookup *v)
751         Token entn = v->entn [intlen (v->entn) - 1];
752         vtblID vt = VirtualInitializer [v->iid].v_t_i;
753         recID dow;
754         Token *proto = args->prototype;
755         bool modular = args->flagz & FUNCP_MODULAR;
757         // find the virtual table entry from vlookup data
758         // get the downcast info
759         {
760                 vt_entry *vp = VirtualTable [vt].first_entry;
761                 while (vp->entry_name != entn) vp = vp->next;
762                 dow = vp->introduced_at;
763         }
765         // create virtuallity function name
766         Token vfn;
767         if (args->fmemb) 
768                 if (!modular) {
769                         // rewrite the prototype
770                         vfn = name_virtual_inner (args->r, dow, args->fname, args->ftype);
771                         proto = allocaint (intlen (args->prototype) + 4);
772                         intcpy (proto, args->prototype);
773                         intsubst1 (proto, MARKER, vfn);
774                         intsubst1 (proto, name_of_struct (args->r), name_of_struct (dow));
775                         if (is_aliasclass (args->r) && !is_aliasclass (dow))
776                                 add_struct_to_this (proto);
777                         else if (!is_aliasclass (args->r) && is_aliasclass (dow))
778                                 remove_struct_from_this (proto, dow);
779                 } else vfn = args->fmemb;
780         else vfn = RESERVED_0;
782         // set the value vfn for the entry at the initializer
783         vti_entry *vtp = VirtualInitializer [v->iid].first_entry;
784         while (vtp->vt_ent->entry_name != entn)
785                 vtp = vtp->next;
786         vtp->value = vfn;
787         vtp->status = args->flagz & FUNCP_FINAL ? VTI_STATUS_FINAL : VTI_STATUS_DD;
788         vtp->cast_avoid_downcast = 0;
789         // create the code of the virtuallity function
790         if (args->fmemb && !modular) 
791                 if (aliasclass (args->r) == aliasclass (dow))
792                         vtp->value = args->fmemb;
793                 else if (zero_offset (args->r, dow)) {
794                         vtp->value = args->fmemb;
795                         vtp->cast_avoid_downcast = 1;
796                 } else {
797                         int i;
798                         Token dc = i_downcast_function (dow, args->r);
799                         OUTSTREAM tmp = new_stream ();
800                         outprintf (tmp, //STRNEXT, proto, linkonce_text (vfn), ';',
801                                    ISTR (proto), '{', RESERVED_return, args->fmemb,
802                                    '(', dc, '(', RESERVED_this, ')', -1);
803                         for (i = 1; args->argv [i] != -1; i++)
804                                 outprintf (tmp, ',', args->argv [i], -1);
805                         outprintf (tmp, ')', ';', '}', -1);
806                         vtp->code = combine_output (tmp);
807                 }
810 void purify_vfunc (Token f)
812         int i;
813         vti_entry *v;
815         for (i = 0; i < nVTI; i++)
816                 for (v = VirtualInitializer [i].first_entry; v; v = v->next)
817                         if (v->value == f || v->code && intchr (v->code, f)) {
818                                 v->value = RESERVED_0;
819                                 VirtualInitializer [i].unused = true;
820                         }
822 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
823 // more virtuallity
824 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
826 static void close_inits (structure *s)
828         if (!s->vtis) return;
829         int i;
830         for (i = 0; s->vtis [i] != -1; i++)
831                 VirtualInitializer [s->vtis [i]].open = false;
834 static void v_t_instances (vtblID vi)
836         int i, hp, ns, ne;
838         for (hp = i = ns = ne = 0; i < VirtualTable [vi].nvti; i++)
839                 if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused) {
840                         if (structs [VirtualInitializer [VirtualTable
841                                         [vi].vti [i].initTbl].rec].keyfunc != -1)
842                                                 ++ne; else ++ns;
843                         hp = 1;
844                 }
846         if (!hp)
847                 return; // ----> leave
849         if (ne) {
850                 outprintf (VTABLE_DECLARATIONS, RESERVED_extern,
851                            CONST_IF (VirtualTable [vi].constd), RESERVED_struct,
852                             VirtualTable [vi].vtname, -1);
853                 for (hp = i = 0; i < VirtualTable [vi].nvti; i++)
854                         if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused
855                         && structs [VirtualInitializer [VirtualTable
856                                  [vi].vti [i].initTbl].rec].keyfunc != -1) {
857                                 outprintf (VTABLE_DECLARATIONS, COMMA_IF (hp),
858                                            VirtualInitializer [VirtualTable [vi].vti
859                                            [i].initTbl].instance_name, -1);
860                                 hp = 1;
861                         }
862                 output_itoken (VTABLE_DECLARATIONS, ';');
863         }
864         if (ns) {
865                 outprintf (VTABLE_DECLARATIONS, RESERVED_static,
866                            CONST_IF (VirtualTable [vi].constd), RESERVED_struct,
867                             VirtualTable [vi].vtname, -1);
868                 for (hp = i = 0; i < VirtualTable [vi].nvti; i++)
869                         if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused
870                         && structs [VirtualInitializer [VirtualTable
871                                  [vi].vti [i].initTbl].rec].keyfunc == -1) {
872                                 outprintf (VTABLE_DECLARATIONS, COMMA_IF (hp),
873                                            VirtualInitializer [VirtualTable [vi].vti
874                                            [i].initTbl].instance_name, -1);
875                                 hp = 1;
876                         }
877                 output_itoken (VTABLE_DECLARATIONS, ';');
878         }
881 void export_virtual_table_instances ()
883         int i;
884         for (i = 0; i < nVTBL; i++)
885                 v_t_instances (i);
888 static void virtual_init_definition (initID i, bool stc)
890         Token inst = VirtualInitializer [i].instance_name;
891         bool constd = VirtualTable [VirtualInitializer [i].v_t_i].constd;
892         vti_entry *ve;
894         // emit the code of the virtuallity downcasting functions
895         for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
896                 if (ve->code && ve->value && ve->value != RESERVED_0)
897                         outprintf (VIRTUALTABLES, RESERVED_inline, RESERVED_static,
898                                    ISTR (ve->code), -1);
900         outprintf (VIRTUALTABLES, CONST_IF (constd), STATIC_IF (stc), RESERVED_struct,
901                    VirtualTable [VirtualInitializer [i].v_t_i].vtname,
902                    inst, -1);
904 #ifdef  HAVE_LINKONCE
905         /* Not used after the discovery of the "key function" technique */
906         if (0)
907                 outprintf (VIRTUALTABLES, (constd ? linkonce_rodata : linkonce_data) (inst), -1);
908         //else  output_itoken (VIRTUALTABLES, section_vtblz (structs));
909 #endif
910         if (constd)
911                 output_itoken (VIRTUALTABLES, section_vtblz (
912                         name_of_struct (VirtualTable [VirtualInitializer [i].v_t_i].appeared_at)));
914         for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
915                 if (ve->value || ve->code)
916                         break;
917         if (!ve) goto closure;
919         outprintf (VIRTUALTABLES, '=', '{', -1);
920         for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
921                 if (ve->status != VTI_STATUS_NI)
922                         if (ve->cast_avoid_downcast && ve->value && ve->value != RESERVED_0)
923                         // cast avoid downcast
924                         outprintf (VIRTUALTABLES, '.', ISTR (ve->vt_ent->zpath),
925                                    '=', '(', RESERVED___typeof__, '(', inst, '.',
926                                    ISTR (ve->vt_ent->zpath), ')', ')', ve->value, ',', -1);
927                         else if (ve->value)             // functions have this
928                         outprintf (VIRTUALTABLES, '.',
929                                    ISTR (ve->vt_ent->zpath), '=', ve->value, ',', -1);
930                         else if (ve->code)      // virtual variables with const initi
931                         outprintf (VIRTUALTABLES, '.',
932                                    ISTR (ve->vt_ent->zpath), '=', ISTR (ve->code), ',', -1);
933         outprintf (VIRTUALTABLES, '}', -1);
935 closure:
936         outprintf (VIRTUALTABLES, ';', -1);
939 void export_virtual_definitions ()
941         int i;
942         for (i = 0; i < nVTI; i++)
943                 if (!VirtualInitializer [i].unused &&
944                  (ExportVtbl || structs [VirtualInitializer [i].rec].evt)) {
945                         recID r = VirtualInitializer [i].rec;
946                         if (structs [r].havekey)
947                                 virtual_init_definition (i, 0);
948                         else if (structs [r].keyfunc == -1)
949                                 virtual_init_definition (i, 1);
950                         else if (!structs [r].keyfunc) {
951 //                              PRINTF (COLS"******** NO KEYFUNC FOR %s *****\n"COLE, SNM(r));
952 //                              exit (1);
953                         } else {
954 //                              PRINTF (COLS"WILL NOT EMIT vtbl FOR %s *****\n"COLE, SNM(r));
955                         }
956                 }
959 void export_virtual_static_definitions ()
961         int i;
962         for (i = 0; i < nVTI; i++)
963                 if (!VirtualInitializer [i].unused
964                 && VirtualInitializer [i].exportdef)
965                         virtual_init_definition (i, 1);
967 // #/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#
968 // allocate structure & all virtual base
969 // classes in one structure.
970 // Mainly useful to free() all of them
971 // with one call.
972 // #/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#
974 static void mark_vtinit_unused (recID r)
976         initID i, j;
977         for (i = 0; (j = structs [r].vtis [i]) != -1; i++)
978                 VirtualInitializer [j].unused = true;
981 /* We can instantiate a class if it has no pure virtual
982    functions and there are unique final overriders for
983    all of them  */
984 static bool can_instantiate (recID r)
986         if (structs [r].vtis) {
988                 initID i;
989                 for (i = 0; structs [r].vtis [i] != -1; i++) {
990                         vti_entry *v = VirtualInitializer [structs [r].vtis [i]].first_entry;
991                         for (; v; v = v->next)
992                                 if (v->status != VTI_STATUS_NI && v->value == RESERVED_0) {
993                                         structs [r].caninst = CANT_PUREV;
994                                         mark_vtinit_unused (r);
995                                         return false;
996                                 } else if (v->status == VTI_STATUS_NU) {
997                                         structs [r].caninst = CANT_NUFO;
998                                         mark_vtinit_unused (r);
999                                         return false;
1000                                 }
1001                 }
1002         }
1004         structs [r].caninst = OK_CAN;
1005         return true;
1008 /* We have either the definition of a common instance (class no longer abstract),
1009  * or collapse of virtual tables due to virtual inheritance.
1010  * vbase is the virtual base, r is the current class and vbpath the path
1011  * that leads to the vb instance. Calculate all related offsets and set
1012  * their values at the entries of the [r] virtual initializer  */
1013 #define VOIDCAST '(', RESERVED_void, '*', ')'
1014 static void dcast_offsets (recID vbase, recID r, Token *vbpath)
1016         if (!structs [vbase].rtti) return;
1017         if (!structs [vbase].vtis) return;
1019         int i, j, ii;
1020         recID dc;
1021         Token rtn, *path, d [128];
1022         vti_entry *ve=ve;
1024         for (i = 0; (dc = structs [vbase].rtti [i].to) != -1; i++)
1025                 if (dc == r || is_ancestor (r, dc, &path, true)) {
1026                         rtn = structs [vbase].rtti [i].entry;
1028                         if (dc == r)
1029                                 sintprintf (d, VOIDCAST, RESERVED_0, -1);
1030                         else {
1031                                 sintprintf (d, VOIDCAST, '&', '(', '(', iRESERVED_struct (r),
1032                                 name_of_struct (r), '*', ')',
1033                                 RESERVED_0, ')', POINTSAT, ISTR (path), -1);
1034                         }
1036                         sintprintf (d + intlen (d), '-', VOIDCAST, '&', '(', '(',
1037                                 iRESERVED_struct (r), name_of_struct (r), '*', ')', 
1038                                 RESERVED_0, ')', POINTSAT, ISTR (vbpath), -1);
1040                         for (j = 0; (ii = structs [r].vtis [j]) != -1; j++)
1041                                 for (ve = VirtualInitializer [ii].first_entry; ve; ve = ve->next)
1042                                         if (ve->vt_ent->entry_name == rtn)
1043                                                 goto dbreak;
1044                         parse_error_ll ("Bug bug bug ()");
1045                 dbreak:
1046                         ve->code = intdup (d);
1047 #ifdef DEBUG
1048         if (debugflag.VIRTUALBASE) {
1049                 PRINTF ("\n "COLS"+"COLE"Changed offset of "COLS"%s"COLE" in the vtable of "COLS"%s"COLE" to \n\t"COLS,
1050                         expand (rtn), SNM (r));
1051                 INTPRINT (d);
1052                 PRINTF (COLE"\n\n");
1053         }
1054 #endif
1055                 }
1058 static inline bool ancestor_is_vbaseclass (ancestor *a)
1060         return (a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2) && a->rec == a->vbase;
1063 static void fix_all_offsets (recID r)
1065         ancestor *a;
1067         for (a = structs [r].ancestors; a->rec != -1; a++)
1068                 if (ancestor_is_vbaseclass (a) && a->cpath)
1069                         dcast_offsets (a->rec, r, a->cpath);
1072 static void update_ancestor_paths (recID r, recID vb, Token sn)
1074         Token *p;
1075         ancestor *a;
1077         for (a = structs [r].ancestors; a->rec != -1; a++)
1078                 if (a->status == ASTATUS_VIRT && a->vbase == vb) {
1079                         Token n = name_inherited (name_of_struct (vb));
1080                         Token tmp [64];
1081                         Token *p = &a->path [intlen (a->path)];
1082                         while (p >= a->path && *p != n) p--;
1083                         if (p [1] == -1 || p < a->path)
1084                                 sintprintf (tmp, sn, -1);
1085                         else
1086                                 sintprintf (tmp, sn, '.', ISTR (p + 2), -1);
1087                         a->cpath = intdup (tmp);
1088                 }
1090         /* this is rare (chained virtual inheritance) */
1091         for (a = structs [r].ancestors; a->rec != -1; a++)
1092                 if ((a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2)
1093                 &&  a->vbase != vb && (a->cpath && intchr (a->cpath, POINTSAT))
1094                 &&  is_ancestor (vb, a->rec, &p, true)) {
1095                         Token tmp [64];
1096                         sintprintf (tmp, sn, '.', ISTR (p), -1);
1097                         if (a->cpath) free (a->cpath);
1098                         a->cpath = intdup (tmp);
1099                         //i = 0;   (restart? very rare) XXX
1100                 }
1101 #ifdef DEBUG
1102         if (debugflag.VIRTUALTABLES) show_ancest (r);
1103 #endif
1106 /* declare common shared instance && update const ancestor paths */
1107 static void decl_vballoc_rec (OUTSTREAM o, recID r)
1109         ancestor *a;
1110         recID vr;
1112         for (a = structs [r].ancestors; a->rec != -1; a++)
1113                 if (a->status == ASTATUS_VIRT && a->vbase == (vr = a->rec)
1114                 && !a->cpath) {
1115                         Token sn = name_storage_inherit (vr);
1116                         outprintf (o, iRESERVED_struct (vr), name_of_struct (vr), sn, ';', -1);
1117                         sintprintf (a->cpath = mallocint (2), sn, -1);
1118                         update_ancestor_paths (r, vr, sn);
1119                         structs [r].need_recalc_offsets = true;
1120                 }
1123 /* Update all the downcast offsets so they all use the same
1124  * shared instance.  This is called after multiple inheritance */
1125 static void update_dcasts (recID r, recID vbs [])
1127         int i;
1128         ancestor *a;
1130         if (!structs [r].need_recalc_offsets)
1131                 for (i = 0; vbs [i] != -1; i++) {
1132                         for (a = structs [r].ancestors; a->rec != vbs [i]; a++)
1133                                 ;;;;;
1134                         if (a->cpath) {
1135                                 structs [r].need_recalc_offsets = true;
1136                                 return;
1137                         }
1138                 }
1140 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1141 // Requesting virtual functions from expressions
1142 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1144 bool lookup_virtual_function_member (recID r, Token f, typeID argv[],
1145                                      Token *vpath, flookup *F)
1147         if (!structs [r].vtis)
1148                 return false;
1150         argv [0] = pthis_of_struct (r);
1151         typeID *va = promoted_arglist (argv);
1152         int i, ret, status;
1153         initID iid=iid; /* this is done to avoid warning for uninitialized possible use */
1154         Token *ent_ret, *entn=entn, entname=entname;
1156         ret = status = VTI_STATUS_NI;
1158         for (i = 0; structs [r].vtis [i] != -1; i++)
1159         if ((ret = lookup_virtual_f_ininit (structs [r].vtis[i], f, va, &ent_ret)) != VTI_STATUS_NI)
1160                 if (status != VTI_STATUS_NI)
1161                         parse_error (0, "Ambiguity virtual inheritance");
1162                 else {
1163                         status = ret;
1164                         iid = structs [r].vtis [i];
1165                         entn = ent_ret;
1166                         entname = entn [intlen (entn) - 1];
1167                 }
1168         free (va);
1170         if (status == VTI_STATUS_NI || status == VTI_STATUS_FINAL)
1171                 return false;
1173 #ifdef  DEBUG
1174         if (debugflag.VIRTUALTABLES)
1175                 PRINTF ("++ Virtual call for ["COLS"%s"COLE"]\n", expand (f));
1176 #endif
1177         /* We must return: The path that leads to the virtual table entry in <vpath>
1178          * The type of the <this> argument in argv [0]
1179          * And finally, the function's type in <F>
1180          *  Let's go and do this
1181          */
1182         vtblID vt = VirtualInitializer [iid].v_t_i;
1183         recID bo_rec;
1184         {
1185                 vt_entry *ve;
1186                 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1187                         if (ve->entry_name == entname) break;
1188                 bo_rec = base_of (ve->arglist [0]);
1189                 F->t = ve->type;
1190                 F->prototype = ve->xproto;
1191                 F->xargs = ve->xargs;
1192                 F->flagz = ve->flagz;
1193                 F->oname = 0;
1194         }
1195         //[1]
1196         {
1197                 Token tpath [128];
1198                 sintprintf (vpath, ISTR (pathto_vt (tpath, iid, false)),
1199                             VirtualTable [vt].inlined ? '.' : POINTSAT, ISTR (entn), -1);
1200         }
1201         //[2]
1202         argv [0] = pthis_of_struct (bo_rec);
1203         return true;
1206 bool Is_pure_virtual (recID r, Token f, typeID argt [], flookup *F)
1208         if (!structs [r].vtis)
1209                 return false;
1211         argt [0] = pthis_of_struct (r);
1212         typeID *va = promoted_arglist (argt);
1213         int i, j;
1214         for (j = 0; (i = structs [r].vtis [j]) != -1; j++) {
1215                 vtblID vi = VirtualInitializer [i].v_t_i;
1216                 vt_entry *ve;
1217                 for (ve = VirtualTable [vi].first_entry; ve; ve = ve->next)
1218                 if (ve->isfunction && ve->fname == f && arglist_compare (va, ve->arglist)) {
1219                         vti_entry *vie;
1220                         free (va);
1221                         F->t = ve->type;
1222                         F->oname = RESERVED_0;
1223                         F->dflt_args = 0;
1224                         for (vie = VirtualInitializer [i].first_entry; ; vie = vie->next)
1225                                 if (vie->vt_ent->entry_name == ve->entry_name)
1226                                 switch (vie->status) {
1227                                 case VTI_STATUS_NI: return false;
1228                                 case VTI_STATUS_NU: return true;
1229                                 default: return vie->value == RESERVED_0;
1230                                 }
1231                 }
1232         }
1233         free (va);
1234         return false;
1237 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
1238 // Setting of pointer to virtual table at
1239 // construction of objects
1240 // Construction of common virtual base
1241 // instances
1242 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
1244 bool need_construction (recID r)
1246         return structs [r].has_vbase || (!structs [r].noctor && (structs [r].vtis
1247                  || structs [r].ctorables || structs [r].ancestors_have_ctors));
1250 bool need_vbase_alloc (recID r)
1252         return structs [r].has_vbase;
1255 /* assignm apropriate virtual table initializer to object */
1256 void gen_vt_init (OUTSTREAM o, recID r, Token obj, bool throuptr)
1258         Token path [128];
1259         int i;
1261         for (i = 0; structs [r].vtis [i] != -1; i++) {
1262                 initID ii = structs [r].vtis [i];
1263                 vtblID vt = VirtualInitializer [ii].v_t_i;
1264                 bool constd = VirtualTable [vt].constd;
1265                 bool inlined = VirtualTable [vt].inlined;
1266                 bool volatiled = VirtualTable [vt].volatiled;
1267                 Token vtn = VirtualTable [vt].vtname;
1268                 Token instn = VirtualInitializer [ii].instance_name;
1270                 if (inlined) // write vtbl despite possible constnesses
1271 #ifdef  HAVE_BUILTIN_MEMCPY     // this is wrong. nothing to do with "__builtin"
1272                         outprintf (o, INTERN_memcpy, '(',
1273                                   '(', RESERVED_void, '*', ')', 
1274                                    '&', obj, throuptr ? POINTSAT : '.',
1275                                    ISTR (pathto_vt (path, ii, true)),
1276                                    ',', '&', instn, ',', RESERVED_sizeof, '(',
1277                                    instn, ')', ')', ';', -1);
1278 #else
1279                         outprintf (o, '*', '(', '(', RESERVED_struct,
1280                                    VirtualTable [vt].vtname, '*', ')',
1281                                    '&', obj, throuptr ? POINTSAT : '.',
1282                                    ISTR (pathto_vt (path, ii, true)),
1283                                    ')', '=', instn, ';', -1);
1284 #endif
1285                 else {
1286                         if (!volatiled)
1287                         outprintf (o, '*', '(', RESERVED_struct, vtn, '*', '*',
1288                                    ')', '&', obj, throuptr ? POINTSAT : '.',
1289                                    ISTR (pathto_vt (path, ii, true)), '=', -1);//'&', instn, ';', -1);
1290                         else outprintf (o, obj, throuptr ? POINTSAT : '.',
1291                                 ISTR (pathto_vt (path, ii, true)), '=', -1);//'&', instn, ';', -1);
1292                         if (constd) outprintf (o, '(', RESERVED_void, '*', ')', -1);
1293                         outprintf (o, '&', instn, ';', -1);
1294                 }
1295         }
1298 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1299 // rtti: when we want to downcast
1300 // from a virtual base class to a
1301 // derrived class.  We have to do
1302 // that in virtual functns anyway
1303 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1305 void downcast_rtti (recID rder, recID rbase, recID rs, Token path[])
1307         int i;
1308         for (i = 0; structs [rbase].rtti [i].to != rder; i++)
1309                 ;
1310         rtti_downcast *rtti = &structs [rbase].rtti [i];
1311         initID vti;
1312         if ((vti = rtti->vti) == -1)
1313                 parse_error (0, "Can't downcast. No virtual table. No RTTI.");
1315         vt_entry *ve;
1316         vtblID vt = VirtualInitializer [vti].v_t_i;
1318         for (ve = VirtualTable [vt].first_entry;; ve = ve->next)
1319                 if (ve->entry_name == rtti->entry) break;
1321         for (vti = 0; VirtualTable [vt].vti [vti].object != rs; vti++);
1322         vti = VirtualTable [vt].vti [vti].initTbl;
1324         Token vpath [128];
1325         sintprintf (path, ISTR (pathto_vt (vpath, vti, false)),
1326                     VirtualTable [vt].inlined ? '.' : POINTSAT, ISTR (ve->zpath), -1);
1329 static int new_rtti_entry (recID obj)
1331         int i = 0;
1333         if (structs [obj].rtti)
1334                 for (i = 1; structs [obj].rtti [i].to != -1; i++);
1335         structs [obj].rtti = (rtti_downcast*) realloc (structs [obj].rtti,
1336                                 (i + 2) * sizeof (rtti_downcast));
1337         structs [obj].rtti [i + 1].to = -1;
1339         return i;
1342 static int lookup_rtti (recID obj, Token c)
1344         int i;
1346         if (structs [obj].rtti)
1347                 for (i = 0; structs [obj].rtti [i].to != -1; i++)
1348                         if (structs [obj].rtti [i].fwd_dcl == c)
1349                                 return i;
1350         return -1;
1353 int virtual_inheritance_decl (OUTSTREAM O, recID obj, Token c)
1355         int i = lookup_rtti (obj, c);
1357         if (i != -1) return i;
1358         if (O) structs [obj].have_vi_decls = true;
1360         i = new_rtti_entry (obj);
1361         structs [obj].rtti [i].fwd_dcl = c;
1362         structs [obj].rtti [i].to = 0;
1364         initID ii = best_vti (obj);
1365         if (ii == -1) {
1366                 if (!O) parse_error_tok (name_of_struct (obj),
1367                                 "In order to do virtual inheritance, please "
1368                                 "create a virtual table for this class");
1369                 Here_virtualtable (O, obj, false, ConstVtables, !vtptrConst);
1370                 ii = best_vti (obj);
1371         }
1373         structs [obj].rtti [i].vti = ii;
1375         /* make virtual table entry */
1376         vtblID vt = VirtualInitializer [ii].v_t_i;
1377         vt_entry *ve = (vt_entry*) malloc (sizeof * ve);
1378         ve->next = 0;
1379         ve->entry_name = structs [obj].rtti [i].entry = name_rtti_slot (obj, c);
1380         ve->fname = 0;
1381         ve->isfunction = false;
1382         ve->introduced_at = obj;
1383         ve->prototype = mallocint (5);
1384         ve->isconst = true;
1385         sintprintf (ve->prototype, /*RESERVED_const,*/ RESERVED_int, ve->entry_name, -1);
1386         add_vt_entry (vt, ve);
1388         return i;
1391 static void add_rtti (recID obj, recID der)
1393         vtblID vt;
1394         initID I;
1395         vt_entry *ve;
1396         int i, j;
1398         i = lookup_rtti (obj, name_of_struct (der));
1399         if (i == -1)
1400                 if (!structs [obj].vtis) {
1401                         // no virtual table! downcast impossible
1402                         i = new_rtti_entry (obj);
1403                         structs [obj].rtti [i].to = der;
1404                         structs [obj].rtti [i].fwd_dcl = name_of_struct (der);
1405                         structs [obj].rtti [i].vti = -1;
1406                         return;
1407                 } else if (VIDeclarations || structs [obj].have_vi_decls)
1408                         parse_error_tok (name_of_struct (der), "Virtual inheritance not declared");
1409                 else i = virtual_inheritance_decl (0, obj, name_of_struct (der));
1411         /* activate the virtual table entry */
1412         structs [obj].rtti [i].to = der;
1413         I = structs [obj].rtti [i].vti;
1414         vt = VirtualInitializer [I].v_t_i;
1415         for (ve = VirtualTable [vt].first_entry;
1416                 ve->entry_name != structs [obj].rtti [i].entry; ve = ve->next);
1418         ve->type = pthis_of_struct (der);
1419         for (j = 0; j < VirtualTable [vt].nvti; j++) {
1420                 vti_entry *vte = (vti_entry*) malloc (sizeof * vte);
1421                 vte->next = 0;
1422                 vte->vt_ent = ve;
1423                 vte->code = 0; vte->value = 0;
1424                 vte->status = VirtualTable [vt].vti [j].object == der ?
1425                                 VTI_STATUS_DD : VTI_STATUS_NI;
1426                 vte->cast_avoid_downcast = 0;
1427                 add_vti_entry (VirtualTable [vt].vti [j].initTbl, vte);
1428         }
1431 static void make_rtti (recID r)
1433         ancestor *a;
1435         for (a = structs [r].ancestors; a->rec != -1; a++)
1436                 if (a->path [1] == -1
1437                 && (a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2))
1438                         add_rtti (a->rec, r);
1441 // #<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#
1442 // Virtual data members
1443 // #<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#
1445 typeID lookup_virtual_varmemb (recID r, Token m, Token *path, bool const_path, Token **cval)
1447         int             i;
1448         initID          ii;
1449         vtblID          vt;
1450         vt_entry        *ve;
1451         vti_entry       *vte;
1452         typeID          rett = -1;
1454         if (!structs [r].vtis)
1455                 return -1;
1457         for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1458                 vt = VirtualInitializer [ii].v_t_i;
1459                 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1460                 if (!ve->isfunction && ve->fname == m)
1461                         for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1462                         if (vte->vt_ent->entry_name==ve->entry_name && vte->status != VTI_STATUS_NI)
1463                                 if (rett != -1) expr_errort ("ambiguous virtual member", m);
1464                                 else {
1465                                         Token vpath [128];
1466                                         if (path) {
1467                                         if (!const_path)
1468                                         sintprintf (path, ISTR (pathto_vt (vpath, ii, false)), 
1469                                                     VirtualTable [vt].inlined ? '.' : POINTSAT,
1470                                                     ISTR (vte->vt_ent->zpath), -1);
1471                                         else sintprintf (path, VirtualInitializer [ii].
1472                                                          instance_name, '.',
1473                                                          ISTR (vte->vt_ent->zpath), -1);
1474                                         }
1475                                         if (cval)
1476                                                 *cval = !path || VirtualTable [vt].constd
1477                                                          || ve->isconst ?
1478                                                         vte->code ?: zinit : 0;
1479                                         rett = ve->type;
1480                                         if (objective.recording && VirtualInitializer [ii].unused
1481                                         && const_path)
1482                                                 usage_set_pure ();
1483                                 }
1484         }
1485         return rett;
1488 /* <classname>.<member> syntax */
1489 vtvar access_virtual_variable (recID r, Token m)
1491         vtvar           ret = { .t = -1 };
1492         Token           have = -1;
1493         int             i;
1494         initID          ii;
1495         vtblID          vt;
1496         vt_entry        *ve;
1497         vti_entry       *vte;
1499         if (!structs [r].vtis)
1500                 return ret;
1502         for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1503                 vt = VirtualInitializer [ii].v_t_i;
1504                 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1505                 if (!ve->isfunction && ve->fname == m)
1506                         for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1507                         if (vte->vt_ent->entry_name == ve->entry_name && vte->status != VTI_STATUS_NI)
1508                                 if (have != -1) expr_errort ("ambiguous virtual member", m);
1509                                 else {
1510                                         if (VirtualTable [vt].inlined)
1511                                                 expr_errort ("can't access virtual variable of inlined virtual table", m);
1512                                         ret.rec = have = VirtualInitializer [ii].instance_name;
1513                                         ret.memb = ve->zpath;
1514                                         ret.t = ve->type;
1515                                         ret.expr = vte->code;
1516                                 }
1517         }
1518         return ret;
1521 bool Is_implied_virtual_variable (recID r, Token m)
1523         return lookup_virtual_varmemb (r, m, 0, 0, 0) != -1;
1526 void add_virtual_varmemb (recID r, Token m, Token a, typeID t, Token *expr, Token *proto,
1527                           bool cnst, OUTSTREAM o)
1529         int i;
1530         vt_entry *ve;
1531         vti_entry *vte;
1532         vtblID vt;
1533         bool isconst = proto [0] == RESERVED_const || proto [1] == RESERVED_const;
1535         if (!structs [r].vtis) {
1536 spagetti:;
1537         /* XXX: why don't we call Here_virtual_table() here ?????? */
1538         /* XXX: We demand to see the persons who wrote this */
1539                 /* Virtualize Class */
1540                 add_variable_member (r, RESERVED__v_p_t_r_, typeID_voidP, 0, false, false);
1541                 vt = new_virtual_table ();
1542                 bool inlined = VirtualTable [vt].inlined;
1543                 bool constd = VirtualTable [vt].constd;
1545                 if (m == RESERVED_typeid)
1546                         VirtualTable [vt].typeid = true;
1547                 VirtualTable [vt].appeared_at = r;
1548                 VirtualTable [vt].vtname = name_virtual_table (r);
1549                 outprintf (o, RESERVED_struct, VirtualTable [vt].vtname,
1550                            CONST_IF (constd), STAR_IF (!inlined),
1551                            !inlined && vtptrConst? RESERVED_const : BLANKT,
1552                            RESERVED__v_p_t_r_, ';', -1);
1554                 Token entry_name = name_virtual_variable (r, m);
1555                 ve = (vt_entry*) malloc (sizeof * ve);
1557                 intsubst (proto, MARKER, entry_name);
1558                 *ve = (vt_entry) {
1559                         .next = 0, .entry_name = entry_name, .isconst = isconst,
1560                         .isfunction = false, .type = t, .fname = m,
1561                         .prototype = intdup (proto), .introduced_at = r
1562                 };
1563                 add_vt_entry (vt, ve);
1565                 initID vi = new_v_t_initializer (r);
1566                 VirtualInitializer [vi].v_t_i = vt;
1567                 VirtualInitializer [vi].instance_name = name_instance (r, r);
1568                 add_initializer (vt, vi, r);
1570                 vte = (vti_entry*) malloc (sizeof * vte);
1571                 *vte = (vti_entry) {
1572                         .next = 0, .vt_ent = ve, .value = 0,
1573                         .code = expr, .status = VTI_STATUS_DD
1574                 };
1575                 VirtualInitializer [vi].first_entry = vte;
1577                 structs [r].vtis = mallocint (2);
1578                 structs [r].vtis [0] = vi;
1579                 structs [r].vtis [1] = -1;
1580                 return;
1581         }
1582         Token *initexpr;
1583         typeID ht = lookup_virtual_varmemb (r, m, 0, 0, &initexpr);
1584         if (ht == -1) {
1585                 if (!has_vtable (r))
1586                          goto spagetti;
1588                 /* New Entry To Best Virtual Table */
1589                 vt = VirtualInitializer [best_vti (r)].v_t_i;
1590                 if (m == RESERVED_typeid)
1591                         VirtualTable [vt].typeid = true;
1592                 ve = (vt_entry*) malloc (sizeof * ve);
1593                 Token entry_name = name_virtual_variable (r, m);
1595                 intsubst (proto, MARKER, entry_name);
1596                 *ve = (vt_entry) {
1597                         .next = 0, .entry_name = entry_name, .isconst = isconst,
1598                         .isfunction = false, .type = t, .fname = m,
1599                         .prototype = intdup (proto), .introduced_at = r
1600                 };
1601                 add_vt_entry (vt, ve);
1603                 for (i = 0; i < VirtualTable [vt].nvti; i++) {
1604                         vte = (vti_entry*) malloc (sizeof * vte);
1605                         *vte = (vti_entry) {
1606                                 .next = 0, .vt_ent = ve, .value = 0
1607                         };
1608                         if (VirtualTable [vt].vti [i].object != r) {
1609                                 vte->code = 0;
1610                                 vte->status = VTI_STATUS_NI;
1611                         } else {
1612                                 vte->code = expr;
1613                                 vte->status = VTI_STATUS_DD;
1614                         }
1615                         add_vti_entry (VirtualTable [vt].vti [i].initTbl, vte);
1616                 }
1617                 return;
1618         }
1619         if (ht != t)
1620                 parse_error_tok (m, "Virtual member redefined with different type");
1621         if (in2 (a, ASSIGNBO, ASSIGNBA) && initexpr) {
1622                 Token *xx = mallocint (intlen (expr) + intlen (initexpr) + 5);
1623                 sintprintf (xx, '(', ISTR (initexpr), ')', a == ASSIGNBO ? '|' : '&',
1624                            ISTR (expr), -1);
1625                 free (expr);
1626                 expr = xx;
1627         }
1628         initID ii;
1629         for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1630                 vt = VirtualInitializer [ii].v_t_i;
1631                 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1632                 if (ve->fname == m)
1633                         for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1634                         if (vte->vt_ent->entry_name == ve->entry_name && vte->status != VTI_STATUS_NI) {
1635                                 if (vte->status == VTI_STATUS_DD) parse_error_tok (m, "redefined?");
1636                                 vte->status = VTI_STATUS_DD;
1637                                 vte->code = expr;
1638                                 return;
1639                         }
1640         }
1641         parse_error_tok (m, "Some strange kind of bug (:)");
1644 void mk_typeid (recID r)
1646         int i;
1647         vti_entry *v;
1648         vt_entry *ve;
1650         if (!structs [r].vtis)
1651                 return;
1653         for (i = 0; structs [r].vtis [i] != -1; i++)
1654                 if (VirtualTable [VirtualInitializer [structs [r].vtis [i]].v_t_i].typeid)
1655                         for (v = VirtualInitializer [structs [r].vtis [i]].first_entry; v;
1656                              v = v->next)
1657                                 if (!(ve = v->vt_ent)->isfunction && ve->fname == RESERVED_typeid) {
1658                                         if (v->status != VTI_STATUS_NI)
1659                                                 v->code = sintprintf (mallocint (2),
1660                                                         i_typeid_var (name_of_struct (r)), -1);
1661                                         break;
1662                                 }
1665 Token get_class_vptr (recID r)
1667         int i;
1668         initID *j = structs [r].vtis;
1669         int vid = -1;
1671         if (!j) expr_errort ("No _v_p_t_r_ for class", name_of_struct (r));
1673         if (j [1] == -1)
1674                 vid = j [0];
1675         else for (i = 0; j [i] != -1; i++)
1676                 if (VirtualTable [VirtualInitializer [j[i]].v_t_i].appeared_at == r)
1677                         vid = j [i];
1678         if (vid == -1)
1679                 expr_errort ("Ambiguous _v_p_t_r_ for class", name_of_struct (r));
1680         if (objective.recording && VirtualInitializer [vid].unused)
1681                 usage_set_pure ();
1682         return VirtualInitializer [vid].instance_name;