ZMACRO contains two macro packages --
(1) YMACS -- basically useful macros and fexprs.
(2) YSAIMACS -- macros used to simulate many SAIL constructs.
YMACS -- USEFUL MACROS AND FEXPRS (see also YSAIMAC)
* ( X:any ): NIL MACRO
** ( X:list ) MACRO
NEQ ( X:any Y:any ):boolean MACRO
NEQN ( X:any Y:any ):boolean MACRO
NEQUAL ( X:any Y:any ):boolean MACRO
MAKE ( variable template ) MACRO
SETQQ ( variable value ) MACRO
EXTEND ( function series ) MACRO
DREVERSE( list ):list MACRO
APPENDL ( lists ) MACRO
NCONCL ( lists ) MACRO
NCONC1 ( lst exp1 ... expn ): any MACRO
SELECTQ ( exp cases last-resort ) MACRO
WHILE ( test body ) MACRO
REPEAT ( body test ) MACRO
FOREACH ( var in/of lst do/collect exp ) MACRO
SAY ( test expressions ) MACRO
DIVERT ( channel expressions ) MACRO
CAT ( list of any ):string MACRO
CAT-ID ( list of any ):<uninterned id> MACRO
TTY ( L:list ):NIL MACRO
TTY-TX ( L:list ):NIL MACRO
TTY-XT ( L:list ):NIL MACRO
TTY-TT ( L:list ):NIL MACRO
ERRSET ( expression label ) MACRO
GRAB ( file ) MACRO
GRABFNS ( ids file-dscr ) MACRO
DUMP ( file-dscr ) MACRO
DUMPFNS ( ids file-dscr ) MACRO
used to expand macros:
XP#SELECTQ (#L#) EXPR
XP#WHILE (#BOOL #BODY) EXPR
XP#FOREACH (#VAR #MOD #LST #ACTION #BODY) EXPR
XP#SAY1 ( expression ) EXPR
*( X:any ): NIL MACRO
===> NIL
For comments--doesn't evaluate anything. Returns NIL.
Note: expressions starting with * which are read by the
lisp scanner must obey all the normal syntax rules.
**( X:list ) MACRO
===> (PROGN <lists>)
For comments--all atoms are ignored, lists evaluated as in PROGN.
NEQ( X:any Y:any ):boolean MACRO
===> (NOT (EQ X Y))
Changed to CDM because NEQ in PSL means NOT EQUAL. We hope to change
that situation, however.
NEQN( X:any Y:any ):boolean MACRO
===> (NOT (EQN X Y))
NEQUAL( X:any Y:any ):boolean MACRO
===> (NOT (EQUAL X Y))
MAKE( variable template ) MACRO
===> (SETQ <var> <some form using var>)
To change the value of a variable depending upon template.
Uses similar format for template as editor MBD. There are 3 cases.
1) template is numerical:
(MAKE VARIABLE 3)
= (SETQ VARIABLE (PLUS VARIABLE 3))
2) Template is a series, whose first element is an atom:
(MAKE VARIABLE ASSOC ITEM)
= (SETQ VARIABLE (ASSOC ITEM VARIABLE))
3) Otherwise, variable is substituted for occurrences of * in template.
(MAKE VARIABLE (ASSOC (CADR *) (CDDR *))
= (SETQ VARIABLE (ASSOC (CADR VARIABLE) (CDDR VARIABLE))
SETQQ( variable value ) MACRO
===> (SETQ VARIABLE 'VALUE)
EXTEND( function series ) MACRO
===> (FN ELT1 (FN ELT2 ... (FN ELTn-1 ELTn)))
Applies 2-place function to series, similarly to PLUS.
E.g.: (EXTEND SETQ A B C D 5) = (SETQ A (SETQ B (SETQ C (SETQ D 5))))
DREVERSE( L: list ):list MACRO
===> (REVERSIP L)
Synonym for REVERSIP.
APPENDL( lists ) MACRO
===> (APPEND LIST1 (APPEND LIST2 ....))
EXPAND's APPEND to a list of arguments instead of just 2.
NCONCL( lists ) MACRO
===> (NCONC LST1 (NCONC LST2 ....))
EXPAND's NCONC to a list of arguments instead of just 2.
NCONC1( lst exp1 ... expn ): any MACRO
===> (NCONC LST (LIST EXP1 ... EXPn))
Destructively add exp1 ... exp-n to the end of lst.
SELECTQ( exp cases last-resort ) MACRO
===> (COND ...)
Exp is a lisp expression to be evaluated.
Each case-i is of the form (key-i exp1 exp2...expm).
Last-resort is a lisp expression to be evaluated.
Generates a COND statement:
If key-i is an atom, case-i becomes the cond-pair:
((EQUAL exp key-i) (PROGN exp1 exp2 ... expm))
If key-i is a list, case-i becomes the cond-pair:
((MEMBER exp key-i) (PROGN exp1 exp2 ... expm))
Last-resort becomes the final cond-pair:
(T last-resort)
If exp is non-atomic, it should not be re-evaluated in each clause,
so a dummy variable (#SELECTQ) is set to the value of exp in the
first test and that dummy variable is used in all successive tests.
Note:
(1) A FEXPR version of SELECTQ would forbid use of RETURN and GO.
(2) The form created must NOT have a prog or lambda wrapped around
the cond expression, as this would also forbid RETURN and GO.
Since #SELECTQ can't be lambda-bound by any means whatsoever
and remain consistent with the standard-lisp report (if GO or
RETURN appears inside a consequent), there is no way we can make
SELECTQ re-entrant. If you go into a break with ^B or ^H and
execute another SELECTQ you will clobber the one and only
incarnation of #SELECTQ, and if it happened to be in the middle
of deciding which consequent to execute, then when you continue
the computation it won't work correctly.
Update -- IMSSS break pkg now tries to protect #SELECTQ.
Update -- uses XP#SELECTQ which can be compiled to speed up
macro expansion.
WHILE( test body ) MACRO
===> (PROG ...) <while loop>
While test is true do body.
REPEAT( body test ) MACRO
===> (PROG ...) <repeat loop>
Repeat body until test is true.
Jim found that this fn as we had it was causing compiler errors.
The BODY was (CDDR U) and the BOOL was (CADR U). Question:
Does the fact that Utah was unable to reproduce our compiler
errors lie in this fact. Does function until test becomes non-NIL.
FOREACH( var in/of lst do/collect exp ) MACRO
===> (MAPxx LST (FUNCTION (LAMBDA (VAR) EXP)))
Undocumented FOREACH supplied by Utah. Required by compiler.
Update: modified to call xp#foreach which can be compiled
to speed up macro expansion.
SAY( test expressions ) MACRO
===> (COND (<test> (PROGN (PRIN2 ...) (PRIN2 ...) ...)))
If test is true then evaluate and prin2 all expressions.
Exceptions: the value of printing functions, those flaged with
SAY:PRINT (including: PRINT PRIN1 PRIN2 PRINC TYO PPRINT TERPRI
POSN DOHOME DORIGH DOLEFT DOUP DODOWN DPYNCH DPYCHR SETCUR MOVECUR)
are just evaluated. E.g.: (In the example @ is used for quotes)
(SAY T @this @ (PRIN1 '!!AND!!) @ that@)
appears as:
this !!AND!! that
DIVERT( channel expressions ) MACRO
===> (PROG (ochan) <select given chan> <eval exps> <select ochan>)
Yields PROG that selects channel for output,
evaluates each expression, and then reselects prior channel.
CAT( list of any ):string MACRO
===> (CAT-DE (LIST <list>))
Evaluates all arguments given and forms a string from the
concatenation of their prin2 names.
CAT-ID( list of any ):<uninterned id> MACRO
===> (CAT-ID-DE (LIST <list>))
Evaluates all arguments given and forms an id from the
concatenation of their prin2 names.
TTY ( L:list ):NIL MACRO
TTY-TX( L:list ):NIL MACRO
TTY-XT( L:list ):NIL MACRO
TTY-TT( L:list ):NIL MACRO
===> (TTY-xx-DE (LIST <list>))
TTY is selected for output, then each elt of list is evaluated and
PRIN2'ed, except for $EOL$'s, which cause a TERPRI.
Then prior output channel is reselected.
TTY-TX adds leading TERPRI. TTY-XT adds trailing TERPRI.
TTY-TT adds leading and trailing TERPRI's.
CDMs were making all of the following unloadable into existing
QDRIVER.SAV core image. I flushed the 'C' July 27
TTY-DE now takes two extra arguments, for the number of TERPRIs
to preceed and follow the other printed material.
ERRSET (expression label) MACRO
===> (ERRSET-DE 'exp 'label)
Named errset. If error matches label, then acts like errorset.
Otherwise propagates error upward.
Matching: Every label stops errors NIL, $EOF$.
Label 'ERRORX stops any error.
Other labels stop errors whose first arg is EQ to them.
GRAB( <file description> ) MACRO
===> (GRABBER NIL '<file-dscr>)
Reads in entire file, whose system name is created using
conventions described in FORM-FILE.
GRABFNS( <ids> . <file description> ) MACRO
===> (GRABBER FNS <file-dscr>)
Like grab, but only reads in specified fns/vars.
DUMP( <file description> ) MACRO
===> (DUMPER '<file-dscr>)
Dumps file onto disk. Filename as in GRAB. Prettyprints.
DUMPFNS( <ids> . <file dscr> ) MACRO
===> (DUMPFNS-DE <fns> '<file-dscr>)
Like DUMP, but copies old file, inserting new defs for
specified fns/vars
We are currently defining these to be macros everywhere, but might
want them to be exprs while interpreted, in which case use the
following to get compile-time macros.
PUT (QUOTE NEQ) (QUOTE CMACRO) (QUOTE (LAMBDA (!#X !#Y) (NOT (EQ !#X !#Y))))
)
PUT (QUOTE NEQN) (QUOTE CMACRO) (QUOTE (LAMBDA (!#X !#Y) (NOT (EQN !#X
!#Y)))))
PUT (QUOTE NEQUAL) (QUOTE CMACRO) (QUOTE (LAMBDA (!#X !#Y) (NOT (EQUAL
!#X !#Y)))))
YSAIMAC -- MACROS used to simulate SAIL constructs.
macros:
DO-UNTIL SAI-IF SAI2-IF SAI-DONE SAI-CONTINUE SAI-WHILE SAI-FOREACH
SAI-FOR SAI-BEGIN PBEGIN PRETURN SAI-ASSIGN MSETQ SAI-COLLECT IFC
OUTSTR SAI-SAY SAI-& SAI-LENGTH CVSEST CVSEN CVS SUBSTRING-FOR
SUBSTRING-TO PUSHES PUSHVARS SLIST SAI-MAPC SAI-EQU
auxiliary exprs used to expand macros:
XP#SAY-IF XP#SAI-WHILE XP#SAI-FOREACH XP#SAI-FOR XP#SUBSTRING-TO
SAI-IF ( sailish if-expression ) MACRO
(IF test1 THEN exp1 [ ELSEIF testi THEN expi ] [ELSE expn])
===> (COND (test1 exp1) ... (testi expi) ... (T expn))
Embedded expressions do not cause embedded COND's, (unlike ALGOL!).
Examples:
(IF (ATOM Y) THEN (CAR X))
(IF (ATOM Y) THEN (CAR X) ELSE (CADR X))
(IF (ATOM Y) THEN (CAR X) ELSEIF (ATOM Z) THEN (CADR X))
SAI-WHILE ( sailish while-expression ) MACRO
(WHILE b DO e1 e2 ... en) does e1,..., en as long as b is non-nil.
===> (PROG NIL CONTINUE:
(COND ((NULL b) (RETURN NIL)))
e1 ... en
(GO CONTINUE:))
N.B. (WHILE b DO ... (RETURN e)) has the RETURN relative to the PROG
in the expansion. As in SAIL, (CONTINUE) and DONE work as statements.
(They are also macros.)
REM is planning on cleaning this up so it works in all cases...
The form that (SUBSTRING-TO stringexpr low high) should expand into is
((LAMBDA (#STRING) (SUBSTR #STRING low high)) stringexpr)
except that low and high have been modified to replace INF by
explicit calls to (FLATSIZE2 #STRING). Thus things like
(SUBSTRING-TO (READ) 2 (SUB1 INF))
should work without requiring the user to type the same string twice.
Probably that inner (SUBSTR ...) should simply be
((LAMBDA (INF) (SUBSTR #STRING low high)) (FLATSIZE2 #STRING))
where we don't have to internally modify low or high at all!