{Begin SubSec PROG and Associated Control Functions}
{Title PROG and Associated Control Functions}
{Text

{FnDef {FnName PROG1} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
Evaluates its arguments in order, and returns the value of its first argument {arg X{sub 1}}.  For example, {lisp (PROG1 X (SETQ X Y))} sets {lisp X} to {lisp Y}, and returns {lisp X}'s original value.
}}


{FnDef {FnName PROG2} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}}
{Type NOSPREAD}
{Text
Similar to {fn PROG1}.  Evaluates its arguments in order, and returns the value of its second argument {arg X{sub 2}}.

{note arg! takes advantage of fact that evaluator evals ALL args given to a spread fn ... even excess ones.}
}}



{FnDef {FnName PROGN} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
{fn PROGN} evaluates each of its arguments in order, and returns the value of its last argument.  {fn PROGN} is used to specify more than one computation where the syntax allows only one, e.g., {lisp (SELECTQ {ellipsis} (PROGN {ellipsis}))} allows evaluation of several expressions as the default condition for a {lisp SELECTQ}.
}}



{FnDef {FnName PROG}
{FnArgs VARLST E{SUB 1} E{SUB 2} {ellipsis} E{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
This function allows the user to write an ALGOL-like program containing Interlisp expressions (forms) to be executed.  The first argument, {arg VARLST}, is a list of local variables{index local variables} (must be {lisp NIL} if no variables are used).  Each atom in {arg VARLST} is treated as the name of a local variable and bound to {lisp NIL}.  {arg VARLST} can also contain lists  of the form {lisp ({arg LITATOM} {arg FORM})}.  In this case, {arg LITATOM} is the name of the variable and is bound to the value of {arg FORM}.  The evaluation takes place before any of the bindings are performed, e.g., {lisp (PROG ((X Y) (Y X)) {ellipsis})} will bind local variable {lisp X} to the value of {lisp Y} (evaluated {it outside} the {fn PROG}) and local variable {lisp Y} to the value of {lisp X} (outside the {fn PROG}).  An attempt to use anything other than a litatom as a {fn PROG} variable will cause an error, {index ARG NOT LITATOM Error}{lisp ARG NOT LITATOM}.  An attempt to use {lisp NIL} or {lisp T} as a {fn PROG} variable will cause an error, {index ATTEMPT TO BIND NIL OR T Error}{lisp ATTEMPT TO BIND NIL OR T}.

The rest of the {fn PROG} is a sequence of non-atomic statements (forms) and litatoms (labels).  The forms are evaluated sequentially;{index PROG label} the labels serve only as markers.  The two special functions {fn GO} and {fn RETURN} alter this flow of control as described below.  The value of the {fn PROG} is usually specified by the function {fn RETURN}.  If no {fn RETURN} is executed before the {fn PROG} "falls off the end," the value of the {fn PROG} is {lisp NIL}.

{Note Example!!}
}}


{FnDef {FnName GO} {FnArgs U}
{Type NOSPREAD NLAMBDA}
{Text
{fn GO} is used to cause a transfer in a {fn PROG}.  {lisp (GO L)} will cause the {fn PROG} to evaluate forms starting at the label {lisp L} ({fn GO} does not evaluate its argument).  A {fn GO} can be used at any level in a {fn PROG}.  If the label is not found, {fn GO} will search higher progs {it within the same function,} e.g., {lisp (PROG {ellipsis} A {ellipsis} (PROG {ellipsis} (GO A)))}.
If the label is not found in the function in which the {fn PROG} appears, an error is generated, {lisp UNDEFINED OR ILLEGAL GO}.{index UNDEFINED OR ILLEGAL GO Error}
}}


{FnDef {FnName RETURN} {FnArgs X}
{Text
A {fn RETURN} is the normal exit for a {fn PROG}.
Its argument is evaluated and is immediately returned the value
of the {fn PROG} in which it appears.
}}


Note:  If a {fn GO} or {fn RETURN} is executed in an interpreted function which is not a {fn PROG}, the {fn GO} or {fn RETURN} will be executed in the last interpreted {fn PROG} entered if any, otherwise cause an error.{index ILLEGAL RETURN Error}{index UNDEFINED OR ILLEGAL GO Error}

{fn GO} or {fn RETURN} inside of a compiled function that is not a {fn PROG} is not allowed, and will cause an error at compile time.

As a corollary, {fn GO} or {fn RETURN} in a functional argument, e.g., to {fn SORT}, will not work compiled.  Also, since {fn NLSETQ}'s and {fn ERSETQ}'s compile as {it separate} functions, a {fn GO} or {fn RETURN} {it cannot} be used inside of a compiled {index NLSETQ FN}{fn NLSETQ} or {index ERSETQ FN}{fn ERSETQ} if the corresponding {fn PROG} is outside, i.e., above, the {fn NLSETQ} or {fn ERSETQ}.


{Note Is the above also true for ERRORSET in general (on which NLSETQ and ERSETQ are based)? ---mjs  <-- No! ERRORSET doesn't create a seperate function ... however, it seems that GO and RETURN won't work under a compiled call to ERRORSET anyway (compiles OK, but gives undef or illegal GO error on execution).

Heres the story: it seems that GO (and RETURN too) will not work if inside a function called (via fn call) from a compiled function containing a PROG.  If the "function" is actually a macro, so that it is compiled open, or is one of the specially-compiled fns (PROG, COND, etc.), then it works.  The important thing is the function call from a compiled function containing a PROG.  This is not immediately observable by the random user.  Should this explaination be documented??  (perhaps in compiler section??)}



{Def {Type (Macro)} {Name LET}
{PrintName {lisp (LET {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}}
{Text
{lisp LET} is essentially a {fn PROG} that can't contain {fn GO}'s or {fn RETURN}'s, and whose last form is the returned value.
}}

{Def {Type (Macro)} {Name LET*}
{PrintName {lisp (LET* {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}} }

{Def {Type (Macro)} {Name PROG*}
{PrintName {lisp (PROG* {arg VARLST} {arg E{SUB 1}} {arg E{SUB 2}} {ellipsis} {arg E{SUB N}})}} 
{Text
{lisp LET*} and {lisp PROG*} differ from {lisp LET} and {fn PROG} only in that the binding of the bound variables is done "sequentially."  Thus

{lispcode
(LET* ((A (LIST 5))
      (B (LIST A A)))
   (EQ A (CADR B)))}

would evaluate to {lisp T}; whereas the same form with {lisp LET} might even find {lisp A} an unbound variable when evaluating {lisp (LIST A A)}.
}}

}{End SubSec PROG and Associated Control Functions}