MANUAL UPDATE Thursday, November 15, 1974 This document is a list of changes to the MACLISP language between the time the MACLISP Reference Manual (Revision 0) was written and the present date. References to the manual are made by section number and page number. This document does not purport to correct typographical errors in said manual. New Functions \\ This subr of two arguments is like gcd, but only accepts fixnums. This makes it faster than gcd. copysymbol A subr of two arguments. The first argument must be a symbol, and the second should be t or nil. The result is a new, uninterned symbol, with the same pname as the argument. If the second argument is t, the new symbol will be given the same value as the original and will have a copy of its property list. Thus the new will start out with the same value and properties as the old, but if it is setq'ed or putprop'ed, the value or property of the old will not be changed. If the second argument is nil, the new symbol has no value and no properties (except possibly internal system properties.) nreconc A subr of two arguments. (nreconc x y) is exactly the same as (nconc (nreverse x) y) except that it is more efficient. getcharn A subr of two arguments. gethcharn is identical to getchar except that the selected character is returned as a fixnum rather than as a character object. subrcall An fsubr. subrcall is used to invoke a subr-pointer directly, rather than by referring to an atomic symbol of which the subr-pointer is the subr property. The form is: (subrcall type p a1 a2 ... an) All arguments except the first are evaluated. type is the type of result expected: fixnum, flonum, or nil (any type.) p is the subr pointer to be called. a1 through an are the arguments to be passed to the subr. subrcall compiles into efficient machine code. lsubrcall An fsubr. lsubrcall is identical to subrcall except that the subr-pointer called has to be an lsubr instead of a subr. This is because many LISPs use different internal calling sequences for lsubrs and subrs. arraycall An fsubr. arraycall is similar to subrcall and lsubrcall except that an array-pointer is used instead of a subr-pointer. (See the section below on arrays.) The first argument of arraycall must correspond to the type that the array was given when it was created. An arraycall expression may be used as the first argument to store. Section 2.1, page 7 An array is NOT always associated with an atomic symbol which is its name. Rather, an array is always designated by an array-pointer, which is a special kind of atomic LISP object. Frequently, an array-pointer will be placed on the property list of a symbol under the indicator array and then that symbol will be used as the name of the array, since symbols can have mnemonic names and are more easily referred to in typing at lisp than "pointers." Section 2.2, page 9 (typep) typep can also return the atom array, if its argument is an array-pointer. Section 4.1, page 24 (equal) The definition of equal given is grossly incorrect. The correct definition is: (defun equal (x y) (or (eq x y) (and (numberp x) (numberp y) (numequal x y)) (and (not (atom x)) (not (atom y)) (equal (car x) (car y)) (equal (cdr x) (cdr y))))) with an auxiliary function for numeric equality, defined (approximately) as follows: (defun numequal (x y) ;numerical equality (and (eq (typep x) (typep y)) (zerop (difference x y)))) Section 2.1, page 6. Another property of the special atomic symbol nil is that its car and its cdr are always nil. This is true even if a property is putprop'ed onto nil; thus, unlike all other atomic symbols, (cdr nil) is not its property list. [This is not yet implemented in ITS LISP.] Section 6.1, page 48. The existence of the definedp predicate should not be relied upon. boundp no longer returns (nil . value) if the symbol is bound; instead it is a true predicate and returns t if the symbol is bound, nil if it is not. Section 6.2, page 49. NOTE: the property list of nil is not kept on (cdr nil). Section 6.4, page 53. getcharn is the same as getchar except that a number is returned instead of a single character object. Section 7.7, page 71 (zunderflow) If zunderflow is non-nil, quotient of a flonum by a bignum which is too large to be converted to a flonum will be regarded as a floating underflow and so will return 0.0. Chapter 9, page 79. In the "new array" scheme which is now in MACLISP, the following changes to the handling of arrays exist. (In addition, the introductory portion of Chapter 9 ought to explain what an array is, for the benefit of those not cursed with a knowledge of FORTRAN.) There are several types of arrays. The main types are ordinary arrays, referred to by the type-code t, fixnum arrays, referred to by the type-code fixnum, and flonum arrays referred to by the type-code flonum. Ordinary arrays are the same arrays as before, capable of holding any type of data. Fixnum arrays and flonum arrays are "number" arrays, which can only hold fixnums or flonums respectively. These arrays permit more efficient code to be compiled for numerical applications. (See the array* declaration in chapter 14 and the arraycall function.) The type of an array must be declared when it is created with array or *array. Some other types of arrays are un-garbage-collected arrays, with a type-code of nil, which are the same as ordinary arrays except that they are not protected by the garbage collector and therefore can be used for certain esoteric hacks; obarrays, with a type-code of obarray, which are used to maintain tables of known atomic symbols so that the same atomic symbol will be referenced when the same pname is typed in; and readtables, with a type-code of readtable, which are used to remember the syntax specifications for the LISP input reader. Normally, there is only one readtable and one obarray, supplied by the system as the values of the atoms readtable and obarray, respectively, but the user may create additional readtables and obarrays in order to provide special non-LISP environments or to gain additional control over the LISP environment. The atoms readtable and obarray can be bound to make the various functions which need them, such as read, employ a user-supplied readtable or obarray. An array-pointer may also be "dead", in which case it does not point to any array. One of the functions array, *array, or *rearray may be used to revivify a dead array-pointer. An array is designated by a special atomic object called an array-pointer. Array pointers can be returned by the array-creation functions array and *array. An array pointer may either be used directly to refer to the array, or, for convenience in referring to the array through input/output media, it may be placed on the property list of an atomic symbol under the indicator array, and then that symbol can be used as the name of the array (as before.) The first argument of array or *array may be an atomic symbol, which makes that atomic symbol the name of an array, redefining the array pointer on its property list if there already was one, or it may be an array pointer, which causes that array pointer to be redefined, or it may be nil, which causes a new array pointer to be created and returned. Except in the latter case, array returns its first argument. *array always returns the array pointer, never the atomic symbol (this is an incompatibility.) A readtable or an obarray may not be created with user-specified dimensions. The dimensions are always determined by LISP. Ordinary and un-garbage-collected arrays are initialized to nil, as before. Fixnum arrays are initialized to 0. Flonum arrays are initialized to 0.0. Obarrays are initialized according to the third argument of array or *array. nil causes a completely empty obarray to be created. Not even nil will be interned on this obarray. t causes the current obarray (value of the symbol obarray) to be copied. An array-pointer which is an obarray, or an atomic symbol which names an obarray, causes that obarray to be copied. If no third argument is given, the current obarray is copied. Readtables are initialized in a similar fashion. If the third argument of array or *array is nil, then the current obarray is copied. If it is t, then the readtable being created is initialized to the initial standard LISP readtable, including the macro characters ' and ;. An array-pointer or symbol of a readtable to be copied may also be given. If no third argument is given, the current readtable is copied. The reason that the interpretation of t and nil for readtables if reversed from obarrays is for compatibility with the old makreadtable function. Note that an array-pointer may be REDEFINED to an entirely different type and size of array. It remains the same array-pointer, eq to itself. If a variable was setq'ed to the array-pointer, that variable will now indicate the new array. The *rearray function allows its first argument to be either an atomic symbol with an array property, or an array-pointer. If there is only one argument, the array is killed. The array becomes a "dead array" as described above. If more than one argument is given, they are the same arguments as to array or *array. *rearray with more than argument cannot be used to change the type of an array, and cannot operate on a readtable or an obarray. The modified array will be initialized from its old contents rather than nil, 0, or 0.0. The elements are taken in row-major order for initialization purposes, and if there are not enough, nil, 0, or 0.0 will be used to fill the remaining elements of the modified array according to the type. The array functions fillarray, listarray, bltarray, arraydims, sort, and sortcar will accept array-pointers as well as symbols with array properties. In bltarray the types must match, except that ordinary (t) and un-garbage-collected (nil) are considered the same type. In order to get the range of subscripts on arrays checked, it is necessary to set the *rset flag non-nil, i.e. run in (*rset t) mode, and to use interpreted code. The amount of checking performed when *rset is nil and/or compiled code is used is not defined. Section 12.3.1, page 95. CTRL/U is not actually implemented anywhere and some LISPs use CTRL/H instead of CTRL/B. Section 12.5.2, page 109. The form of the "frames" returned by evalframe and errframe is a list where the car is the type of frame, the cadr is a pdl-pointer, the caddr is some data depending on the type of frame, and the cadddr of the list is an alist-pointer (binding context pointer.) The three types of frames are eval (evaluation), apply (apply, map, compiled call, funcall, etc.), and err (error.) The formats are: (eval ) (apply ( . ) ) (err ( ) ) In an err frame, the and/or may be omitted, depending on the type of error. Note that applying the function error to caddr of an err frame will re-create the error. Section 12.7, page 120 (status & sstatus) The following 'status' functions have been added: (sstatus uuolinks t) - causes all "uuo links" from compiled code that has been loaded to compiled functions or builtin subrs, lsubrs, or fsubrs to be "snapped." This can be used to perform the link-snapping overhead only once, just before a software package for general use is "save"ed. (This only exists in the Multics implementation at present.) (sstatus uuolinks nil) or (sstatus uuolinks) performs the previous function of unsnapping all uuo-links so that subrs may be redefined. (status dow) returns an atomic symbol which is the name of the current day of the week. (status linmode) reads the "line mode," and (sstatus linemode x) sets the "line mode" to x (t or nil.) In some implementations the "line mode" may not be changed. If the "line mode" is t, user input is buffered up a line at a time before being sent to LISP. The input-editing conventions of the host operating system are used. If the "line mode" is nil, LISP sees each character as it is typed and applies its own input editing conventions. This mode can provide input facilities more suited to LISP and possibly better handling of the terminal, if it is a type that LISP knows a great deal about. However, it uses more machine resources. It is possibly for a user program to take direct control of the terminal when the "line mode" is t, however this may require knowledge of the undocumented (sstatus tty) function. The Multics implementation always operates with a "line mode" of t. The ITS implementation at present only operates with a "line mode" of nil. (status newline) - returns a fixnum which is the ascii code for the character used to mark the end of a line of input. End of line may be checked for by (= (setq ch (tyi)) (status newline)) (sstatus feature foo) - makes foo a feature. Thus user- or system-supplied packages which are loaded into the environment can set features indicating their presence, as an extension of the features set by LISP itself to indicate its own features. foo is not evaluated. For example, the "trace" package does (sstatus feature trace) and the "grind" and "grindef" S-expression formatting package does (sstatus feature grind) and (sstatus feature grindef), depending on how much of it has been loaded in. Similarly, the compiler will set (sstatus feature compiler), and (sstatus feature fastarith) if it has the capability of producing fast code for arithmetic operations, to inform the program being compiled of what is going on. (sstatus nofeature foo) turns off the foo feature. foo is not evaluated. This is used by packages that have the ability to remove themselves from the environment upon a command such as (remtrace). (sstatus crfile foo bar) sets the file names in the defaults used by uread, etc. to foo bar. In effect, this sets the "current file." Section 13.4.1, page 152 (cursorpos.) (cursorpos 'L) is intended to supersede (cursorpos ']). They do the same thing, it is just a better name for the function. Section 13.7, page 164. The printer prints an array-pointer as a sharp sign (#), followed by the type of array, followed by the dimensions, followed by the machine address of the array in a format useful to system debuggers. In the case of a dead-array, only "#dead-array" is printed. An example of the format is shown below: #FIXNUM-4:3-343425 (ITS) or #fixnum-4:3-335|2206 (Multics) The reader will not recognize such strings, if fed back into it, as array-pointers. They will probably be read as atomic symbols. Section 13.9, page 175. The "display slave" still does not exist in Multics LISP, unfortunately. Section 14.2, page 186 (array* declaration.) The extended form (array* (type (arr1 dim1.1 dim1.2 ... dim1.n) ...)) can be used. The dimensions declared must be either fixnums or nil or ?, which indicate a dimension not known at compile time. If dimensions are declared, the compiler can generate faster code. The array* declaration causes the compiler to generate in-line code for accesses of and "store"s into the arrays declared. This code is somewhat faster than the usual subroutine-call array accessing. The compiler will also generate in-line code if the arraycall function is used; in this case the array must be named by an array-pointer rather than by an atomic symbol. Section 14.2, page 187. (closed declaration) The following declaration was accidentally omitted: (closed t) causes arithmetic operations to be close-compiled, that is the function + will generate in-line code but the function plus will not in any circumstances. This declaration is necessary if you take plus of two fixnums and want a bignum if the result overflows. If the declaration is not specified, the compiler will produce code that assumes overflow will not occur, which may give incorrect results in the above case. (closed nil) reverses the effect of (closed t), allowing the compiler to generate in-line code for functions such as plus when it can identify, by declaration or implication, the operands to be all fixnums or all flonums. Section 15, page 224. The "strace" package is a highly out of date version of trace; in fact, you may not be able to find it at all at your site. However, if the variable sprinter is setq'ed non-nil, trace will use the grind package to do its output, so "strace" is no longer necessary. The trace specifications may be "factored." For example, (trace ((foo bar) value wherein baz)) is equivalent to (trace (foo value wherein baz) (bar value wherein baz)) Section 16.5, page 237. The grinder directive ;;*ppage has been renamed to ;;*user-paging. Section 4.1, page 28. Append the following to the end of the section: maknum SUBR 1 arg (maknum x) returns a non-negative fixnum which is uniquely associated with x. x may be any LISP object. It is uniquely associated in the sense that (maknum x) is numerically equal to (maknum y) if and only if (eq x y) is true. munkam SUBR 1 arg munkam is the reverse of maknum. Given a number which was obtained from maknum, munkam returns the object which was given to maknum to get it to return that number. Chapter 15, page 224. Replace the last two paragraphs on page 224 with the following: All output printed by trace can be ground into an indented, readable format, by simply setting the variable sprinter to t. Setting sprinter to nil changes the output back to use the ordinary print function, which is faster and uses less storag but is less readable for large list structures. Add to the end of chapter 9. Number arrays may be efficiently saved in the file system and restored by using the functions loadarrays and dumparrays. loadarrays SUBR 1 arg (loadarrays ) reloads the arrays in the file, and returns a list of 3-lists, of the form: ( ( ) ... ) is a gensym'ed atom, which is the name of the reloaded array. is the name the array had when it was dumped. is the number of elements in the array. dumparrays SUBR 2 args (dumparrays ( ... ) ) dumps the listed arrays into the specified file. The arrays must be fixnum or flonum arrays. In both of the above, the argument is dependent on the system. In ITS or DEC-10 LISP, the is a list of 0 to 4 items, as in uread, and the same defaults apply. In Multics LISP, the is an atomic symbol or a string which gives the pathname of the segment to be used. The defaults and other features of the LISP I/O system are not applied. Only a segment may be specified; not a stream. As a special compatibility feature, in Multics LISP loadarrays will recognize a pdp-10 dumparrays file. (One can be moved to Multics through the ARPA network File Transfer Protocol if the type image and bytesize 36 commands are employed.) The pnames will be converted to lower case and any flonums present will be converted appropriately. dumparrays can create a file which pdp-10 loadarrays can read, including upper-case pnames and pdp-10 format flonums, if it is invoked as follows: (dumparrays ( ...) '(pdp10 )) More New Functions maknum SUBR of 1 argument (maknum x) returns a positive fixnum which is unique to the object x; that is, (maknum x) and (maknum y) are numerically equal if and only if (eq x y). This can be used in hashing. In the pdp-10 implementations, maknum returns the memory address of its argument. In the Multics implementation, an internal hash table is employed. Note that unlike sxhash, maknum will not return the same value on an expression which has been print'ed out and read bac in again. munkam SUBR of 1 argument munkam is the opposite of maknum. Given a number, it returns the object which was given to maknum to get that number. ^ SUBR of 2 arguments ^ is the fixnum-only exponentiation function. It is somewhat faster than expt, but requires its arguments to be fixnums, uses fixnum arithmetic, and always returns a fixnum result. Note that in situations where expt would have returned the correct result in bignum form, ^ will give an arithmetic overflow error. ^$ SUBR of 2 arguments ^$ is the flonum-only exponentiation function. The first argument must be a flonum, the second must be a fixnum (repeat, a FIXNUM), and the result is a flonum. symeval SUBR of 1 argument symeval is used to get the value of an atomic symbol, when which symbol is to be used is not known when the program is written, for example in an interpreter written in lisp. If the argument to symeval is not an atomic symbol, or is an atomic symbol but does not currently have a value, an error is signalled. The advantage of symeval over eval is that it is compiled into very efficient code (which will not detect the above error, so watch out.) [The ITS implementation does not seem to have this function yet.] uprobe FSUBR Takes arguments like uread and returns t if the specified file exists, nil if it does not. uappend FSUBR Takes arguments like uread, but opens the specified file for output like uwrite does, renaming the file so no one else will get at it while you are outputting to it. ufile is used to finish outputting and rename the file back. The difference between uappend and uwrite is that the output is stuck onto the end of the file, instead of replacing what was previously there. uclose SUBR of no arguments (uclose) closes the uread input file. This is useful before a suspend (ITS) or a save (Multics.) Changes to Existing Functions expt now allows its second argument to be a flonum, in which case the first argument is converted to a flonum and the exponentiation is performed in floating point, using logarithms. The result is a flonum. defprop and defun now do a remprop before they do a putprop. This ensures that the property they put on always comes first in the property list, which is useful in cases such as replacing a subr with an expr when the subr replaced a previous expr. remprop returns a different value when it finds the property to be removed. Instead of t, the part of the property list beginning with the indicator removed is returned. This is a value similar to what getl returns. On page 19, chapter 3. The statement that the funarg facility does not correctly handle setq's is no longer operative. setq's will be performed in the correct environment no matter what combination of *function's, a-list (or binding context) pointers, etc. you use. In chapter 13. You should no longer use nil to indicate the terminal to an I/O function, for instance (read nil) or (print x nil). Instead, t should be used. nil will still work for quite a while. Later nil will be changed to mean "the default." Consequently, On page 145 (read t) should be changed to (read infile t). Add to page 89. Variables used by the top-level read-eval-print loop * contains the last S-expression printed out by the read-eval-print loop, that is, the value of the last form typed in. After an error return to top level, the value of * is * itself, since a star has just been typed out. + contains the value of the last S-expression typed in. This can be used to edit it or to do it over again. - contains the value of the current S-expression typed in. This is mostly just used to hold this form until after it has been evaluated, at which time (setq + -) is done. By special dispensation the value of + is preserved across a break. That is, when an error-break is entered (assuming the user has not replaced the system handler for the error with his own) the value of + is the form which was last typed, normally the one which caused the error. While the user types forms at the break-loop, the value of + is set to each form he types in the usual way. When the user returns from the break, + is set back to the form typed before the break was entered (the last form typed at top level.) Actually, if you think about it you will see that this is done by binding -, not +. // is used to temporarily hold the value of errlist when an error returns to top level. This is so that lambda-binding errlist will have an effect (assuming no one lambda-binds //). The top-level form given on page 89 should be revised to read: (errset (progn (setq ^r nil ^q nil ^w nil) ;reset internal vars (mapc 'eval //) ;do errlist, which // was set to (setq * '*) ;cause an asterisk to be typed ;now enter the read-eval-print loop, remaining ; there unless an error should occur. (do nil (nil) ;= do forever (setq * (cond ((status toplevel) (eval (status toplevel))) (t (print *) (terpri) (eval (setq - (read)))) )) (setq + -)) )) The defpl1 declaration, page 187. Using the `defpl1' feature of the lisp compiler The Multics lisp compiler provides a feature by which you can compile a lisp subr which represents, in the lisp environment, a subroutine in the outside world which has a PL/I-compatible calling sequence. When the lisp subr is applied, the subroutine will be called with arguments derived from the arguments given to the lisp subr. Results returned by the subroutine may be passed back to lisp either as the return value of the lisp subr, or by setq'ing an atomic symbol. Because lisp and PL/I use different data types, a correspondence between the types must be set up: Numbers. fixed binary with a precision not more than 35. corresponds to the lisp fixnum. float binary with a precision of not more than 27. corresponds to the lisp flonum. Nonzero scale factors, complex numbers, decimal or pictured numbers, and large precisions are not supported. Bit strings. A bit string of up to 36. bits corresponds to a lisp fixnum. The bits are stored left-justified in the fixnum, thus in the case of bit(1) the fixnum is 0 for "0"b and negative for "1"b. Note that because of the left-justification most bit strings map into "illegal" fixnums which cannot be typed in as octal numbers (because a bignum would be produced.) The `lsh' function can be useful here. These bit strings work as either `aligned' or `unaligned.' Bit strings longer than 36. bits are not supported. Character strings. Lisp character strings and PL/I character strings correspond directly. For input arguments, lisp will also automatically convert an atomic symbol to a character string by taking its pname, as usual. Usually the PL/I argument will be declared `char(*).' For output arguments, you must declare the character string with some fixed length, even if it is declared "char (*)" in the PL/I program. The construct "(return char (*))", however, IS supported, for the last argument only, to produce the arbitrary-length result of the PL/I "returns char (*)" construct. Varying Character Strings. Varying character strings are somewhat special. Lisp will take whatever string argument you supplied (the null string if it is a `return' argument) and create a varying string of the length you declared, initialized to the string you supplied. Thus usually its current length will be less that its maximum length. This varying string will be passed to the PL/I subroutine. When the subroutine returns, whatever it leaves in the varying string will be made back into a lisp string and returned (if it is an `update' or `return' argument.) This procedure is necessary because lisp strings may not vary in length. Note that you must declare the length of the string; `char(*) varying' is illegal. However, the PL/I subroutine may declare it `char(*) varying' since a descriptor is passed. Pointers. Both packed and unpacked pointers are supported. These are both represented in lisp as fixnums in packed pointer format, that is 2 octal digits of bit offset, 4 octal digits of segment number, and 6 octal digits of word offset. The null pointer is 007777000001 octal. It is not possible to reference, within lisp, what a pointer points at. Because of the packed pointer representation, ring numbers in pointers are not supported. If you declare the PL/I subroutine to take unpacked pointers, which is the default, lisp will do the conversion between packed and unpacked representations. Raw lisp objects. A PL/I subroutine which knows about lisp may be passed (or return) raw lisp objects. In PL/I these should be declared `fixed bin(71)' and then the based overlays declared in sundry lisp include files should be used. Arrays. Arrays of any number of dimensions may be passed. The arrays can only contain numbers or raw lisp objects however. Usually you would pass a lisp fixnum (or flonum) array and in PL/I declare it dimension(*,*) fixed bin(35) (or float bin(27).) In the dimension attribute put as many stars as there are dimensions. Proper matching of types and dimensions will be checked at run time. NOTES: Arrays with more than 15 dimensions may tend to lose. If you are calling a Fortran program, you need to be aware that for multi dimensional arrays, Fortran interchanges the order of the subscripts. Arrays as return or update arguments (defined below) are not supported. However, the lisp array is passed by reference, so if the PL/I subroutine stores into elements of the array the appropriate thing will happen. Because lisp passes arguments by value, while PL/I passes arguments by reference, it is necessary to pay attention to whether an argument is input to the PL/I subroutine, output from (returned by) the PL/I subroutine, or both (updated by the PL/I subroutine.) `Output from' includes both arguments that are stored into and values returned by a return statement. If the PL/I subroutine has a `returns' attribute, this is considered to be an extra argument stuck on the end of the argument list. Note that PL/I `returns(char(*))' is a special case, and is supported. Return of bit (*) is not supported. Input arguments to the PL/I subroutine are derived from arguments to the lisp subr according to the data type transformations described above. Return arguments from the PL/I subroutine are passed back to lisp according to the user's declaration; they may be ignored, setq'ed onto an atomic symbol, or passed back as the value of the lisp subr. If more than one is passed back in the latter way, they are consed up into a list. If there are none, nil is returned. Update arguments are a combination of the two types described above. They are derived from the arguments to the lisp subr, and they are also passed back like return arguments. Now the detailed syntax of the `defpl1' feature will be described. It is invoked by using the defpl1 declaration in the lisp compiler, in a form generally as follows: (declare (defpl1 lisp-name external-name (arg-dcl-1) (arg-dcl-2) ... (arg-dcl-n) )) lisp-name is an atomic symbol, which will be defined as a subr when the output of the compilation is `load'ed. This subr will take as many arguments as the PL/I subroutine has input and update arguments. external-name is a string which is the name of the subroutine to be called, as it would be written in PL/I. If external name is "", the pname of lisp-name will be used so that you need not type the same thing twice. (arg-dcl-1) through (arg-dcl-n) are lists. Each one gives the attributes of one of the arguments to the PL/I subroutine. First you must give attributes describing whether it is an input, update, or return argument. These are: an input argument return a return argument, passed back as the value of the subr. return ignore a return argument which is ignored. return (setq var) a return argument to which the atomic symbol var is setq'ed. var should be declared special. update an update argument, passed back as the value of the subr. update ignore an update argument whose returned value is ignored. update (setq var) an update argument whose returned value is setq'ed onto var. Next you specify the data type attributes, in a form quite similar to the way you would in PL/I. (But don't forget that the declaration of each argument is enclosed in its own pair of parentheses, instead of being separated from the others with commas.) The following keywords are recognized for data type attributes: fixed float binary bin bit pointer ptr packed-ptr packed-pointer character char aligned unaligned lisp array varying Note that `packed-pointer' is used rather than `pointer unaligned,' and `array' is used rather than `dimension.' `lisp' means a raw lisp object. Precisions, array extents, and string lengths are specified as parenthesized numbers or asterisks, just as in PL/I. Note that unless you declare otherwise to the compiler or put a decimal point, these numbers will be interpreted as octal. Here is an example, although not of a very useful case: (declare (defpl1 hcs_$initiate "" (char(*)) (char(*)) (char(*)) (fixed bin(1)) (fixed bin(2)) (return pointer) (return (setq code) fixed bin(35)))) If this was compiled and loaded into lisp, you could type (hcs_$initiate ">system_control_1" "whotab" "" 0 0) and lisp would reply with a number such as 356000000, and code would have been setq'ed to 0 presumably. [END] ----------------------------------------------------------- Historical Background This edition of the Multics software materials and documentation is provided and donated to Massachusetts Institute of Technology by Group BULL including BULL HN Information Systems Inc. as a contribution to computer science knowledge. This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology, Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell BULL Inc., Groupe BULL and BULL HN Information Systems Inc. to the development of this operating system. Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970), renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership of Professor Fernando Jose Corbato. Users consider that Multics provided the best software architecture for managing computer hardware properly and for executing programs. Many subsequent operating systems incorporated Multics principles. Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. . ----------------------------------------------------------- Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without fee is hereby granted,provided that the below copyright notice and historical background appear in all copies and that both the copyright notice and historical background and this permission notice appear in supporting documentation, and that the names of MIT, HIS, BULL or BULL HN not be used in advertising or publicity pertaining to distribution of the programs without specific prior written permission. Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc. Copyright 2006 by BULL HN Information Systems Inc. Copyright 2006 by Bull SAS All Rights Reserved