|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.