1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module mforma macro
)
15 ;;; A mini version of FORMAT for macsyma error messages, and other
17 ;;; George J. Carrette - 10:59am Tuesday, 21 October 1980
19 ;;; This file is used at compile-time for macsyma system code in general,
20 ;;; and also for MFORMT and MERROR.
21 ;;; Open-coding of MFORMAT is supported, as are run-time MFORMAT string
22 ;;; interpretation. In all cases syntax checking of the MFORMAT string
23 ;;; at compile-time is done.
25 ;;; For the prettiest output the normal mode here will be to
26 ;;; cons up items to pass as MTEXT forms.
28 ;;; Macro definitions for defining a format string interpreter.
29 ;;; N.B. All of these macros expand into forms which contain free
30 ;;; variables, i.e. they assume that they will be expanded in the
31 ;;; proper context of an MFORMAT-LOOP definition. It's a bit
32 ;;; ad-hoc, and not as clean as it should be.
33 ;;; (Macrofy DEFINE-AN-MFORMAT-INTERPRETER, and give the free variables
34 ;;; which are otherwise invisible, better names to boot.)
36 ;;; There are 3 definitions of MFORMAT.
37 ;;; [1] The interpreter.
38 ;;; [2] The compile-time syntax checker.
39 ;;; [3] The open-compiler.
41 ;; Some commentary as to what the hell is going on here would be greatly
42 ;; appreciated. This is probably very elegant code, but I can't figure
44 ;; This is macros defining macros defining function bodies man.
45 ;; top-level side-effects during macroexpansion consing up shit
46 ;; for an interpreter loop. I only do this to save address space (sort of
49 (defmacro +def-mformat-var
(type var val init-condition
)
51 (cdr (or (assoc init-condition
(get type
'mformat-state-vars
))
52 (car (push (ncons init-condition
)
53 (get type
'mformat-state-vars
))))))
56 (defmacro +def-mformat-op
(type char
&rest body
) ;; can also be a list of CHAR's
58 (setq char
(list char
)))
59 (push (cons char body
) (get type
'mformat-ops
))
60 `',(maknam (nconc (exploden (symbol-name '#:mformat-
)) (mapcar #'ascii char
))))
62 (defmacro pop-mformat-arg
()
63 `(cond ((= arg-index n
)
64 (maxima-error "POP-MFORMAT-ARG: ran out of mformat args ~a" (listify n
)))
69 (defmacro leftover-mformat-args?
() ;; To be called after we are done.
70 '(unless (= arg-index n
)
71 (maxima-error "LEFTOVER-MFORMAT-ARGS?: extra mformat args ~a" (listify n
))))
73 (defmacro bind-mformat-state-vars
(type &rest body
)
75 (v (get type
'mformat-state-vars
) (cdr v
)))
77 (do ((conds (cdr (car v
)) (cdr conds
)))
79 (push (car conds
) l
)))
82 (defmacro pop-mformat-string
()
84 (maxima-error "POP-MFORMAT-STRING: 'mformat' string already exhausted.")
87 (defmacro null-mformat-string
()
90 (defmacro top-mformat-string
()
92 (maxima-error "TOP-MFORMAT-STRING: 'mformat' string already exhausted.")
95 (defmacro cdr-mformat-string
()
96 `(setq sstring
(cdr sstring
)))
98 (defmacro mformat-dispatch-on-char
(type)
100 (cond ,@(mapcar #'(lambda (pair)
101 `(,(if (atom (car pair
))
102 `(char-equal char
,(car pair
))
104 #'(lambda (c) `(char-equal char
,c
))
107 (get type
'mformat-ops
))
108 ;; perhaps optimize the COND to use ">" "<".
110 (maxima-error "MFORMAT-DISPATCH-ON-CHAR: unknown format op. _~a_ ~a" ',type
(ascii char
))))
111 ,@(mapcar #'(lambda (state)
113 (setq ,@(apply #'append
(cdr state
)))))
114 (get type
'mformat-state-vars
))))
117 (defmacro white-space-p
(x)
118 `(member ,x
'(#\linefeed
#\return
#\space
#\tab
#\page
119 #-
(or clisp gcl openmcl abcl
) #\vt
124 (defmacro +mformat-loop
(type &rest end-code
)
125 `(bind-mformat-state-vars ,type
127 ((null-mformat-string)
128 (leftover-mformat-args?
)
130 (setq char
(pop sstring
))
131 (cond ((char= char
#\~
)
134 (setq char
(pop-mformat-string))
135 (cond ((char= char
#\
@)
140 (push char text-temp
)
142 ((white-space-p char
)
144 ((not (white-space-p (top-mformat-string))))
145 (cdr-mformat-string))
147 ((or (char< char
#\
0) (char> char
#\
9))
148 (mformat-dispatch-on-char ,type
)
151 (setq parameter
(+ (- (char-code char
) (char-code #\
0))
156 (push char text-temp
))))))
158 ;;; The following definitions of MFORMAT ops are for compile-time,
159 ;;; the runtime definitions are in MFORMT.
161 (defvar *want-open-compiled-mformat
* nil
)
162 (defvar *cant-open-compile-mformat
* nil
)
164 (setf (get '-c
'mformat-ops
) nil
)
165 (setf (get '-c
'mformat-state-vars
) nil
)
167 (defmacro def-mformat-op-c
(char &rest body
)
168 `(+def-mformat-op
,'-c
,char
,@body
))
170 (defmacro def-mformat-var-c
(var val init
)
171 `(+def-mformat-var
,'-c
,var
,val
,init
))
173 (defmacro mformat-loop-c
(&rest endcode
)
174 `(+mformat-loop
,'-c
,@endcode
))
176 (def-mformat-var-c |
:-FLAG| nil t
)
177 (def-mformat-var-c |
@-FLAG| nil t
)
178 (def-mformat-var-c parameter
0 t
)
179 (def-mformat-var-c parameter-p nil t
)
180 (def-mformat-var-c text-temp nil nil
)
181 (def-mformat-var-c code nil nil
)
186 (defmacro push-text-temp-c
()
189 (emitc `(princ ',(maknam (nreverse text-temp
)) ,stream
))
190 (setq text-temp nil
))))
192 (def-mformat-op-c (#\%
#\
&)
193 (cond (*want-open-compiled-mformat
*
196 (emitc `(fresh-line ,stream
))
197 (emitc `(terpri ,stream
))))))
199 (def-mformat-op-c #\M
200 (cond (*want-open-compiled-mformat
*
202 (emitc `(,(if |
:-FLAG|
'mgrind
'displaf
)
203 (,(if |
@-FLAG|
'getop
'progn
)
206 (t (pop-mformat-arg))))
208 (def-mformat-op-c (#\A
#\S
)
209 (cond (*want-open-compiled-mformat
*
211 (emitc `(,(if (char-equal char
#\A
) 'princ
'prin1
)
214 (t (pop-mformat-arg))))
216 (defun optimize-print-inst (l)
217 ;; Should remove extra calls to TERPRI around DISPLA.
218 ;; Mainly want to remove (PRINC FOO NIL) => (PRINC FOO)
219 ;; although I'm not sure this is correct. geezz.
221 ((null l
) `(progn ,@new
))
223 (cond ((eq (car a
) 'terpri
)
224 (if (eq (cadr a
) nil
)
227 ((and (eq (caddr a
) nil
)
228 (not (eq (car a
) 'mgrind
)))
229 (if (eq (car a
) 'displaf
)
230 (push `(displa ,(cadr a
)) new
)
231 (push `(,(car a
) ,(cadr a
)) new
)))
235 (defun-maclisp mformat-translate-open n
236 (let ((stream (arg 1))
237 (sstring (exploden (arg 2)))
238 (*want-open-compiled-mformat
* t
)
239 (*cant-open-compile-mformat
* nil
)
244 (when *cant-open-compile-mformat
*
245 (maxima-error "MFORMAT-TRANSLATE-OPEN: can't open compile 'mformat' on this case: ~a" (listify n
)))
246 (optimize-print-inst code
)))))
249 (defmacro mformat-open
(stream sstring
&rest other-shit
)
250 (if (not (stringp sstring
))
251 (maxima-error "MFORMAT-OPEN: ~a is not a string, can't open-compile the 'mformat' call." sstring
)
252 (apply #'mformat-translate-open stream sstring other-shit
)))
254 (defmacro mtell-open
(message &rest other-shit
)
255 `(mformat-open nil
,message
,@other-shit
))