Annotation of researchv10no/cmd/cfront/ooptcfront/simpl.c, revision 1.1.1.1

1.1       root        1: /*ident        "@(#)ctrans:src/simpl.c 1.5.4.25" */
                      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 rigths Reserved
                      8:        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.
                      9: 
                     10: simpl.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: 
                     31: Pname new_fct;
                     32: Pname del_fct;
                     33: Pname vec_new_fct;
                     34: Pname vec_del_fct;
                     35: 
                     36: Pstmt del_list;
                     37: Pstmt break_del_list;
                     38: Pstmt continue_del_list;
                     39: 
                     40: //bit not_inl; // is the current function an inline?
                     41: Pname curr_fct;        // current function
                     42: Pexpr init_list;
                     43: Pexpr one;
                     44: 
                     45: Ptype Pfct_type;
                     46: Ptype Pvptr_type;
                     47: Pbase mptr_type;
                     48: Ptype size_t_type;
                     49: 
                     50: Pexpr cdvec(Pname f, Pexpr vec, Pclass cl, Pname cd, int,Pexpr);
                     51: Pstmt trim_tail(Pstmt tt);
                     52: Pname find_vptr(Pclass);
                     53: char *get_classname(char*);
                     54: char *drop_classname(char*);
                     55: loc no_where;  // 0,0
                     56: 
                     57: int imeasure;  // a counter trying to measure the complexity of a function
                     58:                // body to try to avoid expanding ``monster'' inlines.
                     59: 
                     60: extern Pexpr initialize_vptrs (Pclass cl, Pexpr this_expr);
                     61: 
                     62:     /* Constructs an expression which initializes the given class's vptrs.
                     63:        The this_expr forms the first part of the path expression for each
                     64:        vptr assignment. The vptr assignments are combined into a comma
                     65:        expression. */
                     66:        
                     67: 
                     68: static Pclass topclass;
                     69: 
                     70: void simpl_init()
                     71: {
                     72:        char* ns = oper_name(NEW);
                     73:        char* ds = oper_name(DELETE);
                     74: 
                     75:        size_t_type = Pvoid_type->tsizeof()>uint_type->tsizeof()?ulong_type:uint_type;
                     76: 
                     77:        Pname nw = new name(ns);
                     78:        nw->n_oper = NEW;
                     79:        Pname a = new name;
                     80:        a->tp = size_t_type;
                     81:        nw->tp = new fct(Pvoid_type,a,1);
                     82:        new_fct = nw->dcl(gtbl,EXTERN); // void* operator new(long);
                     83:        delete nw;
                     84:  //    new_fct->use();
                     85: 
                     86:        Pname dl = new name(ds);
                     87:        dl->n_oper = DELETE;
                     88:        a = new name;
                     89:        a->tp = Pvoid_type;
                     90:        dl->tp = new fct(void_type,a,1);
                     91:        del_fct = dl->dcl(gtbl,EXTERN);
                     92:        delete dl;
                     93:  //    del_fct->use();
                     94: 
                     95: 
                     96:        Pname vn = new name("__vec_new");
                     97:        Pname vd = new name("__vec_delete");
                     98: 
                     99:        a = new name;
                    100:        a->tp = Pvoid_type;
                    101:        Pname al = a;
                    102:        a = new name;
                    103:        a->tp = int_type;
                    104:        a->n_list = al;
                    105:        al = a;
                    106:        a = new name;
                    107:        a->tp = int_type;
                    108:        a->n_list = al;
                    109:        al = a;
                    110:        a = new name;   
                    111:        a->tp = Pvoid_type;
                    112:        a->n_list = al;
                    113:        al = a;                         /* (Pvoid, int, int, Pvoid) */
                    114: 
                    115:        vec_new_fct = gtbl->insert(vn,0);
                    116:        delete vn;
                    117:        vec_new_fct->tp = new fct(Pvoid_type,al,1);
                    118:        vec_new_fct->n_scope = EXTERN;
                    119:        PERM(vec_new_fct);
                    120:        PERM(vec_new_fct->tp);
                    121:        vec_new_fct->use();
                    122: 
                    123:         vec_new_fct->dcl_print(0);
                    124: 
                    125:        a = new name;
                    126:        a->tp = int_type;
                    127:        al = a;
                    128:        a = new name;
                    129:        a->tp = int_type;
                    130:        a->n_list = al;
                    131:        al = a;
                    132:        a = new name;
                    133:        a->tp = Pvoid_type;
                    134:        a->n_list = al;
                    135:        al = a;
                    136:        a = new name;
                    137:        a->tp = int_type;
                    138:        a->n_list = al;
                    139:        al = a;
                    140:        a = new name;
                    141:        a->tp = int_type;
                    142:        a->n_list = al;
                    143:        al = a;
                    144:        a = new name;   
                    145:        a->tp = Pvoid_type;
                    146:        a->n_list = al;
                    147:        al = a;                         /* (Pvoid, int, int, Pvoid, int, int) */
                    148: 
                    149:        vec_del_fct = gtbl->insert(vd,0);
                    150:        delete vd;
                    151:        vec_del_fct->tp = new fct(void_type,al,1);
                    152:        vec_del_fct->n_scope = EXTERN;
                    153:        PERM(vec_del_fct);
                    154:        PERM(vec_del_fct->tp);
                    155:        vec_del_fct->use();
                    156: 
                    157:         vec_del_fct->dcl_print(0);
                    158: 
                    159:        one = new ival(1);
                    160:        one->tp = int_type;
                    161:        PERM(one);
                    162:        
                    163:        Pfct_type = new fct(int_type,0,1);      // int (*)()
                    164:        Pfct_type = Pfct_type->addrof();
                    165:        PERM(Pfct_type);
                    166: 
                    167:         putstring("typedef int (*__vptp)();\n");
                    168:         putstring("struct __mptr {short d; short i; __vptp f; };\n");
                    169: 
                    170:        Pname b = new name("__mptr");
                    171:         b->tp = new classdef(STRUCT);
                    172:         b->tp->defined = 1;
                    173:         Pclass(b->tp)->obj_size = 8;
                    174:        mptr_type = new basetype(COBJ,b);
                    175:        PERM(mptr_type);
                    176: 
                    177:        Pvptr_type = mptr_type->addrof();
                    178:        PERM(Pvptr_type);
                    179: }
                    180: 
                    181: Ptable scope;          /* current scope for simpl() */
                    182: Pname expand_fn;       /* name of function being expanded or 0 */
                    183: Ptable expand_tbl;     /* scope for inline function variables */
                    184: 
                    185: Pname classdef::has_oper(TOK op)
                    186: {
                    187:        Pexpr n = find_name(oper_name(op),0);
                    188:        if (n == 0) return 0;
                    189: 
                    190:        while (n->base==REF || n->base==MDOT) {
                    191:                Pexpr e = Pexpr(n);
                    192:                n = Pname(n->mem);
                    193:                delete e;
                    194:        }
                    195:        if (n->tp->base==FCT && Pname(n)->n_dcl_printed==0) Pname(n)->dcl_print(0);
                    196:        return Pname(n);
                    197: }
                    198: 
                    199: int is_expr(Pstmt s)
                    200: /*
                    201:        is this statement simple enough to be converted into an expression for
                    202:        inline expansion?
                    203: */
                    204: {
                    205:        int i = 0;
                    206:        if (s->base == BLOCK) {
                    207:                if (s->s == 0) return 1;
                    208:                s = s->s;
                    209:        }
                    210:        for (Pstmt ss = s; ss; ss = ss->s_list) {
                    211: //error('d',"ss %k",ss->base);
                    212:                switch (ss->base) {
                    213:                case BLOCK:
                    214:                        if (Pblock(ss)->memtbl || is_expr(ss->s)==0) return 0;
                    215:                case SM:
                    216:                        if (ss->e && ss->e->base==ICALL) {
                    217:                                Pname fn = ss->e->il->fct_name;
                    218:                                Pfct f = Pfct(fn->tp);
                    219:                                if (f->f_expr == 0) return 0;
                    220:                        }
                    221:                        break;
                    222:                case IF:
                    223:                        if (is_expr(ss->s)==0) return 0;
                    224:                        if (ss->else_stmt && is_expr(ss->else_stmt)==0) return 0;
                    225:                        break;
                    226:                default:
                    227:                        return 0;
                    228:                }
                    229:                i++;
                    230:        }
                    231:        return i;
                    232: }
                    233: 
                    234: int no_of_returns;
                    235: 
                    236: void name::simpl()
                    237: {
                    238: //error('d',"name::simpl%n %d %k",this,tp->base,tp->base);
                    239:        if (base == PUBLIC) return;
                    240: 
                    241:        if (tp == 0) error('i',"%n->N::simple(tp==0)",this);
                    242: 
                    243:        switch (tp->base) {
                    244:        case 0:
                    245:                error('i',"%n->N::simpl(tp->B==0)",this);
                    246: 
                    247:        case OVERLOAD:
                    248:        {       for (Plist gl = Pgen(tp)->fct_list; gl; gl=gl->l) gl->f->simpl();
                    249:                break;
                    250:        }
                    251: 
                    252:        case FCT:
                    253:        {       Pfct f = Pfct(tp);
                    254:                Pname n;
                    255:                Pname th = f->f_this;
                    256: 
                    257:                if (th) {
                    258:                        // Make "this" a register if it is used more than twice:
                    259:                        if (th->n_addr_taken) error("&this");
                    260:                        th->n_stclass = (2 < th->n_used) ? REGISTER : AUTO;
                    261:                        if (warning_opt
                    262:                        && th->n_assigned_to
                    263:                        && th->n_assigned_to!=FUDGE111)
                    264:                                error('w',&where,"assignment to this");
                    265:                }
                    266: 
                    267: 
                    268:                if (ansi_opt && f->body==0) {
                    269:                // make sure arguments can be printed for decls
                    270:                        
                    271:                        for (Pname n = f->f_args; n; n = n->n_list) {
                    272:                                n->n_scope = ARG;
                    273:                                if (n->string) {
                    274:                                        char* ps = new char[strlen(n->string)+1];
                    275:                                        strcpy(ps,n->string);
                    276:                                        n->string = ps;
                    277:                                }
                    278: /*
                    279:                                if (n_oper==DTOR && n->n_list==0) {
                    280:                                        // add __free argument
                    281:                                        Pname fa=new name;
                    282:                                        fa->tp = int_type;
                    283:                                        n->n_scope = ARG;
                    284:                                //      ps = new char[6];
                    285:                                //      strcpy(ps, "__free");
                    286:                                //      fa->string = ps;
                    287:                                        n->n_list = fa;
                    288:                                        break;
                    289:                                }
                    290: */
                    291:                        }
                    292:                }
                    293: 
                    294:                if (tp->defined & (SIMPLIFIED | ~DEFINED) ) return;
                    295: 
                    296:                for (n=f->f_args; n; n=n->n_list) n->simpl();
                    297: 
                    298:                if (f->body) {
                    299:                        Ptable oscope = scope;
                    300:                        Pname ocurr = curr_fct;
                    301:                        int oim = imeasure;
                    302:                        scope = f->body->memtbl;
                    303: //error('d',"body");
                    304:                        if (scope == 0) error('i',"%n memtbl missing",this);
                    305:                        curr_fct = this;
                    306:                        f->simpl();
                    307:                        if (f->f_inline==0 || debug_opt)
                    308:                                f->f_imeasure = 0;      // not a converted inline
                    309:                        else {
                    310:                                // first check if the function is too large to
                    311:                                // be worth inlining
                    312:                                if (12<f->f_imeasure) { // cut-over point:
                    313:                                                        // about 12 assignments
                    314:                                                        // f->f_imeasure indicates
                    315:                                        f->f_inline = 0;// a converted inline
                    316: //error('d',"don't inline%n %d %d %d",this,this,f,f->f_imeasure);
                    317:                                        tp->defined |= SIMPLIFIED;
                    318:                                        return;
                    319:                                }
                    320:                                int i = 0;
                    321:                                for (n=f->f_args; n; n=n->n_list) {
                    322:                                        n->base = ANAME;
                    323:                                        n->n_val = i++;
                    324:        // ??                           if (n->n_table != scope) error('i',"aname scope: %d %n %d %d\n",n,n,n->n_table,scope);
                    325:                                }
                    326:                                expand_tbl = (f->returns->base!=VOID || n_oper==CTOR) ? scope : 0;
                    327:                                expand_fn = this;
                    328: 
                    329:                                if (expand_tbl) {
                    330:                                genlab:
                    331:                                                // value returning: generate expr
                    332:                                                // the body still holds the memtbl
                    333:                                        Pexpr ee = Pexpr(f->body->expand());
                    334:                                        Ptype t = 0;
                    335:                                        if (f->s_returns) {
                    336:                                                if (ee->tp!=f->s_returns) t = f->s_returns;
                    337:                                        }
                    338:                                        else if (ee->tp!=f->returns)
                    339:                                                t = f->returns;
                    340:                                        // VCVC assumes VOID is output as CHAR:
                    341: /* But this is not needed on a sun, and just makes the debugger print trash */
                    342: #ifndef sun
                    343:                                        if (t && t==void_type && ansi_opt == 0)
                    344:                                                ee = new expr(CM,ee,new cast(char_type,zero));
                    345: #endif
                    346:                                        f->f_expr = (ee->base==CM) ? ee : new expr(CM,zero,ee);
                    347:                                        // print.c assumes expansion into comma expression
                    348:                                }
                    349:                                else {
                    350:                                        if (is_expr(f->body)) {
                    351:                                                // can generate expr: do
                    352:                                                expand_tbl = scope;
                    353:                                                goto genlab;
                    354:                                        }
                    355:                                        // not value return: can generate block
                    356:                                        f->f_expr = 0;
                    357:                                        f->body = Pblock(f->body->expand());
                    358:                                }
                    359:                                expand_fn = 0;
                    360:                                expand_tbl = 0;
                    361:                        }
                    362:                        scope = oscope;
                    363:                        curr_fct = ocurr;
                    364:                        imeasure = oim;
                    365:                }
                    366:                break;
                    367:        }
                    368: 
                    369:        case CLASS:
                    370:                Pclass(tp)->simpl();
                    371:        }
                    372: 
                    373:        if (n_initializer) n_initializer->simpl();
                    374:        tp->defined |= SIMPLIFIED;
                    375: }
                    376: 
                    377: Pexpr call_ctor(Ptable tbl, Pexpr p, Pexpr ctor, Pexpr args, int d, Pexpr vb_args)
                    378: {
                    379:        Pexpr ee = new ref(d,p,ctor);
                    380:        if (p==0 || tbl==0) ee->tp = ctor->tp;
                    381: //error('d',"call_ctor(tbl %d, p %d, %n, args %d)",tbl,p,ctor,args);
                    382:        if (args && args->base!=ELIST) args = new expr(ELIST,args,0);
                    383:        ee = new expr(G_CALL,ee,args);
                    384:        Pname n = Pname(ctor);
                    385:        while (n->base == MDOT) n = Pname(n->mem);
                    386:        if (n->tp->base == FCT) ee->fct_name = n;
                    387:        if (tbl)
                    388:                ee = ee->typ(tbl);
                    389:        else if (n->tp->base == FCT)
                    390:                ee->tp = Pfct(n->tp)->s_returns;
                    391:        if (ee->tp == any_type) return ee;
                    392:        args = ee->e2;
                    393: 
                    394:        if (vb_args == 0) {             // attach zero vbase arguments
                    395:                Pfct f = Pfct(ee->fct_name->tp);        // not n->fct_name
                    396:                for (Pname nn = f->f_args->n_list; nn && nn!=f->argtype; nn=nn->n_list)
                    397:                        args = new expr(ELIST,zero,args);
                    398:        }
                    399:        else {                          // attach vbase arguments
                    400:                if (args) {
                    401:                        for (Pexpr d = vb_args; d->e2; d=d->e2);
                    402:                        d->e2 = args;
                    403:                }
                    404:                args = vb_args;
                    405:        }
                    406: 
                    407:        ee->e2 = args;
                    408:        return ee;
                    409: }
                    410: 
                    411: Pexpr call_dtor(Pexpr p, Pexpr dtor, Pexpr arg, int d, Pexpr vb_args)
                    412: {
                    413: // error('d',"call dtor %k %n %t vb_args %d",d,dtor,dtor->tp,vb_args);
                    414:        Pexpr r = new ref(d,p,dtor);
                    415: 
                    416:        if (arg && vb_args) {
                    417:                arg = new ival(3);
                    418:                arg->tp = int_type;
                    419:        }
                    420:        else if (vb_args) {
                    421:                arg = new ival(2);
                    422:                arg->tp = int_type;
                    423:        }
                    424:        else if (arg==0)
                    425:                arg = zero;
                    426: 
                    427:        Pexpr aa = new expr(ELIST,arg,0); // argument controlling deallocation
                    428:                                          // 2: destroy vbases
                    429:                                          // 1: dealllocate, 0: don't
                    430: 
                    431:        Pfct f = Pfct(dtor->tp);                // attach virtual base arguments
                    432: //     for (Pname nn = f->f_args->n_list; nn && nn->n_list; nn=nn->n_list) {
                    433: //             Pexpr xx = vb_args ? new cast(nn->tp,one) : zero;
                    434: //             aa = new expr(ELIST,xx,aa);
                    435: //     }
                    436: 
                    437: 
                    438:        Pexpr ee = new call(r,aa);
                    439:        while (dtor->base == MDOT) dtor = dtor->mem;
                    440:        if (d == REF)   // could be virtual
                    441:                ee->fct_name = Pname(dtor);
                    442:        else {  // virtual suppressed, store fct name 
                    443:                r->n_initializer = dtor;
                    444:                ee->fct_name = 0;
                    445:        }
                    446:        ee->base = G_CALL;
                    447:        ee->tp = void_type;
                    448: 
                    449:         if (f->memof->c_body == 1) f->memof->dcl_print(0);
                    450:        if (Pname(dtor)->n_dcl_printed==0) Pname(dtor)->dcl_print(0);
                    451: 
                    452:        return ee;
                    453: }
                    454: 
                    455: //extern int new_used; // pre-define new and delete only if the user didn't
                    456: 
                    457: Pstmt fct::dtor_simpl(Pclass cl, Pexpr th)
                    458: {
                    459:        Pstmt dtail = 0;
                    460: //error('d',"simpl_dtor(%t) a %d",cl,f_args);
                    461: //     if (new_used == 0) new_init();
                    462: 
                    463:        Pname fa = new name("__free");  // fake argument for dtor
                    464:        fa->tp = int_type;
                    465:        Pname free_arg = fa->dcl(body->memtbl,ARG);
                    466:        free_arg->where = no_where;
                    467:        delete fa;
                    468:        Pname a = f_args;
                    469:        if (a==0 || a->n_list==0) error('i',"__freeA missing in destructor for %t",cl);
                    470:        Pname p = 0;
                    471:        for(;;p=a,a=a->n_list) {        // replace nameless fake argument
                    472: //error('d',"a %d %t",a,a->tp);
                    473:                if (a->n_list == 0) {
                    474:                //      a->n_list = free_arg;
                    475:                        DEL(p->n_list);
                    476:                        p->n_list = free_arg;
                    477:                        break;
                    478:                }
                    479:        } 
                    480: 
                    481:        // generate calls to destructors for all members of class cl:
                    482:        Ptable tbl = cl->memtbl;
                    483:        int i = 1;
                    484:        for (Pname m=tbl->get_mem(i); m; m=tbl->get_mem(++i) ) {
                    485: 
                    486:                if (m->n_stclass == STATIC) continue;
                    487: 
                    488:                Ptype t = m->tp;
                    489:                Pexpr ee = 0;
                    490:                Pname cn;
                    491:                Pname dtor;
                    492: 
                    493:                if (cn = t->is_cl_obj()) {
                    494:                        Pclass cl = (Pclass)cn->tp;
                    495:                        if (dtor = cl->has_dtor()) {    // dtor(this,0,ones);
                    496:                                ee = new ref(REF,th,m);
                    497:                                ee->tp = m->tp;
                    498:                                ee = call_dtor(ee,dtor,0,DOT,one);
                    499:                                check_visibility(dtor,0,Pclass(dtor->n_table->t_name->tp),tbl,curr_fct);
                    500:                        }
                    501:                }
                    502:                else if (cl_obj_vec) {
                    503:                        Pclass cl = Pclass(cl_obj_vec->tp);
                    504:                        if (dtor = cl->has_dtor()) {
                    505:        Pfct f = Pfct(dtor->tp);
                    506:        int i = 0;
                    507:        for (Pname nn = f->f_args->n_list; nn && nn->n_list; nn=nn->n_list) i++;
                    508: //error('d',"dtor %n i %d",dtor,i);
                    509:                                ee = new ref(REF,th,m);
                    510:                                ee->tp = m->tp;
                    511:                                ee = cdvec(vec_del_fct,ee,cl,dtor,0,new ival(i));
                    512:                                check_visibility(dtor,0,Pclass(dtor->n_table->t_name->tp),tbl,curr_fct);
                    513:                        }
                    514:                }
                    515: 
                    516:                if (ee) {
                    517:                        Pstmt es = new estmt(SM,curloc,ee,0);
                    518:                        // reverse order of destructors for members
                    519:                        es->s_list = del_list;
                    520:                        del_list = es;
                    521:                        if (dtail == 0) dtail = es;
                    522:                }
                    523:        }
                    524: 
                    525: 
                    526:        Pexpr ee = 0;
                    527:        // look for bases with destructors:
                    528:        // generate: dtor(base,0);
                    529: 
                    530:        Pbcl b = 0;     // get dtors in order with virtual bases last
                    531:        Pbcl t = 0;
                    532:        for (Pbcl l = cl->baselist; l; l=l->next) {
                    533:                if (l->base != VIRTUAL) {
                    534:                        Pbcl x = new basecl(l->bclass,0);
                    535:                        if (t == 0)
                    536:                                b  = x;
                    537:                        else
                    538:                                t->next = x;
                    539:                        t = x;
                    540:                        x->base = l->base;
                    541:                        x->obj_offset = l->obj_offset;
                    542:                }
                    543:        }
                    544:        for (l = cl->baselist; l; l=l->next) {
                    545:                if (l->base == VIRTUAL) {
                    546:                        b = new basecl(l->bclass,b);
                    547:                        b->base = l->base;
                    548:                        b->obj_offset = l->obj_offset;
                    549:                }
                    550:        }
                    551:        Pexpr ve = 0;
                    552: 
                    553:        for (; b; b=l) {
                    554:                Pclass bcl = b->bclass;
                    555:                l = b->next;
                    556:                Pname dtor = bcl->has_dtor();
                    557: 
                    558:                if (dtor) {
                    559:                        Pexpr val = rptr(bcl->this_type,th,b->obj_offset);
                    560:                        val = val->contents();
                    561:                        Pexpr e = call_dtor(val,dtor);
                    562:                        if (b->base == VIRTUAL) {
                    563:                                // if (x) this->x.dtor(); where x is a vbase
                    564:                                for (Pname dd = f_this->n_list; dd!=argtype; dd=dd->n_list) 
                    565:                                if (strcmp(dd->string,bcl->string)==0) break;
                    566: 
                    567: #ifndef sun
                    568:                                if (ansi_opt) { // q?void:int would be an error
                    569: #endif
                    570:                                        e = new expr(G_CM,e,zero);
                    571:                                        e->tp = zero_type;
                    572: #ifndef sun
                    573:                                }
                    574: #endif
                    575:                                e = new expr(QUEST,e,zero);
                    576:                                Pexpr two = new ival(2);
                    577:                                two->tp = int_type;
                    578:                                e->cond = new expr (AND,free_arg,two);//dd;
                    579:                        }
                    580:                        ee = ee ? new expr(CM,e,ee) : e;
                    581:                }
                    582:                delete b;
                    583:        }
                    584: 
                    585:        Pstmt es = ee ? new estmt(SM,curloc,ee,0) : 0;
                    586: 
                    587:        ee = new expr(ELIST,th,0);      // free storage
                    588:        Pname n = new name(oper_name(DELETE));
                    589:        Pexpr del = find_name(n,cl,scope,CALL,curr_fct);
                    590:        if (del->tp->base==OVERLOAD || Pfct(del->tp)->nargs==2) {
                    591:                Pexpr ss = new texpr(SIZEOF,cl,0);
                    592:                ss->tp = uint_type;
                    593:                ee->e2 = new expr(ELIST,ss,0);
                    594:        }
                    595:        ee = new call(del,ee);
                    596:        ee->tp = ee->call_fct(scope);
                    597: 
                    598:        Pstmt ess = new estmt(SM,curloc,ee,0);
                    599:        ess = new ifstmt(curloc,new expr(AND,free_arg,one),ess,0);
                    600:        if (es)
                    601:                es->s_list = ess;
                    602:        else
                    603:                es = ess;
                    604: 
                    605:        free_arg->use();
                    606:        Pname(th)->use();
                    607: 
                    608:        if (dtail)
                    609:                dtail->s_list = es;
                    610:        else
                    611:                del_list = es;
                    612: 
                    613:        del_list = new ifstmt(curloc,th,del_list,0);
                    614:        if (del_list) del_list->simpl();
                    615:        return dtail;
                    616: }
                    617: 
                    618: 
                    619: Pclass find_vbase_ptr(Pclass cl, Pclass vbase)
                    620: {
                    621:        for (Pbcl bb = cl->baselist; bb; bb = bb->next) {
                    622:                if (bb->bclass==vbase && bb->ptr_offset) return cl;
                    623:                Pclass f = find_vbase_ptr(bb->bclass,vbase);
                    624:                if (f) return f;
                    625:        }
                    626:        return 0;
                    627: }
                    628: 
                    629: Pclass second_base(Pclass cl, Pclass base)
                    630: {
                    631: //error('d',"second_base(%t,%t)",cl,base);
                    632:        for (Pbcl b = cl->baselist; b && b->base==NAME; b = b->next) {
                    633:                if (b->bclass==base) {
                    634:                        if (b==cl->baselist) return 0;
                    635:                        return base;
                    636:                }
                    637:                Pclass bb = second_base(b->bclass,base);
                    638:                if (bb == Pclass(-1)) continue; // not found
                    639:                if (bb) {
                    640:                        if (b!=cl->baselist) error('s',"C hierarchy too complicated");
                    641:                        return bb;      // second base of b->bclass
                    642:                }
                    643:                if (b==cl->baselist) return 0;
                    644:                return b->bclass;       // b->bclass is second base
                    645:        }
                    646:        return Pclass(-1);
                    647: }
                    648: 
                    649: //Pclass topclass;
                    650: 
                    651: Pexpr classdef::get_vptr_exp(char *s)
                    652: {
                    653: //error('d',"%t::get_vptr_exp(%s)",this,s?s:"0");
                    654:        if (c_body == 1) dcl_print(0);
                    655:        if (c_body == 3) print_all_vtbls(this);
                    656:        if (s == 0) return find_vptr(this);
                    657:        Pbcl b = get_base(get_classname(s));
                    658:        Pexpr vp = b->bclass->get_vptr_exp(drop_classname(s));
                    659:        if (b==baselist && b->base!=VIRTUAL) return vp;
                    660:        vp = new mdot(b->bclass->string,vp);
                    661:        if (c_body == 1) b->bclass->dcl_print(0);
                    662:        if (c_body == 3) b->bclass->print_all_vtbls(b->bclass);
                    663:        if (b->base == VIRTUAL) {
                    664:                vp->i1 = 1;
                    665:                if (b->ptr_offset == 0) { // pointer to base in intermediate base
                    666:                        Pclass bb = find_vbase_ptr(this,b->bclass);
                    667:                        Pclass sb = second_base(topclass,bb);
                    668: //error('d',"mdot %t %t : %d %t ",topclass,bb,sb,sb==Pclass(-1)?0:sb);
                    669:                        if (sb && sb!=Pclass(-1)) vp = new mdot(sb->string,vp);
                    670:                }
                    671:        }
                    672:        return vp;
                    673: }
                    674: 
                    675: int fct::ctor_simpl(Pclass cl, Pexpr th)
                    676: {
                    677:        Ptable tbl = cl->memtbl;
                    678: 
                    679:        int ass_count = 0;
                    680:        init_list = 0;
                    681: //error('d',"ctor_simpl %t: %t",cl,this);
                    682:        /*
                    683:                initialization order:
                    684:                (1)     virtual base pointers and virtual bases
                    685:                                (they may be used in non-virtual bases)
                    686:                (2)     non-virtual bases
                    687:                (3)     virtual function pointers
                    688:                (4)     members
                    689:        */
                    690: 
                    691:        // initialize virtual base pointers and virtual base objects
                    692:        for (Pbcl l = cl->baselist; l; l=l->next) {
                    693:                Pexpr i = l->init;
                    694:                if (l->base != VIRTUAL) continue;
                    695:                l->init = 0;
                    696: //error('d',"simpl virtual base %t i %d ",l->bclass,i);
                    697: 
                    698:                // assign virtual OP to virtual base AP
                    699:                Pclass bc = l->bclass;
                    700:                Pexpr dp = 0;
                    701: 
                    702:                // dd = pointer argument for this base;
                    703:                // non-zero if already initialized
                    704:                for (Pname dd = f_this->n_list; dd!=argtype; dd=dd->n_list) 
                    705:                        if (strcmp(dd->string,bc->string)==0) break;
                    706: 
                    707:                // initialize virtual base object
                    708: //error('d',"bc %t dd %n offset %d init %d",bc,dd,l->obj_offset,l->init);
                    709:                // => bc_arg = (bc*)((char*)this+offset)
                    710:                int off = l->obj_offset;
                    711:                Pexpr val = rptr(bc->this_type,th,off);
                    712:                dp = new expr(ASSIGN,dd,val);
                    713:                dd->assign();
                    714: 
                    715:                // => bc::bc()
                    716:                if (i)  {
                    717:                        switch (i->base) {
                    718:                        case ASSIGN:
                    719:                        case CM:
                    720:                                break;
                    721:                        case CALL:
                    722:                        case G_CALL:
                    723:                        {       Pcall cc = Pcall(i);
                    724:                                Pname bn = cc->fct_name;
                    725:                                ass_count = Pfct(bn->tp)->f_this->n_assigned_to;
                    726:                                cc->simpl();
                    727:                                break;
                    728:                        }
                    729:                        default:
                    730:                                error('i',"badBCIr %k",i->base);
                    731:                        }
                    732:                        dp = new expr(CM,dp,i);
                    733:                }
                    734: 
                    735:                // => (bc_arg==0)?dp:bc_arg
                    736:                for (Pname a = f_args->n_list; a; a = a->n_list)
                    737:                        if (strcmp(bc->string,a->string)==0) {
                    738:                                dp = new expr(QUEST,dp,a);
                    739:                                dp->cond = new expr(EQ,a,zero);
                    740:                                break;
                    741:                        }
                    742: 
                    743:                //      Pname dpp = find_vbase_ptr(bc,cl);
                    744:                for (Pbcl ll=cl->baselist; ll; ll=ll->next) {
                    745:                        if (ll->bclass==bc && ll->ptr_offset) {
                    746:                                // make sure that the delegate_arg is needed
                    747:                                // here and not just in a base
                    748: 
                    749:                                // this->Pd = (bc_arg==0)?dp:bc_arg
                    750:                                Pexpr dpp = new mdot(bc->string,th);
                    751:                                dpp->i1 = 3;
                    752:                                dp = new expr(ASSIGN,dpp,dp);
                    753: //error('d',"dpp %n",dpp);
                    754:                                break;
                    755:                        }
                    756:                }
                    757: 
                    758:                // reverse init order
                    759:                if (dp) init_list = init_list ? new expr(CM,dp,init_list) : dp;
                    760:        }
                    761: 
                    762:        //      generate: this=base::base(args) (non-virtual bases)
                    763: {      
                    764:        for (Pbcl l = cl->baselist; l; l=l->next) {
                    765:                Pexpr i = l->init;
                    766:                if (i==0 || l->base==VIRTUAL) continue;
                    767: //error('d',"simpl base %t i %d ",l->bclass,i);
                    768:                l->init = 0;
                    769:        
                    770:                switch (i->base) {
                    771:                case ASSIGN:
                    772:                case CM:
                    773:                        break;
                    774:                case CALL:
                    775:                case G_CALL:
                    776:                {       Pcall cc = Pcall(i);
                    777:                        Pname bn = cc->fct_name;
                    778:                        ass_count = Pfct(bn->tp)->f_this->n_assigned_to;
                    779:                        cc->simpl();
                    780:                        // assign to ``this'' only from only base
                    781:                        if (l==cl->baselist && cl->baselist->next==0) i = new expr(ASSIGN,th,cc);
                    782:                        break;
                    783:                }
                    784:                default:
                    785:                        error('i',"badBCIr %k",i->base);
                    786:                }
                    787: 
                    788:                init_list = init_list ? new expr(G_CM,init_list,i) : i;
                    789:        }
                    790: }
                    791: 
                    792:        // initialize the vptrs that are updated by this class
                    793: 
                    794:         if (th) {
                    795:            Pexpr ee = initialize_vptrs (cl, th);
                    796:            if (ee)
                    797:                init_list = init_list ? new expr(CM,init_list,ee) : ee;
                    798:          }
                    799: 
                    800:         else {
                    801:             error('i', "%t->fct::ctor_simpl(): th found to be null", cl);
                    802:          }
                    803: 
                    804: 
                    805:        // initialize members in declaration order:
                    806:        int i;
                    807:        for (Pname m=tbl->get_mem(i=1); m; m=tbl->get_mem(++i) ) {
                    808:                Ptype t = m->tp;
                    809:                Pname cn;
                    810:                Pname ctor;
                    811:                if (t == 0) continue;
                    812: 
                    813:                switch (t->base) {
                    814:                case FCT:
                    815:                case OVERLOAD:
                    816:                case CLASS:
                    817:                case ENUM:
                    818:                        continue;
                    819:                }
                    820: 
                    821:                switch (m->n_stclass) {
                    822:                case STATIC:
                    823:                case ENUM:
                    824:                        continue;
                    825:                }
                    826: 
                    827:                if (m->base == PUBLIC) continue;
                    828: 
                    829:                Pexpr ee = m->n_initializer;
                    830:                if (ee) m->n_initializer = 0;   // from fct must not persist until next fct
                    831: //error('d',"simpl m %n ee %d",m,ee);
                    832:                if (ee) {
                    833:                        // init of non-class mem
                    834:                        // set in fct::mem_init()
                    835:                }
                    836:                else if (cn=t->is_cl_obj()) {   // try for default
                    837:                        Pclass cl = Pclass(cn->tp);
                    838:                        if (ctor = cl->has_ictor()) {
                    839:                                Pexpr r = new ref(REF,th,m);
                    840:                                ee = call_ctor(tbl,r,ctor,0,DOT);
                    841:        check_visibility(ctor,0,Pclass(ctor->n_table->t_name->tp),tbl,curr_fct);
                    842:                        }
                    843:                        else if (cl->has_ctor()) {
                    844:                                error("M%n needsIr (no defaultK forC %s)",m,cl->string);
                    845:                        }
                    846:                }
                    847:                else if (cl_obj_vec) {
                    848:                        Pclass cl = Pclass(cl_obj_vec->tp);
                    849:                        if (ctor = cl->has_ictor()) { // _new_vec(vec,noe,sz,ctor);
                    850:                                Pexpr mm = new ref(REF,th,m);
                    851:                                mm->tp = m->tp;
                    852:                                ee = cdvec(vec_new_fct,mm,cl,ctor,-1,0);
                    853:        check_visibility(ctor,0,Pclass(ctor->n_table->t_name->tp),tbl,curr_fct);
                    854:                        }
                    855:                        else if (cl->has_ctor()) {
                    856:                                error("M%n[] needsIr (no defaultK forC %s)",m,cl->string);
                    857:                        }
                    858:                }
                    859:                else if (t->is_ref()) {
                    860:                        error("RM%n needsIr",m);
                    861:                }
                    862:                else if (t->tconst() && vec_const==0) {
                    863:                        error("constM%n needsIr",m);
                    864:                }
                    865:        
                    866:                if (ee) {
                    867:                        ee->simpl();
                    868:                        init_list = init_list ? new expr(CM,init_list,ee) : ee;
                    869:                }
                    870:        } // for m
                    871: //error('d',"ctor->");
                    872:        return ass_count;
                    873: }
                    874: 
                    875: void fct::simpl()
                    876: /*
                    877:        call only for the function definition (body != 0)
                    878: 
                    879:        simplify argument initializers, and base class initializer, if any
                    880:        then simplify the body, if any
                    881: 
                    882:        for constructor:call allocator if this==0 and this not assigned to
                    883:                        (auto and static objects call constructor with this!=0,
                    884:                        the new operator generates calls with this==0)
                    885:                        call base & member constructors
                    886:        for destructor: call deallocator (no effect if this==0)
                    887:                        case base & member destructors
                    888: 
                    889:        for arguments and function return values look for class objects
                    890:        that must be passed by constructor X(X&).
                    891: 
                    892:        Allocate temporaries for class object expressions, and see if
                    893:        class object return values can be passed as pointers.
                    894: 
                    895:        call constructor and destructor for local class variables.
                    896: */
                    897: {
                    898:        Pexpr th = f_this;
                    899:        Ptable tbl = body->memtbl;
                    900:        Pstmt ss = 0;
                    901:        Pstmt tail;
                    902:        Pclass cl = th ? Pclass(Pbase(Pptr(th->tp)->typ)->b_name->tp) : 0;
                    903:        Pstmt dtail = 0;
                    904: 
                    905:        Pname ocurr_fct = curr_fct;
                    906:        int oret = no_of_returns;
                    907:        int oim = imeasure;
                    908: 
                    909: //error('d',"fct::simpl %n %t",curr_fct,this);
                    910: //     not_inl = f_inline==0;
                    911:        del_list = 0;
                    912:        continue_del_list = 0;
                    913:        break_del_list = 0;
                    914:        scope = tbl;
                    915:        if (scope == 0) error('i',"F::simpl()");
                    916:        int ass_count = 0;
                    917:        imeasure = 0;
                    918:        no_of_returns = 0;
                    919: 
                    920:        cc->stack();
                    921:        cc->nof = curr_fct;
                    922:        cc->ftbl = tbl;
                    923: 
                    924: //      modification for local classes defined within inline functions
                    925:        extern Plist local_class;
                    926: // error( 'd', "simpl local_class: %d", local_class );
                    927:        for ( Plist l = local_class; l; l = l->l ) {
                    928:                Pname n = l->f; 
                    929:                Pclass cl = Pclass(Pbase(n->tp)->b_name->tp);
                    930:                if ( cl->in_fct == 0 ) cl->in_fct = cc->nof;
                    931:                if ( cl->lcl == 0 ) cl->lcl = make_name( 'L' );
                    932:                if ( cl->c_body == 1 ) cl->dcl_print(0);
                    933:        }
                    934: 
                    935:        Pfct(cc->nof->tp)->local_class = local_class; 
                    936:        local_class = 0;
                    937: // error( 'd', "simpl nof: %n %d local_class: %d", cc->nof, cc->nof, Pfct(cc->nof->tp)->local_class );
                    938: 
                    939:        switch (curr_fct->n_scope) {
                    940:        case 0:
                    941:        case PUBLIC:
                    942:                cc->not = curr_fct->n_table->t_name;
                    943:                cc->cot = Pclass(cc->not->tp);
                    944:                cc->tot = cc->cot->this_type;
                    945:        }
                    946: 
                    947:        switch (curr_fct->n_oper) {
                    948:        case  DTOR:
                    949:                dtail = dtor_simpl(cl,th);
                    950:                break;
                    951:        case CTOR:
                    952:                ass_count = ctor_simpl(cl,th);
                    953:        }
                    954: 
                    955:        tail = body->simpl();
                    956: 
                    957:        if (returns->base!=VOID || f_result) {  // return must have been seen
                    958:                if (no_of_returns) {            // could be OK
                    959:                        Pstmt tt = (tail->base==RETURN || tail->base==LABEL) ? tail : trim_tail(tail);
                    960: 
                    961:                        switch (tt->base) {
                    962:                        case RETURN:
                    963:                        case GOTO:
                    964:                                del_list = 0;   // no need for del_list
                    965:                                break;
                    966:                        case SM:
                    967:                                if (tt->e)
                    968:                                        switch (tt->e->base) {
                    969:                                        case ICALL:
                    970:                                        case G_CALL:
                    971:                                                goto chicken;
                    972:                                        }
                    973:                        default:
                    974:                                if (warning_opt || strcmp(curr_fct->string,"main"))     
                    975:                                        error('w',"maybe no value returned from%n",curr_fct);
                    976:                        case IF:
                    977:                        case SWITCH:
                    978:                        case DO:
                    979:                        case WHILE:
                    980:                        case FOR:
                    981:                        case LABEL:
                    982:                        chicken:                // don't dare write a warning
                    983:                                break;
                    984:                        }
                    985:                }
                    986:                else {  // must be an error
                    987:                        // but we don't dare complain about main()
                    988:                //      if (strcmp(curr_fct->string,"main"))
                    989:                //              error(Pfct(curr_fct->tp)->returns->is_cl_obj()?0:'w',"no value returned from%n",curr_fct);
                    990:                //      else if (warning_opt)   
                    991:                //              error('w',"no value returned from%n",curr_fct);
                    992:                        if (Pfct(curr_fct->tp)->f_inline
                    993:                        && Pfct(curr_fct->tp)->returns!=void_type
                    994:                        && Pfct(curr_fct->tp)->returns->is_cl_obj())
                    995:                                // can cause code generation errors if allowed
                    996:                                error("no value returned from%n",curr_fct);
                    997:                        else if (warning_opt || strcmp(curr_fct->string,"main"))        
                    998:                                error('w',"no value returned from%n",curr_fct);
                    999:                }
                   1000:                if (del_list) goto zaq;
                   1001:        }
                   1002:        else if (del_list) {    // return may not have been seen
                   1003:        zaq:
                   1004:                if (tail)
                   1005:                        tail->s_list = del_list;
                   1006:                else
                   1007:                        body->s = del_list;
                   1008:                tail = dtail;
                   1009:        }
                   1010: 
                   1011:        if (curr_fct->n_oper == DTOR) { // body => if (this == 0) body
                   1012: 
                   1013: // reset the vptrs that were set by this class
                   1014:        for (Pvirt blist = cl->virt_list; blist; blist = blist->next) {
                   1015: //error('d',"vptr init %s in %s",blist->string,cl->string);
                   1016:                topclass = cl;
                   1017:                Pexpr vp = cl->get_vptr_exp(blist->string);
                   1018: 
                   1019: extern char *make_local_name(Pclass, int=0);
                   1020:                 char *str = 0;
                   1021:                 if ( cl->lex_level ) str = make_local_name( cl );
                   1022:                 Pexpr vtbl = new text_expr(blist->string,str?str:cl->string);
                   1023: 
                   1024:                Pexpr ee = new ref(REF,th,vp);
                   1025:                ee->tp = vp->tp;
                   1026:                ee = new expr(ASSIGN,ee,vtbl);
                   1027:                        Pstmt es = new estmt(SM,curloc,ee,0);
                   1028:                        es->s_list = body->s;
                   1029:                        body->s = es;
                   1030:        }
                   1031: 
                   1032:                body->s = new ifstmt(body->where,th,body->s,0);
                   1033:        }
                   1034: 
                   1035:        if (curr_fct->n_oper == CTOR) {
                   1036: 
                   1037:                if  (Pname(th)->n_assigned_to == 0) {
                   1038:                /* generate:
                   1039:                        if (this || (this=_new( sizeof(class cl) ))) {
                   1040:                                init_list ;
                   1041:                                body;
                   1042:                        }
                   1043:                */
                   1044:                        Pname(th)->n_assigned_to = ass_count ? ass_count : FUDGE111;
                   1045:                        Pexpr sz = new texpr(SIZEOF,cl,0);
                   1046:                        (void) cl->tsizeof();
                   1047:                        sz->tp = uint_type;
                   1048:                        Pexpr ee = new expr(ELIST,sz,0);
                   1049:                                Pname n = new name(oper_name(NEW));
                   1050:                                Pexpr p = find_name(n,cl,scope,CALL,curr_fct);
                   1051: //error('d',"in ctor %n call %n",curr_fct,p);
                   1052:                                ee = new call(p,ee);
                   1053:                                ee->tp = ee->call_fct(cl->memtbl);
                   1054:                        ee->simpl();
                   1055:                        ee = new expr(ASSIGN,th,ee);
                   1056:                        ee = new expr(OROR,th,ee);
                   1057:                        /*ifs->simpl();
                   1058:                                do not simplify
                   1059:                                or "this = " will cause an extra call of base::base
                   1060:                        */
                   1061:                        if (init_list) {
                   1062:                                Pstmt es = new estmt(SM,body->where,init_list,0);
                   1063:                                es->s_list = body->s;
                   1064:                                body->s = es;
                   1065:                        //      if (tail == 0) tail = es;
                   1066:                        }
                   1067:                        else if (body->s == 0)
                   1068:                                body->s = new estmt(SM,body->where,0,0);
                   1069:                        ifstmt* ifs = new ifstmt(body->where,ee,body->s,0);
                   1070:                        body->s = ifs;
                   1071:                //      if (tail == 0) 
                   1072:                        tail = ifs;
                   1073:                }
                   1074:                // generate: body; return this;
                   1075:                Pstmt st = new estmt(RETURN,curloc,th,0);
                   1076:                if (tail)
                   1077:                        tail->s_list = st;
                   1078:                else
                   1079:                        body->s = st;
                   1080:                tail = st;
                   1081:        }
                   1082:        f_imeasure = imeasure;
                   1083:        curr_fct = ocurr_fct;
                   1084:        no_of_returns = oret;
                   1085:        imeasure = oim;
                   1086:        cc->unstack();
                   1087: }
                   1088: 
                   1089: 
                   1090: void classdef::simpl()
                   1091: {
                   1092:        int i;
                   1093: //error('d',"classdef::simpl %s %d",string,defined&SIMPLIFIED);
                   1094: 
                   1095:        if (defined&SIMPLIFIED) return;
                   1096: 
                   1097:        Pclass oc = in_class;
                   1098:        in_class = this;
                   1099: 
                   1100:        for (Pname m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) {
                   1101:                Pexpr i = m->n_initializer;
                   1102:                m->n_initializer = 0;
                   1103:                m->simpl();
                   1104:                m->n_initializer = i;
                   1105:        }
                   1106: 
                   1107:        in_class = oc;
                   1108: 
                   1109:        for (Plist fl=friend_list; fl; fl=fl->l) {      // simplify friends
                   1110:                Pname p = fl->f;
                   1111:                switch (p->tp->base) {
                   1112:                case FCT:
                   1113:                case OVERLOAD:
                   1114:                        p->simpl();
                   1115:                }
                   1116:        }
                   1117: 
                   1118:        defined |= SIMPLIFIED;
                   1119: }
                   1120: 
                   1121: 
                   1122: 
                   1123: 
                   1124: Pexpr initialize_vptrs (Pclass cl, Pexpr this_expr)
                   1125: 
                   1126:     /* Constructs an expression which initializes the given class's vptrs.
                   1127:        The this_expr forms the first part of the path expression for each
                   1128:        vptr assignment. The vptr assignments are combined into a comma
                   1129:        expression. */
                   1130: 
                   1131: {
                   1132: 
                   1133:     Pexpr init_list = 0;
                   1134: 
                   1135: 
                   1136:     /* initialize the vptrs that are updated by this class */
                   1137: 
                   1138:     for (Pvirt blist = cl->virt_list; blist; blist = blist->next) {
                   1139: 
                   1140:        topclass = cl;
                   1141:        Pexpr vptr_exp = cl->get_vptr_exp(blist->string);
                   1142: 
                   1143:        extern char *make_local_name(Pclass, int=0);
                   1144:        char *str = 0;
                   1145:        if ( cl->lex_level ) str = make_local_name(cl);
                   1146:        Pexpr vtbl = new text_expr(blist->string,str?str:cl->string);
                   1147: 
                   1148:        Pexpr ee;
                   1149:        if (this_expr)
                   1150:            ee = new ref(REF, this_expr, vptr_exp);
                   1151:        else
                   1152:            ee = vptr_exp;
                   1153: 
                   1154:        ee->tp = vptr_exp->tp;
                   1155:        ee = new expr(ASSIGN, ee, vtbl);
                   1156:        init_list = init_list ? new expr(CM, init_list, ee) : ee;
                   1157:       }
                   1158:     
                   1159:     return init_list;
                   1160: 
                   1161: } /* initialize_vptrs */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.