|
|
1.1 root 1: /*ident "@(#)ctrans:src/simpl2.c 1.5" */
2: /******************************************************************
3:
4: C++ source for cfront, the C++ compiler front-end
5: written in the computer science research center of Bell Labs
6:
7: Copyright (c) 1984 AT&T, Inc. All rights Reserved
8: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.
9:
10: simpl2.c:
11:
12: simplify the typechecked function
13: remove: classes:
14: class fct-calls
15: operators
16: value constructors and destructors
17: new and delete operators (replace with function calls)
18: initializers (turn them into statements)
19: constant expressions (evaluate them)
20: inline functions (expand the calls)
21: enums (make const ints)
22: unreachable code (delete it)
23: make implicit coersions explicit
24:
25: in general you cannot simplify something twice
26:
27: *******************************************************************/
28:
29: #include "cfront.h"
30: #include "size.h"
31: #include <ctype.h>
32:
33: extern Pname Ntmp;
34: Pname find_vptr(Pclass);
35:
36: extern int no_of_returns;
37:
38: extern Pname new_fct;
39: //extern Pname del_fct;
40:
41: extern Pstmt del_list;
42: extern Pstmt break_del_list;
43: extern Pstmt continue_del_list;
44:
45: extern Pname curr_fct; // current function
46: extern Pexpr init_list;
47: extern int imeasure;
48:
49: Pexpr cdvec(Pname f, Pexpr vec, Pclass cl, Pname cd, int tail, Pexpr i, Pexpr vec2)
50: /*
51: generate a call to construct or destroy the elements of a vector
52: */
53: {
54: Pexpr sz = new texpr(SIZEOF,cl,0); // sizeof elem
55: sz->tp = uint_type;
56: (void) cl->tsizeof();
57:
58: Pexpr esz = new texpr(SIZEOF,cl,0); // noe = sizeof(vec)/sizeof(elem)
59: esz->tp = int_type;
60:
61: Pexpr noe;
62: if (vec2) noe = new texpr(SIZEOF,vec2->tp,0);
63: else noe = new texpr(SIZEOF,vec->tp,0);
64:
65: // Pexpr noe = new texpr(SIZEOF,vec->tp,0);
66: noe->tp = int_type;
67: noe = new expr(DIV,noe,esz);
68: noe->tp = uint_type;
69: // error('d',"cdvec tail %d i %d",tail,i);
70: // Pexpr arg = (0<=tail) ? new expr(ELIST,zero,0) : 0; // 0 or 1 for dtors
71: Pexpr arg = (i) ? new expr(ELIST,i,0) : 0;
72: arg = (0<=tail) ? new expr(ELIST,zero,arg) : arg; // 0 or 1 for dtors
73: arg = new expr(ELIST,cd,arg); // constructor or destructor
74: cd->lval(ADDROF); // cd->take_addr();
75:
76: arg = new expr(ELIST,sz,arg);
77: arg = new expr(ELIST,noe,arg);
78: arg = new expr(ELIST,vec,arg);
79:
80: arg = new call(f,arg);
81: arg->base = G_CALL;
82: arg->fct_name = f;
83:
84: return arg;
85: }
86:
87: /*
88: int new_used; // pre-define new and delete only if the user didn't
89:
90: void new_init()
91: {
92: char* ns = oper_name(NEW);
93: char* ds = oper_name(DELETE);
94:
95: new_used = 1;
96:
97: new_fct = gtbl->look(ns,0);
98: del_fct = gtbl->look(ds,0);
99:
100: if (new_fct && !del_fct)
101: error('w',"%n defined but not operator delete()",new_fct);
102: if (del_fct && !new_fct)
103: error('w',"%n defined but not operator new()",del_fct);
104:
105: if (Pfct(new_fct->tp)->body==0) new_fct->dcl_print(0);
106: if (Pfct(del_fct->tp)->body==0) del_fct->dcl_print(0);
107: }
108: */
109: Pstmt trim_tail(Pstmt tt)
110: /*
111: strip off statements after RETURN etc.
112: NOT general: used for stripping off spurious destructor calls
113: */
114: {
115: if (tt == 0) return 0;
116:
117: while (tt->s_list) {
118: Pstmt tpx;
119: switch (tt->base) {
120: case PAIR:
121: tpx = trim_tail(tt->s2);
122: goto tpxl;
123: case BLOCK:
124: tpx = trim_tail(tt->s);
125: tpxl:
126: if (tpx == 0) return 0;
127:
128: switch (tpx->base) {
129: case SM:
130: break;
131: case CONTINUE:
132: case BREAK:
133: case GOTO:
134: case RETURN:
135: if (tt->s_list->base != LABEL) tt->s_list = 0;
136: default:
137: return tpx;
138: }
139: default:
140: if (tt = tt->s_list) break;
141: return 0;
142: case RETURN:
143: if (tt->s_list->base != LABEL) tt->s_list = 0;
144: return tt;
145: }
146: }
147:
148: switch (tt->base) {
149: case PAIR: return trim_tail(tt->s2);
150: // case LABEL: return trim_tail(tt->s);
151: case BLOCK: if (tt->s) return trim_tail(tt->s);
152: default: return tt;
153: }
154: }
155:
156: extern Ptype Pfct_type;
157:
158: Pexpr mptr_assign(Pexpr n, Pexpr in)
159: {
160: Pexpr i1;
161: Pexpr i2;
162: Pexpr i3;
163:
164: if ( n->base == NAME )
165: Pname(n)->use();
166:
167: if (in->base == NAME) {
168: i1 = new mdot("d",in);
169: i1->i1 = 9;
170: i2 = new mdot("i",in);
171: i2->i1 = 9;
172: i3 = new mdot("f",in);
173: i3->i1 = 9;
174: }
175: else {
176: i1 = in->e1->e1;
177: i2 = in->e1->e2;
178: i3 = in->e2;
179: }
180: Pexpr nd = new mdot("d",n);
181: nd->i1 = 9;
182: Pexpr e1 = new expr(ASSIGN,nd,i1);
183:
184: Pexpr ni = new mdot("i",n);
185: ni->i1 = 9;
186: Pexpr e2 = new expr(ASSIGN,ni,i2);
187:
188: Pexpr nf = new mdot("f",n);
189: nf->i1 = 9;
190: // Pexpr ii = in->e2; //new cast(Pfct_type,in->e2);
191: Pexpr e3 = new expr(ASSIGN,nf,i3);
192:
193: Pexpr ee = new expr(CM,e2,e3);
194: return new expr(CM,e1,ee);
195: }
196:
197: Pstmt block::simpl()
198: {
199: int i;
200: Pname n;
201: Pstmt ss=0, sst=0;
202: Pstmt dd=0, ddt=0;
203: Pstmt stail;
204: Ptable old_scope = scope;
205: DB( if(Sdebug>=1)
206: error('d',"%d->block::simple() own_tbl %d memtbl %d curr_fct%n",this,own_tbl,memtbl,curr_fct);
207: );
208: if (own_tbl == 0) {
209: ss = (s) ? s->simpl() : 0;
210: return ss;
211: }
212:
213: scope = memtbl;
214: if (scope->init_stat == 0) scope->init_stat = 1; /* table is simplified. */
215:
216: for (n=scope->get_mem(i=1); n; n=scope->get_mem(++i)) {
217: Pstmt st = 0;
218: Pname cln;
219: Pexpr in = n->n_initializer;
220: // error('d',"local %k %n in %k %t",n->n_sto,n,in?in->base:0,in?in->tp:0);
221: if (in || n->n_evaluated) {
222: scope->init_stat = 2; /* initializer in this scope */
223: if (n->n_sto == EXTERN) {
224: error(&n->where,"Id local extern%n",n);
225: continue;
226: }
227: }
228:
229: switch (n->n_scope) {
230: case ARG:
231: case 0:
232: case PUBLIC:
233: continue;
234: }
235:
236: if (n->n_stclass == STATIC) { // local static class object
237: /* initialization of local static objects;
238: * set up first pass switch
239: * temp_switch ? 0
240: * : (stat_obj=init_expr, temp_switch=1);
241: *
242: * ARGS: temporary class object in init_expr with dtor
243: * must call dtor once in std function
244: */
245:
246: if ((in==0 && n->n_scope==ARGS) ||
247: (in && in->base==STAT_INIT))
248: {
249: Pname cn;
250: Pname x;
251: Ptype ct;
252: int vec_seen = 0;
253:
254: cn = n->tp->is_cl_obj();
255: if ( cn == 0 ) { ++vec_seen; cn = cl_obj_vec; }
256:
257: if ( cn ) {
258: ct = new ptr(PTR,vec_seen?Pvec(n->tp)->typ:n->tp);
259: x = make_tmp('F', ct, gtbl );
260: x->n_initializer = zero;
261: }
262: else
263: x = make_tmp('F',int_type,scope);
264:
265: x->n_sto = n->n_stclass = STATIC;
266:
267: if (in) {
268: if (in->e2)
269: in->base = ASSIGN;
270: else in = in->e1;
271: }
272:
273: Pexpr set;
274: if ( cn ) {
275: x->dcl_print(0);
276: Pclass cl = Pclass(cn->tp);
277: Pname dtor = cl->has_dtor();
278:
279: Pexpr cc;
280: if ( dtor ) {
281: if ( vec_seen == 0 ) {
282: Pexpr eee = new expr(DEREF, x, 0 );
283: Pexpr c = call_dtor(eee,dtor,0,DOT,one);
284: c->tp = any_type;
285: cc = new expr( QUEST, c, zero );
286: cc->cond = x;
287: }
288: else cc = cdvec(vec_del_fct,x,cl,dtor,0,zero,n);
289: cc->tp = any_type; // arghh!
290:
291: Pstmt dls = new estmt( SM, n->where, cc, 0 );
292: if ( st_dlist ) dls->s_list = st_dlist;
293: st_dlist = dls;
294: }
295:
296: Pexpr xe;
297: if (cn) {
298: if ( vec_seen == 0 )
299: xe = new expr( G_ADDROF, 0, n );
300: else {
301: Pexpr ee = new expr( DEREF, n, zero );
302: xe = new expr( G_ADDROF, 0, ee );
303: }
304: }
305:
306: set = new expr(ASSIGN,x,xe);
307: set->tp = ct;
308: }
309: else {
310: set = new expr(ASSIGN,x,one);
311: set->tp = int_type;
312: }
313:
314: // set pointer to static object and continue
315: // sorry for goto, but beats rewriting code
316: if ( n->n_scope == ARGS && in == 0 ) {
317: set = new expr( QUEST, zero, set );
318: set->cond = x;
319: st = new estmt(SM,n->where,set,0);
320: goto init_stat3;
321: }
322:
323: in = new expr(G_CM,in,set);
324: in = new expr(STAT_INIT,zero,in);
325: in->cond = x;
326: }
327: else
328: continue;
329: }
330:
331: if ( in ) {
332: if ((in->base == ILIST && in->e2 == 0) ||
333: (in->base == STRING && n->tp->base == VEC))
334: if (ansi_opt==0) {
335: error('s',&n->where,"initialization of%n (automatic aggregate)",n);
336: continue;
337: }
338: }
339:
340: if (n->tp == 0) continue; /* label */
341: if (n->n_evaluated) continue;
342:
343: /* construction and destruction of temporaries is handled locally */
344: { char* s = n->string;
345: register char c3 = s[4];
346: if (s[0]=='_' && s[1]=='_' && s[2]=='D' && isdigit(c3)) continue;
347: }
348:
349: if ( cln=n->tp->is_cl_obj() ) {
350: Pclass cl = Pclass(cln->tp);
351: Pname d = cl->has_dtor();
352:
353: if ( n->n_stclass == STATIC // local static class object
354: && in && in->base==STAT_INIT )
355: goto stat_init;
356:
357: if (d) { // n->cl.dtor(0);
358: Pexpr dl = call_dtor(n,d,0,DOT,one);
359: // Pstmt dls = new estmt(SM,n->where,dl,0);
360: Pstmt dls = new estmt(SM,no_where,dl,0);
361: if (dd) {
362: dls->s_list = dd;
363: dd = dls;
364: }
365: else
366: ddt = dd = dls;
367: }
368:
369: // error('d',"%n: in %d",n,in?in->base:0);
370: if (in) {
371: switch (in->base) {
372: case DEREF: // *constructor?
373: if (in->e1->base == G_CALL) {
374: Pname fn = in->e1->fct_name;
375: if (fn==0 || fn->n_oper!=CTOR) goto ddd;
376: st = new estmt(SM,n->where,in->e1,0);
377: n->n_initializer = 0;
378: break;
379: }
380: goto ddd;
381: case STAT_INIT:
382: stat_init:
383: // error('d', "block::simpl: case #1 stat_init : n: %n", n );
384: in->base = QUEST;
385: st = new estmt(SM,n->where,in,0);
386: n->n_initializer = 0;
387: break;
388: case G_CM:
389: st = new estmt(SM,n->where,in->e1,0);
390: n->n_initializer = 0;
391: break;
392: case ASSIGN: // assignment to "n"?
393: if (in->e1 == n) {
394: st = new estmt(SM,n->where,in,0);
395: n->n_initializer = 0;
396: break;
397: }
398: default:
399: goto ddd;
400: }
401: }
402: }
403: else if (cl_obj_vec) {
404: Pclass cl = Pclass(cl_obj_vec->tp);
405: Pname d = cl->has_dtor();
406: Pname c = cl->has_ictor();
407: n->n_initializer = 0;
408:
409: if ( n->n_stclass == STATIC // local static class object
410: && in && in->base==STAT_INIT )
411: goto stat_init2;
412:
413: if (c) { // _vec_new(vec,noe,sz,ctor);
414: if (in==0 || in->base==ILIST) {
415: Pexpr a = cdvec(vec_new_fct,n,cl,c,-1,0);
416: st = new estmt(SM,n->where,a,0);
417: }
418: else
419: st = new estmt(SM,n->where,in,0);
420: }
421: // no default ctor but provided all elements with argument
422: else if ( in ) st = new estmt(SM,n->where,in,0);
423:
424:
425: if (d) { // __vec_delete(vec,noe,sz,dtor,0);
426: Pfct f = Pfct(d->tp);
427: int i = 0;
428: for (Pname nn = f->f_args->n_list;
429: nn && nn->n_list; nn=nn->n_list) i++;
430: Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
431: // Pstmt dls = new estmt(SM,n->where,a,0);
432: Pstmt dls = new estmt(SM,no_where,a,0);
433: if (dd) {
434: dls->s_list = dd;
435: dd = dls;
436: }
437: else
438: ddt = dd = dls;
439: }
440: }
441: else if (in) {
442: switch (in->base) {
443: case ILIST:
444: switch (n->n_scope) {
445: case FCT:
446: if (in->e2) { // pointer to member
447: Pexpr ee = mptr_assign(n,in);
448: st = new estmt(SM,n->where,ee,0);
449: n->n_initializer = 0;
450: break;
451: }
452: case ARG:
453: if (ansi_opt == 0) error('s',"Ir list for localV%n",n);
454: }
455: break;
456: case STAT_INIT:
457: stat_init2:
458: // error('d', "block::simpl: case #2 stat_init : n: %n", n );
459: in->base = QUEST;
460: st = new estmt(SM,n->where,in,0);
461: n->n_initializer = 0;
462: break;
463: case STRING:
464: if (n->tp->base==VEC) break; /* BUG char vec only */
465: default:
466: ddd:
467: { Pexpr ee = new expr(ASSIGN,n,in);
468: st = new estmt(SM,n->where,ee,0);
469: n->n_initializer = 0;
470: }
471: }
472: }
473:
474: init_stat3: if (st) {
475: if (ss)
476: sst->s_list = st;
477: else
478: ss = st;
479: sst = st;
480: }
481: }
482:
483: if (dd) {
484: Pstmt od = del_list;
485: Pstmt obd = break_del_list;
486: Pstmt ocd = continue_del_list;
487:
488: dd->simpl();
489: del_list = (od) ? Pstmt(new pair(curloc,dd,od)) : dd;
490: break_del_list = (break_del_list&&obd) ? Pstmt(new pair(curloc,dd,obd)) : dd;
491: continue_del_list = (continue_del_list&&ocd) ? Pstmt(new pair(curloc,dd,ocd)) : dd;
492:
493: stail = s ? s->simpl() : 0;
494:
495: Pfct f = Pfct(curr_fct->tp);
496: if (this!=f->body
497: || f->returns->base==VOID
498: || (f->returns->base!=VOID && no_of_returns==0 ) // you have been warned!
499: || strcmp(curr_fct->string,"main")==0 ) {
500: // not dropping through the bottom of a value returning function
501: if (stail) {
502: Pstmt tt = (stail->base==RETURN || stail->base==LABEL) ? stail : trim_tail(stail);
503: if (tt && tt->base != RETURN) stail->s_list = dd;
504: }
505: else
506: s = dd;
507: stail = ddt;
508: }
509:
510: del_list = od;
511: continue_del_list = ocd;
512: break_del_list = obd;
513: }
514: else
515: stail = s ? s->simpl() : 0;
516:
517: if (ss) { /* place constructor calls */
518: ss->simpl();
519: sst->s_list = s;
520: s = ss;
521: if (stail == 0) stail = sst;
522: }
523:
524: scope = old_scope;
525:
526: return stail;
527: }
528:
529: int no_sizeof;
530:
531: void expr::simpl()
532: {
533: DB(if(Sdebug>=2){
534: error('d',"%d->expr::simpl() %k",this,this?base:0);
535: if(Sdebug>=3) display_expr(this);
536: });
537: if (this==0 || permanent==2) return; // already expanded
538: static TOK obase = 0;
539:
540: switch (base) {
541: case MDOT:
542: obase = base;
543: mem->simpl();
544: obase = 0;
545: // no break
546:
547: case ICALL: // already expanded
548: return;
549:
550: case G_ADDROF:
551: case ADDROF:
552: // error('d',"simpl & %k",e2->base);
553:
554: e2->simpl();
555: switch (e2->base) {
556: case DOT:
557: case REF:
558: { Pref r = Pref(e2);
559: Pname m = Pname(r->mem);
560: while (m->base == MDOT) m = Pname(m->mem);
561: if (m->n_stclass == STATIC) { // & static member
562: Pexpr x;
563: delp:
564: x = e2;
565: e2 = m;
566: r->mem = 0;
567: DEL(x);
568: }
569: else if (m->tp->base == FCT) { // & member fct
570: Pfct f = Pfct(m->tp);
571: if (f->f_virtual) { // &p->f ==> p->vtbl[fi].f
572: int index = f->f_virtual;
573: Pexpr ie = index ? new ival(index):0;
574: if (ie) ie->tp = int_type;
575: Pname cn = m->n_table->t_name;
576: Pname vp = find_vptr(Pclass(cn->tp));
577: r->mem = vp;
578:
579: if ( obase == MDOT ) {
580: base = DEREF;
581: e1 = e2;
582: e2 = ie;
583: }
584: else { // support old style &b.vf
585: base = MDOT;
586: mem = new expr(DEREF,e2,ie);
587: string2 = "f";
588: i1 = 9;
589: }
590: }
591: else {
592: goto delp;
593: }
594: }
595: break;
596: }
597: }
598: break;
599:
600: case ANDAND:
601: case OROR:
602: Ntmp = 0;
603: // no break
604:
605: default:
606: if (e1) e1->simpl();
607: if (e2) e2->simpl();
608: break;
609:
610: case CM:
611: case G_CM:
612: {
613: Pname n = 0;
614: e1->simpl();
615: e2->simpl();
616: if (e1->base==ICALL && e1->e1==0) n = e1->il->fct_name;
617: if (e2->base==ICALL && e2->e1==0) n = e2->il->fct_name;
618: if (n) error('s',"cannot expand inline void%n called in commaE",n);
619: // no break
620: }
621: case NAME:
622: case DUMMY:
623: case ICON:
624: case FCON:
625: case CCON:
626: case IVAL:
627: // case FVAL:
628: // case LVAL:
629: case STRING:
630: case ZERO:
631: case ILIST:
632: // case MDOT:
633: return;
634: /*
635: case SIZEOF:
636: base = IVAL;
637: i1 = tp2->tsizeof();
638: tp2 = 0; // can't DEL(tp2)
639: break;
640: */
641: case SIZEOF:
642: if (e1) e1->simpl();
643: return;
644:
645: case G_CALL:
646: case CALL:
647: Pcall(this)->simpl();
648: break;
649:
650: case NEW:
651: case GNEW:
652: simpl_new();
653: return;
654:
655: case DELETE:
656: case GDELETE:
657: simpl_delete();
658: break;
659:
660: case QUEST:
661: cond->simpl();
662: Ntmp = 0;
663: e2->simpl();
664: // no break
665:
666: case CAST:
667: case REF:
668: e1->simpl();
669: break;
670:
671: case DOT:
672: e1->simpl();
673: switch (e1->base) {
674: case CM:
675: case G_CM:
676: { // &( , name). => ( ... , &name)->
677: Pexpr ex = e1;
678: cfr:
679: switch (ex->e2->base) {
680: case NAME:
681: base = REF;
682: ex->e2 = ex->e2->address();
683: break;
684: case CM:
685: case G_CM:
686: ex = ex->e2;
687: goto cfr;
688: }
689: }
690: }
691: break;
692:
693: case ASSIGN:
694: {
695: Pfct f = 0;
696: Pexpr th = 0;
697: if ( curr_fct ) {
698: f = Pfct(curr_fct->tp);
699: th = f->f_this;
700: }
701:
702: imeasure++;
703: if (e1) e1->simpl();
704: if (e2) {
705: Pexpr c = e2;
706: c->simpl();
707: while (c->base == CAST) c = c->e1;
708: if (c->base == ILIST) e2 = c;
709:
710: if (e2->base == ILIST) { // pointer to member assignment
711: Pexpr ee = mptr_assign(e1,e2);
712: Pexpr eee = new expr(CM,ee->e2,e1);
713: e1 = ee->e1;
714: e2 = eee;
715: base = CM;
716: delete ee;
717: }
718: }
719:
720: if (th && th==e1 && curr_fct->n_oper==CTOR && init_list) {
721: // this=e2 => (this=e2,init_list)
722: Pclass cl = Pclass(Pbase(Pptr(th->tp)->typ)->b_name->tp);
723: if (cl->c_body == 1) cl->dcl_print(0);
724: imeasure++;
725: base = CM;
726: e1 = new expr(ASSIGN,e1,e2);
727: e2 = init_list;
728: if (warning_opt) // timid
729: error('w',"assignment to ``this'' inK: try defining%t::operator new() instead",f->memof);
730: }
731: break;
732: }
733: }
734:
735: switch (base) {
736: case QUEST:
737: case ANDAND:
738: case OROR:
739: if (Ntmp) error('s',"temporary ofC%n with destructor needed in%kE",Ntmp,base);
740: // no break;
741: default:
742: Ntmp = 0;
743: }
744:
745: if (tp==int_type || tp==defa_type) {
746: Neval = 0;
747: no_sizeof = 1; // do not convert sizeof's to ints
748: long i = eval();
749: no_sizeof = 0;
750: if (Neval == 0) {
751: base = IVAL;
752: i1 = i;
753: }
754: }
755:
756: }
757:
758: Pexpr vptr_entry(Pexpr pp, Pexpr ie, Pclass cl)
759: {
760: Pptr ttemp = pp->tp->is_ptr_or_ref();
761:
762: if (ttemp) {
763: Ptype pt = ttemp->typ; // check if cast pp = (base*)pp
764: Pclass pc = Pclass(pt->is_cl_obj()->tp); // is needed
765: if (pc!=cl) pp = new cast(cl,pp);
766: }
767: Pname vp = find_vptr(cl);
768: if (vp == 0) error('i',"can't find vptr");
769: Pexpr vptr = new ref(REF,pp,vp); // pp->vptr
770: return new expr(DEREF,vptr,ie); // pp->vptr[i]
771: }
772:
773: Pexpr new_this(Pexpr pp, Pexpr ee)
774: {
775: //error('d',"new this");
776: Pexpr dee = new mdot("d",ee); // pp->vptr[i].d
777: dee->i1 = 9;
778: Pexpr nthis = new cast(Pchar_type,pp);
779: nthis = new expr(PLUS,nthis,dee); // ((char*)pp)+delta
780: Ptype ct = pp->tp;
781: if (pp->base==NAME && Pname(pp)->n_xref) ct = pp->tp->addrof();
782: return new cast(ct,nthis);
783: }
784:
785: Pcall vcall(Pexpr pp, Pexpr ie, Pfct f, Pclass cl, Pexpr args)
786: /*
787: generate a call of the virtual function with the index ``ie''
788: and type "f" in class ``cl'' for the object pointed to by ``pp''
789:
790: multiple inheritance virtual call:
791:
792: p->f(x) is resolved like this
793: pp = p; // avoid side effects
794: pp = p.base_object; // often: pp = p;
795: // done when the name was resolved
796: i = index(f);
797: entry = pp->_vtbl[i-1];
798: pp = (T*)(((char*)pp)+entry.d)
799: (*(ftype)entry.f)(pp,x)
800: */
801: {
802: //error('d',"vcall %t",cl);
803: if (cl->c_body==1) cl->dcl_print(0); // look for first use of cl
804:
805: imeasure+=6;
806: Pexpr ee = vptr_entry(pp,ie,cl);
807:
808: Pexpr fee = new mdot("f",ee);
809: fee->i1 = 9;
810: Ptype pft = f->addrof();
811: fee = new cast(pft,fee); // (T)pp->vptr[i].f
812: Pexpr r = new expr(DEREF,fee,0); // *(T)pp->vptr[i].f
813: // e1->tp must be 0, means "argtype encoded"
814: r->tp2 = Ptype(f->f_this); // encode argtype
815:
816: Pexpr nthis = new_this(pp,ee);
817:
818: args = new expr(ELIST,nthis,args);
819: args->simpl();
820:
821: Pcall c = new call(r,args);
822: c->tp = f->returns;
823: return c;
824: }
825:
826: void call::simpl()
827: /*
828: fix member function calls:
829: p->f(x) becomes f(p,x)
830: o.f(x) becomes f(&o,x)
831: or if f is virtual:
832: p->f(x) is resolved like this
833: pp = p;
834: i = index(f);
835: entry = pp->_vtbl[i-1];
836: pp = (T*)(((char*)pp)+entry.i)
837: (*entry.f)(pp,x)
838: replace calls to inline functions by the expanded code
839: */
840: {
841: Pname fn = fct_name;
842: //error('d',"%d call::simpl() fn %n %d e1 %d",this,fn,fn,e1);
843: Pfct f = fn ? Pfct(fn->tp) : 0;
844:
845: if (fn == 0) e1->simpl();
846:
847: if (f) {
848: switch(f->base) {
849: case ANY:
850: return;
851: case OVERLOAD:
852: fct_name = fn = Pgen(f)->fct_list->f;
853: f = Pfct(fn->tp);
854: }
855: }
856:
857: switch (e1->base) {
858: case MEMPTR: // (p ->* q)(args)
859: {
860: Pexpr p = e1->e1;
861: Pexpr q = e1->e2;
862: Pclass cl = Pclass(e1->tp2);
863: Pfct f = Pfct(q->tp->deref());
864:
865: if (e2) e2->simpl();
866:
867: if (f->f_this == 0) { // might not know about ``this'' yet
868: if (f->memof == 0) error('i',"memof missing");
869: Pname tt = new name("this");
870: tt->n_scope = ARG;
871: tt->tp = f->memof->this_type;
872: PERM(tt);
873: // f->f_this = f->f_args = tt;
874: tt->n_list = f->argtype;
875: // f->f_this = tt;
876: tt->n_list = f->f_result ? f->f_result : f->argtype;
877: f->f_this = f->f_args = tt;
878: }
879: //error('d',"f_this %d",f->f_this);
880: extern has_virt(Pclass);
881:
882: // beware of sideeffects:
883: nin = 1;
884: if (q->not_simple()) error('s',"2nd operand of .* too complicated");
885: nin = 0;
886:
887: Pexpr qq = new mdot("f",q); // the function: (*(right type)q.f)
888: qq->i1 = 9;
889: qq = new cast(f->addrof(),qq);
890: Pexpr nc = new expr(DEREF,qq,0);
891: nc->tp2 = Ptype(f->f_this); // encode argtype
892:
893: Pexpr nthis = new_this(p,q); // arguments: (p+q.d,args)
894: Pexpr args = new expr(ELIST,nthis,e2);
895: imeasure+=3;
896:
897: if (has_virt(cl) == 0) { // no virtuals: simple
898: if (cl->defined == 0)
899: error("call throughP toMF before definition ofC %t",cl);
900: //error('d',"no virt");
901: // (p ->* q)(args) => (*q.f)(p+q.d,args)
902: e1 = nc;
903: e2 = args;
904: return;
905: }
906:
907: if (find_vptr(cl) == 0) { // must be a call to a second base
908: // that we cannot handle yet
909: // it is OK not to to generate
910: // a virtual call since a
911: // `sorry' will have been generated
912: // at the point of initialization
913: e1 = nc;
914: e2 = args;
915: return;
916:
917: }
918: // beware of sideeffects:
919: nin = 1;
920: if (p->not_simple()) error('s',"1st operand of .* too complicated");
921: nin = 0;
922:
923: Pexpr c = new mdot("i",q); // condition (q.i<0)
924: c->i1 = 9;
925: c = new expr(LT,c,zero);
926:
927: Pexpr ie = new mdot("i",q);
928: ie->i1 = 9;
929:
930: base = QUEST;
931: e1 = new call(nc,args);
932: e2 = vcall(p,ie,f,cl,e2);
933: cond = c;
934: return;
935: }
936: case DOT:
937: // if e1 is an object and not just a reference
938: // the vtbl need not be used
939: case REF:
940: { Pref r = Pref(e1);
941: Pexpr a1 = r->e1;
942: int obj = r->n_initializer!=0; // if B::f don't use vcall
943:
944: if (obj == 0) { // don't use vcall if we have an object
945: // (not a pointer or a reference)
946: if (e1->base==DOT && a1->base!=DEREF) obj = 1;
947: }
948:
949: //error('d',"fct_name %n f %d %d obj %d",fct_name,f,f->f_virtual,obj);
950: if (f && obj==0 && f->f_virtual) {
951: Pexpr a11 = 0;
952:
953: switch(a1->base) { // see if temporary might be needed
954: case NAME:
955: case MDOT:
956: a11 = a1;
957: break;
958: case REF:
959: case DOT:
960: if (a1->e1->base==NAME
961: || ((a1->e1->base==DOT || a1->e1->base==REF) && a1->e1->e1->base==NAME)) a11 = a1;
962: break;
963: case ADDROF:
964: case G_ADDROF:
965: if (a1->e2->base == NAME
966: || ((a1->e2->base==DOT || a1->e2->base==REF) && a1->e2->e1->base==NAME)) a11 = a1;
967: break;
968: case CAST:
969: switch (a1->e1->base) {
970: case NAME:
971: case MDOT:
972: a11 = a1;
973: }
974: }
975:
976: // if( a1->base==REF && fn->n_oper==DTOR ){
977: // a11 = a1;
978: // goto zsw;
979: // }
980: //
981: if (e1->base == DOT) {
982: // zsw:
983: if (a11) a11 = a11->address();
984: a1 = a1->address();
985: }
986:
987: if (a11 == 0) { // temporary (maybe) needed
988: // e->f() => (t=e,t->f(t))
989: if (a1->base==NAME)
990: a11 = a1; // &*name has become name
991: else {
992: Pname nx = new name(make_name('K'));
993: nx->tp = a1->tp;
994: Pname n = nx->dcl(scope,ARG); // no init!
995: delete nx;
996: Pname cln = a1->tp->is_cl_obj();
997: if (cln) {
998: Pclass cl = Pclass(cln->tp);
999: if (Ntmp==0 && cl->has_dtor()) Ntmp = cln;
1000: if (cl->has_itor()) n->n_xref = 1;
1001: }
1002: n->n_scope = FCT;
1003: n->assign();
1004: a11 = n;
1005: a1 = new expr(ASSIGN,n,a1);
1006: a1->tp = n->tp;
1007: a1->simpl();
1008: Pcall cc = new call(0,0);
1009: *cc = *this;
1010: base = CM;
1011: e1 = a1;
1012: e2 = cc;
1013: this = cc;
1014: }
1015: }
1016:
1017: int i = f->f_virtual;
1018: Pexpr ie = i?new ival(i):0; // index
1019: Pname cn = fn->n_table->t_name;
1020: if (fn
1021: && fn->n_initializer
1022: && cc->nof
1023: && cc->nof->n_oper==CTOR
1024: && Pfct(cc->nof->tp)->memof->c_abstract
1025: && strcmp(Pfct(cc->nof->tp)->memof->string, cn->string) == 0 ) {
1026: // permit x::x( x& xx ) { xx.pvf(); }
1027: Pexpr ee = e1->e1;
1028: while ( ee && ee->base != NAME ) ee = ee->e1;
1029: if ( ee && strcmp( ee->string, "this" )==0)
1030: error("call of pure virtualF%n inK%n",fn,cc->nof);
1031: }
1032: Pcall vc = vcall(a11,ie,f,Pclass(cn->tp),e2);
1033: *this = *vc;
1034: return;
1035: }
1036:
1037: Ptype tt = r->mem->tp;
1038: llp:
1039: //error('d',"llp %t",tt);
1040: switch (tt->base) {
1041: // default: // pointer to function: (n->ptr_mem)(args); do nothing
1042: case TYPE:
1043: tt = Pbase(tt)->b_name->tp;
1044: goto llp;
1045: case OVERLOAD: // n->fctmem(args);
1046: case FCT:
1047: if (fct_name==0) {
1048: // reconstitute fn destroyed to suppress "virtual"
1049: fct_name = fn = Pname(e1->n_initializer);
1050: f = Pfct(fn->tp);
1051: }
1052:
1053: if (e1->base == DOT) a1 = a1->address();
1054: e2 = new expr(ELIST,a1,e2);
1055: e1 = r->mem;
1056: }
1057: }
1058: }
1059:
1060: if (e2) e2->simpl();
1061: //error('d',"fn %n inl %d imes %d",fn,f->f_inline,f->f_imeasure);
1062: if (fn && f->f_inline && debug_opt==0) {
1063: imeasure += f->f_imeasure;
1064: Pclass cl = f->memof;
1065: if (cl && cl->c_body) cl->dcl_print(0);
1066: Ptable oscope = scope;
1067: Pexpr ee = f->expand(fn,scope,e2);
1068: scope = oscope;
1069: if (ee) *Pexpr(this) = *ee;
1070: }
1071: else if (fn && f->f_inline==0 && f->f_imeasure) {
1072: extern void uninline(Pname fn);
1073: uninline(fn);
1074: imeasure += 3;
1075: }
1076: else if (fn && debug_opt && f->f_inline==ITOR) {
1077: extern void expand_itor(Pclass);
1078: expand_itor(f->memof);
1079: }
1080: else
1081: imeasure += 3;
1082: }
1083:
1084: void uninline(Pname fn)
1085: // inline turned static
1086: {
1087: Pfct f = Pfct(fn->tp);
1088: //error('d',"uninline %n %d %d",fn,f->body,f->f_expr);
1089:
1090: if (warning_opt) {
1091: error('w',"%n too complex for inlining",fn);
1092: error('w',"out-of-line copy of %n created",fn);
1093: }
1094: f->f_imeasure = 0; // now it really is just static
1095:
1096: Pstmt s = f->body->s;
1097: // for (s = f->body->s; s; s=s->s_list)
1098: //error('d',"start %d %k",s->e,s->e->base);
1099: // s = f->body->s;
1100: while (s) {
1101: //error('d',"s %k %d %k",s->base,s->e,s->e->base);
1102: if (s->base == SM) {
1103: // turn comma expression into statement list
1104: Pexpr e = s->e;
1105: if (e)
1106: switch (e->base) {
1107: case CM:
1108: case G_CM:
1109: { Pstmt ss = new estmt(SM,no_where,e->e2,0);
1110: s->e = e->e1;
1111: ss->s_list = s->s_list;
1112: s->s_list = ss;
1113: delete e;
1114: continue;
1115: }
1116: }
1117: }
1118: s = s->s_list;
1119: }
1120: // for (s = f->body->s; s; s=s->s_list)
1121: //error('d',"echo %k %d %k",s->base,s->e,s->e->base);
1122:
1123: fn->dcl_print(0);
1124: }
1125:
1126: /*
1127: void ccheck(Pexpr e)
1128:
1129: Is there a conditional in this expression? (not perfect)
1130:
1131: {
1132: //error('d',"ccheck(e %k)",e,e?e->base,0);
1133: if (e)
1134: switch (e->base) {
1135: case QUEST:
1136: case ANDAND:
1137: case OROR:
1138: error('s',"E too complicated: uses%k and needs temporary ofCW destructor",e->base);
1139: break;
1140: case LT:
1141: case LE:
1142: case GT:
1143: case GE:
1144: case EQ:
1145: case NE:
1146: case ASSIGN:
1147: case ASPLUS:
1148: case ASMINUS:
1149: case G_CM:
1150: case CM:
1151: case PLUS:
1152: case MINUS:
1153: case MUL:
1154: case DIV:
1155: case OR:
1156: case ER:
1157: case AND:
1158: case G_CALL:
1159: case CALL:
1160: case ELIST:
1161: case DEREF:
1162: ccheck(e->e1);
1163: case NOT:
1164: case COMPL:
1165: case CAST:
1166: case ADDROF:
1167: case G_ADDROF:
1168: ccheck(e->e2);
1169: break;
1170: case ICALL: // check inlined arguments
1171: { Pin il = e->il;
1172: for (int i = 0; il->args[i].arg && i<il->i_slots; i++) ccheck(il->args[i].arg);
1173: }
1174: }
1175: }
1176: */
1177:
1178: void temp_in_cond(Pexpr ee, Pstmt ss, Ptable tbl)
1179: /*
1180: insert destructor calls 'ss' into condition 'ee'
1181: ee => (Qnn = ee, dtors, Qnn)
1182: */
1183: {
1184: //error('d',"temp_in_cond");
1185: // ccheck(ee);
1186: while (ee->base==CM || ee->base==G_CM) ee = ee->e2;
1187: Ptype ct = ee->tp;
1188: Pname n = new name(make_name('Q')); // int Qnn;
1189: n->tp = ct;
1190: Pname tmp = n->dcl(tbl,ARG);
1191: delete n;
1192: tmp->n_scope = FCT;
1193:
1194: Pexpr v = new expr(0,0,0);
1195: *v = *ee;
1196: PERM(ct);
1197: v = new cast(ct,v);
1198:
1199: tmp->n_assigned_to = 1;
1200: Pexpr c = new expr(ASSIGN,tmp,v); // Qnn = ee
1201: c->tp = ct;
1202: ee->base = CM;
1203: ee->e1 = c;
1204:
1205: Pexpr ex = 0; // add dtors at end
1206:
1207: for (Pstmt sx = ss; sx; sx = sx->s_list) {
1208: if (ex) {
1209: ex = new expr(CM,ex,sx->e);
1210: ex->tp = sx->e->tp;
1211: }
1212: else
1213: ex = sx->e;
1214: }
1215: ee->e2 = new expr(CM,ex,tmp); // add Qnn at end
1216: ee->e2->tp = ct;
1217: }
1218:
1219: bit not_safe(Pexpr e)
1220: {
1221:
1222: switch (e->base) {
1223: default:
1224: return 1;
1225: /*
1226: case CALL:
1227: case G_CALL:
1228: case DOT:
1229: case REF:
1230: case ANAME:
1231: return 1;
1232: */
1233: case NAME:
1234: // if the name is automatic and has a destructor it is not safe
1235: // to destroy it before returning an expression depending on it
1236: { Pname n = Pname(e);
1237: if (n->n_table!=gtbl && n->n_table->t_name==0) {
1238: Pname cn = n->tp->is_cl_obj();
1239: if (cn && Pclass(cn->tp)->has_dtor()) return 1;
1240: }
1241: }
1242: case IVAL:
1243: case ICON:
1244: case CCON:
1245: case FCON:
1246: case STRING:
1247: return 0;
1248: case NOT:
1249: case COMPL:
1250: case ADDROF:
1251: case G_ADDROF:
1252: return not_safe(e->e2);
1253: case DEREF:
1254: // return not_safe(e->e1) || e->e2?not_safe(e->e2):0;
1255: { int i = not_safe(e->e1);
1256: if (i) return i;
1257: if (e->e2) return not_safe(e->e2);
1258: return 0;
1259: }
1260: case CM:
1261: case PLUS:
1262: case MINUS:
1263: case MUL:
1264: case DIV:
1265: case MOD:
1266: case ASSIGN:
1267: case ASPLUS:
1268: case ASMINUS:
1269: case ASMUL:
1270: case ASDIV:
1271: case OR:
1272: case AND:
1273: case OROR:
1274: case ANDAND:
1275: case LT:
1276: case LE:
1277: case GT:
1278: case GE:
1279: case EQ:
1280: case NE:
1281: return not_safe(e->e1) || not_safe(e->e2);
1282: case QUEST:
1283: return not_safe(e->cond) || not_safe(e->e1) || not_safe(e->e2);
1284: }
1285: }
1286:
1287:
1288: Pexpr curr_expr; /* to protect against an inline being expanded twice
1289: in a simple expression keep track of expressions
1290: being simplified
1291: */
1292: Pstmt stmt::simpl()
1293: /*
1294: return a pointer to the last statement in the list, or 0
1295: */
1296: {
1297: if (this == 0) error('i',"0->S::simpl()");
1298: DB( if(Sdebug>=1){
1299: error('d',"%d->stmt::simpl(): %k",this,base);
1300: if(Sdebug>=2) display_stmt(this);
1301: });
1302: //Pstmt ostmt = Cstmt;
1303: //if ( where.line ) Cstmt = this;
1304:
1305: stmtno++;
1306: curr_expr = e;
1307: //error('d',"stmt::simpl %k s_list %d",base,s_list);
1308:
1309: switch (base) {
1310: default:
1311: error('i',"S::simpl(%k)",base);
1312:
1313: case ASM:
1314: break;
1315:
1316: case BREAK:
1317: if (break_del_list) { // break => { _dtor()s; break; }
1318: Pstmt bs = new stmt(base,where,0);
1319: Pstmt dl = break_del_list->copy();
1320: base = BLOCK;
1321: s = new pair(where,dl,bs);
1322: }
1323: break;
1324:
1325: case CONTINUE:
1326: if (continue_del_list) { // continue => { _dtor()s; continue; }
1327: Pstmt bs = new stmt(base,where,0);
1328: Pstmt dl = continue_del_list->copy();
1329: base = BLOCK;
1330: s = new pair(where,dl,bs);
1331: }
1332: break;
1333:
1334: case DEFAULT:
1335: s->simpl();
1336: break;
1337:
1338: case SM:
1339: if (e) {
1340: if (e->base == DEREF) e = e->e1;
1341: e->simpl();
1342: if (e->base == DEREF) e = e->e1;
1343: }
1344: break;
1345:
1346: case RETURN:
1347: { /* return x;
1348: =>
1349: { dtor()s; return x; }
1350: OR (returning an X where X(X&) is defined) =>
1351: { ctor(_result,x); _dtor()s; return; }
1352: OR (where x needs temporaries)
1353: OR (where x might involve an object to be destroyed) =>
1354: { _result = x; _dtor()s; return _result; }
1355: return; =>
1356: { _dtor()s; return; }
1357: OR (in constructors) =>
1358: { _dtor()s; return _this; }
1359: */
1360: Pstmt sx = this;
1361: Pexpr ex = e;
1362:
1363: no_of_returns++;
1364:
1365: Pstmt dl = (del_list) ? del_list->copy() : 0;
1366: Pfct f = Pfct(curr_fct->tp);
1367:
1368: if (e == 0) e = dummy;
1369: if (e==dummy && curr_fct->n_oper==CTOR) e = f->f_this;
1370:
1371:
1372: // need to generate a temporary for mptr return
1373: Pexpr tt = e;
1374: while ( tt->base == CAST )
1375: tt = tt->e1;
1376: if ( tt->base == ILIST )
1377: e = tt;
1378:
1379: if (e->base == ILIST) {
1380: extern Pbase mptr_type;
1381: extern Ptype Pvptr_type;
1382: Pexpr mptr_assign(Pexpr, Pexpr);
1383: // memptr constant
1384: // return({1,2,f}) ==> memptr t; return((t={1,2,f},&t))
1385:
1386: Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
1387: Pname temp = make_tmp('A',mptr_type,ftbl);
1388:
1389: // placed in mptr_assign()
1390: // temp->use(); // necessary for inlines to force declaration
1391:
1392: e = mptr_assign(temp,e);
1393: e = new expr(G_CM,e,temp);
1394: e->tp = mptr_type;
1395: }
1396:
1397: if (f->f_result) { // ctor(_result,x); dtors; return;
1398: if (e->base == G_CM) e = replace_temp(e,f->f_result);
1399: e->simpl();
1400: Pstmt cs = new estmt(SM,where,e,0);
1401: if (dl) cs = new pair(where,cs,dl);
1402: base = PAIR;
1403: s = cs;
1404: s2 = new estmt(RETURN,where,0,0);
1405: //#ifdef RETBUG
1406: // s2->empty = 1; // fudge to bypass C bug (see print.c)
1407: // s2->ret_tp = ret_tp;
1408: //#endif
1409: }
1410: else { // dtors; return e;
1411: e->simpl();
1412: if (dl) {
1413: if (e!=dummy && not_safe(e)) {
1414: // { _result = x; _dtor()s; return _result; }
1415: Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
1416:
1417: Pname r = ftbl->look("_result",0);
1418: if (r == 0) {
1419: r = new name("_result");
1420: r->tp = ret_tp;
1421: Pname rn = r->dcl(ftbl,ARG);
1422: rn->n_scope = FCT;
1423: rn->where = no_where;
1424: rn->assign();
1425: delete r;
1426: r = rn;
1427: }
1428: Pexpr as = new expr(ASSIGN,r,e);
1429: as->tp = ret_tp; // wrong if = overloaded, but then X(X&) ought to have been used
1430: Pstmt cs = new estmt(SM,where,as,0);
1431: cs = new pair(where,cs,dl);
1432: base = PAIR;
1433: s = cs;
1434: s2 = new estmt(RETURN,where,r,0);
1435: // s2->ret_tp = ret_tp;
1436: }
1437: else { // { _dtor()s; return x; }
1438: base = PAIR;
1439: s = dl;
1440: s2 = new estmt(RETURN,where,e,0);
1441: }
1442: s2->ret_tp = ret_tp;
1443: }
1444: }
1445:
1446: // if (sx->memtbl) {
1447: // int i;
1448: // for (Pname n=sx->memtbl->get_mem(i=1); n; n=sx->memtbl->get_mem(++i)) {
1449: // Pname cn = n->tp->is_cl_obj();
1450: // if (cn && Pclass(cn->tp)->has_dtor()) {
1451: // ccheck(ex);
1452: // break;
1453: // }
1454: // }
1455: // }
1456: break;
1457: }
1458:
1459: case WHILE:
1460: case DO:
1461: e->simpl();
1462: { Pstmt obl = break_del_list;
1463: Pstmt ocl = continue_del_list;
1464: break_del_list = 0;
1465: continue_del_list = 0;
1466: s->simpl();
1467: break_del_list = obl;
1468: continue_del_list = ocl;
1469: }
1470: break;
1471:
1472: case SWITCH:
1473: e->simpl();
1474: { Pstmt obl = break_del_list;
1475: break_del_list = 0;
1476: s->simpl();
1477: break_del_list = obl;
1478: }
1479: switch (s->base) {
1480: case DEFAULT:
1481: case LABEL:
1482: case CASE:
1483: break;
1484: case BLOCK:
1485: if (s->s)
1486: switch (s->s->base) {
1487: case BREAK: // to cope with #define Case break; case
1488: case CASE:
1489: case LABEL:
1490: case DEFAULT:
1491: break;
1492: default:
1493: goto df;
1494: }
1495: break;
1496: default:
1497: df:
1498: error(&s->where,"S orIdE not reached: (case label missing?)");
1499: }
1500: break;
1501:
1502: case CASE:
1503: e->simpl();
1504: s->simpl();
1505: break;
1506:
1507: case LABEL:
1508: if (del_list) error('s',"label in blockW destructors");
1509: s->simpl();
1510: break;
1511:
1512: case GOTO:
1513: /* If the goto is going to a different (effective) scope,
1514: then it is necessary to activate all relevant destructors
1515: on the way out of nested scopes, and issue errors if there
1516: are any constructors on the way into the target.
1517:
1518: Only bother if the goto and label have different effective
1519: scopes. (If mem table of goto == mem table of label, then
1520: they're in the same scope for all practical purposes.
1521: */
1522: {
1523: Pname n = scope->look( d->string, LABEL );
1524: if (n == 0) error('i',&where,"label%n missing",d);
1525: if(n->n_realscope!=scope && n->n_assigned_to) {
1526:
1527: /* Find the root of the smallest subtree containing
1528: the path of the goto. This algorithm is quadratic
1529: only if the goto is to an inner or unrelated scope.
1530: */
1531:
1532: Ptable r = 0;
1533:
1534: for(Ptable q=n->n_realscope; q!=gtbl; q=q->next) {
1535: for( Ptable p = scope; p != gtbl; p = p->next ) {
1536: if( p==q ) {
1537: r = p; // found root of subtree!
1538: goto xyzzy;
1539: }
1540: }
1541: }
1542:
1543: xyzzy: if( r==0 ) error( 'i',&where,"finding root of subtree" );
1544:
1545: /* At this point, r = root of subtree, n->n_realscope
1546: * = mem table of label, and scope = mem table of goto. */
1547:
1548: /* Climb the tree from the label mem table to the table
1549: * preceding the root of the subtree, looking for
1550: * initializers and ctors. If the mem table "belongs"
1551: * to an unsimplified block(s), the n_initializer field
1552: * indicates presence of initializer, otherwise initializer
1553: * information is recorded in the init_stat field of
1554: * mem table. */
1555:
1556: for( Ptable p=n->n_realscope; p!=r; p=p->next )
1557: if( p->init_stat == 2 ) {
1558: error(&where,"goto%n pastDWIr",d);
1559: goto plugh; /* avoid multiple error msgs */
1560: }
1561: else if( p->init_stat == 0 ) {
1562: int i;
1563: for(Pname nn=p->get_mem(i=1);nn;nn=p->get_mem(++i))
1564: if(nn->n_initializer||nn->n_evaluated){
1565: error(&nn->where,"goto%n pastId%n",d,nn);
1566: goto plugh;
1567: }
1568: }
1569: plugh:
1570:
1571: /* Proceed in a similar manner from the point of the goto,
1572: * generating the code to activate dtors before the goto. */
1573: /* There is a bug in this code. If there are class objects
1574: * of the same name and type in (of course) different mem
1575: * tables on the path to the root of the subtree from the
1576: * goto, then the innermost object's dtor will be activated
1577: * more than once. */
1578:
1579: {
1580: Pstmt dd = 0, ddt = 0;
1581:
1582: for( Ptable p=scope; p!=r; p=p->next ) {
1583: int i;
1584: for(Pname n=p->get_mem(i=1);n;n=p->get_mem(++i)) {
1585: Pname cln;
1586: if (n->tp == 0) continue; /* label */
1587:
1588: if ( cln=n->tp->is_cl_obj() ) {
1589: Pclass cl = (Pclass)cln->tp;
1590: Pname d = cl->has_dtor();
1591:
1592: if (d) { /* n->cl::~cl(0); */
1593: Pexpr dl = call_dtor(n,d,0,DOT,one);
1594: Pstmt dls = new estmt(SM,n->where,dl,0);
1595: if (dd)
1596: ddt->s_list = dls;
1597: else
1598: dd = dls;
1599: ddt = dls;
1600: }
1601:
1602: }
1603: else if (cl_obj_vec) {
1604: Pclass cl = (Pclass)cl_obj_vec->tp;
1605: // Pname c = cl->has_ictor();
1606: Pname d = cl->has_dtor();
1607:
1608: if (d) { // __vec_delete(vec,noe,sz,dtor,0);
1609: Pfct f = Pfct(d->tp);
1610: int i = 0;
1611: for (Pname nn = f->f_args->n_list;
1612: nn && nn->n_list; nn=nn->n_list) i++;
1613: Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
1614: Pstmt dls = new estmt(SM,n->where,a,0);
1615: if (dd)
1616: ddt->s_list = dls;
1617: else
1618: dd = dls;
1619: ddt = dls;
1620: }
1621: }
1622: } /* end mem table scan */
1623: } /* end dtor loop */
1624:
1625: /* "activate" the list of dtors obtained. */
1626:
1627: if( dd ) {
1628: dd->simpl();
1629: Pstmt bs = new stmt( base, where, 0 );
1630: *bs = *this;
1631: base = PAIR;
1632: s = dd;
1633: s2 = bs;
1634: }
1635: }
1636: } /* end special case for non-local goto */
1637: }
1638: break;
1639:
1640: case IF:
1641: e->simpl();
1642: s->simpl();
1643: if (else_stmt) else_stmt->simpl();
1644: break;
1645:
1646: case FOR: // "for (s;e;e2) s2; => "s; for(;e,e2) s2"
1647: if (for_init) for_init->simpl();
1648: if (e) {
1649: curr_expr = e;
1650: e->simpl();
1651: }
1652: if (e2) {
1653: curr_expr = e2;
1654: e2->simpl();
1655: if (e2->base==ICALL)
1656: if (e2->e1 == 0) error('s',"cannot expand inline void%n called in forE", e2->il->fct_name);
1657: }
1658: { Pstmt obl = break_del_list;
1659: Pstmt ocl = continue_del_list;
1660: break_del_list = 0;
1661: continue_del_list = 0;
1662: s->simpl();
1663: break_del_list = obl;
1664: continue_del_list = ocl;
1665: }
1666: break;
1667:
1668: case BLOCK:
1669: Pblock(this)->simpl();
1670: break;
1671:
1672: case PAIR:
1673: break;
1674: }
1675:
1676: /*if (s) s->simpl();*/
1677: //error('d',"base %k memtbl %d",base,memtbl);
1678: if (base!=BLOCK && memtbl) {
1679: Pstmt t1 = (s_list) ? s_list->simpl() : 0;
1680: Pstmt tpx = t1 ? t1 : this;
1681:
1682: Pstmt ss = 0;
1683: Pname cln; // used for warnings
1684: int i;
1685: Pname tn = memtbl->get_mem(i=1);
1686: for (; tn; tn=memtbl->get_mem(++i)) {
1687: if (cln = tn->tp->is_cl_obj()) {
1688: Pname d = Pclass(cln->tp)->has_dtor();
1689: if (d) { /* n->cl::~cl(0); */
1690: Pexpr dl = call_dtor(tn,d,0,DOT,one);
1691: Pstmt dls = new estmt(SM,tn->where,dl,0);
1692: dls->s_list = ss;
1693: ss = dls;
1694: }
1695: }
1696: }
1697:
1698: if (ss) {
1699: Pstmt t2 = ss->simpl();
1700:
1701: switch (base) {
1702: case IF:
1703: case WHILE:
1704: case DO:
1705: case SWITCH:
1706: temp_in_cond(e,ss,memtbl);
1707: break;
1708:
1709: case PAIR: // can hide a return
1710: { Pstmt ts = s2;
1711: while (ts->base==PAIR) ts = ts->s2;
1712: if (ts->base == RETURN) { // sordid
1713: this = ts;
1714: goto retu;
1715: }
1716: goto def;
1717: }
1718: case RETURN:
1719: retu:
1720: {
1721: if (e == 0) {
1722: // return; dtors; => dtors; return;
1723: Pstmt rs = new estmt(RETURN,where,0,0);
1724: //rs->empty = empty; // BSD fudge
1725: rs->ret_tp = ret_tp;
1726: base = PAIR;
1727: s = ss;
1728: s2 = rs;
1729: //Cstmt = ostmt;
1730: return t1 ? t1 : rs;
1731: }
1732:
1733: Pname cln = e->tp->is_cl_obj();
1734: if (cln==0
1735: || Pclass(cln->tp)->has_oper(ASSIGN)==0) {
1736: // ... return e; dtors; =>
1737: // ... X r; ... r = e; dtors; return r;
1738: Pname rv = new name("_rresult"); // NOT "_result"
1739: rv->tp = ret_tp /* e->tp */;
1740: if (memtbl == 0) memtbl = new table(4,0,0);
1741: Pname n = rv->dcl(memtbl,ARG);
1742: n->where = no_where;
1743: n->n_scope = FCT;
1744: n->n_assigned_to = 1;
1745: delete rv;
1746: Pstmt rs = new estmt(RETURN,where,n,0);
1747: rs->ret_tp = ret_tp;
1748: base = SM;
1749: e = new expr(ASSIGN,n,e);
1750: e->tp = n->tp;
1751: Pstmt ps = new pair(where,ss,rs);
1752: ps->s_list = s_list;
1753: s_list = ps;
1754: //Cstmt = ostmt;
1755: return t1 ? t1 : rs;
1756: }
1757: }
1758:
1759: case FOR: // don't know which expression the temp comes from
1760: error('s',&where,"E in %kS needs temporary ofC%nW destructor",base,cln);
1761: break;
1762:
1763: case SM: // place dtors after all "converted" DCLs
1764: if (t1) {
1765: // ccheck(e);
1766: for (Pstmt ttt, tt=this;
1767: (ttt=tt->s_list) && ttt->base==SM;
1768: tt = ttt) ;
1769: t2->s_list = ttt;
1770: tt->s_list = ss;
1771: //Cstmt = ostmt;
1772: return t1!=tt ? t1 : t2;
1773: }
1774: default:
1775: def:
1776: // if (e) ccheck(e);
1777: if (t1) { // t1 == tail of statment list
1778: t2->s_list = s_list;
1779: s_list = ss;
1780: //Cstmt = ostmt;
1781: return t1;
1782: }
1783: s_list = ss;
1784: //Cstmt = ostmt;
1785: return t2;
1786: }
1787: }
1788: //Cstmt = ostmt;
1789: return (t1) ? t1 : this;
1790: }
1791:
1792: //Cstmt = ostmt;
1793: return (s_list) ? s_list->simpl() : this;
1794: }
1795:
1796: Pstmt stmt::copy()
1797: // now handles dtors in the expression of an IF stmt
1798: // not general!
1799: {
1800: Pstmt ns = new stmt(0,curloc,0);
1801:
1802: *ns = *this;
1803: if (s) ns->s = s->copy();
1804: if (s_list) ns->s_list = s_list->copy();
1805:
1806: switch (base) {
1807: case PAIR:
1808: ns->s2 = s2->copy();
1809: break;
1810: }
1811:
1812: return ns;
1813: }
1814:
1815: Pname overFound = 0;
1816:
1817: static Pexpr
1818: mk_new_with_args( Pexpr pe, Ptype tt, Pclass cl, Pexpr vec = 0 )
1819: { // allocate using operator new(sizeof(cl),args1)
1820: Pexpr p;
1821: Pexpr args = pe->e2;
1822:
1823: // Pexpr ce = new texpr(SIZEOF,tt,0);
1824: Pexpr ce;
1825: if (vec)
1826: ce = vec;
1827: else ce = new texpr(SIZEOF,tt,0);
1828:
1829: (void) tt->tsizeof();
1830: ce->tp = size_t_type;
1831: args = new expr(ELIST,ce,args);
1832: char* s = oper_name(NEW);
1833: Pname n = new name(s);
1834: if (pe->base == GNEW) // ::new
1835: p = gtbl->look(s,0);
1836: else
1837: p = find_name(n,cl,scope,CALL,curr_fct);
1838: p = new call(p,args);
1839: overFound=0; // set in call_fct
1840: (void) p->call_fct(cl->memtbl);
1841: if (overFound && overFound->n_scope != EXTERN)
1842: check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
1843: overFound=0;
1844: return p;
1845: }
1846:
1847: void expr::simpl_new()
1848: /*
1849: change NEW or GNEW node to CALL node
1850: */
1851: {
1852: Pname cln;
1853: Pname ctor;
1854: int sz = 1;
1855: // int esz;
1856: Pexpr var_expr = 0;
1857: Pexpr const_expr = 0;
1858: Ptype tt = tp2;
1859: Pexpr arg;
1860: Pexpr szof;
1861: Pname nf;
1862: Pexpr init = e1;
1863:
1864: if (init && init->base) init = 0; // only non-ctor init
1865: // error('d',"simpl_new %k e1 %k e2 %k init %k",base, e1?e1->base:0,e2?e2->base:0,init?init->base:0);
1866:
1867: if ((cln=tt->is_cl_obj()) && init == 0) {
1868: Pclass cl = Pclass(cln->tp);
1869: Pexpr p;
1870: ctor=cl->has_ctor();
1871: // error('d',"cl %t ctor %n",cl, ctor);
1872: if (e2 // placement
1873: || ctor==0 // no constructor
1874: || ctor->n_table!=cl->memtbl // inherited constructor???
1875: || (base==GNEW && cl->has_oper(NEW)) )
1876: p = mk_new_with_args( this, tt, cl ); // new(sizeof(cl),args1)
1877: else {
1878: p = zero; // 0->ctor(args)
1879: // check visibility anyway...
1880: (void)mk_new_with_args(this,tt,cl);
1881: }
1882:
1883: if (ctor) {
1884: Pexpr c = e1; // ctor call generated in expr::typ
1885: Ptype ttt = tp;
1886: c->e1->e1 = p; // p->ctor
1887: c->simpl();
1888: *this = *c;
1889: tp = ttt;
1890: delete c;
1891: }
1892: else { // (tp)new(args)
1893: base = CAST;
1894: tp2 = tp;
1895: e1 = p;
1896: e2 = 0;
1897: simpl();
1898: }
1899: return;
1900: } else if ( cln ) {
1901: Pclass cl = Pclass(cln->tp);
1902: // check visibility anyway...
1903: (void)mk_new_with_args(this,tt,cl);
1904: }
1905:
1906: Pclass covn = 0;
1907: if (cl_obj_vec) {
1908: covn = Pclass(cl_obj_vec->tp);
1909: ctor = covn->has_ictor();
1910: if (ctor == 0) {
1911: if (covn->has_ctor()) error("new %s[], no defaultK",covn->string);
1912: cl_obj_vec = 0;
1913: }
1914: }
1915:
1916: xxx:
1917: //error('d',"xxx %t",tt);
1918: switch (tt->base) {
1919: case TYPE:
1920: tt = Pbase(tt)->b_name->tp;
1921: goto xxx;
1922:
1923: default:
1924: (void) tt->tsizeof();
1925: szof = new texpr(SIZEOF,tt,0);
1926: szof->tp = uint_type;
1927: break;
1928:
1929: case VEC:
1930: { Pvec v = Pvec(tt);
1931: //error('d',"v %d %d",v->size,v->dim);
1932: if (v->size)
1933: sz *= v->size;
1934: else if (v->dim)
1935: var_expr = v->dim;
1936: else
1937: sz = 0;
1938: tt = v->typ;
1939: goto xxx;
1940: }
1941: }
1942:
1943: if (cl_obj_vec) { // _vec_new(0,no_of_elements,element_size,ctor)
1944: const_expr = new ival(sz);
1945: Pexpr noe = (var_expr) ? (sz!=1) ? new expr(MUL,const_expr,var_expr) : var_expr : const_expr;
1946: const_expr = szof;
1947: const_expr->tp = uint_type;
1948: base = CALL;
1949: arg = new expr(ELIST,ctor,0);
1950: /*ctor->take_addr();*/
1951: ctor->lval(ADDROF);
1952: Pexpr sub=0;
1953: if (e2 && e2->e1 &&
1954: e2->e1->tp &&
1955: e2->e1->tp->base != PTR )
1956: { // new(size_t, args)
1957: Pexpr vec_sz = new expr(MUL, noe, const_expr);
1958: sub = mk_new_with_args( this, tt, covn, vec_sz );
1959: }
1960: arg = new expr(ELIST,const_expr,arg);
1961: arg = new expr(ELIST,noe,arg);
1962: // arg = new expr(ELIST,e2?e2:zero,arg); // may be preallocated
1963: arg = new expr(ELIST,e2?(sub?sub:e2):zero,arg); // may be preallocated
1964: base = CAST;
1965: tp2 = tp;
1966: e1 = new expr(G_CALL,vec_new_fct,arg);
1967: e1->fct_name = vec_new_fct;
1968: e1->tp = Pfct(vec_new_fct->tp)->returns;
1969: simpl();
1970: return;
1971: }
1972:
1973: /* call _new(element_size*no_of_elements) */
1974: //error('d',"sz %d var %d",sz,var_expr);
1975: if (sz == 1)
1976: arg = (var_expr) ? new expr(MUL,szof,var_expr) : szof;
1977: else {
1978: const_expr = new ival(sz);
1979: const_expr->tp = uint_type;
1980: const_expr = new expr(MUL,const_expr,szof);
1981: const_expr->tp = uint_type;
1982: arg = (var_expr) ? new expr(MUL,const_expr,var_expr) : const_expr;
1983: }
1984:
1985: arg->tp = uint_type;
1986: base = CAST;
1987: tp2 = tp;
1988: arg = new expr(ELIST,arg,e2);
1989: nf = gtbl->look(oper_name(NEW),0); // always global,
1990: // all class object handled above
1991: e1 = new expr(G_CALL,nf,arg);
1992: (void) e1->call_fct(gtbl);
1993: simpl();
1994:
1995: if (init) { // alloc(sz) => (p=alloc(sz),*p=init,p);
1996: Pexpr p = init->e1;
1997: Pexpr ee = new expr(0,0,0);
1998: *ee = *this;
1999: ee = new expr(ASSIGN,p,ee); // ee: p = alloc(sz);
2000: init->base = ASSIGN;
2001: init->e1 = p->contents(); // init: *p = init_val
2002: ee = new expr(CM,ee,init);
2003: ee->simpl();
2004: base = CM;
2005: e1 = ee;
2006: e2 = p;
2007: }
2008: }
2009:
2010: void expr::simpl_delete()
2011: /*
2012: delete p => _delete(p);
2013: or cl::~cl(p,1);
2014: delete[s]p => _delete(p);
2015: or vec_del_fct(p,vec_sz,elem_sz,~cl,1);
2016: */
2017: {
2018: for (Ptype tt = e1->tp; tt->base==TYPE; tt=Pbase(tt)->b_name->tp);
2019: tt = Pptr(tt)->typ;
2020: //error('d',"simpl_delete() %t",e1->tp);
2021: Pname cln = tt->is_cl_obj();
2022: Pname n;
2023: Pclass cl;
2024:
2025: if (cln) {
2026: cl = Pclass(cln->tp);
2027: if ((cl->defined&DEFINED) == 0) error('w',"delete%t (%t not defined)",cl,cl);
2028: }
2029: else
2030: cl = 0;
2031:
2032: if (cl && (n=cl->has_dtor())) { // ~cl() might be virtual
2033: //xxx check for private/protected op delete
2034: {
2035: Pexpr ee = new expr(ELIST,e1,0);
2036: char* s = oper_name(DELETE);
2037: Pname n;
2038: //error('d',"%s( %k )",s,e1->base);
2039: if (base!=GDELETE) {
2040: n = new name(s);
2041: n = (Pname)find_name(n,cl,scope,CALL,curr_fct);
2042: //error('d',"found%n %t",n,n->tp);
2043: if (n->tp->base==OVERLOAD
2044: || Pfct(n->tp)->nargs==2) {
2045: Pexpr ss = new texpr(SIZEOF,cl,0);
2046: ss->tp = size_t_type;
2047: ee->e2 = new expr(ELIST,ss,0);
2048: }
2049: }
2050: else
2051: n = gtbl->look(s,0);
2052: //error('d',"found%n %t",n,n->tp);
2053: ee = new call(n,ee);
2054: ee->base = G_CALL;
2055: //error('d',"delete..."); display_expr(ee);
2056: // following commented out to avoid typ::checking problems
2057: //overFound=0; // set in call_fct
2058: //(void) ee->call_fct(cl->memtbl);
2059: //if (overFound && overFound->n_scope != EXTERN)
2060: //check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
2061: //overFound=0;
2062: }
2063:
2064: //if ( base!=GDELETE ) (void) cl->has_oper(DELETE);
2065:
2066: if(base==GDELETE && e2==0 || Pfct(n->tp)->f_virtual) { // may need temp
2067: nin=1;
2068: int needtemp = e1->not_simple();
2069: nin=0;
2070: if(needtemp) {
2071: // convert: delete [e2] e1
2072: // to: (T=e1), delete [e2] T
2073: // where T is a new temporary.
2074: Pname tnx = new name(make_name('K'));
2075: tnx->tp = e1->tp;
2076: Pname tn = tnx->dcl(scope,FCT);
2077: delete tnx;
2078: tn->assign();
2079: e1 = new expr(ASSIGN,tn,e1);
2080: e2 = new expr(base,tn,e2);
2081: base=CM;
2082:
2083: simpl();
2084: return;
2085: }
2086: }
2087: Pexpr r = e1;
2088:
2089: // handle delete p, where p has a private destructor
2090: if (n->n_scope != PUBLIC) check_visibility(n,0,cl,cc->ftbl,cc->nof);
2091: //error('d',"e2 %d %k",e2,base);
2092: if (e2 == 0) { // e1->cl::~cl(1)
2093: Pexpr ee = call_dtor(r,n,base==GDELETE?0:one,REF,one);
2094: if (Pfct(n->tp)->f_virtual) {
2095: if (ansi_opt) { // q?void:int would be an error
2096: ee = new expr(G_CM,ee,zero);
2097: ee->tp = zero_type;
2098: }
2099: ee = new expr(QUEST,ee,zero);
2100: ee->tp = ee->e1->tp;
2101: ee->cond = r;
2102: }
2103: if (base == GDELETE) {
2104: char* s = oper_name(DELETE);
2105: Pexpr p = gtbl->look(s,0);
2106: e2 = new call(p,new expr(ELIST,e1,0));
2107: base = CM;
2108: e1 = ee;
2109: }
2110: else {
2111: *this = *ee;
2112: delete ee;
2113: }
2114: simpl();
2115: return;
2116: }
2117: else { // del_cl_vec(e1,e2,elem_size,~cl,1);
2118: Pexpr sz = new texpr(SIZEOF,tt,0);
2119: (void)tt->tsizeof();
2120: Pfct f = Pfct(n->tp);
2121: int i = 0;
2122: Pname nn = f->f_args->n_list;
2123: for (; nn && nn->n_list; nn=nn->n_list) i++;
2124: //error('d',"n %n i %d",n,i);
2125: Pexpr arg = new ival(i);
2126: sz->tp = uint_type;
2127: // Pexpr arg = one;
2128: arg = new expr(ELIST,one,arg);
2129: if (Pfct(n->tp)->f_virtual) {
2130: Pexpr a = new ref(REF,e1,n);
2131: a = a->address();
2132: a = new mdot( "f", a );
2133: a->i1 = 9;
2134: arg = new expr(ELIST,a,arg);
2135: }
2136: else {
2137: arg = new expr(ELIST,n,arg);
2138: n->lval(ADDROF); // n->take_addr();
2139: }
2140:
2141: arg = new expr(ELIST,sz,arg);
2142: if (e2->base==DUMMY) {
2143: e2 = new ival(-1); // handle `delete[]p'
2144: }
2145:
2146: arg = new expr(ELIST,e2,arg);
2147: arg = new expr(ELIST,e1,arg);
2148: Pexpr ee = new expr(G_CALL,vec_del_fct,arg);
2149: ee->fct_name = vec_del_fct;
2150: ee->tp = tp;
2151: // if (ansi_opt) { // q?void:int would be an error
2152: // ee = new expr(G_CM,ee,zero);
2153: // ee->tp = zero_type;
2154: // }
2155: // ee = new expr(QUEST,ee,zero);
2156: // ee->tp = tp;
2157: // ee->cond = r;
2158: *this = *ee;
2159: simpl();
2160: return;
2161: }
2162: }
2163: else if (cl_obj_vec) {
2164: error("delete array of arrays");
2165: }
2166: else { // _delete(e1)
2167: Pexpr ee = new expr(ELIST,e1,0);
2168: char* s = oper_name(DELETE);
2169: if (cl && base!=GDELETE) {
2170: Pname n = new name(s);
2171: e1 = find_name(n,cl,scope,CALL,curr_fct);
2172: if (e1->tp->base==OVERLOAD || Pfct(e1->tp)->nargs==2) {
2173: Pexpr ss = new texpr(SIZEOF,cl,0);
2174: ss->tp = size_t_type;
2175: ee->e2 = new expr(ELIST,ss,0);
2176: }
2177: }
2178: else
2179: e1 = gtbl->look(s,0);
2180: base = G_CALL;
2181: e2 = ee;
2182: overFound=0; // set in call_fct
2183: (void) call_fct(scope);
2184: if (overFound && overFound->n_scope != EXTERN)
2185: check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
2186: overFound=0;
2187: }
2188:
2189: Pcall(this)->simpl();
2190: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.