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: }

Defined functions

call defined in line 275; used 5 times
call_formal defined in line 409; used 1 times
call_refinement defined in line 432; used 1 times
endsta defined in line 541; used 1 times
formula defined in line 469; used 4 times
mk_formal defined in line 498; used 1 times
newenv defined in line 257; used 3 times
pop defined in line 176; used 50 times
popenv defined in line 265; used 3 times
proposition defined in line 478; used 3 times
push defined in line 184; used 33 times
rest_curnv_chain defined in line 584; used 1 times
ret defined in line 336; used 2 times
save_curnv_chain defined in line 548; used 2 times
st_grow defined in line 159; used 1 times
udfpr defined in line 441; used 2 times
v_mystery defined in line 487; used 1 times
x_user_command defined in line 504; used 1 times

Defined variables

Hidden defined in line 584; never used
Procedure defined in line 184; never used
Visible defined in line 184; never used
boundtags defined in line 138; used 5 times
call_level defined in line 151; used 6 times
next defined in line 132; used 4 times
noloc defined in line 135; used 4 times
pc defined in line 131; never used
report defined in line 133; used 1 times
sp defined in line 150; used 9 times
st_base defined in line 150; used 14 times
st_bottom defined in line 150; used 7 times
st_top defined in line 150; used 4 times

Defined macros

BotOffset defined in line 154; used 2 times
C_formal defined in line 206; used 1 times
C_howto defined in line 198; used 1 times
C_immcmd defined in line 195; never used
C_immexp defined in line 194; never used
C_prmnv defined in line 193; never used
C_read defined in line 196; never used
C_refcmd defined in line 202; used 1 times
C_refexp defined in line 203; used 1 times
C_reftest defined in line 204; used 1 times
C_test defined in line 200; used 1 times
C_yield defined in line 199; used 1 times
Checksum defined in line 250; used 2 times
Cpy defined in line 212; used 7 times
EmptyStack defined in line 153; used 1 times
INCREMENT defined in line 157; used 1 times
Ipop defined in line 254; used 5 times
Ipush defined in line 253; used 5 times
MAXTYPE defined in line 248; used 2 times
New defined in line 213; used 6 times
Non defined in line 214; used 13 times
Old defined in line 211; used 26 times
SetBotOffset defined in line 155; used 2 times
YOU_TEST defined in line 438; used 1 times
YOU_YIELD defined in line 439; used 1 times
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4684
Valid CSS Valid XHTML 1.0 Strict