Annotation of 43BSD/contrib/icon/docs/tr83-10c.roff, revision 1.1

1.1     ! root        1: .NH 3
        !             2: \*Mrt/arith.s\fR
        !             3: .SH
        !             4: Overview
        !             5: .PP
        !             6: \*Marith.s\fP contains code for routines that add,\^ subtract,\^ and
        !             7: multiply integers and check for overflow.  If overflow occurs,\^
        !             8: run-time error 203 is produced.
        !             9: .PP
        !            10: The arguments to \*Mckadd\fP,\^ \*Mcksub\fP,\^ and \*Mckmul\fP are
        !            11: two C \*Mlong\fP integers on which to operate.  For example,\^
        !            12: if \*Mckadd\fP were written in C,\^ it would be declared
        !            13: .Ds
        !            14: long ckadd(a,\^b)
        !            15: long a,\^b;
        !            16: {
        !            17: \&\*(El
        !            18: }
        !            19: .De
        !            20: The routines return the result of the operation
        !            21: using standard C return conventions.
        !            22: .SH
        !            23: \*Marith\fP on the VAX
        !            24: .PP
        !            25: The two arguments appear on the stack; \*Ma\fP is at \*M4(ap)\fP and
        !            26: \*Mb\fP is at \*M8(ap)\fP.  The appropriate 3-operand VAX instruction
        !            27: is used to perform the operation and the result is placed in \*Mr0\fP
        !            28: in accordance with C return conventions.  If overflow occurs
        !            29: during the operation,\^ the overflow bit in the program status word
        !            30: is set.
        !            31: .PP
        !            32: After the operation is performed,\^ the overflow bit is
        !            33: checked.  If it is on,\^ indicating that an overflow occurred,\^ a branch
        !            34: is taken to \*Moflow\fP,\^ where \*Mrunerr(203,\^0)\fP is called.
        !            35: If overflow did not occur,\^ the routine returns and the value in
        !            36: \*Mr0\fP is the value returned to the calling expression.
        !            37: .PP
        !            38: \*Marith.s\fP is trivial on the VAX because the hardware supports
        !            39: operations on C \*Mlong\fP integers.  This may not be the case on the
        !            40: target machine.  If so,\^ \*Marith.s\fP will be considerably more
        !            41: complicated.  However,\^ it usually is not difficult to locate routines
        !            42: that perform these functions.  As a last resort,\^ look at the code the C
        !            43: compiler generates for the various arithmetic operations on long
        !            44: integers.
        !            45: .NH 3
        !            46: \*Mrt/fail.s\fR
        !            47: .SH
        !            48: Overview
        !            49: .PP
        !            50: \*Mfail\fP handles the failure of built-in procedures and operations.
        !            51: Built-in procedures and operations are C routines and they signal
        !            52: failure by calling \*Mfail()\fP.  When a failure of this type
        !            53: occurs,\^ the failure must be transmitted to the Icon expression
        !            54: whose evaluation is in progress and that requires the services of
        !            55: a C routine.
        !            56: .SH
        !            57: Generic Operation
        !            58: .PP
        !            59: \*Mfail\fP itself does very little,\^ the real work is done by
        !            60: \*Mefail\fP.  \*Mfail\fP pops the stack
        !            61: back to where it was before the C routine was called and then
        !            62: branches to \*Mefail\fP to make the enclosing expression fail.
        !            63: .PP
        !            64: \*Mfail\fP is akin to \*Mpfail\fP in that it pops the stack back
        !            65: to a state that it was in when an expression was being evaluated
        !            66: and then causes failure of the expression.  The primary difference
        !            67: is that an Icon procedure frame is being removed in \*Mpfail\fP and
        !            68: it contains extra information that must be restored.
        !            69: .SH
        !            70: \*Mfail\fP on the VAX
        !            71: .PP
        !            72: \*M_boundary\fP points to the procedure frame for the first C routine
        !            73: that was called from Icon.  \*Mfp\fP is loaded from \*M_boundary\fP and
        !            74: this puts the stack back to the state that it was in when the 
        !            75: C routine was entered.  The C routine is for either a built-in procedure
        !            76: such as \*Mread\fP or for an operator such as \*M+\fP.  For a
        !            77: built-in procedure,\^ the procedure frame now on the top of the stack
        !            78: (after loading \*Mfp\fP from \*M_boundary\fP) is the frame constructed
        !            79: in \*Minvoke\fP.  For an operator,\^ the frame on the stack is the
        !            80: one constructed when the interpreter loop called the C routine
        !            81: for the operator.
        !            82: .PP
        !            83: The task at hand is to remove the procedure frame and restore the
        !            84: registers that were saved in the frame.  The mask/psw word of the
        !            85: frame is manipulated so that the mask portion of the word resides
        !            86: in bits 0:11 of \*Mr0\fP and the remaining bits of \*Mr0\fP are 0.
        !            87: The VAX \*Mpopr\fP instruction takes a register mask as an operand
        !            88: and pops words from the stack into the registers indicated by
        !            89: the mask.  For example,\^
        !            90: .Ds
        !            91: popr   $0x0005
        !            92: .De
        !            93: moves the top word of the stack into \*Mr0\fP and the second stack
        !            94: word into \*Mr2\fP.  \*Msp\fP is then incremented by 8.
        !            95: .PP
        !            96: The saved registers start at \*M20(fp)\fP and \*Msp\fP is loaded
        !            97: with this address.  Then \*Mpopr r0\fP restores the registers
        !            98: that are saved in the frame.  Note that the manipulations of the
        !            99: mask/psw are necessary because it is not known \fIa priori\fP which
        !           100: registers were saved.  In particular,\^ \*Mpopr $0x0fff\fP would
        !           101: be disastrous.
        !           102: .PP
        !           103: After the registers have been restored,\^ \*Map\fP and \*Mfp\fP are
        !           104: restored from the saved \*Map\fP and \*Mfp\fP values in the
        !           105: frame.
        !           106: .PP
        !           107: At this point,\^ the stack is as it was before the frame for
        !           108: the built-in procedure or operator was created.  All that
        !           109: remains is to signal failure in the expression being evaluated
        !           110: and this is done by branching to \*Mefail\fP.
        !           111: .ne 1i
        !           112: .NH 3
        !           113: \*Mlib/pret.s\fR
        !           114: .SH
        !           115: Overview
        !           116: .PP
        !           117: \*Mpret\fP handles the return of a value from an Icon procedure.
        !           118: \*Mpret\fP is called from the interpreter loop with a single
        !           119: argument (which is on the stack)
        !           120: that is the value being returned.  The value is dereferenced
        !           121: if necessary.  If tracing is on,\^ a trace message is produced.  The
        !           122: return value is copied over \*(e0 in the frame of the procedure that
        !           123: is returning a value.  The procedure frame is removed,\^ leaving
        !           124: the result on the stack,\^ and \*Mpret\fP returns.
        !           125: .SH
        !           126: Generic Operation
        !           127: .LP
        !           128: .Ls
        !           129: .Np
        !           130: \*M&level\fP is decremented because a procedure is being exited.
        !           131: .Np
        !           132: The stack address where the return value is
        !           133: to be placed is calculated.  Recall that when a procedure is invoked,\^ the
        !           134: return value (if any) ultimately replaces \*(e0,\^ the descriptor
        !           135: for the procedure returning the value.
        !           136: .Np
        !           137: The value being returned must be dereferenced if it is a local
        !           138: variable or argument.  This is because local variables and arguments
        !           139: are on the stack and the portion of the stack associated with
        !           140: a procedure ``goes away'' when a procedure returns.  If the
        !           141: return value is a variable (is of type \*MT_VAR\fP)
        !           142: and its address
        !           143: is between the base of the current expression stack*,\^
        !           144: and the stack pointer,\^ it is dereferenced.
        !           145: If it is a substring trapped variable (is of type \*MT_TVAR\fP
        !           146: and points to a block of type \*MT_TVSUBS\fP),\^ and the address of the
        !           147: variable containing the substring 
        !           148: is between the base of the current expression stack
        !           149: and the stack pointer,\^ it is dereferenced.
        !           150: .FS
        !           151: *For purposes of uniformity,\^ the system stack is treated
        !           152: as if it were a co-expression stack.  The global variable
        !           153: \*Mcurrent\fP is a pointer to the descriptor for the co-expression
        !           154: stack block for the current co-expression.  Co-expressions
        !           155: need not be implemented; it is only important that \*Mcurrent\fP
        !           156: and the descriptor that it points to be initialized correctly.
        !           157: This is done in \*Miconx/init.c\fP.
        !           158: .FE
        !           159: .Np
        !           160: If \*M&trace\fP is non-zero,\^ \*Mrtrace\fP is called with the
        !           161: address of the block for the returning procedure and the
        !           162: address of the value being returned.
        !           163: .Np
        !           164: \*Mfp\fP,\^ \*M_line\fP,\^ and
        !           165: \*M_file\fP are restored from the returning procedure.
        !           166: Because the impending return restores control to the Icon
        !           167: environment,\^ \*M_boundary\fP is cleared.
        !           168: .Np
        !           169: \*Mpret\fP returns from the Icon procedure by executing
        !           170: a return instruction.  Because the current \*Mfp\fP points to the
        !           171: procedure frame for the Icon procedure,\^ and the frame was
        !           172: built by \*Minvoke\fP,\^ the return is effectively a return
        !           173: from \*Minvoke\fP and the net result is the return value
        !           174: left on the stack. 
        !           175: .Le
        !           176: .SH
        !           177: \*Mpret\fP on the VAX
        !           178: .PP
        !           179: \*Mpret\fP does not save any registers because the frame built
        !           180: upon entry to \*Mpret\fP is discarded.
        !           181: .PP
        !           182: \*M_boundary\fP is set because \*Mderef\fP may be called and \*Mderef\fP
        !           183: can cause a garbage collection.
        !           184: .PP
        !           185: \*M_k_level\fP is decremented because a procedure is being exited.
        !           186: .PP
        !           187: \*Mpret\fP needs to know the address of the descriptor for the Icon
        !           188: procedure that is returning.  Before \*Mpret\fP was called,\^ \*Mfp\fP
        !           189: pointed at the procedure frame for the current Icon procedure (which
        !           190: is now returning),\^ and \*Map\fP pointed at its argument list.  The
        !           191: call to \*Mpret\fP created a procedure frame which contains the old
        !           192: \*Map\fP.  This value is extracted and used in conjunction with
        !           193: \fInargs\fP to calculate the address of the descriptor for the
        !           194: procedure.  This value is stored in \*Mr11\fP for future use.
        !           195: .PP
        !           196: As described,\^ the value being returned needs to be dereferenced
        !           197: in certain cases.  The return value is a descriptor and is the
        !           198: argument to \*Mpret\fP.  The first word of this descriptor
        !           199: lies at \*M8(ap)\fP and contains type and flag information.  This
        !           200: word is placed in \*Mr1\fP for further examination.
        !           201: .PP
        !           202: The VAX \*Mbitl\fP instruction tests a set of bits.  The two
        !           203: operand values are ANDed together and the condition codes
        !           204: are set according to the value of the result.  The result itself
        !           205: is discared.  The instruction
        !           206: .Ds
        !           207: bitl   $F_NQUAL,\^r1
        !           208: .De
        !           209: ANDs the type and flags word with the \*MF_NQUAL\fP mask.
        !           210: The \*MF_NQUAL\fP bit is set if a descriptor is \fInot\fP a
        !           211: string qualifier.
        !           212: If the \*MF_NQUAL\fP bit is not on,\^ the result of the
        !           213: AND is a 0.  The test is followed by
        !           214: .Ds
        !           215: beql   chktrace
        !           216: .De
        !           217: Thus,\^ if the return value \fIis\fP a string qualifier,\^ a branch
        !           218: is taken to \*Mchktrace\fP,\^ and no dereferencing is performed.
        !           219: .PP
        !           220: If the return value does have the \*MF_NQUAL\fP attribute,\^ it
        !           221: is checked to see if it is a variable. The \*MF_VAR\fP bit is tested.
        !           222: If it is not on,\^ the return value is not a variable and does
        !           223: not have to be dereferenced.  A branch is made to \*Mchktrace\fP if
        !           224: this is the case.
        !           225: .PP
        !           226: If a variable is in hand,\^ the \*MF_TVAR\fP bit is checked to see
        !           227: if it is a trapped variable.  If it is not a trapped variable,\^ the
        !           228: address field of the return value's descriptor is moved into \*Mr1\fP for
        !           229: further testing and a branch is taken to \*Mchkloc\fP.
        !           230: .PP
        !           231: If the return value is a substring trapped variable,\^ it may reference
        !           232: a local variable or an argument.  The type bits of the descriptor
        !           233: are isolated by ORing it with \*MTYPEMASK\fP.  If the type
        !           234: is not \*MT_TVSUBS\fP,\^ no dereferencing is needed and a branch
        !           235: is taken to \*Mchktrace\fP.  If it is a substring trapped variable,\^
        !           236: the address of the variable containing the substring is obtained
        !           237: from the trapped variable's data block and is loaded into \*Mr1\fP.
        !           238: .PP
        !           239: At this point (\*Mchkloc\fP),\^ \*Mr1\fP points to a descriptor
        !           240: that is directly or indirectly referenced by the return value.
        !           241: If the descriptor is in the current expression stack,\^ the return
        !           242: value must be dereferenced.  \*Mr1\fP is first compared to
        !           243: \*Msp\fP.  If it is less than \*Msp\fP,\^ the descriptor is below
        !           244: the stack and a branch is made to \*Mchktrace\fP.  Otherwise,\^
        !           245: \*Mr1\fP is compared to the base address of the current expression
        !           246: stack.  If \*Mr1\fP is greater than the base of stack,\^ it is
        !           247: above the stack and a branch is made to \*Mchktrace\fP.
        !           248: .PP
        !           249: It is now certain that the return value must be
        !           250: dereferenced,\^ lest it ``disappear'' when the portion of the stack
        !           251: it is in is re-used.  The address of the return value is pushed
        !           252: on the stack and \*Mderef\fP is called.  Note that \*Mderef\fP completely
        !           253: handles dereferencing of substring trapped variables and thus no
        !           254: special provisions need to be made.
        !           255: .PP
        !           256: At \*Mchktrace\fP,\^ the return value has been dereferenced if
        !           257: necessary and it is time to produce a tracing message if \*M&trace\fP
        !           258: is non-zero.  \*Mrtrace\fP does the work and it
        !           259: requires two arguments: the address of the block for the returning
        !           260: procedure,\^ and the address of the return value.  Earlier,\^ the
        !           261: address of descriptor for the procedure block was calculated and left
        !           262: in \*Mr11\fP.  The second word of this descriptor is pushed on
        !           263: the stack along with the address of the return value.
        !           264: .PP
        !           265: \*Mpret\fP ``returns'' the designated
        !           266: value by overwriting the procedure's descriptor
        !           267: with the descriptor of the return value.  \*Mr11\fP points at the
        !           268: descriptor for the procedure and \*M8(ap)\fP still points at the
        !           269: descriptor for the return value,\^ so
        !           270: .Ds
        !           271: movq   8(ap),\^(r11)
        !           272: .De
        !           273: does the trick.
        !           274: .PP
        !           275: Everything is set,\^ the actual return must be performed.  The \*Mfp\fP
        !           276: saved in the current frame is the procedure frame pointer of the Icon
        !           277: procedure and the saved value is loaded into \*Mfp\fP to bring
        !           278: the Icon procedure frame to the top of the stack.  \*M_line\fP and
        !           279: \*M_file\fP are restored from the Icon procedure frame.
        !           280: \*M_boundary\fP is cleared because the return will take execution back
        !           281: into an Icon realm.
        !           282: .PP
        !           283: A \*Mret\fP is executed.  The return goes through the procedure
        !           284: frame built by \*Minvoke\fP.  Thus,\^ control is returned to the point
        !           285: just after the call to \*Minvoke\fP and it appears as if \*Minvoke\fP
        !           286: itself had just returned.
        !           287: .NH 3
        !           288: \*Mlib/esusp.s\fR
        !           289: .SH
        !           290: Overview
        !           291: .LP
        !           292: \*Mesusp\fP suspends a value from an expression.  \*Mesusp\fP is
        !           293: called from the interpreter loop and the value to suspend appears
        !           294: as an argument.  A generator frame hiding the current expression
        !           295: is created.  The surrounding expression frame is duplicated.
        !           296: \*Mesusp\fP leaves the value being suspended on the top of the stack.
        !           297: .PP
        !           298: The \*Mesusp\fP operation arises from the alternation
        !           299: (\*M\*(x1\ |\ \^\*(x2\fR) control
        !           300: structure.  For example
        !           301: .Ds
        !           302: p(5 | 10)
        !           303: .De
        !           304: indicates that the call \*Mp(5)\fP should be made and if it fails,\^ then
        !           305: \*Mp(10)\fP should be called. 
        !           306: .PP
        !           307: The function of \*Mesusp\fP is best explained using an example.
        !           308: The following ucode is generated for \*Mp(5 | 10)\fP
        !           309: .Ds
        !           310: .ta .8i +.8i +.8i +.8i
        !           311:        mark    L1
        !           312:        var     0       \fR(the variable \*Mp\fR)\*M
        !           313:        mark    L2
        !           314:        int     0       \fR(constant 5)\*M
        !           315:        esusp
        !           316:        goto    L3
        !           317: lab L2
        !           318:        int     1       \fR(constant 10)\*M
        !           319: lab L3
        !           320:        invoke  1
        !           321:        unmark  1
        !           322: lab L1
        !           323: .De
        !           324: When execution reaches \*Mesusp\fP,\^ the stack looks like
        !           325: .Ds
        !           326: .ft R
        !           327: .ta 1i
        !           328:        expression marker with \*ML1\fR as failure address
        !           329:        descriptor for variable \*Mp\fR
        !           330: \*Mefp\fR \*(ar        expression marker with \*ML2\fR as failure address
        !           331: \*Msp\fR \*(ar descriptor for constant 5
        !           332: .De
        !           333: \*Mgfp\fP is zero at this point.
        !           334: After the \*Mesusp\fP is performed,\^ the stack is
        !           335: .Ds
        !           336: .ft R
        !           337: .ta 1i
        !           338: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
        !           339:        descriptor for variable \*Mp\fR
        !           340:        expression marker with \*ML2\fR as failure address
        !           341:        descriptor for constant 5
        !           342: \*Mgfp\fR \*(ar        generator frame built by \*Mesusp\fR
        !           343: .ta 1i 3.3i
        !           344:        descriptor for variable \*Mp\fR } duplicated region
        !           345: \*Msp\fR \*(ar descriptor for constant 5
        !           346: .De
        !           347: A branch is taken to \*ML3\fP,\^ where \*Minvoke 1\fP is performed.
        !           348: This invokes \*Mp\fP with one argument,\^ the constant 5 on the
        !           349: stack.  If \*Mp(5)\fP succeeds,\^ the \*Munmark 1\fP is performed
        !           350: and the stack is popped back through the \*ML1\fP expression frame,\^
        !           351: the current location of \*Mefp\fP.
        !           352: .PP
        !           353: Suppose that instead of succeeding,\^ \*Mp(5)\fP fails.
        !           354: \*Mp\fP fails by calling \*Mpfail\fP,\^ which removes the
        !           355: procedure frame from the stack and then calls \*Mefail\fP.  The
        !           356: previous stack picture shows what the stack looks like after the
        !           357: procedure frame has been removed.  \*Mefail\fP finds that
        !           358: \*Mgfp\fP is not null and restores certain values that are saved
        !           359: in the generator frame.  The frame,\^ which was created by \*Mesusp\fP,\^
        !           360: contains a return address that points to \*Mefail\fP.  Thus,\^ when
        !           361: \*Mefail\fP removes the frame by returning through it,\^ control goes
        !           362: back to the start of \*Mefail\fP and the stack is
        !           363: .Ds
        !           364: .ft R
        !           365: .ta 1i
        !           366:        expression marker with \*ML1\fR as failure address
        !           367:        descriptor for variable \*Mp\fR
        !           368: \*Mefp\fR \*(ar        expression marker with \*ML2\fR as failure address
        !           369: \*Msp\fR \*(ar descriptor for constant 5
        !           370: .De
        !           371: This time around,\^ \*Mgfp\fP is zero,\^ so \*Mefail\fP must remove
        !           372: the current expression frame and branch to the failure address in
        !           373: the frame's marker.  When the expression frame is removed,\^ the
        !           374: stack looks like
        !           375: .Ds
        !           376: .ft R
        !           377: .ta 1i
        !           378:        expression marker with \*ML1\fR as failure address
        !           379: \*Msp\fR \*(ar descriptor for variable \*Mp\fR
        !           380: .De
        !           381: The failure address in the expression frame was \*ML2\fP,\^ so control
        !           382: is transferred to \*Mlabel L2\fP in the ucode.  (Note how much went
        !           383: on as the result of the \*Minvoke\fP being executed.)  The
        !           384: instruction \*Mint 1\fP is executed and a descriptor for the constant
        !           385: 10 is pushed on the stack giving:
        !           386: .Ds
        !           387: .ft R
        !           388: .ta 1i
        !           389:        expression marker with \*ML1\fR as failure address
        !           390:        descriptor for variable \*Mp\fR
        !           391: \*Msp\fR \*(ar descriptor for constant 10
        !           392: .De
        !           393: \*Minvoke 1\fP is performed again,\^ which does \*Mp(10)\fP.
        !           394: .PP
        !           395: If \*Mp(10)\fP succeeds,\^ the \*Munmark 1\fP is executed,\^ which
        !           396: removes the \*ML1\fP marker and transfers control to \*ML1\fP.
        !           397: If \*Mp(10)\fP fails,\^ the same thing happens,\^ but \*Mefail\fP
        !           398: does the work rather than \*Munmark\fP.
        !           399: .SH
        !           400: Generic Operation
        !           401: .LP
        !           402: .Ls
        !           403: .Np
        !           404: The procedure frame created by the call to \*Mesusp\fP partially
        !           405: forms the generator frame. The frame is completed by pushing
        !           406: \*M_boundary\fP,\^ \*M_k_level\fP,\^ \*M_line\fP,\^ and \*M_file\fP.
        !           407: The generator frame pointer is set to point at the word of the
        !           408: frame which contains the boundary.
        !           409: .Np
        !           410: The bounds of the expression frame to be duplicated are determined.
        !           411: The lower bound is the stack word above the current expression frame
        !           412: marker.
        !           413: The upper bound is dependent on \*Mefp\fP and \*Mgfp\fP
        !           414: values saved in the current expression marker.  If the saved \*Mgfp\fP is
        !           415: non-zero,\^ the upper bound is the first word below the generator
        !           416: frame marker.  If the saved \*Mgfp\fP is zero,\^ the upper bound is
        !           417: the first word below the expression frame marker referenced by the
        !           418: saved \*Mefp\fP.  In the example,\^ this region only contains
        !           419: the descriptor for the variable \*Mp\fP.
        !           420: The region is copied to the top of the stack.  The stack pointer is
        !           421: adjusted to point to the new top of stack.
        !           422: .Np
        !           423: The value being suspended is pushed on the stack.
        !           424: .Np
        !           425: The return address in the new generator frame is replaced by the address of
        !           426: \*Mefail\fP so that when \*Mefail\fP removes the frame by returning through
        !           427: it,\^ \*Mefail\fP regains control.  The old return address is
        !           428: momentarily retained.  The procedure frame pointer and argument
        !           429: pointer are restored.  \*M_boundary\fP is cleared because control is
        !           430: returning to Icon code.
        !           431: .Np
        !           432: \*Mefp\fP in the current expression
        !           433: marker replaces the expression frame pointer.  Thus,\^ if an \*Munmark\fP
        !           434: is performed,\^ the entire expression frame is removed.  In the example,\^
        !           435: this happens if \*Mp(5)\fP or \*Mp(10)\fP succeeds.
        !           436: .Np
        !           437: The return \*Mpc\fP value which was saved is jumped to.  This is in
        !           438: effect a return from \*Mesusp\fP,\^ but the stack is untouched.
        !           439: .Le
        !           440: .SH
        !           441: \*Mesusp\fP on the VAX
        !           442: .PP
        !           443: When \*Mesusp\fP is entered,\^ the generator frame is partially
        !           444: constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
        !           445: the frame.  \*M_boundary\fP is set to the current \*Mfp\fP value
        !           446: and is pushed on the stack.  The generator frame pointer,\^ is pointed at
        !           447: the word containing the boundary.
        !           448: The frame is completed by pushing \*M_k_level\fP,\^ \*M_line\fP,\^
        !           449: and \*M_file\fP on the stack.
        !           450: .PP
        !           451: The lower bound of the region to copy is the first word above the
        !           452: current expression frame marker.  Recall that an expression frame
        !           453: looks like
        !           454: .Ds
        !           455: .ft R
        !           456: .St
        !           457: \*Mefp\fR \*(ar        0       old expression frame pointer
        !           458:        -4      old generator frame pointer
        !           459:        -8      failure address
        !           460: .De
        !           461: Thus,\^
        !           462: .Ds
        !           463: addl3   $4,\^efp,\^r0
        !           464: .De
        !           465: points \*Mr0\fP at the lower end of the region to copy.
        !           466: .PP
        !           467: The upper bound of the region to copy is the low word of the marker
        !           468: for the enclosing generator or expression frame.  If \*Mgfp\fP
        !           469: is non-zero the generator frame marker is used.
        !           470: Otherwise,\^ the expression frame marker is used.  Recall that a
        !           471: generator frame looks like
        !           472: .Ds
        !           473: .ft R
        !           474: .St
        !           475:                saved registers
        !           476:        20      reactivation address (saved \*Mpc\fR)
        !           477:        16      saved \*Mfp\fR
        !           478:        12      saved \*Map\fR
        !           479:        8       \*Mpsw\fR and register mask
        !           480:        4       0
        !           481: \*Mgfp\fR \*(ar        0       boundary
        !           482:        -4      saved \*M_k_level\fR
        !           483:        -8      saved \*M_line\fR
        !           484:        -12     saved \*M_file\fR
        !           485: .De
        !           486: So,\^ if the saved \*Mgfp\fP is non-zero,\^ the upper bound of the region
        !           487: to copy is
        !           488: .Ds
        !           489: .ft R
        !           490: saved \*Mgfp\fR - 12
        !           491: .De
        !           492: Otherwise,\^ it is
        !           493: .Ds
        !           494: .ft R
        !           495: saved \*Mefp\fR - 8
        !           496: .De
        !           497: The appropriate calculation is performed and \*Mr2\fP pointed at the
        !           498: bounding word.
        !           499: .LP
        !           500: At this point,\^ the stack looks something like
        !           501: .Ds
        !           502: .ft R
        !           503: .St
        !           504: \*Mr2\fR \*(ar         low word of expression or generator frame marker
        !           505:                last word of region to copy
        !           506:                \*(El
        !           507: \*Mr0\fR \*(ar 4       first word of region to copy
        !           508: \*Mefp\fR \*(ar        0       saved expression frame pointer
        !           509:        -4      saved generator frame pointer   expression marker
        !           510:        -8      failure label
        !           511:        8       descriptor for value to suspend
        !           512:        4       \*Mnargs\fR (1)
        !           513: \*Map\fR \*(ar 0       \*Mnwords\fR (3)
        !           514:        -4      saved \*Mr11\fR (\*Mefp\fR)
        !           515:                saved \*Mr10\fR (\*Mgfp\fR)
        !           516:        24      saved \*Mr9\fR (\*Mipc\fR)
        !           517:        20      reactivation address (saved \*Mpc\fR)
        !           518:        16      saved \*Mfp\fR
        !           519:        12      saved \*Map\fR  generator marker
        !           520:        8       \*Mpsw\fR and register mask
        !           521:        4       0
        !           522:        0       boundary (\*Mfp\fR at entry to \*Mesusp\fR)
        !           523:        -4      \*M_k_level\fR
        !           524:        -8      \*M_line\fR
        !           525: \*Msp\fR \*(ar -12     \*M_file\fR
        !           526: .De
        !           527: .PP
        !           528: The region starting at \*Mr0\fP and extending to \*Mr2\fP is to be
        !           529: copied to the top of the stack.  The length of the region in bytes is
        !           530: calculated in \*Mr2\fP.
        !           531: The value of \*Mr2\fP is subtracted from \*Msp\fP,\^ moving \*Msp\fP
        !           532: down to accommodate the region.  The region is then copied using
        !           533: .Ds
        !           534: movc3   r2,\^(r0),\^(sp)
        !           535: .De
        !           536: which moves \*Mr2\fP bytes starting at \*M0(r0)\fP to \*M0(sp)\fP.
        !           537: .PP
        !           538: The descriptor for the value to suspend is at \*M8(ap)\fP and it
        !           539: is pushed on the stack using
        !           540: .Ds
        !           541: movq   8(ap),\^(sp)
        !           542: .De
        !           543: .LP
        !           544: The stack now looks like
        !           545: .Ds
        !           546: .ft R
        !           547: .ta 0.90i
        !           548: \*Mr2\fR \*(ar low word of expression or generator frame marker
        !           549:        last word of region to copy
        !           550:        \*(El
        !           551: \*Mr0\fR \*(ar first word of region to copy
        !           552: \*Mefp\fR \*(ar        expression frame marker
        !           553: \*M8(ap)\fR \*(ar      descriptor for value to suspend
        !           554:        \*(El
        !           555: \*Mgfp\fR \*(ar        generator frame marker
        !           556:        last word of copied region
        !           557:        \*(El
        !           558:        first word of copied region
        !           559: \*Msp\fR \*(ar descriptor for value to suspend
        !           560: .De
        !           561: .PP
        !           562: The reactivation address that is saved in the generator frame is moved
        !           563: into \*Mr1\fP for later use.  It is then replaced by the address
        !           564: of \*Mefail\fP so that when the frame is returned through,\^ control
        !           565: will go to \*Mefail\fP.
        !           566: .PP
        !           567: \*Mfp\fP and \*Map\fP are restored from the generator frame.  \*M_boundary\fP
        !           568: is cleared because control is being returned to Icon code.
        !           569: .PP
        !           570: \*Mefp\fP is pointed at the previous expression frame.  That is,\^ \*Mefp\fP
        !           571: is moved back one step in the expression frame chain.
        !           572: .PP
        !           573: Control is returned to the interpreter loop by branching to
        !           574: \*M0(r1)\fP,\^ the reactivation address originally saved in the generator frame.
        !           575: .NH 3
        !           576: \*Mlib/lsusp.s\fR
        !           577: .SH
        !           578: Overview
        !           579: .PP
        !           580: \*Mlsusp\fP suspends a value from a limited expression.  A limited
        !           581: expression arises from a source code expression of the form
        !           582: .Ds
        !           583: \*(x1\ \e\ \^\*(x2
        !           584: .De
        !           585: This limits \*(x1 to at most \*(x2 results.  (\*(x2
        !           586: must be a non-negative integer.)
        !           587: .PP
        !           588: \*Mlsusp\fP is just like \*Mesusp\fP except that it has provisions for
        !           589: checking and decrementing the limit counter and taking the appropriate
        !           590: action when the counter reaches zero.  As a simple example,\^ consider
        !           591: .Ds
        !           592: p(x\ \e\ \^2)
        !           593: .De
        !           594: which generates the ucode
        !           595: .Ds
        !           596: .ta .8i +.8i +.8i
        !           597:        mark    L1
        !           598:        var     0       \fR(variable \*Mp\fR)\*M
        !           599:        int     0       \fR(constant 2)\*M
        !           600:        limit
        !           601:        mark    L0
        !           602:        var     1       \fR(variable \*Mx\fR)\*M
        !           603:        lsusp
        !           604:        invoke  1
        !           605:        unmark  1
        !           606:        \*(El
        !           607: .De
        !           608: When control reaches the \*Mlsusp\fP,\^ the stack looks like
        !           609: .Ds
        !           610: .ft R
        !           611: .S1
        !           612:        expression marker with \*ML1\fR as failure label
        !           613:        descriptor for variable \*Mp\fR
        !           614:        descriptor for integer with value of 2
        !           615: \*Mefp\fR \*(ar        expression marker with \*ML0\fR as failure label
        !           616: \*Msp\fR \*(ar descriptor for variable \*Mx\fR
        !           617: .De
        !           618: The \*Mlimit\fP instruction insures that the value on the top of
        !           619: the stack (its argument) is a non-negative integer.  After \*Mlsusp\fP,\^ the
        !           620: stack is
        !           621: .Ds
        !           622: .ft R
        !           623: .ta 0.75i 3.3i
        !           624: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure label
        !           625:        descriptor for variable \*Mp\fR
        !           626:        descriptor for integer with value of 2
        !           627:        expression marker with \*ML0\fR as failure label
        !           628:        descriptor for variable \*Mx\fR
        !           629: \*Mgfp\fR \*(ar        generator frame built by \*Mlsusp\fR
        !           630:        descriptor for variable \*Mp\fR } duplicated region
        !           631: \*Msp\fR \*(ar descriptor for variable \*Mx\fR
        !           632: .De
        !           633: This is the same thing that \*Mesusp\fP would do,\^ with the
        !           634: exception that the limit counter,\^ the integer descriptor,\^ is not
        !           635: part of the duplicated region.
        !           636: .SH
        !           637: Generic Operation
        !           638: .LP
        !           639: .Ls
        !           640: .Np
        !           641: The procedure frame created by the call to \*Mesusp\fP partially
        !           642: forms the generator frame.
        !           643: .Np
        !           644: The limit counter is decremented and if it is zero,\^ no suspension
        !           645: is performed.  Instead,\^ the current expression frame is removed
        !           646: and the limit counter is replaced by the value that would have been
        !           647: suspended had the limitation not been in effect.  \*Mlsusp\fP returns,\^
        !           648: leaving the value on the top of the stack.
        !           649: .Np
        !           650: If the limit counter is not zero,\^ execution proceeds exactly
        !           651: as it does for \*Mesusp\fP with the exception that the determination
        !           652: of the region to copy takes the limit counter into consideration and
        !           653: does not include it in the region that is copied.
        !           654: .Le
        !           655: .SH
        !           656: \*Mlsusp\fP on the VAX
        !           657: .PP
        !           658: When \*Mlsusp\fP is entered,\^ the generator frame is partially
        !           659: constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
        !           660: the frame.
        !           661: .PP
        !           662: The expression frame and associated limit counter have the following
        !           663: layout:
        !           664: .Ds
        !           665: .ft R
        !           666: .St
        !           667:        8       number of results left
        !           668: \u                     limit counter\d
        !           669: .sp -1
        !           670:        4       \*MD_INTEGER\fR (type and flags word)
        !           671: \*Mefp\fR \*(ar        0       old expression frame pointer
        !           672:        -4      old generator frame pointer     expression frame
        !           673:        -8      failure label
        !           674: .De
        !           675: .PP
        !           676: The limit counter is decremented and if it is not zero,\^ control
        !           677: passes to \*Mdosusp:\fP and from then on execution proceeds
        !           678: exactly as it does in \*Mesusp\fP.  Specifically,\^ 
        !           679: the code beginning at \*Mdosusp:\fP
        !           680: is an exact duplicate of that in \*Mesusp\fP with the
        !           681: exception of the instruction that determines the lower bound of
        !           682: the region to be duplicated.  \*Mesusp\fP uses
        !           683: .Ds
        !           684: addl3 $4,\^efp,\^r0
        !           685: .De
        !           686: which points \*Mr0\fP at the word immediately above the expression
        !           687: frame.  \*Mlsusp\fP uses
        !           688: .Ds
        !           689: addl3 $12,\^efp,\^r0
        !           690: .De
        !           691: which points \*Mr0\fP at the word above the limit counter that is
        !           692: directly above the expression frame.
        !           693: .PP
        !           694: If the limit counter is zero,\^ the counter is to be replaced with the
        !           695: value which was to be suspended.  The value appears as an argument to
        !           696: \*Mlsusp\fP.  This is accomplished with
        !           697: .Ds
        !           698: movq   8(ap),\^4(efp)
        !           699: .De
        !           700: .PP
        !           701: The value of \*Mgfp\fP that is stored in the
        !           702: expression frame is restored.
        !           703: .PP
        !           704: The saved \*Mpc\fP in \*Mlsusp\fP's frame is moved into \*Mr0\fP for
        !           705: later use.
        !           706: .PP
        !           707: The expression frame is removed by moving \*Mefp\fP into \*Msp\fP,\^
        !           708: which leaves the expression frame marker word that contains the old
        !           709: \*Mefp\fP on the top of the stack.  This word is popped of the stack
        !           710: and moved into \*Mefp\fP,\^ restoring \*Mefp\fP and leaving the
        !           711: return (would-be suspended) value on the top of the stack.
        !           712: .PP
        !           713: \*Map\fP and \*Mfp\fP are restored from the procedure frame made upon
        !           714: entry to \*Mlsusp\fP.
        !           715: .PP
        !           716: \*Mlsusp\fP ``returns'' by jumping to \*M0(r0)\fP,\^ the return point
        !           717: that was saved in the frame.  The value that was to be suspended,\^ but
        !           718: was not because of the limitation,\^ is left on the top of the stack.
        !           719: .NH 3
        !           720: \*Mlib/psusp.s\fR
        !           721: .SH
        !           722: Overview
        !           723: .PP
        !           724: \*Mpsusp\fP suspends a result from an Icon procedure.  \*Mpsusp\fP is
        !           725: called from the interpreter loop and the value to suspend appears
        !           726: as an argument to \*Mpsusp\fP.  A generator frame is created and
        !           727: the generator or expression frame immediately containing the frame
        !           728: for the suspending procedure
        !           729: is duplicated on top of the stack.  \*Mpsusp\fP returns through
        !           730: the duplicated frame,\^ leaving the suspending value on top
        !           731: of the stack.  A return from \*Mpsusp\fP is manifested as a return
        !           732: from \*Minvoke\fP.
        !           733: .PP
        !           734: The \*Mpsusp\fP operation arises from the \*Msuspend \*(xx\fR statement.
        !           735: .PP
        !           736: \*Mpsusp\fP is conceptually similar to \*Mesusp\fP,\^ the difference
        !           737: being that a procedure frame is part of the expression frame
        !           738: being duplicated and that requires some extra work.
        !           739: To get a feel for what \*Mpsusp\fP does,\^ consider a simple example:
        !           740: .PP
        !           741: .Ds
        !           742: .ta .5i +.5i +.5i +.5i +.5i
        !           743: procedure main()
        !           744:        f(p(3))
        !           745: end
        !           746: 
        !           747: procedure p(a)
        !           748:        suspend a
        !           749: end
        !           750: .De
        !           751: .LP
        !           752: The generated ucode for \*Mmain\fP is
        !           753: .Ds
        !           754: .ta .8i +.8i +.8i +.8i +.8i
        !           755:        \*(El
        !           756:        mark    L1
        !           757:        var     0       \fR(the variable \*Mf\fR)\*M
        !           758:        var     1       \fR(the variable \*Mp\fR)\*M
        !           759:        int     0       \fR(the constant 3)\*M
        !           760:        invoke  1
        !           761:        invoke  1
        !           762:        \*(El
        !           763: lab    L1
        !           764: .De
        !           765: and the generated code for \*Mp\fP is
        !           766: .Ds
        !           767:        mark    p.L1
        !           768:        mark    L0
        !           769:        var     0       \fR(the argument \*Ma\fR)\*M
        !           770:        psusp
        !           771:        \*(El
        !           772: lab    p.L1
        !           773: .De
        !           774: .LP
        !           775: When control reaches the \*Minvoke\fP instruction,\^ the stack resembles
        !           776: .Ds
        !           777: .ft R
        !           778: .S1
        !           779: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
        !           780:        descriptor for variable \*Mf\fR
        !           781:        descriptor for variable \*Mp\fR
        !           782: \*Msp\fR \*(ar descriptor for constant 3
        !           783: .De
        !           784: after \*Mp\fP has been invoked,\^ just before the \*Mpsusp\fP is
        !           785: executed the stack is
        !           786: .Ds
        !           787: .ft R
        !           788: .S1
        !           789:        expression marker with \*ML1\fR as failure address
        !           790:        descriptor for variable \*Mf\fR
        !           791:        descriptor for variable \*Mp\fR
        !           792:        descriptor for constant 3 (becomes argument \*Ma\fR)
        !           793:        procedure frame for \*Mp\fR (created by \*Minvoke\fR)
        !           794:        expression marker with \*Mp.L1\fR as failure address
        !           795: \*Mefp\fR \*(ar        expression marker with \*ML0\fR as failure address
        !           796: \*Msp\fR \*(ar descriptor for argument \*Ma\fR
        !           797: .De
        !           798: Just before control returns from \*Mpsusp\fP,\^ the stack is
        !           799: .Ds
        !           800: .ta 0.75i 3.25i
        !           801: .ft R
        !           802:        expression marker with \*ML1\fR as failure address
        !           803:        descriptor for variable \*Mf\fR
        !           804:        descriptor for variable \*Mp\fR
        !           805:        descriptor for constant 3
        !           806:        procedure frame for \*Mp\fR
        !           807:        expression marker with \*Mp.L1\fR as failure address
        !           808:        expression marker with \*ML0\fR as failure address
        !           809:        descriptor for argument \*Ma\fR (being suspended)
        !           810: \*Mgfp\fR \*(ar        generator frame built by \*Mpsusp\fR
        !           811:        descriptor for variable \*Mf\fR
        !           812:        descriptor for variable \*Mp\fR duplicated region
        !           813:        descriptor for constant 3
        !           814: \*Msp\fR \*(ar procedure frame for \*Mp\fR
        !           815: .De
        !           816: After \*Mpsusp\fP returns,\^ the situation is
        !           817: .Ds
        !           818: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
        !           819:        descriptor for variable \*Mf\fR
        !           820:        descriptor for variable \*Mp\fR
        !           821:        descriptor for constant 3
        !           822:        procedure frame for \*Mp\fR
        !           823:        expression marker with \*Mp.L1\fR as failure address
        !           824:        expression marker with \*ML0\fR as failure address
        !           825:        descriptor for argument \*Ma\fR
        !           826: \*Mgfp\fR \*(ar        generator frame built by \*Mpsusp\fR
        !           827:        descriptor for variable \*Mf\fR
        !           828: \*Msp\fR \*(ar descriptor for constant 3 (the suspended value)
        !           829: .De
        !           830: .PP
        !           831: The return from \*Mpsusp\fP goes to the second \*Minvoke\fP,\^ which
        !           832: calls \*Mf\fP with one argument,\^ the constant 3 that was
        !           833: suspended.  If \*Mf(3)\fP fails,\^ the procedure frame for
        !           834: \*Mf\fP is removed.  \*Mefail\fP takes control and returns through
        !           835: the generator frame built by \*Mpsusp\fP.  This leaves the
        !           836: descriptor for \*Ma\fP on top of the stack.  Execution continues
        !           837: by \*Mp\fP failing,\^ and then \*Mmain\fP failing.
        !           838: .SH
        !           839: Generic Operation
        !           840: .LP
        !           841: .Ls
        !           842: .Np
        !           843: The procedure frame created by the call to \*Mpsusp\fP partially forms
        !           844: the generator frame.  \*M_boundary\fP is set as the current location
        !           845: of \*Mfp\fP and it is added to the generator frame.
        !           846: .Np
        !           847: As in \*Mpret\fP,\^ the value being suspended must be dereferenced
        !           848: in certain cases.  For example,\^ if the value is a local variable
        !           849: or an argument,\^ it is dereferenced.  The same code that handles
        !           850: dereferencing in \*Mpret\fP appears in \*Mpsusp\fP as well.
        !           851: Note that while suspension leaves the local variables and arguments
        !           852: of a procedure intact,\^ if the enclosing expression frame should
        !           853: be removed by an \*Munmark\fP,\^ the procedure frame would be destroyed,\^
        !           854: leaving undeferenced values pointing at meaningless data.
        !           855: .Np
        !           856: The generator frame is completed by pointing \*Mgfp\fP at the boundary
        !           857: value already in the frame and by adding \*M_k_level\fP,\^ \*M_line\fP,\^
        !           858: and \*M_file\fP.
        !           859: .Np
        !           860: The bounds of the expression frame to be duplicated are determined.
        !           861: The lower bound is the low word of the procedure frame for the
        !           862: suspending procedure and the upper bound is the marker for the
        !           863: expression frame or generator frame which is just prior to the
        !           864: procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
        !           865: the marker it points to is used.  Otherwise,\^ the marker referenced
        !           866: by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
        !           867: are those found in the procedure frame of the suspending procedure.
        !           868: The region is copied to the top of the stack.
        !           869: In the example,\^ the duplicated region contained the procedure
        !           870: frame marker for \*Mp\fP,\^ and the descriptors for the constant 3,\^
        !           871: and the variables \*Mp\fP and \*Mf\fP.
        !           872: .Np
        !           873: If \*M&trace\fP is non-zero,\^ \*Mstrace\fP is called to produce
        !           874: a trace message noting that the procedure is suspending a value.
        !           875: \*Mstrace\fP requires the address of the block for the suspending
        !           876: procedure and the address of the descriptor for the value being
        !           877: suspended.
        !           878: .Np
        !           879: \*M_line\fP and \*M_file\fP are restored from the frame of the
        !           880: suspending procedure.  This is done because when \*Mpsusp\fP is
        !           881: finished,\^ it is as if the Icon procedure had returned.  Thus,\^
        !           882: the line number and file name need to be what they were before
        !           883: the procedure was called.
        !           884: .Np
        !           885: The generator frame pointer saved in the duplicated procedure frame
        !           886: on the top of the stack is replaced by the current value of
        !           887: \*Mgfp\fP,\^ which points to the newly created generator frame.
        !           888: When \*Mpsusp\fP returns through the frame on the top of the stack,\^
        !           889: \*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
        !           890: then references the new generator frame.
        !           891: .Np
        !           892: The descriptor for \*(a0 in the argument list of the Icon procedure
        !           893: that is suspending is a descriptor for the procedure itself.  This
        !           894: descriptor is replaced with the descriptor for the value being
        !           895: suspended.  When \*Mpsusp\fP is done,\^ this descriptor is left on the
        !           896: top of the stack.
        !           897: .Np
        !           898: \*M_boundary\fP is cleared because control is returning to Icon code.
        !           899: .Np
        !           900: \*Mpsusp\fP returns.  The return uses the duplicated procedure frame
        !           901: on the top of the stack.  The result is that it appears as if the
        !           902: \*Minvoke\fP that originally called the suspending procedure has
        !           903: returned.
        !           904: .Le
        !           905: .SH
        !           906: \*Mpsusp\fP on the VAX
        !           907: .PP
        !           908: When \*Mpsusp\fP is entered,\^ the generator frame is partially
        !           909: constructed as a result of the call.  \*M_boundary\fP is set to the
        !           910: current value of \*Mfp\fP and this value is pushed on the stack
        !           911: as part of the generator frame.
        !           912: .PP
        !           913: The value being suspended needs to be dereferenced if it is a local
        !           914: variable or an argument.  This operation is the same as is done in
        !           915: \*Mpret\fP; consult the section on it for details of the actions
        !           916: taken.
        !           917: .PP
        !           918: The generator frame is completed by pointing \*Mgfp\fP at the frame
        !           919: word containing the boundary value and by adding \*M_k_level\fP,\^
        !           920: \*M_line\fP,\^ and \*M_file\fP to the frame.
        !           921: .PP
        !           922: The region to be duplicated is determined.  The low word to be copied
        !           923: is the low word of the procedure frame of the suspending procedure.
        !           924: (The word that contains the 0.)  This is readily accessible as the
        !           925: \*Mfp\fP saved the procedure frame of \*Mpsusp\fP and is placed in \*Mr7\fP.
        !           926: .PP
        !           927: The high word to be copied is dependent upon the expression and generator
        !           928: environment of the suspending procedure.  If the \*Mgfp\fP
        !           929: in the suspender's environment is not zero,\^ the word just below the
        !           930: generator frame marker is the highest word to be copied.  If
        !           931: \*Mgfp\fP is zero,\^ the word just below the expression marker pointed at
        !           932: by \*Mefp\fP in the suspender's environment is the highest word to
        !           933: be copied.
        !           934: .PP
        !           935: The fact that the saved \*Mefp\fP and \*Mgfp\fP
        !           936: appear on the stack just below the \fInwords\fP word (referenced by
        !           937: \*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
        !           938: if the saved \*Mgfp\fP is non-zero,\^
        !           939: .Ds
        !           940: .ft R
        !           941: saved \*Mgfp\fR - 12
        !           942: .De
        !           943: is used for the lower bound,\^ otherwise
        !           944: .Ds
        !           945: .ft R
        !           946: saved \*Mefp\fR - 8
        !           947: .De
        !           948: is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
        !           949: the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
        !           950: accommodate the region to be duplicated and the region is copied to
        !           951: the top of the stack using a \*Mmovc3\fP.
        !           952: .PP
        !           953: After \*M_k_level\fP is decremented,\^ \*M_k_trace\fP is checked to see
        !           954: if a trace message should be produced.  If so,\^ \*Mstrace\fP is called with
        !           955: pointers to the descriptors for the suspending procedure and the
        !           956: value being suspended.  The address of the value being suspended is
        !           957: \*M8(ap)\fP and the address of the descriptor for the procedure is
        !           958: determined using the standard
        !           959: .Ds
        !           960: &\*(a0 = (nargs * 8) + 8 + ap
        !           961: .De
        !           962: calculation.
        !           963: .PP
        !           964: The values of \*M_line\fP and \*M_file\fP are restored from the
        !           965: suspender's frame.
        !           966: .PP
        !           967: The saved \*Mgfp\fP in the duplicated procedure frame on the top of
        !           968: the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
        !           969: location of the saved \*Mgfp\fP is a little tricky.  The distance
        !           970: between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
        !           971: by subtracting the value of \*Mfp\fP from the \*Map\fP value and putting
        !           972: the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
        !           973: from the top of the stack to \*M0(ap)\fP.  Adding the
        !           974: current \*Msp\fP (which points at the low word of the duplicated
        !           975: procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
        !           976: of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
        !           977: so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
        !           978: is the second word below the \fInwords\fP word; thus the new \*Mgfp\fP
        !           979: is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Mpsusp\fP
        !           980: returns through the duplicated frame,\^ the value just stored is
        !           981: the restored value of \*Mgfp\fP.
        !           982: .PP
        !           983: The descriptor for the suspending procedure must be replaced by the
        !           984: descriptor for the return value.  The previous calculation left
        !           985: \*Mr0\fP pointing at \*M0(ap)\fP in the duplicated frame.  The
        !           986: address of \*(a0 is calculated using
        !           987: .Ds
        !           988: &\*(a0 = (nwords * 4) + 4 + r0
        !           989: .De
        !           990: Note that \*M+ 4\fP accounts for the four bytes that the \fInwords\fP
        !           991: word itself occupies.  The descriptor for the return value is put in
        !           992: place using a \*Mmovq\fP.
        !           993: .PP
        !           994: \*Msp\fP is moved into \*Mfp\fP so that the pending return uses the
        !           995: new frame on the top of the stack.
        !           996: .PP
        !           997: \*M_boundary\fP is cleared because control is going back into Icon
        !           998: code.
        !           999: .PP
        !          1000: A \*Mret\fP is executed to return from \*Mpsusp\fP.  This return uses
        !          1001: the duplicated procedure frame and thus the duplicated frame is
        !          1002: removed.  The final result is that it looks like the original call to
        !          1003: \*Minvoke\fP that started the Icon procedure has returned and
        !          1004: the suspended value is left on the top of the stack.
        !          1005: .ne 3v
        !          1006: .NH 3
        !          1007: \*Mrt/suspend.s\fR
        !          1008: .SH
        !          1009: Overview
        !          1010: .PP
        !          1011: \*Msuspend\fP suspends a value from a built-in procedure or operator.
        !          1012: \*Msuspend\fP is similar to \*Mpsusp\fP and amounts to little
        !          1013: more than a simplified version of it.  Recall that built-in
        !          1014: procedures are C functions; thus,\^ \*Msuspend\fP is directly called
        !          1015: from C.
        !          1016: .PP
        !          1017: A generator frame is created and the generator or expression frame
        !          1018: immediately containing the frame for the suspending procedure
        !          1019: is duplicated on the top of the stack.  \*Msuspend\fP returns through
        !          1020: the duplicated frame,\^ leaving the value being suspended on the top
        !          1021: of the stack.  When \*Msuspend\fP returns,\^ it appears as a return
        !          1022: from the original call to the built-in procedure.
        !          1023: .PP
        !          1024: Note that \*Msuspend\fP handles the suspension of values from both
        !          1025: built-in procedures such as \*Mupto\fP and from operators such as
        !          1026: the element generation operator,\^ \*M!\fP.  For built-in procedures,\^
        !          1027: the procedure frame is built by \*Minvoke\fP,\^ while for operators,\^
        !          1028: the procedure frame is built directly by the call to the appropriate
        !          1029: function from the interpreter loop.  
        !          1030: The value being suspended by the C function is represented
        !          1031: by the \*(a0 descriptor in the argument list.  When
        !          1032: \*Msuspend\fP is called,\^ the value to suspend is in place in
        !          1033: \*Marg0\fP.
        !          1034: .SH
        !          1035: Generic Operation
        !          1036: .PP
        !          1037: \*Msuspend\fP can be considered as a ``subset'' of \*Mpsusp\fP.  The
        !          1038: descriptions of operations in this section and the next are excerpts
        !          1039: from \*Mpsusp\fP.
        !          1040: .LP
        !          1041: The actions of \*Mpsusp\fP that are \fInot\fP taken by \*Msuspend\fP are:
        !          1042: .Ls
        !          1043: .Np
        !          1044: The return value does not need to be dereferenced because the
        !          1045: suspending function has already taken care of that.
        !          1046: .Np
        !          1047: No tracing message is produced because tracing is only done
        !          1048: for Icon procedures.
        !          1049: .Np
        !          1050: The return value does not need to be moved into the duplicated
        !          1051: procedure frame because it is already in place in the original procedure
        !          1052: frame and when the frame is duplicated,\^ the return value is
        !          1053: duplicated along with it.
        !          1054: .Np
        !          1055: \*M_k_level\fP is not decremented because \*M&level\fP keeps track of
        !          1056: Icon procedure calls and \*Msuspend\fP is returning from a C routine.
        !          1057: \*M_line\fP,\^ and \*M_file\fP are not restored because they are
        !          1058: not part of the procedure frame of the built-in procedure.
        !          1059: .Le
        !          1060: .LP
        !          1061: The operations that are performed by \*Msuspend\fP are:
        !          1062: .Ls
        !          1063: .Np
        !          1064: The procedure frame created by the call to \*Msuspend\fP partially forms
        !          1065: the generator frame.  \*M_boundary\fP is set as the current location
        !          1066: of \*Mfp\fP and it is added to the generator frame.
        !          1067: .Np
        !          1068: The bounds of the expression frame to be duplicated are determined.
        !          1069: The lower bound is the low word of the procedure frame for the
        !          1070: suspending procedure and the upper bound is the marker for the
        !          1071: expression frame or generator frame which is just prior to the
        !          1072: procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
        !          1073: the marker it points to is used.  Otherwise,\^ the marker referenced
        !          1074: by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
        !          1075: are those found in the procedure frame of the suspending procedure.
        !          1076: The region is copied to the top of the stack.
        !          1077: .Np
        !          1078: The generator frame pointer saved in the duplicated procedure frame
        !          1079: on the top of the stack is replaced by the current value of
        !          1080: \*Mgfp\fP,\^ which points to the newly created generator frame.
        !          1081: When \*Msuspend\fP returns through the frame on the top of the stack,\^
        !          1082: \*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
        !          1083: then references the new generator frame.
        !          1084: .Np
        !          1085: \*M_boundary\fP is cleared because control is returning to Icon code.
        !          1086: .Np
        !          1087: \*Msuspend\fP returns.  The return uses the duplicated procedure frame
        !          1088: on the top of the stack.  The result is that it appears as if the
        !          1089: original call to the suspending procedure has returned.
        !          1090: .Le
        !          1091: .SH
        !          1092: \*Msuspend\fP on the VAX
        !          1093: .PP
        !          1094: When \*Msuspend\fP is entered,\^ the generator frame is partially
        !          1095: constructed as a result of the call.  \*M_boundary\fP is set to the
        !          1096: current value of \*Mfp\fP and this value is pushed on the stack
        !          1097: as part of the generator frame.
        !          1098: The generator frame is completed by pointing \*Mgfp\fP at the frame
        !          1099: word containing the boundary value and by adding \*M_k_level\fP,\^
        !          1100: \*M_line\fP,\^ and \*M_file\fP to the frame.
        !          1101: .PP
        !          1102: The region to be duplicated is determined.  The low word to be copied
        !          1103: is the low word of the procedure frame of the suspending function.
        !          1104: (The word that contains the 0.)  This is readily accessible as the
        !          1105: \*Mfp\fP saved in the procedure frame of \*Msuspend\fP and \*Mr7\fP is
        !          1106: pointed at the word containing the saved \*Mfp\fP.
        !          1107: .PP
        !          1108: The high word to be copied is dependent upon the expression and generator
        !          1109: environment of the suspending function.  If the \*Mgfp\fP
        !          1110: in the suspender's environment is not zero,\^ the word just below the
        !          1111: generator frame marker is the highest word to be copied.  If
        !          1112: \*Mgfp\fP is zero,\^ the just word below the expression marker pointed at
        !          1113: by \*Mefp\fP in the suspender's environment is the highest word to
        !          1114: be copied.
        !          1115: .PP
        !          1116: The fact that the saved \*Mefp\fP and \*Mgfp\fP
        !          1117: appear on the stack just below the \fInwords\fP word (referenced by
        !          1118: \*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
        !          1119: if the saved \*Mgfp\fP is non-zero,\^
        !          1120: .Ds
        !          1121: .ft R
        !          1122: saved \*Mgfp\fR - 12
        !          1123: .De
        !          1124: is used for the lower bound,\^ otherwise
        !          1125: .Ds
        !          1126: .ft R
        !          1127: saved \*Mefp\fR - 8
        !          1128: .De
        !          1129: is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
        !          1130: the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
        !          1131: accommodate the region to be duplicated and the region is copied to
        !          1132: the top of the stack using a \*Mmovc3\fP.
        !          1133: .PP
        !          1134: The saved \*Mgfp\fP in the duplicated procedure frame on the top of
        !          1135: the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
        !          1136: location of the saved \*Mgfp\fP is a little tricky.  The distance
        !          1137: between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
        !          1138: by subtracting the \*Mfp\fP value from the \*Map\fP value and putting
        !          1139: the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
        !          1140: from the top of the stack to \*M0(ap)\fP.  Adding the
        !          1141: current \*Msp\fP (which points at the low word of the duplicated
        !          1142: procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
        !          1143: of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
        !          1144: so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
        !          1145: is the second word below the \fInwords\fP word and thus the new \*Mgfp\fP
        !          1146: is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Msuspend\fP
        !          1147: returns through the duplicated frame,\^ the value just stored is
        !          1148: the restored value of \*Mgfp\fP.
        !          1149: .PP
        !          1150: A \*Mret\fP is executed to return from \*Msuspend\fP.  This return uses
        !          1151: the duplicated procedure frame and thus the duplicated frame is
        !          1152: removed.  The final result is that it looks like the original call to
        !          1153: function has returned and
        !          1154: the suspended value is left on the top of the stack.
        !          1155: .ne 2i
        !          1156: .NH 3
        !          1157: \*Mfunctions/display.c\fR
        !          1158: .SH
        !          1159: Overview
        !          1160: .PP
        !          1161: \*Mdisplay.c\fP implements the Icon function \*Mdisplay()\fP.
        !          1162: \*Mdisplay\fP traces back through Icon procedure frames printing various
        !          1163: sorts of information.  Therefore,\^ some of the code in \*Mdisplay\fP
        !          1164: is machine dependent.
        !          1165: .SH
        !          1166: Generic Operation
        !          1167: .PP
        !          1168: \*Mdisplay\fP makes one calculation that is machine dependent.  The
        !          1169: calculation is to take a frame whose address is contained in the
        !          1170: variable \*Mfp\fP and calculate the address of the procedure
        !          1171: descriptor in the frame that is pointed at by the \*Mfp\fP value
        !          1172: saved in the frame that \*Mfp\fP references.
        !          1173: .SH
        !          1174: \*Mdisplay\fP on the VAX
        !          1175: .PP
        !          1176: \*Map\fP and \*Mfp\fP are restored from the frame referenced by
        !          1177: \*Mfp\fP.  The number of arguments to the procedure is contained in
        !          1178: \*Map\^[1]\fP.  This is loaded into the variable \*Mn\fP.  The address
        !          1179: of the procedure descriptor (\*(a0) is calculated using:
        !          1180: .Ds
        !          1181: dp = ap + 2 + 2*n
        !          1182: .De
        !          1183: Note that this is the same computation that is made at several points
        !          1184: in the assembly language routines.  As in \*Msweep\fP,\^ the calculations are
        !          1185: being made using \*Mint *\fP variables and thus the constants
        !          1186: represent word counts instead of byte counts as they do in the
        !          1187: assembly language routines.
        !          1188: 
        !          1189: .NH 3
        !          1190: \*Mrt/gcollect.s\fR
        !          1191: .SH
        !          1192: Overview
        !          1193: .PP
        !          1194: \*Mgcollect\fP is a simple routine that insures that garbage
        !          1195: collections are done using the stack for the main co-expression.
        !          1196: This done by saving certain values in the co-expression block of the
        !          1197: current co-expression,\^ restoring values from the co-expression block
        !          1198: for \*M&main\fP,\^ calling the garbage collector,\^ and then restoring
        !          1199: the original values.
        !          1200: \*Mgcollect\fP takes a single argument that is passed directly
        !          1201: to \*Mcollect\fP.
        !          1202: .PP
        !          1203: If co-expressions are not implemented,\^ \*Mgcollect\fP need only
        !          1204: consist of a call to \*Mcollect\fP,\^ being sure to pass its argument
        !          1205: on through.
        !          1206: .SH
        !          1207: \*Mgcollect\fP on the VAX
        !          1208: .PP
        !          1209: \*Mr0\fP is pointed at the heap block for the current co-expression.
        !          1210: \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP are saved in the appropriate
        !          1211: words of the block.
        !          1212: .PP
        !          1213: \*Mr0\fP is pointed at the heap block for \*M&main\fP,\^ the
        !          1214: co-expression that is initially active.  \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP
        !          1215: are restored from values saved in the block.
        !          1216: .PP
        !          1217: The argument to \*Mgcollect\fP is pushed on the stack,\^ and
        !          1218: \*Mcollect\fP is called with one argument.
        !          1219: .PP
        !          1220: \*Mr0\fP is pointed at the heap block for the current co-expression
        !          1221: and the \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP values saved at the
        !          1222: start of the routine are restored.
        !          1223: .PP
        !          1224: \*Mgcollect\fP returns.
        !          1225: .NH 3
        !          1226: \*Mrt/sweep.c\fR
        !          1227: .SH
        !          1228: Overview
        !          1229: .PP
        !          1230: \*Msweep\fP is used during garbage collection to sweep a stack,\^
        !          1231: marking all the descriptors in the stack.  \*Msweep\fP begins at
        !          1232: the low word (the top) of a stack and moves up through the stack,\^
        !          1233: looking for descriptors and marking them.
        !          1234: A stack is composed of four kinds of
        !          1235: objects: descriptors,\^ and markers for procedure,\^
        !          1236: generator,\^ and expression frames.  \*Msweep\fP uses knowledge of
        !          1237: frame marker formats to skip over markers and to process the
        !          1238: intervening descriptors.
        !          1239: .PP
        !          1240: Although \*Msweep\fP is written in C,\^ the knowledge of frame formats that it
        !          1241: employs requires that it be written on a per-machine basis.
        !          1242: .SH
        !          1243: Generic Operation
        !          1244: .PP
        !          1245: There are three places that descriptors can appear on the stack:
        !          1246: above an expression marker,\^ in an argument list,\^ and above an
        !          1247: argument list.  This can be considered as only two places because
        !          1248: descriptors above the argument list can be considered as part of the
        !          1249: argument list.
        !          1250: .PP
        !          1251: \*Msweep\fP is called with a single argument that is the address of
        !          1252: the first word of a stack to mark.  For purposes of discussion assume
        !          1253: that \*Msp\fP references the stack word of current interest.
        !          1254: \*Msweep\fP has a loop and each time through the loop,\^ one of four actions
        !          1255: is taken based on the word that \*Msp\fP is pointing at:
        !          1256: .Ls
        !          1257: .Np
        !          1258: If \*Msp\fP is pointing at the low word of a procedure frame marker,\^ \*Msp\fP
        !          1259: is moved to point at the low word of the argument list of the
        !          1260: procedure.  \*Mefp\fP,\^ \*Mgfp\fP,\^ and \*Mpfp\fP are restored from the
        !          1261: procedure frame.  The number of arguments to the procedure is placed
        !          1262: in \fInargs\fP.
        !          1263: .Np
        !          1264: If \*Msp\fP is pointing at the low word of a generator frame marker,\^
        !          1265: \*Mfp\fP is restored from the boundary word of the generator frame
        !          1266: and \*Msp\fP is pointed at the low word of the frame referenced by \*Mfp\fP.
        !          1267: .Np
        !          1268: If \*Msp\fP is pointing at the low word of an expression frame
        !          1269: marker,\^ \*Mgfp\fP and \*Mefp\fP are restored from the marker and
        !          1270: \*Msp\fP is pointed at the word above the marker.
        !          1271: .Np
        !          1272: If none of the preceding conditions are true,\^ the word that \*Msp\fP
        !          1273: points at is assumed to be the low word of a descriptor and that
        !          1274: descriptor is marked.  \*Msp\fP is incremented by 2 to move past
        !          1275: the descriptor.  If \fInargs\fP is not zero,\^ it is decremented.
        !          1276: .Le
        !          1277: .PP
        !          1278: This process continues as long as \*Mfp\fP and \fInargs\fP are not
        !          1279: both zero.  \fInargs\fP is used so that the arguments in the very
        !          1280: last frame are processed.  The \*Mfp\fP at that point is 0.
        !          1281: .SH
        !          1282: \*Msweep\fP on the VAX
        !          1283: .PP
        !          1284: The routine \*Mgetap\fP is used by \*Msweep\fP.  \*Mgetap\fP
        !          1285: takes the address of a frame and returns the address of \*M0(ap)\fP
        !          1286: in that frame.  That is,\^ it returns the address of the start of the
        !          1287: argument list for the frame.
        !          1288: .PP
        !          1289: Note that the C code uses \*Mint *\fP variables for the various
        !          1290: calculations that are performed.  Thus,\^ a calculation such as
        !          1291: \*Mx + 2\fP is actually performing \*Mx + 8\fP.  Similarly,\^
        !          1292: \*Mx\^[\-1]\fP would be the address \*Mx \- 4\fP.
        !          1293: .PP
        !          1294: \*Msweep\fP is called with a single parameter,\^ \*Mfp\fP.  \*Mfp\fP
        !          1295: holds the address of the frame with which to start the marking process.  This
        !          1296: address is a \*M_boundary\fP value,\^ and thus it
        !          1297: points to the 0 (condition handler) word of a procedure frame.
        !          1298: .PP
        !          1299: \*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP,\^ so that the first time
        !          1300: throughout the loop,\^ the procedure frame on the top of the stack
        !          1301: is processed.  This gets the ball rolling,\^ so to speak.
        !          1302: .PP
        !          1303: \*Msweep\fP loops while \*Mfp\fP and \fInargs\fP are not both zero.
        !          1304: It should be noted that the variables used in \*Msweep\fP have no
        !          1305: connection to actual registers other than having the same name.
        !          1306: .PP
        !          1307: If \*Msp\fP is equal to \*Mfp \- FRAMELIMIT\fP,\^ it indicates that \*Msp\fP
        !          1308: is pointing at a procedure frame marker.
        !          1309: \*MFRAMELIMIT\fP is 2 on the VAX because
        !          1310: there are two words,\^ the saved values of \*M_line\fP and \*M_file\fP,\^
        !          1311: that lie below the word in the frame that \*Mfp\fP points at.
        !          1312: .PP
        !          1313: When a procedure frame marker is encountered,\^ \*Mefp\fP and \*Mgfp\fP values
        !          1314: are restored using negative displacements from \*Map\fP.  \*Map\fP
        !          1315: points at the \fInwords\fP word of the frame,\^ and \*Msp\fP is set to
        !          1316: \*Map + 2\fP so that it points at the descriptor for the first
        !          1317: argument.  \fInargs\fP is loaded from the argument list.  \*Map\fP
        !          1318: and \*Mfp\fP are restored from the frame
        !          1319: .PP
        !          1320: A generator frame is indicated by \*Msp\fP being equal to \*Mgfp \-
        !          1321: 3\fP.  This is because there are three words,\^ \*M_line\fP,\^
        !          1322: \*M_file\fP,\^ and \*M_k_level\fP in the generator frame below the
        !          1323: word that generator frame pointer points at.  \*Mfp\fP is restored
        !          1324: from the frame.  A new \*Map\fP value is calculated from \*Mfp\fP
        !          1325: using \*Mgetap\fP.  \*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP to cause
        !          1326: recognition of a procedure frame the next time around.
        !          1327: .PP
        !          1328: An expression frame marker is indicated by \*Msp\fP being equal to \*Mefp \-
        !          1329: 2\fP.  \*Mefp\fP and \*Mgfp\fP are restored from the marker.
        !          1330: \*Msp\fP is incremented by 3 which leaves it pointing at the word
        !          1331: above the marker,\^ which may be a descriptor.
        !          1332: .PP
        !          1333: If \*Msp\fP suits none of the preceding criteria,\^ it is assumed to
        !          1334: point at a descriptor.  \*Mmark\fP is called with the value of \*Msp\fP as
        !          1335: its argument.  \*Msp\fP is incremented by 2 to move past the
        !          1336: descriptor just marked.  If \fInargs\fP is non-zero,\^ it is
        !          1337: decremented.
        !          1338: .bp
        !          1339: .SH
        !          1340: Acknowledgements
        !          1341: .PP
        !          1342: Ralph Griswold patiently suffered through a number of drafts of this
        !          1343: document and made innumerable suggestions about grammar,\^ form,\^ and content.
        !          1344: Steve Wampler graciously answered a number of questions about the internal
        !          1345: workings of Icon and also made a number of comments on a late draft.
        !          1346: .SH
        !          1347: References
        !          1348: .LP
        !          1349: .IP 1.
        !          1350: R. E. Griswold,\^ R. K. McConeghy,\^ and W. H. Mitchell,\^ \fIA Tour Through the
        !          1351: C Implementation of Icon; Version 5.9\fR,\^
        !          1352: Technical Report 84-11, Department of Computer Science, The University of
        !          1353: Arizona, August 1984.
        !          1354: .IP 2.
        !          1355: \fIVAX Architecture Handbook\fP,\^ Digital Equipment Corporation,\^
        !          1356: Maynard,\^ Massachusetts,\^ 1982.
        !          1357: .IP 3.
        !          1358: D. M. Ritchie,\^ A Tour Through the UNIX C Compiler,\^ \fIUNIX Programmers
        !          1359: Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
        !          1360: New Jersey,\^ 1979.
        !          1361: .IP 4.
        !          1362: S. C. Johnson,\^ A Tour Through the Portable C Compiler,\^ \fIUNIX Programmers
        !          1363: Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
        !          1364: New Jersey,\^ 1979.
        !          1365: .IP 5.
        !          1366: R. E. Griswold,\^ \fIAn Overview of the Porting Process for Version 5.9
        !          1367: of Icon\fR,
        !          1368: Department of Computer Science,\^ The University of Arizona,\^ August 1984.

unix.superglobalmegacorp.com

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