perm filename UTIL.2[AID,LSP] blob
sn#582352 filedate 1981-04-22 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00010 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 The following is a file of useful Maclisp macro definitions.
C00012 00003 While loop
C00014 00004 These functions do some file defaulting and are
C00018 00005 (FOR X {IN,ε} L {DO,APPEND,COLLECT,CONC,SELECT,SCAN} form {RETURN} form)
C00024 00006 (princ x)
C00026 00007 Loops n times
C00028 00008 Not similar to Interlisp SELECTQ (uses eq instead of equal)
C00033 00009 If-then-else
C00034 00010 TAIL-RECURSIVE-DEFUN
C00039 ENDMK
C⊗;
;;; The following is a file of useful Maclisp macro definitions.
(setq %%%ofasload%%% fasload)
(setq fasload ())
(declare (cond ((eq (cadr (status uname)) 'rpg)
(setq no-disk-hacks t))))
(declare (mapex t))
(declare (special ↑R ↑W ↑T ↑Q)
(*expr macrobind))
;;; Selects the disk for input
(declare (special x))
(macrodef select-disk-input x
((lambda(↑Q) . x) t))
(macrodef unselect-disk-input x
((lambda(↑Q) . x) nil))
;;; Selects the disk for output
;(macrodef select-disk-output x
; (lambda(↑R ↑W . x) t t))
(macrodef select-disk-output x
((lambda(↑R) . x) t))
(macrodef unselect-disk-output x
((lambda(↑R) . x) nil))
;;; Unselects the tty for output
(macrodef unselect-tty x
((lambda(↑W) . x) t))
;;; Selects the tty for output
(macrodef select-tty x
((lambda(↑W) . x) nil))
;;; Reads from disk until an end of file is encountered. ?step
;;; is bound to the input object, and form is performed after each read.
(match-macro (read-until-eof) (with ?step do *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(code ((lambda (eof)
(do ((?step (read eof)(read eof)))
((eq ?step eof) *form2)
*form1)) (list nil))))
*form nil))
;;; TYI's from disk until an end of file is encountered. ?step
;;; is bound to the input object, and form is performed after each read.
(match-macro (tyi-until-eof) (with ?step do *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(code
(progn (eoffn infile
(function
(lambda
(()
b)(close infile) b)))
(do ((?step (tyi infile -1)(tyi infile -1)))
((= ?step -1) *form2)
*form1))))
*form nil))
;;; While loop
(declare (special ?cond *form *form1 *form2))
(match-macro (while) (?cond do *form)
((lambda(*form1 *form2)
(%match '(*form1 return *form2) *form)
(cond ((or (%match '(not ?x) ?cond)
(%match '(null ?x) ?cond))
(code (do () (?x *form2) *form1)))
(t
(code (do () ((not ?cond) *form2) *form1)))))
*form nil))
;;; Until loop
(match-macro (until) (?cond do *form)
((lambda(*form1 *form2)
(%match '(*form1 return *form2) *form)
(cond ((null *form2) (setq *form2 '(nil))))
(code (prog nil
loop *form1
(cond (?cond (return *form2))
(t (go loop))))))
*form nil))
;;; These functions do some file defaulting and are
;;; similar to DSKIN & DSKOUT in Ilisp. (DSKIN <file>) (DSKOUT <form><file>)
(macrodef %push% (x) (setq pdl (cons x pdl)))
(macrodef %pop% () (setq file (cdr file)))
(macrodef %check% () (cond ((null file)(throw (nreverse pdl) out))))
(macrodef %default% (filespecs)
(let file ← filespecs do
(cond (file
(catch (prog (pdl)
(%push% (car file))
(%pop%)
(%push% (cond ((or (null file)
(memq (car file) '(dsk sys))
(not (atom (car file)))) (cond ((status features newio)
'|←←←|)
(t '| |)))
(t (prog2 nil (car file) (%pop%)))))
(%check%)
(%push% (cond ((atom (car file)) (prog2 nil (car file)(%pop%)))
(t 'dsk)))
(%check%)
(%push% (cond ((= (length (car file)) 2)(car file))
(t (list (caar file)(cadr (status udir))))))
(throw (nreverse pdl) out))
out)))))
(declare (read))
(cond ((and (boundp 'no-disk-hacks) no-disk-hacks)
(read)(read)(read)(read)))
(declare (cond ((and (boundp 'no-disk-hacks)
no-disk-hacks)(read)(read)(read))))
(defun dskin fexpr (file)
((lambda (ocrunit file)
(apply 'eread file)
(select-disk-input
(read-until-eof with form do (print (eval form))))
(terpri)
(apply 'crunit (list 'dsk ocrunit)))
(status udir) (%default% file))
(uclose)
'Done)
(defun slurpin fexpr (file)
(unselect-tty
(let file ← (%default% file) do
((lambda (ocrunit fns atom)
(apply 'eread file)
(select-disk-input
(read-until-eof with form do (cond ((memq (car form)
'(defun macrodef macro))
(setq fns (cons (eval form) fns)))
(t (eval form)))))
(terpri)
(apply 'crunit (list 'dsk ocrunit))
(set atom fns)
(uclose)
atom)
(status udir) nil
(intern (implode (append (explode (car file))'(!) (explode (cadr file))
'(- f n s)))) ))))
(defun dskout fexpr (form)
((lambda(file ocrunit)
(apply 'uwrite (cddr file))
(select-disk-output (eval (car form)))
(terpri)
(prog2 nil
(apply 'ufile file)
(apply 'crunit (list 'dsk ocrunit))))
(%default% (cdr form)) (status udir)))
;;; (FOR X {IN,ε} L {DO,APPEND,COLLECT,CONC,SELECT,SCAN} form {RETURN} form)
;;; (FOR X FROM LOWER TO UPPER {by STEPPER} DO form {return} form)
(declare (special *x ?prep ?step ?lower ?upper ?stepper *l ?verb *x *form1 *form2))
(defun for-in-from-memq
(q)
(memq q '(ε in from)))
(defun for-do-collect-append-etc-memq (q)
(memq q '(do collect append conc select to scan)))
(match-macro (multi-for)
(*x
($r ?prep
for-in-from-memq)
*l
($r ?verb
for-do-collect-append-etc-memq)
*form)
(cons (cond ((memq ?verb '(do scan)) 'progn)
(t 'append))
(mapcan (function (lambda (x l)
(mapcar
(function
(lambda (i)
`(for ,x ε ,i ,?verb . ,*form)))
l)))
*x *l))))))))))))
(match-macro (for) (*x
($r ?prep
for-in-from-memq)
*l
($r ?verb
for-do-collect-append-etc-memq)
*form)
((lambda (*form1 *form2 ?step ?lower ?upper ?stepper)
(%match '(*form1 return *form2) *form)
(caseq ?verb
(append
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
((lambda (q) (cond (q (ncons q))))
(progn *form1)))) *l) *form2)))
(t (code (mapcan (function (lambda(*x)((lambda(q)(cond (q (ncons q))))
(progn *form1)))) *l)))))
(conc
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
(progn *form1))) *l) *form2)))
(t (code (mapcan (function (lambda (*x)
(progn *form1))) *l)))))
(select
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
(and (progn *form1) (list *x)))) *l)
*form2)))
(t (code (mapcan (function (lambda (*x)
(and (progn *form1) (list *x)))) *l)))))
(scan
((lambda (?steppers aux *setqs ?ender)
(setq ?ender
((lambda (q)
(cond ((= (length q) 1)
(car q))
(t (cons 'or q))))
(mapcar
(function
(lambda (x)
(list 'null (car x))))
?steppers)))
(setq *setqs
(mapcan
(function
(lambda (x y)
(cond (x
`((setq
,x (car ,(car y))))))))
*x ?steppers))
(setq ?steppers (nconc ?steppers aux))
(code (do ?steppers
(?ender *form2)
*setqs
*form1)))
(mapcar
(function
(lambda (x)
((lambda (q)
(list q
x (list 'cdr q)))
(gensym))))
*l)
(mapcar
'ncons
*x)
() ()))
(t (cond
((and (eq ?prep 'from)
(eq ?verb 'to))
(cond (*form2
(or (%match '(?upper by ?stepper do *form1 return *) *form)
(%match '(?upper do *form1 return *) *form) ))
(t (or (%match '(?upper by ?stepper do *form1) *form)
(%match '(?upper do *form1) *form) )) )
(cond (?stepper
(code (do ((?step ?lower (+ ?step ?stepper)))
((< ?upper ?step) *form2) *form1)))
(t (code (do ((?step ?lower (1+ ?step)))
((< ?upper ?step) *form2)
*form1)))))
(t ((lambda (?verb)
(cond (*form2
(code (progn (?verb (function (lambda (*x) *form1)) *l) *form2)))
(t
(code (?verb (function (lambda (*x) *form1)) *l) ))))
(cond ((eq ?verb 'do) 'mapc)
(t 'mapcar))))))))
*form nil (car *X) (car *l) nil nil))
;;; (princ x)
(declare (special ?set mess))
(macrodef tell (mess)(princ mess))
;;; (princ mess)(terpri)
(macrodef speak (mess)
(progn (princ mess)(terpri)))
;;; Reads from selected device until input is in a specified set.
(match-macro (read-until) (?step ($r ? (lambda(q) (memq q '(isin ε)))) ?set do *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(code (do ((?step (read)(read)))
((member ?step ?set) *form2)
*form1)))
*form nil))
;;; Tyis from selected device until input is in a specified set.
(match-macro (inch-until) (?step ($r ? (lambda(q) (memq q '(isin ε)))) ?set do *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(code (do ((?step (tyi)(tyi)))
((member ?step ?set) *form2)
*form1)))
*form nil))
;;; Loops n times
(declare (special ?n))
(match-macro (repeat) (?n do *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(cond ((atom ?n)
(code (or (< ?n 0)
(do ((%%%step%%% 0 (1+ %%%step%%%)))
((= %%%step%%% ?n) *form2)
*form1))))
(t (code ((lambda (%%%stop%%%)
(or (< %%%stop%%% 0)
(do ((%%%step%%% 0 (1+ %%%step%%%)))
((= %%%step%%% %%%stop%%%) *form2)
*form1))) ?n)))))
*form nil))
;;; does n terpri's
(match-macro (newline) ?n
((lambda (?n)
(cond (?n (code (repeat ?n do (terpri))))
(t (code (terpri)))))
(and (not (atom ?n)) (car ?n))))
;;; does n space's
(match-macro (space) ?n
((lambda (?n)
(cond (?n (code (repeat ?n do (tyo 32.))))
(t (code (tyo 32.)))))
(and (not (atom ?n)) (car ?n))))
;;; Prog1
;(macrodef prog1 x (prog2 nil . x))
;;; Push & pop
(declare (special x y))
(macrodef push (x y) (setq y (cons x y)))
(macrodef pop (y) (prog1 (car y) (setq y (cdr y))))
(macrodef top (y) (car y))
(macrodef ask (mess)
(princ mess)
(read))
;;; Not similar to Interlisp SELECTQ (uses eq instead of equal)
(declare (special ?item *list ?else))
;(match-macro (selectq) (?item *list ?else)
; (let item ← (cond ((atom ?item) ?item) (t '%%temp%%)) do
; (let *clauses ← (for i ε *list collect
; (cond ((atom (car i)) (cons (list 'eq item
; (list 'quote (car i)))
; (cdr i)))
; (t (cons (list 'memq item (list 'quote (car i)))
; (cdr i))))) do
; (cond ((atom ?item)
; (code (cond *clauses (t ?else))))
; (t (code
; ((lambda (%%temp%%)
; (cond *clauses (t ?else)))
; ?item)))))))
;(declare (eval (read)))
;(cond ((status features newio)
; (cond ((status features complr)
; (read))
; (t (read (or uread eread-file tyi))))))
;(match-macro (caseq) (?item *list ?else)
; (let item ← (cond ((atom ?item) ?item) (t '%%temp%%)) do
; (let *clauses ← (for i ε *list collect
; (cond ((atom (car i)) (cons (list 'eq item
; (list 'quote (car i)))
; (cdr i)))
; (t (cons (list 'memq item (list 'quote (car i)))
; (cdr i))))) do
; (cond ((atom ?item)
; (code (cond *clauses ?else)))
; (t (code
; ((lambda (%%temp%%)
; (cond *clauses ?else))
; ?item)))))))
;;; Similar to Interlisp SELECTQ (uses equal)
(match-macro (select) (?item *list ?else)
(let item ← (cond ((atom ?item) ?item) (t '%%temp%%)) do
(let *clauses ← (for i ε *list collect
(cons (list 'equal item
(list 'quote (car i)))
(cdr i)))
do
(cond ((atom ?item)
(code (cond *clauses (t ?else))))
(t (code
((lambda (%%temp%%)
(cond *clauses (t ?else)))
?item)))))) )
;;; Similar to Interlisp SELECTQ (uses = instead of eq)
(match-macro (select=) (?item *list ?else)
(let item ← (cond ((atom ?item) ?item) (t '%%temp%%)) do
(let *clauses ← (for i ε *list collect
(cond ((numberp (car i)) (cons (list '= item
(car i))
(cdr i)))
(t (cons (list 'member item (list 'quote (car i)))
(cdr i))))) do
(cond ((atom ?item)
(code (cond *clauses (t ?else))))
(t (code
((lambda (%%temp%%)
(cond *clauses (t ?else)))
?item)))))) )
;;; Similar to Interlisp SELECTQ (uses %match instead of eq)
(match-macro (select-match) (?item *list ?else)
(let item ← (cond ((atom ?item) ?item)
(t '%%temp%%))
do
(let *clauses ← (for i ε *list collect
(cons
(list '%match
(list 'quote (car i)) item)
(cdr i)))
do
(cond ((atom ?item)
(code (cond *clauses (t ?else))))
(t (code
((lambda (%%temp%%)
(cond *clauses (t ?else)))
?item)))))) )
;;; Forever loop. Get out via throw.
(macrodef do-forever x (do nil (nil) . x))
;;; If-then-else
(declare (special *form3))
;(match-macro (if) (*form1 then *form2 )
; (cond ((%match '(*form2 else *form3) *form2)
; (code (cond (*form1 *form2)
; (t *form3))))
; (t (code (cond (*form1 *form2))))))
;;; TAIL-RECURSIVE-DEFUN
;;; a macro to provide tail recursive function definitions
;;; EXPRS and FEXPRS only
(EVAL-WHEN (COMPILE EVAL LOAD)
(DEFUN (CCODE MACRO)(X)
(DO-CODE (CADR X)))
(DEFUN DO-CODE(X)
(COND ((NULL X)NIL)
((ATOM X)
((LAMBDA(CHAR1)
(COND ((MEMQ CHAR1 '(? *))X)
(T (LIST 'QUOTE X))))
(GETCHAR X 1)))
((AND (ATOM (CAR X))(EQ '* (GETCHAR (CAR X) 1)))
(LIST 'APPEND (DO-CODE (CAR X)) (DO-CODE (CDR X))))
(T(LIST 'CONS (DO-CODE (CAR X)) (DO-CODE (CDR X))))))
)
(DEFUN (TAIL-RECURSIVE-DEFUN MACRO)(X)
((LAMBDA(?F-NAME *TYPE)
((LAMBDA(*ARGS *DEFINITION)
((LAMBDA(?GO-LABEL)
(α-GRAB-TAILS *ARGS *DEFINITION ?GO-LABEL)
(CCODE (DEFUN ?F-NAME *TYPE (*ARGS) (PROG NIL
?GO-LABEL
(RETURN (PROGN *DEFINITION))))))
(GENSYM)))
(COND (*TYPE (CADDDR X))(T (CADDR X)))
(COND (*TYPE (CDDDDR X))(T (CDDDR X)))))
(CADR X)
(COND ((MEMQ (CADDR X) '(EXPR FEXPR))
(LIST (CADDR X)))
(T NIL))))
(DEFUN α-GRAB-TAILS (ARGS DEF ?GO-LABEL)
(COND ((ATOM DEF)NIL)
((AND (ATOM(CAR DEF)) (EQ 'TAIL-RECUR (CAR DEF)))
(COND ((EQUAL ARGS (CDR DEF)) ;calling with same args!
(RPLACA DEF 'GO)
(RPLACD DEF (LIST ?GO-LABEL)))
(T(DO ((ARGS ARGS (CDR ARGS))
(NEWARGS (CDR DEF) (CDR NEWARGS))
(SETS NIL (NCONC SETS
(COND ((EQ (CAR ARGS) (CAR NEWARGS))
NIL)
(T (NCONS
((LAMBDA(SYM)
(CONS (CONS (CAR ARGS)SYM)
(LIST 'SETQ
(CAR ARGS)
(SUBLIS (MAPCAR 'CAR
SETS)
(CAR NEWARGS)))))
(GENSYM))))))))
((NULL ARGS)
((LAMBDA(L-EXP)
(RPLACA DEF (CAR L-EXP))
(RPLACD DEF (CDR L-EXP)))
(α-OPTIMIZE-λ (MAPCAR 'CDAR SETS)
(NCONC (MAPCAR 'CDR SETS)
(NCONS(LIST 'GO ?GO-LABEL)))
(MAPCAR 'CAAR SETS))))))))
(T(MAPC (FUNCTION(LAMBDA(DEF)
(α-GRAB-TAILS ARGS DEF ?GO-LABEL)))
DEF))))
(DEFUN α-OPTIMIZE-λ (VARS BODY BINDINGS)
(DO ((VARS VARS (CDR VARS))
(BINDINGS BINDINGS (CDR BINDINGS))
(NVARS NIL (NCONC NVARS
(COND ((ANY-MEMQ (CAR VARS) BODY)(NCONS (CAR VARS)))
(T NIL))))
(NBINS NIL (NCONC NBINS
(COND ((ANY-MEMQ (CAR VARS) BODY)(NCONS (CAR BINDINGS)))
(T NIL)))))
((NULL VARS)(CONS (CONS 'LAMBDA (CONS NVARS BODY))
NBINS))))
(DEFUN ANY-MEMQ(X Y)
(COND ((NULL Y)NIL)
((ATOM Y)(EQ X Y))
(T(OR (ANY-MEMQ X (CAR Y))
(ANY-MEMQ X (CDR Y))))))
)
(declare (read))
(setq util-loaded t)
(setq fasload %%%ofasload%%%)