{Begin SubSec DWIMIFY}
{Title DWIMIFY}
{Text

{index *BEGIN* DWIMIFY FN}
{index *PRIMARY* DWIMIFY FN}

{fn DWIMIFY} is effectively a preprocessor for CLISP.  {fn DWIMIFY} operates by scanning an expression as though it were being interpreted, and for each form that would generate an error, calling DWIM to "fix" it.  {fn DWIMIFY} performs {it all} DWIM transformations, not just CLISP transformations, so it does spelling correction, fixes 8-9 errors, handles {lisp F/L}, etc.  Thus the user will see the same messages, and be asked for approval in the same situations, as he would if the expression were actually run.  If DWIM is unable to make a correction, no message is printed, the form is left as it was, and the analysis proceeds.


{fn DWIMIFY} knows exactly how the interpreter works.  It knows the syntax of {fn PROG}s, {fn SELECTQ}s, {lisp LAMBDA} expressions, {fn SETQ}s, et al.  It knows how variables are bound, and that the argument of {lisp NLAMBDA}s are not evaluated (the user can inform {fn DWIMIFY} of a function or macro's nonstandard binding or evaluation by giving it a suitable {index INFO Prop}{prop INFO} property, see {PageRef Prop INFO}).  In the course of its analysis of a particular expression, {fn DWIMIFY} builds a list of the bound variables from the {lisp LAMBDA} expressions and {fn PROG}s that it encounters.  It uses this list for spelling corrections.  {fn DWIMIFY} also knows not to try to "correct" variables that are on this list
since they would be bound if the expression were actually being run.  However, note that {fn DWIMIFY} cannot, a priori, know about variables that are used freely but would be bound in a higher function if the expression were evaluated in its normal context.  Therefore, {fn DWIMIFY} will try to "correct" these variables.  Similarly, {fn DWIMIFY} will attempt to correct forms for which {fn CAR} is undefined, even when the form is not in error from the user's standpoint, but the corresponding function has simply not yet been defined.

Note:  {fn DWIMIFY} rebinds {index FIXSPELLDEFAULT Var}{var FIXSPELLDEFAULT} to {lisp N}, so that if the user is not at the terminal when dwimifying (or compiling), spelling corrections will not be performed.

{fn DWIMIFY} will also inform the user when it encounters an expression with too {it many} arguments (unless {var DWIMCHECK#ARGSFLG}={lisp NIL}), because such an occurrence, although does not cause an error in the Interlisp interpreter, nevertheless is frequently symptomatic of a parenthesis error.  For example, if the user wrote {lisp (CONS (QUOTE FOO X))} instead of {lisp (CONS (QUOTE FOO) X)}, {fn DWIMIFY} will print:{index POSSIBLE PARENTHESIS ERROR Error}

{lispcode
POSSIBLE PARENTHESIS ERROR IN
(QUOTE FOO X)
TOO MANY ARGUMENTS (MORE THAN 1)}


{fn DWIMIFY} will also check to see if a {fn PROG} label contains a clisp character (unless {index DWIMCHECKPROGLABELSFLG Var}{var DWIMCHECKPROGLABELSFLG}={lisp NIL}, or the label is a member of {var NOFIXVARSLST}), and if so, will alert the user by printing the message {lisp SUSPICIOUS PROG LABEL},{index SUSPICIOUS PROG LABEL Error} followed by the label.  The {fn PROG} label will {it not} be treated as CLISP.


Note that in most cases, an attempt to transform a form that is already as the user intended will have no effect (because there will be nothing to which that form could reasonably be transformed).  However, in order to avoid needless calls to DWIM or to avoid possible confusion, the user can inform {fn DWIMIFY} {it not} to attempt corrections or transformations on certain functions or variables by adding them to the list {index NOFIXFNSLST Var}{var NOFIXFNSLST} or {index NOFIXVARSLST Var}{var NOFIXVARSLST} respectively.  Note that the user could achieve the same effect by simply setting the corresponding variables, and giving the functions dummy definitions.

{fn DWIMIFY} will never attempt corrections on global variables{index global variables}, i.e., variables that are a member of the list {var GLOBALVARS}{index GLOBALVARS Var}, or have the property {prop GLOBALVAR}{index GLOBALVAR Prop} with value {lisp T}, on their property list.  Similarly, {fn DWIMIFY} will not attempt to correct variables declared to
be {lisp SPECVARS} in block declarations or via {fn DECLARE}{index DECLARE Fn} expressions in the function body.  The user can also declare variables that are simply used freely in a function by using the {lisp USEDFREE}{index USEDFREE (CLISP declaration)} declaration.


{fn DWIMIFY} and {index DWIMIFYFNS FN}{fn DWIMIFYFNS} (used to {fn DWIMIFY} several functions) maintain two internal lists of those functions and variables for which corrections were unsuccessfully attempted.  These lists are initialized to the values of {var NOFIXFNSLST} and {var NOFIXVARSLST}.  Once an attempt is made to fix a particular function or variable, and the attempt fails, the function or variable is added to the corresponding list, so that on subsequent occurrences (within this call to {fn DWIMIFY} or {fn DWIMIFYFNS}), no attempt at correction is made.  For example, if {lisp FOO} calls {lisp FIE} several times, and {lisp FIE} is undefined at the time {lisp FOO} is dwimified, {fn DWIMIFY} will not bother with {lisp FIE} after the first occurrence.  In other words, once {fn DWIMIFY} "notices" a function or variable, it no longer attempts to correct it.  {fn DWIMIFY} and {fn DWIMIFYFNS} also "notice" free variables that are set in the expression being processed.  Moreover, once {fn DWIMIFY} "notices" such functions or variables, it subsequently treats them the same as though they were actually defined or set.


Note that these internal lists are local to each call to {fn DWIMIFY} and {fn DWIMIFYFNS}, so that if a function containing {lisp FOOO}, a misspelled call to {lisp FOO}, is {fn DWIMIFY}ed before {lisp FOO} is defined or mentioned, if the function is {fn DWIMIFY}ed again after {lisp FOO} has been defined, the correction will be made.


The user can undo selected transformations performed by {fn DWIMIFY}, as described on {PageRef Tag UndoingDWIM}.{index undoing DWIM corrections}



{FnDef {FnName DWIMIFY} {FnArgs X QUIETFLG L}
{Text
Performs all DWIM and CLISP corrections and transformations on {arg X} that would be performed if {arg X} were run, and prints the result unless {arg QUIETFLG}={lisp T}.

If {arg X} is an atom and {arg L} is {lisp NIL}, {arg X} is treated as the name of a function, and its entire definition is dwimified.  If {arg X} is a list or {arg L} is not {lisp NIL}, {arg X} is the expression to be dwimified.  If {arg L} is not {lisp NIL}, it is the edit push-down list leading to {arg X}, and is used for determining context, i.e., what bound variables would be in effect when {arg X} was evaluated, whether {arg X} is a form or sequence of forms, e.g., a {fn COND} clause, etc.

If {arg X} is an iterative statement and {arg L} is {lisp NIL}, {fn DWIMIFY} will also print the translation, i.e., what is stored in the hash array.
}}



{FnDef {FnName DWIMIFYFNS} {FnArgs FN{sub 1} {ellipsis} FN{sub N}}
{Type NOSPREAD NLAMBDA}
{Text
Dwimifies each of the functions given.  If only one argument is given, it is evalued.  If its value is a list, the functions on this list are dwimified.  If only one argument is given, it is atomic, its value is not a list, and it is the name of a known file, {fn DWIMIFYFNS} will operate on {lisp (FILEFNSLST {arg FN{sub 1}})}, e.g. {lisp (DWIMIFYFNS FOO.LSP)} will dwimify every function in the file {lisp FOO.LSP}.

Every 30 seconds, {fn DWIMIFYFNS} prints the name of the function it is processing, a la {fn PRETTYPRINT}.

{note should be fixed to print out name of each function as it is processed --lmm}

Value is a list of the functions dwimified.
}}

{VarDef {Name DWIMINMACROSFLG}
{Text
Controls how {fn DWIMIFY} treats the arguments in a "call" to a macro, i.e., where the {fn CAR} of the form is undefined, but has a macro definition.  If {var DWIMINMACROSFLG} is {lisp T}, then macros are treated as {lisp LAMBDA} functions, i.e., the arguments are assumed to be evaluated, which means that {fn DWIMIFY} will descend into the argument list.  If {var DWIMINMACROSFLG} is {lisp NIL}, macros are treated as {lisp NLAMBDA} functions.  {var DWIMINMACROSFLG} is initially {lisp T}.
}}

{PropDef {Name INFO}
{Text
{index *PRIMARY* INFO Prop}
Used to inform {fn DWIMIFY} of nonstandard behavior of particular forms with respect to evaluation, binding of arguments, etc.  The {Prop INFO} property of a litatom is a single atom or list of atoms chosen from among the following:

{Begin LabeledList interpretation of INFO}

{Name {Lisp EVAL}{index EVAL Litatom}}
{Text Informs {fn DWIMIFY} (and CLISP and Masterscope) that an nlambda function {it does} evaluate its arguments.  Can also be placed on a macro name to override the behavior of {var DWIMINMACROSFLG} = {lisp NIL}.}

{Name {Lisp NOEVAL}{index NOEVAL Litatom}}
{Text Informs {fn DWIMIFY} that a macro does {it not} evaluate all of its arguments, even when {var DWIMINMACROSFLG} = {lisp T}.}

{Name {Lisp BINDS}{index BINDS Litatom}}
{Text Placed on the {prop INFO} property of a function or the {fn CAR} of a special form to inform {fn DWIMIFY} that the function or form binds variables.  In this case, {fn DWIMIFY} assumes that {fn CADR} of the form is the variable list, i.e., a list of litatoms, or lists of the form {lisp ({arg VAL} {arg VALUE})}.  {lisp LAMBDA}, {lisp NLAMBDA}, {fn PROG}, and {fn RESETVARS} are handled in this fashion.}

{Name {Lisp LABELS}{index LABELS Litatom}}
{Text Informs {fn CLISPIFY} that the form interprets top-level litatoms as labels, so that {fn CLISPIFY} will never introduce an atom (by packing) at the top level of the expression.  {fn PROG} is handled in this fashion.}


{End LabeledList interpretation of INFO}

}}

{VarDef {Name NOFIXFNSLST}
{Text
List of functions that {fn DWIMIFY} will not try to correct.
}}



{VarDef {Name NOFIXVARSLST}
{Text
List of variables that {fn DWIMIFY} will not try to correct.
}}



{VarDef {Name NOSPELLFLG}
{Text
If {lisp T}, {fn DWIMIFY} will not perform any spelling corrections.  Initially {lisp NIL}.  {var NOSPELLFLG} is reset to {lisp T} when compiling functions whose definitions are obtained from a file, as opposed to being in core.
}}



{VarDef {Name CLISPHELPFLG}
{Text
If {lisp NIL}, {fn DWIMIFY} will not ask the user for approval of any CLISP transformations.  Instead, in those situations where approval would be required, the effect is the same as though the user had been asked and said {lisp NO}.  Initially {lisp T}.
}}




{VarDef {Name DWIMIFYCOMPFLG}
{Text
If {lisp T}, {fn DWIMIFY} is called before compiling an expression.  Initially {lisp NIL}.
}}



{VarDef {Name DWIMCHECK#ARGSFLG}
{Text
If {lisp T}, causes {fn DWIMIFY} to check for too many arguments in a form.  Initially {lisp T}.
}}



{VarDef {Name DWIMCHECKPROGLABELSFLG}
{Text
If {lisp T}, causes {fn DWIMIFY} to check whether a {fn PROG} label contains a CLISP character.  Initially {lisp T}.
}}



{VarDef {Name DWIMESSGAG}
{Text
If {lisp T}, suppresses all {fn DWIMIFY} error messages.  Initially {lisp NIL}.
}}


{VarDef {Name CLISPRETRANFLG}
{Text
If {lisp T}, informs {fn DWIMIFY} to (re)translate all expressions which have remote translations in the CLISP hash array.  Initially {lisp NIL}.

{note This is primarily used to tell Interlisp to "do it again".}
}}



{index *END* DWIMIFY FN}


{Begin Note}
Date:  6 JUN 1977 2310-PDT
From: TEITELMAN
To:   MANUAL

document the fact that dwimify makes use of side property of history, and that user might want to rebind lispxhist to nil or some such if he is using dwimify as a production tool.
{End Note}

{Begin Note}
Date: 11 DEC 1981 2156-PST
From: MASINTER
Subject: DWIMIFY etc.
To:   kaplan, lisp
cc:   masinter

I fixed it so that even if DFNFLG=PROP that DWIM will unsave function definitions. The test there was just wrong; often I define a new function in ABC for immediate use, but since DFNFLG=PROP it gets put on the proplist. 
{End Note}

}{End SubSec DWIMIFY}






{Begin SubSec CLISPIFY}
{Title CLISPIFY}
{Text

{index *BEGIN* CLISPIFY FN}
{index *PRIMARY* CLISPIFY FN}

{fn CLISPIFY} converts Interlisp expressions to CLISP.  Note that the expression given to {fn CLISPIFY} need {it not} have originally been input as CLISP, i.e., {fn CLISPIFY} can be used on functions that were written before CLISP was even implemented.  {fn CLISPIFY} is cognizant of declaration rules as well as all of the precedence rules.  For example, {fn CLISPIFY} will convert {lisp (IPLUS A (ITIMES B C))} into {lisp A+B*C}, but {lisp (ITIMES A (IPLUS B C))} into {lisp A*(B+C)}.  {fn CLISPIFY} handles such cases by first {fn DWIMIFY}ing the expression.  {fn CLISPIFY} also knows how to handle expressions consisting of a mixture of Interlisp and CLISP, e.g., {lisp (IPLUS A B*C)} is converted to {lisp A+B*C}, but {lisp (ITIMES A B+C)} to {lisp (A*(B+C))}.  {fn CLISPIFY} converts calls to the six basic mapping functions, {fn MAP}, {fn MAPC}, {fn MAPCAR}, {fn MAPLIST}, {fn MAPCONC}, and {lisp MAPCON}, into equivalent iterative statements.  It also converts certain easily recognizable internal {fn PROG} loops to the corresponding iterative statements.  {fn CLISPIFY} can convert all iterative statements input in CLISP back to CLISP, regardless of how complicated the translation was, because the original CLISP is saved.


{fn CLISPIFY} is not destructive to the original Interlisp expression, i.e., {fn CLISPIFY} produces a new expression without changing the original.  The new expression may however contain some "pieces" of the original, since {fn CLISPIFY} attempts to minimize the number of {lisp CONS}es by not copying structure whenever possible.

{fn CLISPIFY} will not convert expressions appearing as arguments to {lisp NLAMBDA} functions, except for those functions whose {prop INFO}{index INFO Prop} property is or contains the atom {lisp EVAL}.   {fn CLISPIFY} also contains built in information enabling it to process special forms such as {fn PROG}, {fn SELECTQ}, etc.  If the {lisp INFO} property is or contains the atom {lisp LABELS}{index LABELS Litatom}, {fn CLISPIFY} will never create an atom (by packing) at the top level of the expression.  {fn PROG} is handled in this fashion.


Note:  Disabling a CLISP operator with {fn CLDISABLE} ({PageRef Fn CLDISABLE}) will also disable the corresponding {fn CLISPIFY} transformation.  Thus, if {lisp ←} is "turned off", {lisp A←B} will not transform to {lisp (SETQ A B)}, nor vice versa.


{FnDef {FnName CLISPIFY} {FnArgs X EDITCHAIN}
{Text
Clispifies {arg X}.  If {arg X} is an atom and {arg EDITCHAIN} is {lisp NIL}, {arg X} is treated as the name of a function, and its definition (or {lisp EXPR} property) is clispified.  After {fn CLISPIFY} has finished, {arg X} is redefined (using {lisp /PUTD}) with its new CLISP definition.  The value of {fn CLISPIFY} is {arg X}.  If {arg X} is atomic and not the name of a function, spelling correction is attempted.  If this fails, an error is generated.

If {arg X} is a list, or {arg EDITCHAIN} is not {lisp NIL}, {arg X} itself is the expression to be clispified.  If {arg EDITCHAIN} is not {lisp NIL}, it is the edit push-down list leading to {arg X} and is used to determine context as with {fn DWIMIFY}, as well as to obtain the local declarations, if any.  The value of {index CLISPIFY FN}{fn CLISPIFY} is the clispified version of {arg X}.
}}



{FnDef {FnName CLISPIFYFNS} {FnArgs FN{sub 1} {ellipsis} FN{sub N}}
{Type NOSPREAD NLAMBDA}
{Text
Like {fn DWIMIFYFNS} ({PageRef Fn DWIMIFYFNS}) except calls {fn CLISPIFY} instead of {fn DWIMIFY}.
}}


{VarDef {Name CL:FLG}
{Text
Affects {fn CLISPIFY}'s handling of forms beginning with {fn CAR}, {fn CDR}, {ellipsis} {fn CDDDDR}, as well as pattern match and record expressions.  If {var CL:FLG} is {lisp NIL}, these are not transformed into the equivalent {lisp :} expressions.  This will prevent {fn CLISPIFY} from constructing any expression employing a {lisp :} infix operator, e.g., {lisp (CADR X)} will not be transformed to {lisp X:2}.  If {var CL:FLG} is {lisp T}, {fn CLISPIFY} will convert to {lisp :} notation only when the argument is atomic or a simple list (a function name and one atomic argument).  If {var CL:FLG} is {lisp ALL}, {fn CLISPIFY} will convert to {lisp :} expressions whenever possible.

{var CL:FLG} is initially {lisp T}.
}}



{VarDef {Name CLREMPARSFLG}
{Text
If {lisp T}, {fn CLISPIFY} will remove parentheses in certain cases from simple forms, where "simple" means a function name and one or two atomic arguments.  For example, {lisp (COND ((ATOM X) --))} will {fn CLISPIFY} to {lisp (IF ATOM X THEN --)}.  However, if {var CLREMPARSFLG} is set to {lisp NIL}, {fn CLISPIFY} will produce {lisp (IF (ATOM X) THEN --)}.  Note that regardless of the setting of this flag, the expression can be input in either form.

{var CLREMPARSFLG} is initially {lisp NIL}.
}}



{VarDef {Name CLISPIFYPACKFLG}
{Text
{var CLISPIFYPACKFLG} affects the treatment of infix operators with atomic operands.  If {var CLISPIFYPACKFLG} is {lisp T}, {fn CLISPIFY} will pack these into single atoms, e.g., {lisp (IPLUS A (ITIMES B C))} becomes {lisp A+B*C}.  If {var CLISPIFYPACKFLG} is {lisp NIL}, no packing is done, e.g., the above becomes {lisp A{sp}+{sp}B{sp}*{sp}C}.

{var CLISPIFYPACKFLG} is initially {lisp T}.
}}



{VarDef {Name CLISPIFYUSERFN}
{Text
If {lisp T}, causes the function {lisp CLISPIFYUSERFN}, which should be a function of one argument, to be called on each form (list) not otherwise recognized by {fn CLISPIFY}.  If a non-{lisp NIL} value is returned, it is treated as the clispified form.  Initially {lisp NIL}

Note that {var CLISPIFYUSERFN} must be both set and defined to use this feature.
}}



{VarDef {Name FUNNYATOMLST}
{Text
Suppose the user has variables named {lisp A}, {lisp B}, and {lisp A*B}.  If {fn CLISPIFY} were to convert {lisp (ITIMES A B)} to {lisp A*B}, {lisp A*B} would not translate back correctly to {lisp (ITIMES A B)}, since it would be the name of a variable, and therefore would not cause an error.  The user can prevent this from happening by adding {lisp A*B} to the list {var FUNNYATOMLST}.  Then, {lisp (ITIMES A B)} would {fn CLISPIFY} to {lisp A{sp}*{sp}B}.

Note that {lisp A*B}'s appearance on {var FUNNYATOMLST} would {it not} enable DWIM and CLISP to decode {lisp A*B+C} as {lisp (IPLUS A*B C)}; {var FUNNYATOMLST} is used only by {fn CLISPIFY}.  Thus, if an identifier contains a CLISP character, it should always be separated (with spaces) from other operators.  For example, if {lisp X*} is a variable, the user should write
{lisp (SETQ X* {arg FORM})} in CLISP as {lisp X*{sp}←{arg FORM}}, not {lisp X*←{arg FORM}}.  In general, it is best to avoid use of identifiers containing CLISP character operators as much as possible.
}}


{index *END* CLISPIFY FN}

}{End SubSec CLISPIFY}






{Begin SubSec Miscellaneous Functions and Variables}
{Title Miscellaneous Functions and Variables}
{Text


{note removed bracket-defining info - moved to Stuff.CLISPbrackets}


{VarDef {Name CLISPFLG}
{Text
If {var CLISPFLG}={lisp NIL}, disables all CLISP infix or prefix transformations (but does not affect {lisp IF}/{lisp THEN}/{lisp ELSE} statements, or iterative statements).

If {var CLISPFLG}={lisp TYPE-IN}, CLISP transformations are performed only on expressions that are typed in for evaluation, i.e., not on user programs.

If {var CLISPFLG}={lisp T}, CLISP transformations are performed on all expressions.

The initial value for {var CLISPFLG} is {lisp T}.  {fn CLISPIFY}ing anything will cause {var CLISPFLG} to be set to {lisp T}.
}}


{VarDef {Name CLISPCHARS}
{Text
A list of the operators that can appear in the interior of an atom.  Currently {lisp (+ - * / ↑ ~ ' = ← : < > +- ~= @ !)}.
}}


{VarDef {Name CLISPCHARRAY}
{Text
A bit table of the characters on {var CLISPCHARS} used for calls to {fn STRPOSL} ({PageRef Fn STRPOSL}).  {var CLISPCHARRAY} is initialized by performing {lisp (SETQ CLISPCHARRAY (MAKEBITTABLE CLISPCHARS))}.
}}


{VarDef {Name CLISPINFIXSPLST}
{Text
A list of infix operators used for spelling correction.{index spelling lists}{index spelling correction}
}}


{VarDef {Name CLISPARRAY}
{Text
Hash array used for storing CLISP translations.  {var CLISPARRAY} is checked by {fn FAULTEVAL}  and {fn FAULTAPPLY} on erroneous forms before calling DWIM, and by the compiler.
}}


{FnDef {FnName CLISPTRAN} {FnArgs X TRAN}
{Text
Gives {arg X} the translation {arg TRAN} by storing (key {arg X}, value {arg TRAN}) in the hash array {var CLISPARRAY}.  {fn CLISPTRAN} is called for all CLISP translations, via a non-linked, external function call, so it can be advised.
}}


{FnDef {FnName CLISPDEC} {FnArgs DECLST}
{Text
Puts into effect the declarations in {arg DECLST} (see {PageRef Tag CLISPDeclarations}).  {fn CLISPDEC} performs spelling corrections on words not recognized as declarations.  {fn CLISPDEC} is undoable.
}}



{FnDef {FnName CLDISABLE} {FnArgs OP}
{Text
Disables the CLISP operator {arg OP}.  For example, {lisp (CLDISABLE '-)} makes {lisp -} be just another character.  {fn CLDISABLE} can be used on all CLISP operators, e.g., infix operators, prefix operators, iterative statement operators, etc.  {fn CLDISABLE} is undoable.


{index *PRIMARY* Disabling CLISP operators}

Note:  Simply removing a character operator from {var CLISPCHARS} will prevent it from being treated as a CLISP operator when it appears as part of an atom, but it will continue to be an operator when it appears as a separate atom, e.g. ({lisp FOO + X}) vs {lisp FOO+X}.

{note there needs to be a better way of reenabling CLISP operators than UNDOing the statement with the CLDISABLE in it}
}}



{VarDef {Name CLISPIFTRANFLG}
{Text
Affects handling of translations of {lisp IF}-{lisp THEN}-{lisp ELSE} statements (see {PageRef (Statement) IF}).  If {lisp T}, the translations are stored elsewhere, and the (modified) CLISP retained.  If {lisp NIL}, the corresponding {fn COND} expression replaces the CLISP.  Initially {lisp T}.
}}



{index *PRIMARY* CLISPIFYPRETTYFLG Var}

{VarDef {Name CLISPIFYPRETTYFLG}
{Text
If non-{lisp NIL}, causes {fn PRETTYPRINT} (and therefore {fn PP} and {fn MAKEFILE}) to {fn CLISPIFY} selected function definitions before printing them according to the following interpretations of {var CLISPIFYPRETTYFLG}:

{Begin LabeledList following interpretations of CLISPIFYPRETTYFLG}

{Label {lisp ALL}}
{Item
Clispify all functions.
}

{Label {lisp T} or {lisp EXPRS}}
{Item
Clispify all functions currently defined as {lisp EXPR}s.
}

{Label {lisp CHANGES}}
{Item
Clispify all functions marked as having been changed.
}

{Label a list}
{Item
Clispify all functions in that list.
}

{End LabeledList following interpretations of CLISPIFYPRETTYFLG}

{var CLISPIFYPRETTYFLG} is (temporarily) reset to {lisp T} when 
{fn MAKEFILE} is called with the option {lisp CLISPIFY}, and reset
to {lisp CHANGES} when the file being dumped has the property
{prop FILETYPE}{index FILETYPE Prop} value {lisp CLISP}.{index CLISPIFY (MAKEFILE option)}{index *PRIMARY* MAKEFILE and CLISP}
{var CLISPIFYPRETTYFLG} is initially {lisp NIL}.


Note:  If {var CLISPIFYPRETTYFLG} is non-{lisp NIL}, and the only transformation performed by {lisp DWIM} are well formed {lisp CLISP} transformations, i.e., no spelling corrections, the function will {it not} be marked as changed, since it would only have to be re-clispified and re-prettyprinted when the file was written out.
}}





{Begin comment flushed}
broken in Intermezzo release, quietly dropped
{VarDef {Name PRETTYTRANFLG}
{Text
If {lisp T}, causes {fn PRETTYPRINT} to print translations instead of CLISP expressions.  This is useful for exporting to a LISP system that does not have CLISP.  {var PRETTYTRANFLG} is (temporarily) reset to {lisp T} when {fn MAKEFILE} is called with the option {lisp NOCLISP}.{index NOCLISP (MAKEFILE option)}  {var PRETTYTRANFLG} is initially {lisp NIL}.
}}
{End comment flushed}



{FnDef {Name PPT} {Args X}
{Type NOSPREAD NLAMBDA}
{Text
Both a function and an edit macro for prettyprinting translations.  It performs a {lisp PP} after first resetting {var PRETTYTRANFLG} to {lisp T}, thereby
causing any translations to be printed instead of the corresponding CLISP.

{index PPT EditCom}
}}



{Def {Type EditCom} {Name CLISP:}
{Text
Edit macro that obtains the translation of the correct expression, if any, from {index CLISPARRAY Var}{var CLISPARRAY}, and calls {fn EDITE} on it.
}}



{Def {Type EditCom} {Name CL}
{Text
Edit macro.  Replaces current expression with {fn CLISPIFY}ed current expression.  Current expression can be an element or tail.
}}



{Def {Type EditCom} {Name DW}
{Text
Edit macro.  {fn DWIMIFY}s current expression, which can be an element (atom or list) or tail.
}}


Both {editcom CL} and {editcom DW} can be called when the current expression
is either an element or a tail and will work properly.  Both consult the declarations in the function being edited, if any, and both are undoable.

{index *PRIMARY* Lower case in CLISP}

{FnDef {FnName LOWERCASE} {FnArgs FLG}
{Text
If {arg FLG}={lisp T}, {fn LOWERCASE} makes the necessary internal modifications so that {fn CLISPIFY} will use lower case versions of {lisp AND}, {lisp OR}, {lisp IF}, {lisp THEN}, {lisp ELSE}, {lisp ELSEIF}, and all i.s. operators.  This produces more readable output.  Note that the user can always type in {it either} upper or lower case (or a combination), regardless of the action of {fn LOWERCASE}.  If {arg FLG}={lisp NIL}, {fn CLISPIFY} will use uppercase versions of {lisp AND}, {lisp OR}, et al.  The value of {fn LOWERCASE} is its previous "setting".  {fn LOWERCASE} is undoable.  The initial setting for {fn LOWERCASE} is {lisp T}.
}}


{Begin Note}
currently (Sat, 23 Jul 83 16:30 PDT) CLISPARITHOPLST= (+ - * / +- LT GT lt gt GEQ LEQ GE LE geq leq ge le)  --- mjs

(Date: 12 JUN 1978 0208-PDT
From: TEITELMAN
Subject: clispdec

the quoted list (+ - * / +- LT GT) that appeared in clispdec is now parameterized to be the value of CLISPARITHOPLST.  the quoted list (INTEGER FIXED MIXED FLOATING) is the value of CLISPARITHCLASSLST. feel free to reset or rebind these. however, i dont think i will document this feature.
{End Note}



}{End SubSec Miscellaneous Functions and Variables}




{Begin SubSec CLISP Internal Conventions}
{Title CLISP Internal Conventions}
{Text

{index CLISP internal conventions}

{Tag AddingCLISPinfix}

CLISP is almost entirely table driven by the property lists of the corresponding
infix or prefix operators.  For example, much of the information used for translating the {lisp +} infix operator is stored on the property list of the litatom "{lisp +}".  Thus it is relatively easy to add new infix or prefix operators or change old ones, simply by adding or changing selected property values.  (There {it is} some built in information for handling minus, {lisp :}, {lisp '}, and {lisp ~}, i.e., the user could not himself add such "special" operators, although he can disable or redefine them.)

Global declarations operate by changing the {prop LISPFN} and {prop CLISPINFIX} properties of the appropriate operators.


{PropDef {Name CLISPTYPE}
{Text
The property value of the property {prop CLISPTYPE} is the precedence number of the operator:  higher values have higher precedence, i.e., are tighter.  Note that the actual value is unimportant, only the value relative to other operators.  For example, {prop CLISPTYPE} for {lisp :}, {lisp ↑}, and {lisp *} are 14, 6, and 4 respectively.  Operators with the same precedence group left to right, e.g., {lisp /} also has precedence 4, so {lisp A/B*C} is {lisp (A/B)*C}.

An operator can have a different left and right precedence by making the value of {prop CLISPTYPE} be a dotted pair of two numbers, e.g., {index CLISPTYPE Prop}{prop CLISPTYPE} of {lisp ←} is {lisp (8 . -12)}.  In this case, {fn CAR} is the left precedence, and {fn CDR} the right, i.e., {fn CAR} is used when comparing with operators on the {it left}, and {fn CDR} with operators on the {it right}.  For example, {lisp A*B←C+D} is parsed as {lisp A*(B←(C+D))} because the left precedence of {lisp ←} is 8, which is higher than that of {lisp *}, which is 4.  The right precedence of {lisp ←} is -12, which is lower than that of {lisp +}, which is 2.

If the {index CLISPTYPE Prop}{prop CLISPTYPE} property for any operator is removed, the corresponding CLISP transformation is disabled, as well as the inverse {fn CLISPIFY} transformation.
}}


{PropDef {Name UNARYOP}
{Text
The value of property {prop UNARYOP} must be {lisp T} for unary operators or brackets.  The operand is always on the right, i.e., unary operators or brackets are always prefix operators.
}}


{PropDef {Name BROADSCOPE}
{Text
The value of property {prop BROADSCOPE} is {lisp T} if the operator has lower precedence than Interlisp forms, e.g., {lisp LT}, {lisp EQUAL}, {lisp AND}, etc.  For example, {lisp (FOO X AND Y)} parses as {lisp ((FOO X) AND Y)}.  If the {prop BROADSCOPE} property were removed from the property list of {lisp AND}, {lisp (FOO X AND Y)} would parse as {lisp (FOO (X AND Y))}.
}}


{PropDef {Name LISPFN}
{Text
The value of the property {prop LISPFN} is the name of the function to which the infix operator translates.  For example, the value of {prop LISPFN} for {lisp ↑} is {lisp EXPT}, for {lisp '} {lisp QUOTE}, etc.  If the value of the property {prop LISPFN} is {lisp NIL}, the infix operator itself is also the function, e.g., {lisp AND}, {lisp OR}, {lisp EQUAL}.
}}


{PropDef {Name SETFN}
{Text
If {lisp FOO} has a {prop SETFN} property {lisp FIE}, then {lisp (FOO --)←X} translates to {lisp (FIE -- X)}.  For example, if the user makes {lisp ELT} be an infix operator, e.g. {lisp #}, by putting appropriate {prop CLISPTYPE} and {prop LISPFN} properties on the property list of {lisp #} then he can also make {lisp #} followed by {lisp ←} translate to {lisp SETA}, e.g., {lisp X#N←Y} to {lisp (SETA X N Y)}, by putting {lisp SETA} on the property list of {lisp ELT} under the property {prop SETFN}.  Putting the list {lisp (ELT)} on the property list of {lisp SETA} under property {prop SETFN} will enable {lisp SETA} forms to {fn CLISPIFY} back to {lisp ELT}'s.
}}


{PropDef {Name CLISPINFIX}
{Text
The value of this property is the CLISP infix to be used in {fn CLISPIFY}ing.  This property is stored on the property list of the corresponding Interlisp function, e.g., the value of property {prop CLISPINFIX} for {lisp EXPT} is {lisp ↑}, for {lisp QUOTE} is {lisp '} etc.
}}


{PropDef {Name CLISPWORD}
{Text
Appears on the property list of clisp operators which can appear as {fn CAR} of a form, such as {lisp FETCH}, {lisp REPLACE}, {lisp IF}, iterative statement operators, etc.  Value of property is of the form {lisp ({arg KEYWORD} . {arg NAME})}, where {arg NAME} is the lowercase version of the operator, and {arg KEYWORD} is its type, e.g. {lisp FORWORD}, {lisp IFWORD}, {lisp RECORDWORD}, etc.

{arg KEYWORD} can also be the name of a function.  When the atom appears as {fn CAR} of a form, the function is applied to the form and the result taken as the correct form.  In this case, the function should either physically change the form, or call {fn CLISPTRAN} ({PageRef Fn CLISPTRAN}) to store the translation.
}}


As an example, to make {lisp &} be an infix character operator meaning {lisp OR}, the user could do the following:

{lispcode
←(PUTPROP '& 'CLISPTYPE (GETPROP 'OR 'CLISPTYPE))
←(PUTPROP '& 'LISPFN 'OR)
←(PUTPROP '& 'BROADSCOPE T)
←(PUTPROP 'OR 'CLISPINFIX '&)
←(SETQ CLISPCHARS (CONS '& CLISPCHARS))
←(SETQ CLISPCHARRAY (MAKEBITTABLE CLISPCHARS))}


}{End SubSec CLISP Internal Conventions}