Annotation of 43BSD/contrib/B/src/bint/b3sta.c, revision 1.1

1.1     ! root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
        !             2: 
        !             3: /*
        !             4:   $Header: b3sta.c,v 1.4 85/08/22 16:59:30 timo Exp $
        !             5: */
        !             6: 
        !             7: /* Stacks used by the interpreter */
        !             8: 
        !             9: /* Scratch-pad copying.
        !            10: 
        !            11:    One of the hairiest details of B is scratch-pad copying and its
        !            12:    interaction with formal parameters (to HOW'TO units).
        !            13:    Via formal parameters one can peek and poke into the local environment
        !            14:    of the HOW'TO's in the call chain.  When a parameter is changed from
        !            15:    within an expression- or test-refinement, the scratch-pad copying
        !            16:    prescribes that the whole chain of local environments is restored
        !            17:    to its original state when the refinement exits.  Example:
        !            18: 
        !            19:     >>> HOW'TO X fp:
        !            20:            WRITE fp, ref, fp /
        !            21:        ref:
        !            22:            PUT fp+1 IN fp
        !            23:            RETURN fp
        !            24:     >>> HOW'TO Y fp:
        !            25:            X fp
        !            26:     >>> HOW'TO Z:
        !            27:            PUT 1 IN t
        !            28:            Y t
        !            29:            WRITE t
        !            30:     >>> Z
        !            31:     1 2 1
        !            32:     1
        !            33: 
        !            34:    It is clear that the scratch-pad copying for the call of ref in X
        !            35:    must save the local environments of Y and Z, and restore them when
        !            36:    ref exits.
        !            37:    For similar reasons we must save the permanent environment.
        !            38:    All this also interacts with the practice of 'locating' a target.
        !            39:    All targets eventually refer to (one or more) basic targets.
        !            40:    The location of a basic target is represented as a pair (env, key)
        !            41:    where 'env' is the address of the environment in which the target
        !            42:    resides and 'key' is the target's name (for permanent targets) or
        !            43:    its number (for local targets).  When we consider the PUT fp+1 IN fp
        !            44:    line in unit X above, we can see that the (local) environment
        !            45:    for the location returned by 'fp' is the local environment of Z.
        !            46:    Therefore this whole chain must still be intact.
        !            47:    There can be even trickier cases, where a location is saved for a
        !            48:    long time on the execution stack while the environment it refers to
        !            49:    is subject to scratch-pad copying and restoring; when the location
        !            50:    is finally popped off the stack, it must still refer to the correct
        !            51:    environment.
        !            52: 
        !            53:    Another detail to consider is that for the permanent environment,
        !            54:    we need access to the 'real' permanent environment, i.e., its value
        !            55:    before any scratch-pad copying occurred.  (Example:
        !            56: 
        !            57:     >>> YIELD f:
        !            58:            SHARE x
        !            59:            PUT x+1 IN x
        !            60:            READ t EG 0
        !            61:            RETURN t
        !            62:     >>> PUT 0 IN x
        !            63:     >>> WRITE x, f, x
        !            64:     ??? x
        !            65:     0, 0, 0
        !            66:     >>> 
        !            67: 
        !            68:    Even though at the time the READ is called, x has been given the value
        !            69:    1 temporarily, the value of x used in the evaluation of the input
        !            70:    expression is the original value, 0.)
        !            71: 
        !            72:    A final detail to be observed is the passing back of 'bound tags'
        !            73:    when a refined test is called.
        !            74: 
        !            75:    The chosen implementation is as follows:
        !            76:    - Environments are saved in a linked list of structures (envchain) with
        !            77:      two fields: tab, the actual environment (a table or compound) and
        !            78:      inv_env, the link to the previous entry in the list.
        !            79:    - The routines newenvchain and popenvchain push and pop such lists.
        !            80:    - There is one list for the permanent environment, whose head is prmnv,
        !            81:      and one list for the current environment, whose head is usually curnv.
        !            82:      The last element of both lists is actually the same, because at the
        !            83:      immediate command level the current environment is the permanent
        !            84:      environment.  When we are evaluating or locating a formal parameter,
        !            85:      'curnv' points somewhere in the middle of its chain, to the local
        !            86:      environment of the caller.
        !            87:      The two lists are manipulated separately:
        !            88:    - Prmnv is pushed (with a copy of itself) for each scratch-pad copy,
        !            89:      and popped whe a scratch-pad is thrown away.
        !            90:    - Curnv is pushed for each unit invocation, with the new local
        !            91:      environment, and popped when the unit exits.
        !            92:    - When a scratch-pad copy is required, the chain headed by curnv
        !            93:      is walked until a local environment is found without HOW'TO formal
        !            94:      parameters, and a compound containing copies of all the local
        !            95:      environments thus found is saved on the general-purpose value stack.
        !            96:      This value is popped off that stack again and the local environments
        !            97:      in the chain are restored when the scratch-pad copy has to be thrown
        !            98:      away.  (Thus we work on the real thing and save and restore a copy
        !            99:      of it, while the DP prescribes that the system work on a copy.
        !           100:      The effect is the same, of course.)
        !           101:    - There is a third list for bound tags whose treatment is left as an
        !           102:      exercise for the reader.
        !           103:    - When a formal parameter is called, the current value of 'curnv' must
        !           104:      be saved somewhere, so that it can be restored later; in this case
        !           105:      it doesn't follow the stack-wise discipline of the chain.
        !           106:    - Finally note thate that when a YIELD unit is called during the
        !           107:      evaluation of a formal parameter, the chain of local environments
        !           108:      "splices" temorarily, because the new local environment is linked
        !           109:      to curnv which is not the end of the chain.  No problem!
        !           110: 
        !           111:    All this nonsense can be avoided when a copy-restore parameter mechanism
        !           112:    is used instead: then there are no accesses to other local environments
        !           113:    that the current, except a transfer between two "adjacent" ones at call
        !           114:    and return time.  Maybe ABC will have such a parameter mechanism...
        !           115: 
        !           116: */
        !           117: 
        !           118: #include "b.h"
        !           119: #include "b1mem.h"
        !           120: #include "b1obj.h"
        !           121: #include "b2nod.h"
        !           122: #include "b3env.h"
        !           123: #include "b3err.h"
        !           124: #include "b3int.h"
        !           125: #include "b3sem.h"
        !           126: #include "b3sou.h" /* for permkey() and get_pname() */
        !           127: #include "b3sta.h"
        !           128: 
        !           129: /* Fundamental registers: (shared only between this file and b3int.c) */
        !           130: 
        !           131: Visible parsetree pc; /* 'Program counter', current parsetree node */
        !           132: Visible parsetree next; /* Next parsetree node (changed by jumps) */
        !           133: Visible bool report; /* 'Condition code register', outcome of last test */
        !           134: 
        !           135: Visible bool noloc; /* Set while evaluating (as opposed to locating)
        !           136:                        formal parameters of HOW'TOs */
        !           137: 
        !           138: Hidden env boundtags; /* Holds bound tags chain */
        !           139: 
        !           140: /* Value stack: */
        !           141: 
        !           142: /* The run-time value stack grows upward, sp points to the next free entry.
        !           143:    Allocated stack space lies between st_base and st_top.
        !           144:    In the current invocation, the stack pointer (sp) must lie between
        !           145:    st_bottom and st_top.
        !           146:    Stack overflow is corrected by growing st_top, underflow is a fatal
        !           147:    error (generated code is wrong).
        !           148: */
        !           149: 
        !           150: Hidden value *st_base, *st_bottom, *st_top, *sp;
        !           151: Visible int call_level; /* While run() can be called recursively */
        !           152: 
        !           153: #define EmptyStack() (sp == st_bottom)
        !           154: #define BotOffset() (st_bottom - st_base)
        !           155: #define SetBotOffset(n) (st_bottom= st_base + (n))
        !           156: 
        !           157: #define INCREMENT 100
        !           158: 
        !           159: Hidden Procedure st_grow(incr) int incr; {
        !           160:        if (!st_base) { /* First time ever */
        !           161:                st_bottom= sp= st_base=
        !           162:                        (value*) getmem((unsigned) incr * sizeof(value *));
        !           163:                st_top= st_base + incr;
        !           164:        }
        !           165:        else {
        !           166:                int syze= (st_top - st_base) + incr;
        !           167:                int n_bottom= BotOffset();
        !           168:                int n_sp= sp - st_base;
        !           169:                regetmem((ptr*) &st_base, (unsigned) syze * sizeof(value *));
        !           170:                sp = st_base + n_sp;
        !           171:                SetBotOffset(n_bottom);
        !           172:                st_top= st_base + syze;
        !           173:        }
        !           174: }
        !           175: 
        !           176: Visible value pop() {
        !           177:        if (sp <= st_bottom) {
        !           178:                syserr(MESS(4100, "stack underflow"));
        !           179:                return Vnil;
        !           180:        }
        !           181:        return *--sp;
        !           182: }
        !           183: 
        !           184: Visible Procedure push(v) value v; {
        !           185:        if (sp >= st_top) st_grow(INCREMENT);
        !           186:        *sp++ = (v);
        !           187: }
        !           188: 
        !           189: /* - - - */
        !           190: 
        !           191: /* Various call types, used as index in array: */
        !           192: 
        !           193: #define C_prmnv 0
        !           194: #define C_immexp 1
        !           195: #define C_immcmd 2
        !           196: #define C_read 3
        !           197: 
        !           198: #define C_howto 4
        !           199: #define C_yield 5
        !           200: #define C_test 6
        !           201: 
        !           202: #define C_refcmd 7
        !           203: #define C_refexp 8
        !           204: #define C_reftest 9
        !           205: 
        !           206: #define C_formal 10
        !           207: 
        !           208: 
        !           209: /* What can happen to a thing: */
        !           210: 
        !           211: #define Old 'o'
        !           212: #define Cpy 'c'
        !           213: #define New 'n'
        !           214: #define Non '-'
        !           215: 
        !           216: typedef struct {
        !           217:        literal do_cur;
        !           218:        literal do_prm;
        !           219:        literal do_bnd;
        !           220:        literal do_for;
        !           221:        literal do_cntxt;
        !           222:        literal do_resexp;
        !           223: } dorecord;
        !           224: 
        !           225: 
        !           226: /* Table encoding what to save/restore for various call/return types: */
        !           227: /* (Special cases are handled elsewhere.) */
        !           228: 
        !           229: Hidden dorecord doo[] = {
        !           230:        /*               cur  prm  bnd  for  cntxt    resexp */
        !           231: 
        !           232:        /* prmnv */     {Old, Old, Old, Old, In_prmnv, Voi},
        !           233:        /* imm expr */  {Old, Old, Old, Old, In_command, Voi},
        !           234:        /* imm cmd */   {Old, Old, Old, Old, In_command, Voi},
        !           235:        /* READ EG */   {Non, Non, Non, Non, In_read, Voi},
        !           236: 
        !           237:        /* HOW-TO */    {New, Old, Non, New, In_unit, Voi},
        !           238:        /* YIELD */     {New, Cpy, Non, Non, In_unit, Ret},
        !           239:        /* TEST */      {New, Cpy, Non, Non, In_unit, Rep},
        !           240: 
        !           241:        /* REF-CMD */   {Old, Old, Old, Old, In_unit, Voi},
        !           242:        /* ref-expr */  {Cpy, Cpy, Non, Old, In_unit, Ret},
        !           243:        /* ref-test */  {Cpy, Cpy, New, Old, In_unit, Rep},
        !           244: 
        !           245:        /* formal */    {Non, Old, Non, Non, In_formal, Voi},
        !           246: };
        !           247: 
        !           248: #define MAXTYPE ((sizeof doo) / (sizeof doo[0]))
        !           249: 
        !           250: #define Checksum(type) (12345 - (type)) /* Reversible */
        !           251: 
        !           252: 
        !           253: #define Ipush(n) push(MkSmallInt(n))
        !           254: #define Ipop() SmallIntVal(pop())
        !           255: 
        !           256: 
        !           257: Hidden env newenv(tab, inv_env) envtab tab; env inv_env; {
        !           258:        env e= (env) getmem(sizeof(envchain));
        !           259:        e->tab= tab; /* Eats a reference to tab! */
        !           260:        e->inv_env= inv_env;
        !           261:        return e;
        !           262: }
        !           263: 
        !           264: 
        !           265: Hidden Procedure popenv(pe) env *pe; {
        !           266:        env e= *pe;
        !           267:        *pe= e->inv_env;
        !           268:        release(e->tab);
        !           269:        freemem((ptr) e);
        !           270: }
        !           271: 
        !           272: 
        !           273: Forward value save_curnv_chain();
        !           274: 
        !           275: Hidden Procedure call(type, new_pc) intlet type; parsetree new_pc; {
        !           276:        if (type < 0 || type >= MAXTYPE) syserr(MESS(4101, "bad call type"));
        !           277:        if (tracing) tr_call();
        !           278: 
        !           279:        /* Push other stacks */
        !           280: 
        !           281:        if (doo[type].do_bnd != Old) {
        !           282:                boundtags= newenv(
        !           283:                        (doo[type].do_bnd == New) ? mk_elt() : Vnil,
        !           284:                        boundtags);
        !           285:                bndtgs= &boundtags->tab;
        !           286:        }
        !           287:        switch (doo[type].do_cur) {
        !           288: 
        !           289:        case New:
        !           290:                curnv= newenv(Vnil, curnv);
        !           291:                break;
        !           292: 
        !           293:        case Cpy:
        !           294:                push(save_curnv_chain());
        !           295:                break;
        !           296: 
        !           297:        case Non:
        !           298:                push(mk_int((double) ((int) curnv)));
        !           299:                        /* PORTABILITY?!?! */
        !           300:                break;
        !           301: 
        !           302:        }
        !           303:        if (doo[type].do_prm != Old) {
        !           304:                prmnv= newenv(
        !           305:                        (doo[type].do_prm == Cpy) ? copy(prmnv->tab) : Vnil,
        !           306:                        prmnv);
        !           307:        }
        !           308: 
        !           309:        /* Push those things that depend on the call type: */
        !           310: 
        !           311:        if (doo[type].do_for != Old) {
        !           312:                /* Formal parameter context and unit name/type */
        !           313:                /* FP removed */
        !           314:                push(uname); uname= Vnil;
        !           315:        }
        !           316: 
        !           317:        /* Push miscellaneous context info: */
        !           318:        push(curline);
        !           319:        push(curlino);
        !           320:        Ipush(noloc); noloc= No;
        !           321:        Ipush(resexp); resexp= doo[type].do_resexp;
        !           322:        Ipush(cntxt); cntxt= doo[type].do_cntxt;
        !           323:        resval= Vnil;
        !           324: 
        !           325:        /* Push vital data: */
        !           326:        push(next);
        !           327:        Ipush(BotOffset()); ++call_level;
        !           328:        Ipush(Checksum(type)); /* Kind of checksum */
        !           329: 
        !           330:        /* Set st_bottom and jump: */
        !           331:        st_bottom= sp;
        !           332:        next= new_pc;
        !           333: }
        !           334: 
        !           335: 
        !           336: Visible Procedure ret() {
        !           337:        int type; value rv= resval; literal re= resexp;
        !           338:        value oldcurnvtab= Vnil, oldbtl= Vnil;
        !           339: 
        !           340:        if (tracing) tr_ret();
        !           341:        if (cntxt == In_formal && still_ok) { rv= pop(); re= Ret; }
        !           342: 
        !           343:        /* Clear stack: */
        !           344:        while (!EmptyStack()) release(pop());
        !           345: 
        !           346:        /* Pop type and hope it's good: */
        !           347:        st_bottom= st_base; /* Trick to allow popping the return info */
        !           348:        type= Checksum(Ipop());
        !           349:        if (type < 0 || type >= MAXTYPE) syserr(MESS(4102, "stack clobbered"));
        !           350: 
        !           351:        /* Pop vital data: */
        !           352:        SetBotOffset(Ipop()); --call_level;
        !           353:        next= pop();
        !           354: 
        !           355:        /* Pop context info: */
        !           356:        cntxt= Ipop();
        !           357:        resexp= Ipop();
        !           358:        noloc= Ipop();
        !           359:        curlino= pop();
        !           360:        curline= pop();
        !           361: 
        !           362:        /* Variable part: */
        !           363:        if (doo[type].do_for != Old) {
        !           364:                release(uname); uname= pop();
        !           365:                /* FP removed */
        !           366:        }
        !           367:        if (doo[type].do_prm != Old)
        !           368:                popenv(&prmnv);
        !           369:        switch (doo[type].do_cur) {
        !           370: 
        !           371:        case Cpy:
        !           372:                oldcurnvtab= copy(curnv->tab);
        !           373:                rest_curnv_chain(pop());
        !           374:                break;
        !           375: 
        !           376:        case New:
        !           377:                oldcurnvtab= copy(curnv->tab);
        !           378:                popenv(&curnv);
        !           379:                break;
        !           380: 
        !           381:        case Non:
        !           382:                { value v= pop();
        !           383:                  curnv= (env) intval(v);
        !           384:                 release(v);
        !           385:                }
        !           386:                break;
        !           387: 
        !           388:        }
        !           389:        if (doo[type].do_bnd != Old) {
        !           390:                oldbtl= copy(*bndtgs);
        !           391:                popenv(&boundtags);
        !           392:                bndtgs= &boundtags->tab;
        !           393:        }
        !           394: 
        !           395:        /* Fiddle bound tags */
        !           396:        if (oldbtl != Vnil) {
        !           397:                extbnd_tags(oldbtl, oldcurnvtab);
        !           398:                release(oldbtl);
        !           399:        }
        !           400:        if (oldcurnvtab != Vnil) release(oldcurnvtab);
        !           401:        if (call_level == 0) re_env(); /* Resets bndtgs */
        !           402: 
        !           403:        /* Push return value (if any): */
        !           404:        if (re == Ret && still_ok) push(rv);
        !           405: }
        !           406: 
        !           407: /* - - - */
        !           408: 
        !           409: Visible Procedure call_formal(name, number, targ)
        !           410:  value name, number; bool targ; {
        !           411:        value *aa= envassoc(curnv->tab, number); formal *ff= Formal(*aa);
        !           412:        literal ct;
        !           413:        if (aa == Pnil || !Is_formal(*aa)) syserr(MESS(4103, "formal gone"));
        !           414:        if (cntxt != In_formal) {
        !           415:                release(how_context.uname);
        !           416:                sv_context(&how_context); /* for error messages */
        !           417:        }
        !           418:        call(C_formal, ff->fp);
        !           419: 
        !           420:        /* The following should be different, but for now... */
        !           421:        curnv= ff->con.curnv;
        !           422:        release(uname); uname= copy(ff->con.uname);
        !           423:        curline= ff->con.cur_line; curlino= ff->con.cur_lino;
        !           424:        ct= cntxt; cntxt= ff->con.cntxt;
        !           425:        release(act_context.uname);
        !           426:        sv_context(&act_context); cntxt= ct; /* for error messages */
        !           427: 
        !           428:        if (!targ) noloc= Yes;
        !           429:        else if (!Thread2(next)) error(MESS(4104, "expression used as target"));
        !           430: }
        !           431: 
        !           432: Visible Procedure call_refinement(name, def, test)
        !           433:  value name; parsetree def; bool test; {
        !           434:        call(test ? C_reftest : C_refexp,
        !           435:                *Branch(Refinement(def)->rp, REF_START));
        !           436: }
        !           437: 
        !           438: #define YOU_TEST MESS(4105, "You haven't told me how to TEST ")
        !           439: #define YOU_YIELD MESS(4106, "You haven't told me how to YIELD ")
        !           440: 
        !           441: Hidden Procedure udfpr(nd1, name, nd2, isfunc)
        !           442:  value nd1, name, nd2; bool isfunc; {
        !           443:        value *aa;
        !           444:        parsetree u; int k, nlocals; funprd *fpr;
        !           445:        int adicity= nd1 ? Dya : nd2 ? Mon : Zer;
        !           446:        if (!is_unit(name, adicity, &aa)
        !           447:                || !(isfunc ? Is_function(*aa) : Is_predicate(*aa))) {
        !           448:                error3(isfunc ? YOU_YIELD : YOU_TEST, name, 0);
        !           449:                return;
        !           450:        }
        !           451:        fpr= Funprd(*aa);
        !           452:        if (!(fpr->adic==Zer ? nd2==Vnil : (fpr->adic==Mon) == (nd1==Vnil)))
        !           453:                syserr(MESS(4107, "invoked unit has other adicity than invoker"));
        !           454:        if (fpr->pre != Use) syserr(MESS(4108, "udfpr with predefined unit"));
        !           455: 
        !           456:        u= fpr->unit;
        !           457:        if (fpr->unparsed) fix_nodes(&u, &fpr->code);
        !           458:        if (!still_ok) { rem_unit(u); return; }
        !           459:        fpr->unparsed= No;
        !           460:        nlocals= intval(*Branch(u, FPR_NLOCALS));
        !           461:        call(isfunc ? C_yield : C_test, fpr->code);
        !           462:        curnv->tab= mk_compound(nlocals);
        !           463:        for (k= 0; k < nlocals; ++k) *Field(curnv->tab, k)= Vnil;
        !           464:        release(uname); uname= get_pname(u);
        !           465:        if (nd1 != Vnil) push(copy(nd1));
        !           466:        if (nd2 != Vnil) push(copy(nd2));
        !           467: }
        !           468: 
        !           469: Visible Procedure formula(nd1, name, nd2, tor) value nd1, name, nd2, tor; {
        !           470:        if (tor == Vnil) udfpr(nd1, name, nd2, Yes);
        !           471:        else {
        !           472:                if (!Is_function(tor))
        !           473:                        syserr(MESS(4109, "formula called with non-function"));
        !           474:                push(pre_fun(nd1, Funprd(tor)->pre, nd2));
        !           475:        }
        !           476: }
        !           477: 
        !           478: Visible Procedure proposition(nd1, name, nd2, pred) value nd1, name, nd2, pred; {
        !           479:        if (pred == Vnil) udfpr(nd1, name, nd2, No);
        !           480:        else {
        !           481:                if (!Is_predicate(pred))
        !           482:                        syserr(MESS(4110, "proposition called with non-predicate"));
        !           483:                report= pre_prop(nd1, Funprd(pred)->pre, nd2);
        !           484:        }
        !           485: }
        !           486: 
        !           487: Visible Procedure v_mystery(name, number) value name, number; {
        !           488:        value *aa; fun f;
        !           489:        aa= envassoc(curnv->tab, Is_compound(curnv->tab) ? number : name);
        !           490:        if (aa != Pnil) push(copy(*aa));
        !           491:        else if (is_zerfun(name, &f)) {
        !           492:                if (Funprd(f)->pre == Use) f= Vnil;
        !           493:                formula(Vnil, name, Vnil, f);
        !           494:        }
        !           495:        else error3(0, name, MESS(4111, " has not yet received a value"));
        !           496: }
        !           497: 
        !           498: Hidden value mk_formal(pt) parsetree pt; {
        !           499:        value f= grab_for(); formal *ff= Formal(f);
        !           500:        sv_context(&ff->con); ff->fp= pt;
        !           501:        return f;
        !           502: }
        !           503: 
        !           504: Visible Procedure x_user_command(name, actuals, def)
        !           505:  value name; parsetree actuals; value def;
        !           506: {
        !           507:        how *h; parsetree u; value *aa;
        !           508:        value v, formals; int k, len;
        !           509:        if (def != Vnil) {
        !           510:                if (!Is_refinement(def)) syserr(MESS(4112, "bad def in x_user_command"));
        !           511:                call(C_refcmd, *Branch(Refinement(def)->rp, REF_START));
        !           512:                return;
        !           513:        }
        !           514:        if (!is_unit(name, How, &aa)) {
        !           515:                error3(MESS(4113, "You haven't told me HOW'TO "), name, 0);
        !           516:                return;
        !           517:        }
        !           518:        u= (h= How_to(*aa))->unit;
        !           519:        if (h->unparsed) fix_nodes(&u, &h->code);
        !           520:        if (!still_ok) { rem_unit(u); return; }
        !           521:        h->unparsed= No;
        !           522:        formals= *Branch(u, HOW_FORMALS);
        !           523:        len= intval(*Branch(u, HOW_NLOCALS)); k= 0;
        !           524:        v= mk_compound(len);
        !           525:        while (actuals != Vnil && formals != Vnil) { /* Save actuals */
        !           526:                if (*Branch(actuals, ACT_EXPR) != Vnil) {
        !           527:                        if (k >= len) syserr(MESS(4114, "too many actuals"));
        !           528:                        *Field(v, k++)= mk_formal(*Branch(actuals, ACT_START));
        !           529:                }
        !           530:                actuals= *Branch(actuals, ACT_NEXT);
        !           531:                formals= *Branch(formals, FML_NEXT);
        !           532:        }
        !           533:        for (; k < len; ++k) { *Field(v, k)= Vnil; }
        !           534: 
        !           535:        call(C_howto, h->code);
        !           536:        
        !           537:        curnv->tab= v;
        !           538:        release(uname); uname= permkey(name, How);
        !           539: }
        !           540: 
        !           541: Visible Procedure endsta() {
        !           542:        if (st_base) {
        !           543:                freemem((ptr) st_base);
        !           544:                st_base= Pnil;          
        !           545:        }
        !           546: }
        !           547: 
        !           548: Hidden value save_curnv_chain() {
        !           549:        value pad;
        !           550:        value c, f;
        !           551:        formal *ff;
        !           552:        int cnt, k;
        !           553: 
        !           554:        /* Count how many */
        !           555:        c= curnv->tab;
        !           556:        for (cnt= 0; ; ) {
        !           557:                if (!Is_compound(c)) break;
        !           558:                ++cnt;
        !           559:                f= *Field(c, 0);
        !           560:                if (!Is_formal(f)) break;
        !           561:                ff= Formal(f);
        !           562:                c= ff->con.curnv->tab;
        !           563:        }
        !           564: 
        !           565:        pad= mk_compound(cnt);
        !           566: 
        !           567:        /* Do the copy */
        !           568:        c= curnv->tab;
        !           569:        for (k= 0; ; ) {
        !           570:                if (!Is_compound(c)) break;
        !           571:                *Field(pad, k)= copy(c);
        !           572:                if (++k >= cnt) break;
        !           573:                f= *Field(c, 0);
        !           574:                if (!Is_formal(f)) break;
        !           575:                ff= Formal(f);
        !           576:                c= ff->con.curnv->tab;
        !           577:        }
        !           578:        if (k != cnt)
        !           579:                syserr(MESS(4115, "save_curnv_chain: phase error"));
        !           580: 
        !           581:        return pad;
        !           582: }
        !           583: 
        !           584: Hidden rest_curnv_chain(pad) value pad; {
        !           585:        int k, cnt;
        !           586:        value f, *c= &curnv->tab;
        !           587:        formal *ff;
        !           588: 
        !           589:        if (pad == Vnil || !Is_compound(pad))
        !           590:                syserr(MESS(4116, "rest_curnv_chain: bad pad"));
        !           591:        cnt= Nfields(pad);
        !           592:        for (k= 0; ; ) {
        !           593:                if (!Is_compound(*c)) break;
        !           594:                release(*c);
        !           595:                *c= copy(*Field(pad, k));
        !           596:                if (++k >= cnt) break;
        !           597:                f= *Field(*c, 0);
        !           598:                if (!Is_formal(f)) break;
        !           599:                ff= Formal(f);
        !           600:                c= &ff->con.curnv->tab;
        !           601:        }
        !           602:        if (k != cnt)
        !           603:                syserr(MESS(4117, "rest_curnv_chain: phase error"));
        !           604:        release(pad);
        !           605: }

unix.superglobalmegacorp.com

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