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 1981 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module nparse
)
15 (load-macsyma-macros defcal mopers
)
17 (defvar *ascii-space-chars-for-maxima
* '(#\tab
#\space
#\linefeed
#\return
#\page
#\newline
))
19 (defvar *unicode-space-char-codes-for-maxima
*
20 ;; Adapted from the list given by: https://jkorpela.fi/chars/spaces.html
21 ;; omitting SPACE, OGHAM SPACE MARK, MONGOLIAN VOWEL SEPARATOR, IDEOGRAPHIC SPACE,
22 ;; and ZERO WIDTH NO-BREAK SPACE.
24 #x00A0
;; NO-BREAK SPACE
29 #x2004
;; THREE-PER-EM SPACE
30 #x2005
;; FOUR-PER-EM SPACE
31 #x2006
;; SIX-PER-EM SPACE
32 #x2007
;; FIGURE SPACE
33 #x2008
;; PUNCTUATION SPACE
36 #x200B
;; ZERO WIDTH SPACE
37 #x202F
;; NARROW NO-BREAK SPACE
38 #x205F
;; MEDIUM MATHEMATICAL SPACE
41 (defvar *unicode-space-chars-for-maxima
*
42 #-lisp-unicode-capable nil
43 #+lisp-unicode-capable
(mapcar 'code-char
*unicode-space-char-codes-for-maxima
*))
45 (defmvar *whitespace-chars
* (append *ascii-space-chars-for-maxima
* *unicode-space-chars-for-maxima
*))
49 (or (alpha-char-p n
) #+gcl
(>= (char-code n
) 128)
50 (member n
*alphabet
*))))
52 (defun ascii-numberp (num)
53 (and (characterp num
) (char<= num
#\
9) (char>= num
#\
0)))
55 (defvar *parse-window
* nil
)
56 (defvar *parse-stream
* () "input stream for Maxima parser")
57 (defvar *parse-stream-eof
* -
1 "EOF value for Maxima parser")
58 (defvar *parse-tyi
* nil
)
60 (defvar *mread-prompt
* nil
"prompt used by `mread'")
61 (defvar *mread-eof-obj
* () "Bound by `mread' for use by `mread-raw'")
62 (defvar *current-line-info
* nil
)
64 (defvar *parse-string-input-stream
* ;; reference to the input stream
65 (let ((stream (make-string-input-stream ""))) ;; used by parse-string
66 (close stream
) ;; in share/stringroc/eval_string.lisp
67 stream
)) ;; (see also add-lineinfo below)
69 (defmvar $report_synerr_line t
"If T, report line number where syntax error occurs; otherwise, report FILE-POSITION of error.")
70 (defmvar $report_synerr_info t
"If T, report the syntax error details from all sources; otherwise, only report details from standard-input.")
72 (defun mread-synerr (format-string &rest l
)
73 (let ((fp (and (not (eq *parse-stream
* *standard-input
*))
74 (file-position *parse-stream
*)))
75 (file (and (not (eq *parse-stream
* *standard-input
*))
76 (cadr *current-line-info
*)))
77 (*standard-output
* *error-output
*))
78 (flet ((line-number ()
79 ;; Fix me: Neither batch nor load track the line number
80 ;; correctly. batch, via dbm-read, does not track the
81 ;; line number at all (a bug?).
83 ;; Find the line number by jumping to the start of file
84 ;; and reading line-by-line til we reach the current
86 (cond ((and fp
(file-position *parse-stream
* 0))
87 (do ((l (read-line *parse-stream
* nil nil
) (read-line *parse-stream
* nil nil
))
89 (p (file-position *parse-stream
*) (file-position *parse-stream
*))
91 ((or (null p
) (>= p fp
))
95 (let ((n (get '*parse-window
* 'length
))
97 (loop for i from
(1- n
) downto
(- n
20)
98 while
(setq ch
(nth i
*parse-window
*))
100 (cond ((or (eql ch
*parse-stream-eof
*)
101 (char= ch
#\newline
))
102 (return-from column some
))
107 (print-invert-case (stripdollar x
)))
109 (maybe-invert-string-case x
))
112 (case (and file $report_synerr_line
)
114 ;; print the file, line and column information
115 (let ((line+column
(line-number)))
116 (format t
"~&~a:~a:~a:" file
(car line
+column
) (cdr line
+column
))))
118 ;; if file=nil, then print a fresh line only; otherwise print
119 ;; file and character location
120 (format t
"~&~:[~;~:*~a:~a:~]" file fp
)))
121 (format t
(intl:gettext
"incorrect syntax: "))
122 (apply 'format t format-string
(mapcar #'printer l
))
123 (cond ((or $report_synerr_info
(eql *parse-stream
* *standard-input
*))
124 (let ((some (column)))
125 (format t
"~%~{~c~}~%~vt^" some
(max 0 (- (length some
) 2)))
126 (read-line *parse-stream
* nil nil
))))
129 (if *quit-on-error
* ($quit
1.
) (throw-macsyma-top)))))
131 (defun tyi-parse-int (stream eof
)
133 (progn (setq *parse-window
* (make-list 25))
134 (setf (get '*parse-window
* 'length
) (length *parse-window
*))
135 (nconc *parse-window
* *parse-window
*)))
136 (let ((tem (tyi stream eof
)))
137 (setf (car *parse-window
*) tem
*parse-window
*
138 (cdr *parse-window
*))
139 (if (eql tem
#\newline
)
143 (defun *mread-prompt
* (out-stream char
)
144 (declare (ignore char
))
145 (format out-stream
"~&~A" *mread-prompt
*))
147 (defun aliaslookup (op)
149 (or (get op
'alias
) op
)
154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
156 ;;;;; The Input Scanner ;;;;;
158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
161 (defun gobble-whitespace (&aux
(ch (parse-tyipeek)) (cd (if (eql -
1 ch
) 0 (char-code (the character ch
)))) l i r
)
162 (declare (dynamic-extent l
) (fixnum r
) ((integer 0 5) i
) ((integer 0 255) cd
))
164 (do ((j 5 (1- j
))) ((or (< j
3) (zerop (logand cd
(the fixnum
(ash 1 (the (integer 0 5) j
)))))) (setq i j
))
165 (declare ((integer 0 5) j
)))
166 (setq r
(logand cd
(the fixnum
(1- (the fixnum
(ash 1 (the (integer 0 5) i
)))))) l
(cons (parse-tyi) l
))
167 (do ((i i
(1+ i
))) ((= i
6))
169 (setq ch
(parse-tyi) l
(cons ch l
) cd
(if (eql -
1 ch
) 0 (char-code (the character ch
))) r
(logior (the fixnum
(ash r
6)) (logand cd
#.
(1- (ash 1 6))))))
170 (if (member r
*unicode-space-char-codes-for-maxima
*)
172 (dolist (l l
) (unparse-tyi l
))))
173 ((member ch
*whitespace-chars
*)
175 (gobble-whitespace))))
178 (defun gobble-whitespace ()
179 (do ((ch (parse-tyipeek) (parse-tyipeek)))
180 ((not (member ch
*whitespace-chars
*)))
183 (defun read-command-token (obj)
185 (read-command-token-aux obj
))
187 (defun safe-assoc (item lis
)
188 "maclisp would not complain about (car 3), it gives nil"
191 (equal (car v
) item
))
195 ;; list contains an atom, only check
196 ;; (parser-assoc 1 '(2 1 3)) ==>(1 3)
197 ;; (parser-assoc 1 '(2 (1 4) 3)) ==>(1 4)
199 (defun parser-assoc (c lis
)
202 (cond ((consp (car v
))
208 ;; we need to be able to unparse-tyi an arbitrary number of
209 ;; characters, since if you do
210 ;; PREFIX("ABCDEFGH");
211 ;; then ABCDEFGA should read as a symbol.
212 ;; 99% of the time we don't have to unparse-tyi, and so there will
216 (let ((tem *parse-tyi
*))
218 (tyi-parse-int *parse-stream
* *parse-stream-eof
*))
220 (setq *parse-tyi
* nil
)
223 (setq *parse-tyi
* (cdr tem
))
226 ;; read one character but leave it there. so next parse-tyi gets it
227 (defun parse-tyipeek ()
228 (let ((tem *parse-tyi
*))
230 (setq *parse-tyi
* (tyi-parse-int *parse-stream
* *parse-stream-eof
*)))
234 ;; push characters back on the stream
235 (defun unparse-tyi (c)
236 (let ((tem *parse-tyi
*))
239 (setq *parse-tyi
* (cons c tem
)))))
241 ;;I know that the tradition says there should be no comments
242 ;;in tricky code in maxima. However the operator parsing
243 ;;gave me a bit of trouble. It was incorrect because
244 ;;it could not handle things produced by the extensions
245 ;;the following was broken for prefixes
247 (defun read-command-token-aux (obj)
250 (lis (if (eql ch
*parse-stream-eof
*)
252 (parser-assoc ch obj
))))
257 (cond ((atom (cadr lis
))
258 ;; INFIX("ABC"); puts into macsyma-operators
259 ;;something like: (#\A #\B #\C (ANS $abc))
260 ;; ordinary things are like:
261 ;; (#\< (ANS $<) (#\= (ANS $<=)))
262 ;; where if you fail at the #\< #\X
263 ;; stage, then the previous step was permitted.
264 (setq result
(read-command-token-aux (list (cdr lis
)))))
266 ;; lis something like (#\= (ANS $<=))
267 ;; and this says there are no longer operators
268 ;; starting with this.
270 (and (eql (car (cadr lis
)) 'ans
)
271 ;; When we have an operator, which starts with a
272 ;; literal, we check, if the operator is
273 ;; followed with a whitespace. With this code
274 ;; Maxima parses an expression grad x or grad(x)
275 ;; as (($grad) x) and gradef(x) as (($gradef) x),
276 ;; when grad is defined as a prefix operator.
277 ;; See bug report ID: 2970792.
278 (or (not (alphabetp (cadr (exploden (cadr (cadr lis
))))))
279 (member (parse-tyipeek) *whitespace-chars
*))
282 (let ((res (and (eql (car (cadr lis
)) 'ans
)
284 (com-token (read-command-token-aux (cddr lis
) )))
285 (setq result
(or com-token res
286 (read-command-token-aux (list (cadr lis
))))))))
287 (or result
(unparse-tyi ch
))
290 (defun scan-macsyma-token ()
291 ;; note that only $-ed tokens are GETALIASed.
292 (getalias (implode (cons '#\$
(scan-token t
)))))
294 (defun scan-lisp-token ()
295 (let ((charlist (scan-token nil
)))
298 (mread-synerr "Lisp symbol expected."))))
300 ;; Example: ?mismatch(x+y,x*z,?:from\-end,true); => 3
301 (defun scan-keyword-token ()
302 (let ((charlist (cdr (scan-token nil
))))
304 (let ((*package
* (find-package :keyword
)))
306 (mread-synerr "Lisp keyword expected."))))
308 (defun scan-token (flag)
309 (do ((c (parse-tyipeek) (parse-tyipeek))
311 ((or (eql c
*parse-stream-eof
*)
313 (not (or (digit-char-p c
(max 10 *read-base
*))
316 (nreverse (or l
(list (parse-tyi))))) ; Read at least one char ...
317 (when (char= (parse-tyi) #\\ )
318 (setq c
(parse-tyi)))
321 (defun scan-lisp-string () (scan-string))
322 (defun scan-macsyma-string () (scan-string))
324 (defun scan-string (&optional init
)
325 (let ((buf (make-array 50 :element-type
' #.
(array-element-type "a")
326 :fill-pointer
0 :adjustable t
)))
328 (vector-push-extend init buf
))
329 (do ((c (parse-tyipeek) (parse-tyipeek)))
330 ((cond ((eql c
*parse-stream-eof
*))
334 (if (char= (parse-tyi) #\\ )
335 (setq c
(parse-tyi)))
336 (vector-push-extend c buf
))))
338 (defun readlist (lis)
339 (read-from-string (coerce lis
'string
)))
341 ;; These variables control how we convert bfloat inputs to the
342 ;; internal bfloat representation. These variables should probably go
343 ;; away after some testing.
344 (defmvar $fast_bfloat_conversion t
345 "Use fast, but possibly inaccurate conversion")
346 (defmvar $fast_bfloat_threshold
100000.
347 "Exponents larger than this (in absolute value) will use the fast
348 conversion instead of the accurate conversion")
349 (defvar *fast-bfloat-extra-bits
* 0)
351 ;; Here is a test routine to test the fast bfloat conversion
353 (defun test-make-number (&optional
(n 1000))
356 (flet ((digit-list (n)
357 (coerce (format nil
"~D" n
) 'list
)))
359 ;; Generate a random number with 30 fraction digits and an
361 (push (digit-list (random 10)) numlist
)
362 (push '(#\.
) numlist
)
363 (push (digit-list (random (expt 10 30))) numlist
)
364 (push '(#\B
) numlist
)
365 (push (if (zerop (random 2)) '(#\
+) '(#\-
)) numlist
)
366 (push (digit-list (+ $fast_bfloat_threshold
367 (random $fast_bfloat_threshold
)))
369 ;; Convert using accurate and fast methods and compare the
371 (let ((true (let (($fast_bfloat_conversion nil
))
372 (make-number (copy-list numlist
))))
373 (fast (let (($fast_bfloat_conversion t
))
374 (make-number (copy-list numlist
)))))
375 (format t
"Test ~3A: " k
)
376 (map nil
#'(lambda (x)
381 (unless (equalp true fast
)
383 (format t
"NUM: ~A~% TRUE: ~S~% FAST: ~S~%"
384 (reverse numlist
) true fast
))))))
385 (format t
"~D failures in ~D tests (~F%)~%"
386 failures n
(* 100 failures
(/ (float n
))))))
389 ;; WARNING: MAKE-NUMBER destructively modifies it argument! Should we
391 (defun make-number (data)
392 (setq data
(nreverse data
))
393 ;; Maxima really wants to read in any number as a flonum
394 ;; (except when we have a bigfloat, of course!). So convert exponent
395 ;; markers to the flonum-exponent-marker.
396 (let ((marker (car (nth 3 data
))))
397 (unless (eql marker
+flonum-exponent-marker
+)
398 (when (member marker
'(#\E
#\F
#\S
#\D
#\L
#+cmu
#\W
))
399 (setf (nth 3 data
) (list +flonum-exponent-marker
+)))))
400 (if (not (equal (nth 3 data
) '(#\B
)))
401 (readlist (apply #'append data
))
404 (int-part (readlist (or (first data
) '(#\
0))))
405 (frac-part (readlist (or (third data
) '(#\
0))))
406 (frac-len (length (third data
)))
407 (exp-sign (first (fifth data
)))
408 (exp (readlist (sixth data
))))
409 (if (and $fast_bfloat_conversion
410 (> (abs exp
) $fast_bfloat_threshold
))
411 ;; Exponent is large enough that we don't want to do exact
412 ;; rational arithmetic. Instead we do bfloat arithmetic.
413 ;; For example, 1.234b1000 is converted by computing
414 ;; bfloat(1234)*10b0^(1000-3). Extra precision is used
415 ;; during the bfloat computations.
416 (let* ((extra-prec (+ *fast-bfloat-extra-bits
* (ceiling (log exp
2e0
))))
417 (fpprec (+ fpprec extra-prec
))
418 (mant (+ (* int-part
(expt 10 frac-len
)) frac-part
))
419 (bf-mant (bcons (intofp mant
)))
420 (p (power (bcons (intofp 10))
421 (- (if (char= exp-sign
#\-
)
425 ;; Compute the product using extra precision. This
426 ;; helps to get the last bit correct (but not
427 ;; always). If we didn't do this, then bf-mant and
428 ;; p would be rounded to the target precision and
429 ;; then the product is rounded again. Doing it
430 ;; this way, we still have 3 roundings, but bf-mant
431 ;; and p aren't rounded too soon.
432 (result (mul bf-mant p
)))
433 (let ((fpprec (- fpprec extra-prec
)))
434 ;; Now round the product back to the desired precision.
436 ;; For bigfloats, turn them into rational numbers then
437 ;; convert to bigfloat. Fix for the 0.25b0 # 2.5b-1 bug.
438 ;; Richard J. Fateman posted this fix to the Maxima list
439 ;; on 10 October 2005. Without this fix, some tests in
440 ;; rtestrationalize will fail. Used with permission.
441 (let ((ratio (* (+ int-part
(* frac-part
(expt 10 (- frac-len
))))
442 (expt 10 (if (char= exp-sign
#\-
)
445 ($bfloat
(cl-rat-to-maxima ratio
)))))))
447 ;; Richard J. Fateman wrote the big float to rational code and the function
450 (defun cl-rat-to-maxima (x)
453 (list '(rat simp
) (numerator x
) (denominator x
))))
455 (defun scan-digits (data continuation? continuation
&optional exponent-p
)
456 (do ((c (parse-tyipeek) (parse-tyipeek))
458 ((not (and (characterp c
) (digit-char-p c
(max 10.
*read-base
*))))
459 (cond ((member c continuation?
)
460 (funcall continuation
(list* (ncons (char-upcase
464 ((and (null l
) exponent-p
)
465 ;; We're trying to parse the exponent part of a number,
466 ;; and we didn't get a value after the exponent marker.
468 (mread-synerr "parser: incomplete number; missing exponent?"))
470 (make-number (cons (nreverse l
) data
)))))
473 (defun scan-number-after-dot (data)
474 (scan-digits data
'(#\E
#\e
#\F
#\f #\B
#\b #\D
#\d
#\S
#\s
#\L
#\l
#+cmu
#\W
#+cmu
#\w
) #'scan-number-exponent
))
476 (defun scan-number-exponent (data)
477 (push (ncons (if (or (char= (parse-tyipeek) #\
+)
478 (char= (parse-tyipeek) #\-
))
482 (scan-digits data
() () t
))
484 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 ;;;;; The Expression Parser ;;;;;
488 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
492 ;;; Based on a theory of parsing presented in: ;;;
494 ;;; Pratt, Vaughan R., ``Top Down Operator Precedence,'' ;;;
495 ;;; ACM Symposium on Principles of Programming Languages ;;;
496 ;;; Boston, MA; October, 1973. ;;;
498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
500 ;;; Implementation Notes ....
502 ;;; JPG Chars like ^A, ^B, ... get left around after interrupts and
503 ;;; should be thrown away by the scanner if not used as editing
506 ;;; KMP There is RBP stuff in DISPLA, too. Probably this sort of
507 ;;; data should all be in one place somewhere.
509 ;;; KMP Maybe the parser and/or scanner could use their own GC scheme
510 ;;; to recycle conses used in scan/parse from line to line which
511 ;;; really ought not be getting dynamically discarded and reconsed.
512 ;;; Alternatively, we could call RECLAIM explicitly on certain
513 ;;; pieces of structure which get used over and over. A
514 ;;; local-reclaim abstraction may want to be developed since this
515 ;;; stuff will always be needed, really. On small-address-space
516 ;;; machines, this could be overridden when the last DYNAMALLOC
517 ;;; GC barrier were passed (indicating that space was at a premium
518 ;;; -- in such case, real RECLAIM would be more economical -- or
519 ;;; would the code to control that be larger than the area locked
522 ;;; KMP GJC has a MAKE-EVALUATOR type package which could probably
523 ;;; replace the CALL-IF-POSSIBLE stuff used here.
524 ;;; [So it was written, so it was done. -gjc]
526 ;;; KMP DEFINE-SYMBOL and KILL-OPERATOR need to be redefined.
527 ;;; Probably these shouldn't be defined in this file anyway.
529 ;;; KMP The relationship of thisfile to SYNEX needs to be thought
530 ;;; out more carefully.
532 ;;; GJC Need macros for declaring INFIX, PREFIX, etc ops
534 ;;; GJC You know, PARSE-NARY isn't really needed it seems, since
535 ;;; the SIMPLIFIER makes the conversion of
536 ;;; ((MTIMES) ((MTIMES) A B) C) => ((MTIMES) A B C)
537 ;;; I bet you could get make "*" infix and nobody would
540 ;;; The following terms may be useful in deciphering this code:
542 ;;; NUD -- NUll left Denotation (op has nothing to its left (prefix))
543 ;;; LED -- LEft Denotation (op has something to left (postfix or infix))
545 ;;; LBP -- Left Binding Power (the stickiness to the left)
546 ;;; RBP -- Right Binding Power (the stickiness to the right)
551 (defvar scan-buffered-token
(list nil
)
552 "put-back buffer for scanner, a state-variable of the reader")
554 (defun peek-one-token ()
555 (peek-one-token-g nil nil
))
557 (defun peek-one-token-g (eof-ok? eof-obj
)
559 ((car scan-buffered-token
)
560 (cdr scan-buffered-token
))
561 (t (rplacd scan-buffered-token
(scan-one-token-g eof-ok? eof-obj
))
562 (cdr (rplaca scan-buffered-token t
)))))
564 (defun scan-one-token ()
565 (scan-one-token-g nil nil
))
567 (defun scan-one-token-g (eof-ok? eof-obj
)
568 (declare (special macsyma-operators
))
569 (cond ((car scan-buffered-token
)
570 (rplaca scan-buffered-token
())
571 (cdr scan-buffered-token
))
572 ((read-command-token macsyma-operators
))
574 (let ((test (parse-tyipeek)))
575 (cond ((eql test
*parse-stream-eof
*)
578 (mread-synerr (intl:gettext
"end of file while scanning expression."))))
581 (cond ((char= (parse-tyipeek) #\
*)
584 (scan-one-token-g eof-ok? eof-obj
))
586 ((eql test
#\.
) (parse-tyi) ; Read the dot
587 (if (digit-char-p (parse-tyipeek) 10.
)
588 (scan-number-after-dot (list (ncons #\.
) nil
))
592 (scan-macsyma-string))
595 (cond ((char= (parse-tyipeek) #\")
598 ((char= (parse-tyipeek) #\
:)
599 (scan-keyword-token))
603 (if (digit-char-p test
10.
)
604 (scan-number-before-dot ())
605 (scan-macsyma-token))))))))
607 ;; nested comments are permitted.
608 (defun gobble-comment ()
612 (setq c
(parse-tyipeek))
614 (cond ((= depth
0) (return t
)))
615 (cond ((eql c
*parse-stream-eof
*)
616 (mread-synerr (intl:gettext
"end of file in comment.")))
618 (cond ((char= (parse-tyipeek) #\
/)
621 (cond ((= depth
0) (return t
)))
624 (cond ((char= (parse-tyipeek) #\
*)
625 (incf depth
) (parse-tyi)
630 (defun scan-number-rest (data)
631 (let ((c (caar data
)))
634 (scan-number-after-dot data
))
635 ((member c
'(#\E
#\e
#\F
#\f #\B
#\b #\D
#\d
#\S
#\s
#\L
#\l
#+cmu
#\W
#+cmu
#\w
))
636 ;; Dot missing but found exponent marker. Fake it.
637 (setf data
(push (ncons #\.
) (rest data
)))
638 (push (ncons #\
0) data
)
639 (push (ncons c
) data
)
640 (scan-number-exponent data
)))))
642 (defun scan-number-before-dot (data)
643 (scan-digits data
'(#\.
#\E
#\e
#\F
#\f #\B
#\b #\D
#\d
#\S
#\s
#\L
#\l
#+cmu
#\W
#+cmu
#\w
)
647 ;; "First character" and "Pop character"
649 (defmacro first-c
() '(peek-one-token))
650 (defmacro pop-c
() '(scan-one-token))
652 (defun mstringp (x) (stringp x
)) ;; OBSOLETE. PRESERVE FOR SAKE OF POSSIBLE CALLS FROM NON-MAXIMA CODE !!
654 (defun inherit-propl (op-to op-from getl
)
655 (let ((propl (getl op-from getl
)))
657 (progn (remprop op-to
(car propl
))
658 (putprop op-to
(cadr propl
) (car propl
)))
660 (maxima-error "has no ~a properties. ~a ~a" getl op-from
'wrng-type-arg
)
665 ;;; (LED <op> <left>)
667 ;;; <op> is the name of the operator which was just popped.
668 ;;; <left> is the stuff to the left of the operator in the LED case.
672 (:execute
:compile-toplevel
:load-toplevel
)
673 (defmacro def-nud-equiv
(op equiv
)
674 (list 'putprop
(list 'quote op
) (list 'function equiv
)
677 (defmacro nud-propl
() ''(nud))
679 (defmacro def-nud-fun
(op-name op-l . body
)
680 (list* 'defun-prop
(list* op-name
'nud
'nil
) op-l body
))
682 (defmacro def-led-equiv
(op equiv
)
683 (list 'putprop
(list 'quote op
) (list 'function equiv
)
686 (defmacro led-propl
() ''(led))
688 (defmacro def-led-fun
(op-name op-l . body
)
689 (list* 'defun-prop
(list* op-name
'led
'nil
) op-l body
)))
692 (let ((tem (and (symbolp op
) (getl op
'(nud)))) res
)
696 (mread-synerr "~A is not a prefix operator" (mopstrip op
))
698 (funcall (cadr tem
) op
)))
701 (defun led-call (op l
)
702 (let ((tem (and (symbolp op
) (getl op
'(led)))) res
)
705 (mread-synerr "~A is not an infix operator" (mopstrip op
))
706 (funcall (cadr tem
) op l
)))
709 ;;; (DEF-NUD (op lbp rbp) bvl . body)
711 ;;; Defines a procedure for parsing OP as a prefix operator.
713 ;;; OP should be the name of the symbol as a string or symbol.
714 ;;; LBP is an optional left binding power for the operator.
715 ;;; RBP is an optional right binding power for the operator.
716 ;;; BVL must contain exactly one variable, which the compiler will not
717 ;;; complain about if unused, since it will rarely be of use anyway.
718 ;;; It will get bound to the operator being parsed.
719 ;;; lispm:Optional args not allowed in release 5 allowed, necessary afterwards..
721 (defmacro def-nud
((op . lbp-rbp
) bvl . body
)
722 (let (( lbp
(nth 0 lbp-rbp
))
723 ( rbp
(nth 1 lbp-rbp
)))
724 `(progn ,(make-parser-fun-def op
'nud bvl body
)
725 (set-lbp-and-rbp ',op
',lbp
',rbp
))))
727 (defun set-lbp-and-rbp (op lbp rbp
)
728 (cond ((not (consp op
))
729 (let ((existing-lbp (get op
'lbp
))
730 (existing-rbp (get op
'rbp
)))
731 (cond ((not lbp
) ;; ignore omitted arg
734 (putprop op lbp
'lbp
))
735 ((not (equal existing-lbp lbp
))
736 (maxima-error "Incompatible LBP's defined for this operator ~a" op
)))
737 (cond ((not rbp
) ;; ignore omitted arg
740 (putprop op rbp
'rbp
))
741 ((not (equal existing-rbp rbp
))
742 (maxima-error "Incompatible RBP's defined for this operator ~a" op
)))))
744 (mapcar #'(lambda (x) (set-lbp-and-rbp x lbp rbp
))
747 ;;; (DEF-LED (op lbp rbp) bvl . body)
749 ;;; Defines a procedure for parsing OP as an infix or postfix operator.
751 ;;; OP should be the name of the symbol as a string or symbol.
752 ;;; LBP is an optional left binding power for the operator.
753 ;;; RBP is an optional right binding power for the operator.
754 ;;; BVL must contain exactly two variables, the first of which the compiler
755 ;;; will not complain about if unused, since it will rarely be of use
756 ;;; anyway. Arg1 will get bound to the operator being parsed. Arg2 will
757 ;;; get bound to the parsed structure which was to the left of Arg1.
760 (defmacro def-led
((op . lbp-rbp
) bvl . body
)
761 (let (( lbp
(nth 0 lbp-rbp
))
762 ( rbp
(nth 1 lbp-rbp
)))
763 `(progn ,(make-parser-fun-def op
'led bvl body
)
764 (set-lbp-and-rbp ',op
',lbp
',rbp
))))
766 (defmacro def-collisions
(op &rest alist
)
767 (let ((keys (do ((i 1 (ash i
1))
768 (lis alist
(cdr lis
))
769 (nl () (cons (cons (caar lis
) i
) nl
)))
772 (defprop ,op
,(let nil
773 (copy-tree keys
)) keys
)
774 ,@(mapcar #'(lambda (data)
775 `(defprop ,(car data
)
776 ,(do ((i 0 (logior i
(cdr (assoc (car lis
) keys
:test
#'eq
))))
777 (lis (cdr data
) (cdr lis
)))
783 (defun collision-lookup (op active-bitmask key-bitmask
)
784 (let ((result (logand active-bitmask key-bitmask
)))
785 (if (not (zerop result
))
786 (do ((l (get op
'keys
) (cdr l
)))
787 ((null l
) (parse-bug-err 'collision-check
))
788 (if (not (zerop (logand result
(cdar l
))))
789 (return (caar l
)))))))
791 (defun collision-check (op active-bitmask key
)
792 (let ((key-bitmask (get key op
)))
793 (if (not key-bitmask
)
794 (mread-synerr "~A is an unknown keyword in a ~A statement."
795 (mopstrip key
) (mopstrip op
)))
796 (let ((collision (collision-lookup op active-bitmask key-bitmask
)))
798 (if (eq collision key
)
799 (mread-synerr "This ~A's ~A slot is already filled."
802 (mread-synerr "A ~A cannot have a ~A with a ~A field."
805 (mopstrip collision
))))
806 (logior (cdr (assoc key
(get op
'keys
) :test
#'eq
)) active-bitmask
))))
808 ;;;; Data abstraction
810 ;;; LBP = Left Binding Power
812 ;;; (LBP <op>) - reads an operator's Left Binding Power
813 ;;; (DEF-LBP <op> <val>) - defines an operator's Left Binding Power
815 (defun lbp (lex) (cond ((safe-get lex
'lbp
)) (t 200.
)))
817 (defmacro def-lbp
(sym val
) `(defprop ,sym
,val lbp
))
819 ;;; RBP = Right Binding Power
821 ;;; (RBP <op>) - reads an operator's Right Binding Power
822 ;;; (DEF-RBP <op> <val>) - defines an operator's Right Binding Power
824 (defun rbp (lex) (cond ((safe-get lex
'rbp
)) (t 200.
)))
826 (defmacro def-rbp
(sym val
) `(defprop ,sym
,val rbp
))
828 (defmacro def-match
(x m
) `(defprop ,x
,m match
))
830 ;;; POS = Part of Speech!
837 (defun lpos (op) (cond ((safe-get op
'lpos
)) (t '$any
)))
838 (defun rpos (op) (cond ((safe-get op
'rpos
)) (t '$any
)))
839 (defun pos (op) (cond ((safe-get op
'pos
)) (t '$any
)))
841 (defmacro def-pos
(op pos
) `(defprop ,op
,pos pos
))
842 (defmacro def-rpos
(op pos
) `(defprop ,op
,pos rpos
))
843 (defmacro def-lpos
(op pos
) `(defprop ,op
,pos lpos
))
847 (defun mheader (op) (add-lineinfo (or (safe-get op
'mheader
) (ncons op
))))
849 (defmacro def-mheader
(op header
) `(defprop ,op
,header mheader
))
851 ;;;; Misplaced definitions
853 (defmacro def-operatorp
()
854 `(defun operatorp (lex)
855 (and (symbolp lex
) (getl lex
'(,@(nud-propl) ,@(led-propl))))))
859 (defmacro def-operatorp1
()
860 ;Defmfun -- used by SYNEX if not others.
861 `(defun operatorp1 (lex)
862 ;; Referenced outside of package: OP-SETUP, DECLARE1
863 ;; Use for truth value only, not for return-value.
864 (and (symbolp lex
) (getl lex
'(lbp rbp
,@(nud-propl) ,@(led-propl))))))
868 ;;;; The Macsyma Parser
870 ;;; (MREAD) with arguments compatible with losing maclisp READ style.
872 ;;; Returns a parsed form of tokens read from stream.
874 ;;; If you want rubout processing, be sure to call some stream which knows
875 ;;; about such things. Also, I'm figuring that the PROMPT will be
876 ;;; an attribute of the stream which somebody can hack before calling
877 ;;; MREAD if he wants to.
880 ;;Important for lispm rubout handler
881 (defun mread (&rest read-args
)
884 (and *parse-window
* (setf (car *parse-window
*) nil
885 *parse-window
* (cdr *parse-window
*)))
886 (princ *mread-prompt
*)
888 (apply 'mread-raw read-args
)))
890 (defun mread-prompter (stream char
)
891 (declare (special *mread-prompt-internal
*)
894 (princ *mread-prompt-internal
* stream
))
896 ;; input can look like:
899 (defun mread-raw (*parse-stream
* &optional
*mread-eof-obj
*)
900 (let ((scan-buffered-token (list nil
))
902 (if (eq scan-buffered-token
;; a handly unique object for the EQ test.
903 (peek-one-token-g t scan-buffered-token
))
906 (input (parse '$any
0.
) (parse '$any
0.
)))
910 ;force a separate line info structure
911 (setf *current-line-info
* nil
)
912 (return (list (mheader (pop-c))
913 (if labels
(cons (mheader '|$
[|
) (nreverse labels
)))
919 (mread-synerr "Invalid && tag. Tag must be a symbol")))
921 (parse-bug-err 'mread-raw
)))))))
923 ;;; (PARSE <mode> <rbp>)
925 ;;; This will parse an expression containing operators which have a higher
926 ;;; left binding power than <rbp>, returning as soon as an operator of
927 ;;; lesser or equal binding power is seen. The result will be in the given
928 ;;; mode (which allows some control over the class of result expected).
929 ;;; Modes used are as follows:
930 ;;; $ANY = Match any type of expression
931 ;;; $CLAUSE = Match only boolean expressions (or $ANY)
932 ;;; $EXPR = Match only mathematical expressions (or $ANY)
933 ;;; If a mismatched mode occurs, a syntax error will be flagged. Eg,
934 ;;; this is why "X^A*B" parses but "X^A and B" does not. X^A is a $EXPR
935 ;;; and not coercible to a $CLAUSE. See CONVERT.
937 ;;; <mode> is the required mode of the result.
938 ;;; <rbp> is the right binding power to use for the parse. When an
939 ;;; LED-type operator is seen with a lower left binding power
940 ;;; than <rbp>, this parse returns what it's seen so far rather
941 ;;; than calling that operator.
944 (defun parse (mode rbp
)
945 (do ((left (nud-call (pop-c)) ; Invoke the null left denotation
946 (led-call (pop-c) left
))) ; and keep calling LED ops as needed
947 ((>= rbp
(lbp (first-c))) ; Until next op lbp too low
948 (convert left mode
)))) ; in which case, return stuff seen
950 ;;; (PARSE-PREFIX <op>)
952 ;;; Parses prefix forms -- eg, -X or NOT FOO.
954 ;;; This should be the NUD property on an operator. It fires after <op>
955 ;;; has been seen. It parses forward looking for one more expression
956 ;;; according to its right binding power, returning
957 ;;; ( <mode> . ((<op>) <arg1>) )
959 (defun parse-prefix (op)
960 (list (pos op
) ; Operator mode
961 (mheader op
) ; Standard Macsyma expression header
962 (parse (rpos op
) (rbp op
)))) ; Convert single argument for use
964 ;;; (PARSE-POSTFIX <op> <left>)
966 ;;; Parses postfix forms. eg, X!.
968 ;;; This should be the LED property of an operator. It fires after <left>
969 ;;; has been accumulated and <op> has been seen and gobbled up. It returns
970 ;;; ( <mode> . ((<op>) <arg1>) )
972 (defun parse-postfix (op l
)
973 (list (pos op
) ; Operator's mode
974 (mheader op
) ; Standard Macsyma expression header
975 (convert l
(lpos op
)))) ; Convert single argument for use
977 ;;; (PARSE-INFIX <op> <left>)
979 ;;; Parses infix (non-nary) forms. eg, 5 mod 3.
981 ;;; This should be the led property of an operator. It fires after <left>
982 ;;; has been accumulated and <op> has been seen and gobbled up. It returns
983 ;;; ( <mode> . ((<op>) <arg1> <arg2>) )
985 (defun parse-infix (op l
)
986 (list (pos op
) ; Operator's mode
987 (mheader op
) ; Standard Macsyma expression header
988 (convert l
(lpos op
)) ; Convert arg1 for immediate use
989 (parse (rpos op
) (rbp op
)))) ; Look for an arg2
991 ;;; (PARSE-NARY <op> <left>)
993 ;;; Parses nary forms. Eg, form1*form2*... or form1+form2+...
994 ;;; This should be the LED property on an operator. It fires after <op>
995 ;;; has been seen, accumulating and returning
996 ;;; ( <mode> . ((<op>) <arg1> <arg2> ...) )
998 ;;; <op> is the being parsed.
999 ;;; <left> is the stuff that has been seen to the left of <op> which
1000 ;;; rightly belongs to <op> on the basis of parse precedence rules.
1002 (defun parse-nary (op l
)
1003 (list* (pos op
) ; Operator's mode
1004 (mheader op
) ; Normal Macsyma operator header
1005 (convert l
(lpos op
)) ; Check type-match of arg1
1006 (prsnary op
(lpos op
) (lbp op
)))) ; Search for other args
1008 ;;; (PARSE-MATCHFIX <lop>)
1010 ;;; Parses matchfix forms. eg, [form1,form2,...] or (form1,form2,...)
1012 ;;; This should be the NUD property on an operator. It fires after <op>
1013 ;;; has been seen. It parses <lop><form1>,<form2>,...<rop> returning
1014 ;;; ( <mode> . ((<lop>) <form1> <form2> ...) ).
1016 (defun parse-matchfix (op)
1017 (list* (pos op
) ; Operator's mode
1018 (mheader op
) ; Normal Macsyma operator header
1019 (prsmatch (safe-get op
'match
) (lpos op
)))) ; Search for matchfixed forms
1021 ;;; (PARSE-NOFIX <op>)
1023 ;;; Parses an operator of no args. eg, @+X where @ designates a function
1024 ;;; call (eg, @() is implicitly stated by the lone symbol @.)
1026 ;;; This should be a NUD property on an operator which takes no args.
1027 ;;; It immediately returns ( <mode> . ((<op>)) ).
1029 ;;; <op> is the name of the operator.
1031 ;;; Note: This is not used by default and probably shouldn't be used by
1032 ;;; someone who doesn't know what he's doing. Example lossage. If @ is
1033 ;;; a nofix op, then @(3,4) parses, but parses as "@"()(3,4) would -- ie,
1034 ;;; to ((MQAPPLY) (($@)) 3 4) which is perhaps not what the user will expect.
1036 (defun parse-nofix (op) (list (pos op
) (mheader op
)))
1038 ;;; (PRSNARY <op> <mode> <rbp>)
1040 ;;; Parses an nary operator tail Eg, ...form2+form3+... or ...form2*form3*...
1042 ;;; Expects to be entered after the leading form and the first call to an
1043 ;;; nary operator has been seen and popped. Returns a list of parsed forms
1044 ;;; which belong to that operator. Eg, for X+Y+Z; this should be called
1045 ;;; after the first + is popped. Returns (Y Z) and leaves the ; token
1046 ;;; in the parser scan buffer.
1048 ;;; <op> is the nary operator in question.
1049 ;;; <rbp> is (LBP <op>) and is provided for efficiency. It is for use in
1050 ;;; recursive parses as a binding power to parse for.
1051 ;;; <mode> is the name of the mode that each form must be.
1053 (defun prsnary (op mode rbp
)
1054 (do ((nl (list (parse mode rbp
)) ; Get at least one form
1055 (cons (parse mode rbp
) nl
))) ; and keep getting forms
1056 ((not (eq op
(first-c))) ; until a parse pops on a new op
1057 (nreverse nl
)) ; at which time return forms
1058 (pop-c))) ; otherwise pop op
1060 ;;; (PRSMATCH <match> <mode>)
1062 ;;; Parses a matchfix sequence. Eg, [form1,form2,...] or (form1,form2,...)
1063 ;;; Expects to be entered after the leading token is the popped (ie, at the
1064 ;;; point where the parse of form1 will begin). Returns (form1 form2 ...).
1066 ;;; <match> is the token to look for as a matchfix character.
1067 ;;; <mode> is the name of the mode that each form must be.
1069 (defun prsmatch (match mode
) ; Parse for matchfix char
1070 (cond ((eq match
(first-c)) (pop-c) nil
) ; If immediate match, ()
1072 (do ((nl (list (parse mode
10.
)) ; Get first element
1073 (cons (parse mode
10.
) nl
))) ; and Keep adding elements
1074 ((eq match
(first-c)) ; Until we hit the match.
1075 (pop-c) ; Throw away match.
1076 (nreverse nl
)) ; Put result back in order
1077 (if (eq '|$
,|
(first-c)) ; If not end, look for ","
1078 (pop-c) ; and pop it if it's there
1079 (mread-synerr "Missing ~A" ; or give an error message.
1080 (mopstrip match
)))))))
1082 ;;; (CONVERT <exp> <mode>)
1084 ;;; Parser coercion function.
1086 ;;; <exp> should have the form ( <expressionmode> . <expression> )
1087 ;;; <mode> is the target mode.
1089 ;;; If <expressionmode> and <mode> are compatible, returns <expression>.
1091 (defun convert (item mode
)
1092 (if (or (eq mode
(car item
)) ; If modes match exactly
1093 (eq '$any mode
) ; or target is $ANY
1094 (eq '$any
(car item
))) ; or input is $ANY
1095 (cdr item
) ; then return expression
1096 (mread-synerr "Found ~A expression where ~A expression expected"
1097 (get (car item
) 'english
)
1098 (get mode
'english
))))
1100 (defprop $any
"untyped" english
)
1101 (defprop $clause
"logical" english
)
1102 (defprop $expr
"algebraic" english
)
1104 ;;;; Parser Error Diagnostics
1106 ;; Call this for random user-generated parse errors
1108 (defun parse-err () (mread-synerr "Syntax error"))
1110 ;; Call this for random internal parser lossage (eg, code that shouldn't
1113 (defun parse-bug-err (op)
1115 "Parser bug in ~A. Please report this to the Maxima maintainers,~
1116 ~%including the characters you just typed which caused the error. Thanks."
1119 ;;; Random shared error messages
1121 (defun delim-err (op)
1122 (mread-synerr "Illegal use of delimiter ~A" (mopstrip op
)))
1124 (defun erb-err (op l
) l
;Ignored
1125 (mread-synerr "Too many ~A's" (mopstrip op
)))
1127 (defun premterm-err (op)
1128 (mread-synerr "Premature termination of input at ~A."
1131 ;;;; Operator Specific Data
1133 (def-nud-equiv |$
]| delim-err
)
1134 (def-led-equiv |$
]| erb-err
)
1137 (def-nud-equiv |$
[| parse-matchfix
)
1138 (def-match |$
[| |$
]|
)
1141 (def-mheader |$
[|
(mlist))
1143 (def-lpos |$
[| $any
)
1146 (def-led (|$
[|
200.
) (op left
)
1147 (setq left
(convert left
'$any
))
1148 (if (numberp left
) (parse-err)) ; number[...] invalid
1149 (let ((header (if (atom left
)
1150 (add-lineinfo (list (amperchk left
) 'array
))
1151 (add-lineinfo '(mqapply array
))))
1152 (right (prsmatch '|$
]|
'$any
))) ; get sublist in RIGHT
1153 (cond ((null right
) ; 1 subscript minimum
1154 (mread-synerr "No subscripts given"))
1155 ((atom left
) ; atom[...]
1156 (setq right
(cons header
1158 (cons '$any
(aliaslookup right
)))
1160 (cons '$any
(cons header
1161 (cons left right
)))))))
1164 (def-nud-equiv |$
)| delim-err
)
1165 (def-led-equiv |$
)| erb-err
)
1168 (def-mheader |$
(|
(mprogn))
1170 ;; KMP: This function optimizes out (exp) into just exp.
1171 ;; This is useful for mathy expressions, but obnoxious for non-mathy
1172 ;; expressions. I think DISPLA should be made smart about such things,
1173 ;; but probably the (...) should be carried around in the internal
1174 ;; representation. This would make things like BUILDQ much easier to
1176 ;; GJC: CGOL has the same behavior, so users tend to write extensions
1177 ;; to the parser rather than write Macros per se. The transformation
1178 ;; "(EXP)" ==> "EXP" is done by the evaluator anyway, the problem
1179 ;; comes inside quoted expressions. There are many other problems with
1180 ;; the "QUOTE" concept however.
1182 (def-nud (|$
(|
200.
) (op)
1183 (let ((right)(hdr (mheader '|$
(|
))) ; make mheader first for lineinfo
1184 (cond ((eq '|$
)|
(first-c)) (parse-err)) ; () is illegal
1185 ((or (null (setq right
(prsmatch '|$
)|
'$any
))) ; No args to MPROGN??
1186 (cdr right
)) ; More than one arg.
1187 (when (suspicious-mprogn-p right
)
1188 (mtell (intl:gettext
"warning: parser: I'll let it stand, but (...) doesn't recognize local variables.~%"))
1189 (mtell (intl:gettext
"warning: parser: did you mean to say: block(~M, ...) ?~%") (car right
)))
1190 (cons '$any
(cons hdr right
))) ; Return an MPROGN
1191 (t (cons '$any
(car right
)))))) ; Optimize out MPROGN
1193 (defun suspicious-mprogn-p (right)
1194 ;; Look for a Maxima list of symbols or assignments to symbols.
1195 (and ($listp
(car right
))
1196 (every #'(lambda (e) (or (symbolp e
)
1197 (and (consp e
) (eq (caar e
) 'msetq
) (symbolp (second e
)))))
1198 (rest (car right
)))))
1200 (def-led (|$
(|
200.
) (op left
)
1201 (setq left
(convert left
'$any
)) ;De-reference LEFT
1202 (if (numberp left
) (parse-err)) ;number(...) illegal
1203 (let ((hdr (and (atom left
)(mheader (amperchk left
))))
1204 (r (prsmatch '|$
)|
'$any
)) ;Get arglist in R
1206 (cons '$any
;Result is type $ANY
1207 (cond ((atom left
) ;If atom(...) =>
1208 (cons hdr r
)) ;(($atom) exp . args)
1209 (t ;Else exp(...) =>
1210 (cons '(mqapply) (cons left r
))))))) ;((MQAPPLY) op . args)
1212 (def-mheader |$
'|
(mquote))
1214 (def-nud (|$
'|
) (op)
1216 (cond ((eq '|$
(|
(first-c))
1217 (list '$any
(mheader '|$
'|
) (parse '$any
190.
)))
1218 ((or (atom (setq right
(parse '$any
190.
)))
1219 (member (caar right
) '(mquote mlist $set mprog mprogn lambda
) :test
#'eq
))
1220 (list '$any
(mheader '|$
'|
) right
))
1221 ((eq 'mqapply
(caar right
))
1222 (cond ((eq (caaadr right
) 'lambda
)
1223 (list '$any
(mheader '|$
'|
) right
))
1224 (t (rplaca (cdr right
)
1225 (cons (cons ($nounify
(caaadr right
))
1228 (cons '$any right
))))
1229 (t (cons '$any
(cons (cons ($nounify
(caar right
)) (cdar right
))
1232 (def-nud (|$
''|
) (op)
1235 (cond ((eq '|$
(|
(first-c)) (meval (parse '$any
190.
)))
1236 ((atom (setq right
(parse '$any
190.
))) (meval1 right
))
1237 ((eq 'mqapply
(caar right
))
1239 (cons (cons ($verbify
(caaadr right
)) (cdaadr right
))
1242 (t (cons (cons ($verbify
(caar right
)) (cdar right
))
1245 (def-led-equiv |$
:| parse-infix
)
1249 (def-rpos |$
:| $any
)
1250 (def-lpos |$
:| $any
)
1251 (def-mheader |$
:|
(msetq))
1253 (def-led-equiv |$
::| parse-infix
)
1254 (def-lbp |$
::|
180.
)
1256 (def-pos |$
::| $any
)
1257 (def-rpos |$
::| $any
)
1258 (def-lpos |$
::| $any
)
1259 (def-mheader |$
::|
(mset))
1261 (def-led-equiv |$
:=| parse-infix
)
1262 (def-lbp |$
:=|
180.
)
1264 (def-pos |$
:=| $any
)
1265 (def-rpos |$
:=| $any
)
1266 (def-lpos |$
:=| $any
)
1267 (def-mheader |$
:=|
(mdefine))
1269 (def-led-equiv |$
::=| parse-infix
)
1270 (def-lbp |$
::=|
180.
)
1271 (def-rbp |$
::=|
20.
)
1272 (def-pos |$
::=| $any
)
1273 (def-rpos |$
::=| $any
)
1274 (def-lpos |$
::=| $any
)
1275 (def-mheader |$
::=|
(mdefmacro))
1277 (def-led-equiv |$
!| parse-postfix
)
1280 (def-pos |$
!| $expr
)
1281 (def-lpos |$
!| $expr
)
1283 (def-mheader |$
!|
(mfactorial))
1285 (def-mheader |$
!!|
(%genfact
))
1287 (def-led (|$
!!|
160.
) (op left
)
1290 (convert left
'$expr
)
1291 (list (mheader '$
/) (convert left
'$expr
) 2)
1296 (def-pos |$^| $expr
)
1297 (def-lpos |$^| $expr
)
1298 (def-rpos |$^| $expr
)
1299 (def-mheader |$^|
(mexpt))
1301 (def-led ((|$^| |$^^|
)) (op left
)
1303 (aliaslookup (list (mheader op
)
1304 (convert left
(lpos op
))
1305 (parse (rpos op
) (rbp op
))))))
1307 (mapc #'(lambda (prop) ; Make $** like $^
1308 (let ((propval (get '$^ prop
)))
1309 (if propval
(putprop '$
** propval prop
))))
1310 '(lbp rbp pos rpos lpos mheader
))
1312 (inherit-propl '$
** '$^
(led-propl))
1314 (def-lbp |$^^|
140.
)
1315 (def-rbp |$^^|
139.
)
1316 (def-pos |$^^| $expr
)
1317 (def-lpos |$^^| $expr
)
1318 (def-rpos |$^^| $expr
)
1319 (def-mheader |$^^|
(mncexpt))
1321 ;; note y^^4.z gives an error because it scans the number 4 together with
1322 ;; the trailing '.' as a decimal place. I think the error is correct.
1323 (def-led-equiv |$.| parse-infix
)
1326 (def-pos |$.| $expr
)
1327 (def-lpos |$.| $expr
)
1328 (def-rpos |$.| $expr
)
1329 (def-mheader |$.|
(mnctimes))
1331 ;; Copy properties to noun operator.
1332 (setf (get '%mnctimes
'op
) (get 'mnctimes
'op
))
1334 (def-led-equiv |$
*| parse-nary
)
1337 (def-pos |$
*| $expr
)
1339 (def-lpos |$
*| $expr
)
1340 (def-mheader |$
*|
(mtimes))
1342 (def-led-equiv $
/ parse-infix
)
1348 (def-mheader $
/ (mquotient))
1350 (def-nud-equiv |$
+| parse-prefix
)
1352 (def-rbp |$
+|
134.
) ; Value increased from 100 to 134 (DK 02/2010).
1353 (def-pos |$
+| $expr
)
1354 (def-rpos |$
+| $expr
)
1356 (def-mheader |$
+|
(mplus))
1358 (def-led ((|$
+| |$-|
) 100.
) (op left
)
1359 (setq left
(convert left
'$expr
))
1360 (do ((nl (list (if (eq op
'$-
)
1361 (list (mheader '$-
) (parse '$expr
100.
))
1362 (parse '$expr
100.
))
1364 (cons (parse '$expr
100.
) nl
)))
1365 ((not (member (first-c) '($
+ $-
) :test
#'eq
))
1366 (list* '$expr
(mheader '$
+) (nreverse nl
)))
1367 (if (eq (first-c) '$
+) (pop-c))))
1369 (def-nud-equiv |$-| parse-prefix
)
1372 (def-pos |$-| $expr
)
1373 (def-rpos |$-| $expr
)
1375 (def-mheader |$-|
(mminus))
1377 (def-led-equiv |$
=| parse-infix
)
1380 (def-pos |$
=| $clause
)
1381 (def-rpos |$
=| $expr
)
1382 (def-lpos |$
=| $expr
)
1383 (def-mheader |$
=|
(mequal))
1385 (def-led-equiv |$
#| parse-infix
)
1388 (def-pos |$
#| $clause
)
1389 (def-rpos |$
#| $expr
)
1390 (def-lpos |$
#| $expr
)
1391 (def-mheader |$
#|
(mnotequal))
1393 (def-led-equiv |$
>| parse-infix
)
1396 (def-pos |$
>| $clause
)
1397 (def-rpos |$
>| $expr
)
1398 (def-lpos |$
>| $expr
)
1399 (def-mheader |$
>|
(mgreaterp))
1401 (def-led-equiv |$
>=| parse-infix
)
1404 (def-pos |$
>=| $clause
)
1405 (def-rpos |$
>=| $expr
)
1406 (def-lpos |$
>=| $expr
)
1407 (def-mheader |$
>=|
(mgeqp))
1409 (def-led-equiv |$
<| parse-infix
)
1412 (def-pos |$
<| $clause
)
1413 (def-rpos |$
<| $expr
)
1414 (def-lpos |$
<| $expr
)
1415 (def-mheader |$
<|
(mlessp))
1417 (def-led-equiv |$
<=| parse-infix
)
1420 (def-pos |$
<=| $clause
)
1421 (def-rpos |$
<=| $expr
)
1422 (def-lpos |$
<=| $expr
)
1423 (def-mheader |$
<=|
(mleqp))
1425 (def-nud-equiv $not parse-prefix
)
1428 (def-pos $not $clause
)
1429 (def-rpos $not $clause
)
1430 (def-lpos $not $clause
)
1431 (def-mheader $not
(mnot))
1433 (def-led-equiv $and parse-nary
)
1436 (def-pos $and $clause
)
1438 (def-lpos $and $clause
)
1439 (def-mheader $and
(mand))
1441 (def-led-equiv $or parse-nary
)
1444 (def-pos $or $clause
)
1446 (def-lpos $or $clause
)
1447 (def-mheader $or
(mor))
1449 (def-led-equiv |$
,| parse-nary
)
1454 (def-lpos |$
,| $any
)
1455 (def-mheader |$
,|
($ev
))
1457 (def-nud-equiv $then delim-err
)
1461 (def-nud-equiv $else delim-err
)
1465 (def-nud-equiv $elseif delim-err
)
1466 (def-lbp $elseif
5.
)
1467 (def-rbp $elseif
45.
)
1468 (def-pos $elseif $any
)
1469 (def-rpos $elseif $clause
)
1471 ;No LBP - Default as high as possible
1474 (def-rpos $if $clause
)
1476 (def-mheader $if
(mcond))
1481 (parse-condition op
)))
1483 (defun parse-condition (op)
1484 (list* (parse (rpos op
) (rbp op
))
1485 (if (eq (first-c) '$then
)
1486 (parse '$any
(rbp (pop-c)))
1487 (mread-synerr "Missing `then'"))
1489 (($else
) (list t
(parse '$any
(rbp (pop-c)))))
1490 (($elseif
) (parse-condition (pop-c)))
1491 (t (list t
'$false
)))))
1493 (def-mheader $do
(mdo))
1495 (defun parse-$do
(lex &aux
(left (make-mdo)))
1496 (setf (car left
) (mheader 'mdo
))
1497 (do ((op lex
(pop-c)) (active-bitmask 0))
1499 (if (eq op
'|$
:|
) (setq op
'$from
))
1500 (setq active-bitmask
(collision-check '$do active-bitmask op
))
1501 (let ((data (parse (rpos op
) (rbp op
))))
1503 ($do
(setf (mdo-body left
) data
) (return (cons '$any left
)))
1504 ($for
(setf (mdo-for left
) data
))
1505 ($from
(setf (mdo-from left
) data
))
1506 ($in
(setf (mdo-op left
) 'mdoin
)
1507 (setf (mdo-from left
) data
))
1508 ($step
(setf (mdo-step left
) data
))
1509 ($next
(setf (mdo-next left
) data
))
1510 ($thru
(setf (mdo-thru left
) data
))
1513 (setq data
(list (mheader '$not
) data
)))
1514 (setf (mdo-unless left
)
1515 (if (null (mdo-unless left
))
1517 (list (mheader '$or
) data
(mdo-unless left
)))))
1518 (t (parse-bug-err '$do
))))))
1525 (def-lbp $unless
25.
)
1526 (def-lbp $while
25.
)
1529 (def-nud-equiv $for parse-$do
)
1530 (def-nud-equiv $from parse-$do
)
1531 (def-nud-equiv $step parse-$do
)
1532 (def-nud-equiv $next parse-$do
)
1533 (def-nud-equiv $thru parse-$do
)
1534 (def-nud-equiv $unless parse-$do
)
1535 (def-nud-equiv $while parse-$do
)
1536 (def-nud-equiv $do parse-$do
)
1545 (def-rbp $unless
45.
)
1546 (def-rbp $while
45.
)
1549 (def-rpos $for $any
)
1550 (def-rpos $from $any
)
1551 (def-rpos $step $expr
)
1552 (def-rpos $next $any
)
1553 (def-rpos $thru $expr
)
1554 (def-rpos $unless $clause
)
1555 (def-rpos $while $clause
)
1561 ($from .
($in $from
))
1562 ($in .
($in $from $step $next $thru
))
1563 ($step .
($in $step $next
))
1564 ($next .
($in $step $next
))
1565 ($thru .
($in $thru
)) ;$IN didn't used to get checked for
1569 (def-mheader |$$|
(nodisplayinput))
1570 (def-nud-equiv |$$| premterm-err
)
1572 ;No RBP, POS, RPOS, RBP, or MHEADER
1574 (def-mheader |$
;| (displayinput))
1575 (def-nud-equiv |$
;| premterm-err)
1577 ;No RBP, POS, RPOS, RBP, or MHEADER
1579 (def-nud-equiv |$
&&| delim-err
)
1583 ;; kludge interface function to allow the use of lisp PRINC in places.
1584 (cond ((null x
) 'false
)
1585 ((or (eq x t
) (eq x
't
)) 'true
)
1588 (or (get x
'reversealias
)
1589 (let ((name (symbol-name x
)))
1590 (if (member (char name
0) '(#\$
#\%
) :test
#'char
=)
1595 (define-initial-symbols
1596 ;; * Note: /. is looked for explicitly rather than
1597 ;; existing in this chart. The reason is that
1598 ;; it serves a dual role (as a decimal point) and
1599 ;; must be special-cased.
1601 ;; Same for // because of the /* ... */ handling
1604 |
+| |-| |
*| |^| |
<| |
=| |
>| |
(| |
)| |
[| |
]| |
,|
1605 |
:| |
!| |
#| |
'| |;| |$| |
&|
1607 |
**| |^^| |
:=| |
::| |
!!| |
<=| |
>=| |
''| |
&&|
1612 ;; !! FOLLOWING MOVED HERE FROM MLISP.LISP (DEFSTRUCT STUFF)
1613 ;; !! SEE NOTE THERE
1616 ;;; User extensibility:
1617 (defmfun $prefix
(operator &optional
(rbp 180.
)
1620 (def-operator operator pos
() () rbp rpos
() t
1621 '(nud . parse-prefix
) 'msize-prefix
'dimension-prefix
() )
1624 (defmfun $postfix
(operator &optional
(lbp 180.
)
1627 (def-operator operator pos lbp lpos
() () t
()
1628 '(led . parse-postfix
) 'msize-postfix
'dimension-postfix
() )
1631 (defmfun $infix
(operator &optional
(lbp 180.
)
1636 (def-operator operator pos lbp lpos rbp rpos t t
1637 '(led . parse-infix
) 'msize-infix
'dimension-infix
() )
1640 (defmfun $nary
(operator &optional
(bp 180.
)
1643 (def-operator operator pos bp argpos bp
() t t
1644 '(led . parse-nary
) 'msize-nary
'dimension-nary
() )
1647 (defmfun $matchfix
(operator
1648 match
&optional
(argpos '$any
)
1650 ;shouldn't MATCH be optional?
1651 (def-operator operator pos
() argpos
() () () ()
1652 '(nud . parse-matchfix
) 'msize-matchfix
'dimension-match match
)
1655 (defmfun $nofix
(operator &optional
(pos '$any
))
1656 (def-operator operator pos
() () () () () ()
1657 '(nud . parse-nofix
) 'msize-nofix
'dimension-nofix
() )
1660 ;;; (DEF-OPERATOR op pos lbp lpos rbp rpos sp1 sp2
1661 ;;; parse-data grind-fn dim-fn match)
1662 ;;; OP is the operator name.
1663 ;;; POS is its ``part of speech.''
1664 ;;; LBP is its ``left binding power.''
1665 ;;; LPOS is the part of speech of the arguments to its left, or of all.
1666 ;;; arguments for NARY and MATCHFIX.
1667 ;;; RBP is its ``right binding power.''
1668 ;;; RPOS is the part of speech of the argument to its right.
1669 ;;; SP1 says if the DISSYM property needs a space on the right.
1670 ;;; SP2 says if the DISSYM property needs a space on the left.
1671 ;;; PARSE-DATA is (prop . fn) -- parser prop name dotted with function name
1672 ;;; GRIND-FN is the grinder function for the operator.
1673 ;;; DIM-FN is the dimension function for the operator.
1674 ;;; PARSEPROP is the property name to use for parsing. One of LED or NUD.
1675 ;;; MATCH if non-(), ignores SP1 and SP2. Should be the match symbol.
1676 ;;; sets OP up as matchfix with MATCH.
1678 ;;; For more complete descriptions of these naming conventions, see
1679 ;;; the comments in GRAM package, which describe them in reasonable detail.
1681 (defun def-operator (op pos lbp lpos rbp rpos sp1 sp2
1682 parse-data grind-fn dim-fn match
)
1684 (if (or (and rbp
(not (integerp (setq x rbp
))))
1685 (and lbp
(not (integerp (setq x lbp
)))))
1686 (merror (intl:gettext
"syntax extension: binding powers must be integers; found: ~M") x
))
1687 (if (stringp op
) (setq op
(define-symbol op
)))
1689 (let ((noun ($nounify op
))
1690 (dissym (cdr (exploden op
))))
1693 (setq dissym
(append (if sp1
'(#\space
)) dissym
(if sp2
'(#\space
)))))
1694 (t (if (stringp match
) (setq match
(define-symbol match
)))
1696 (putprop op match
'match
)
1697 (putprop match
5.
'lbp
)
1698 (setq dissym
(cons dissym
(cdr (exploden match
))))))
1699 (putprop op pos
'pos
)
1700 (putprop op
(cdr parse-data
) (car parse-data
))
1701 (putprop op grind-fn
'grind
)
1702 (putprop op dim-fn
'dimension
)
1703 (putprop noun dim-fn
'dimension
)
1704 (putprop op dissym
'dissym
)
1705 (putprop noun dissym
'dissym
)
1707 (putprop op rbp
'rbp
)
1708 (putprop noun rbp
'rbp
))
1710 (putprop op lbp
'lbp
)
1711 (putprop noun lbp
'lbp
))
1712 (when lpos
(putprop op lpos
'lpos
))
1713 (when rpos
(putprop op rpos
'rpos
))
1716 (defun op-setup (op)
1717 (let ((dummy (or (get op
'op
)
1718 (coerce (string* op
) 'string
))))
1719 (putprop op dummy
'op
)
1721 (if (and (operatorp1 op
) (not (member dummy
(cdr $props
) :test
#'eq
)))
1722 (push dummy
*mopl
*))
1723 (add2lnc dummy $props
)))
1725 (defun kill-operator (op)
1728 (noun-form ($nounify op
)))
1729 ;; Refuse to kill an operator which appears on *BUILTIN-$PROPS*.
1730 (unless (member opr
*builtin-$props
* :test
#'equal
)
1731 (undefine-symbol opr
)
1734 (mapc #'(lambda (x) (remprop op x
))
1735 '(nud nud-expr nud-subr
; NUD info
1736 led led-expr led-subr
; LED info
1737 lbp rbp
; Binding power info
1738 lpos rpos pos
; Part-Of-Speech info
1739 grind dimension dissym
; Display info
1740 op
)) ; Operator info
1741 (mapc #'(lambda (x) (remprop noun-form x
))
1742 '(dimension dissym lbp rbp
)))))
1746 ;; the functions get-instream etc.. are all defined in
1747 ;; gcl lsp/debug.lsp
1748 ;; they are all generic common lisp and could be used by
1749 ;; any Common lisp implementation.
1754 (line 0 :type fixnum
)
1758 (defvar *stream-alist
* nil
)
1761 (defun stream-name (path)
1763 (car (errset (namestring (pathname path
))))))
1766 (defun instream-name (instr)
1767 (or (instream-stream-name instr
)
1768 (stream-name (instream-stream instr
))))
1770 ;; (closedp stream) checks if a stream is closed.
1771 ;; how to do this in common lisp!!
1775 #+never-clean-up-dont-know-how-to-close
1776 (dolist (v *stream-alist
*)
1777 (if (closedp (instream-stream v
))
1778 (setq *stream-alist
* (delete v
*stream-alist
*)))))
1781 (defun get-instream (str)
1782 (or (dolist (v *stream-alist
*)
1783 (cond ((eq str
(instream-stream v
))
1786 (errset (setq name
(namestring str
)))
1787 (car (setq *stream-alist
*
1788 (cons (make-instream :stream str
:stream-name name
)
1789 *stream-alist
*))))))
1791 (defun newline (str)
1792 (incf (instream-line (get-instream str
)))
1795 (defun find-stream (stream)
1796 (dolist (v *stream-alist
*)
1797 (cond ((eq stream
(instream-stream v
))
1801 (defun add-lineinfo (lis)
1803 (eq *parse-stream
* *parse-string-input-stream
*) ;; avoid consing *parse-string-input-stream*
1804 ;; via get-instream to *stream-alist*
1805 (and (eq *parse-window
* *standard-input
*)
1806 (not (find-stream *parse-stream
*)) ))
1808 (let* ((st (get-instream *parse-stream
*))
1809 (n (instream-line st
))
1810 (nam (instream-name st
)))
1811 (or nam
(return-from add-lineinfo lis
))
1812 (setq *current-line-info
*
1813 (cond ((eq (cadr *current-line-info
*) nam
)
1814 (cond ((eql (car *current-line-info
*) n
)
1815 *current-line-info
*)
1816 (t (cons n
(cdr *current-line-info
*)))))
1817 (t (list n nam
'src
))))
1818 (cond ((null (cdr lis
))
1819 (list (car lis
) *current-line-info
*))
1820 (t (append lis
(list *current-line-info
*)))))))
1822 ;; Remove debugging stuff.
1823 ;; STRIP-LINEINFO does not modify EXPR.
1825 (defun strip-lineinfo (expr)
1826 (if (or (atom expr
) (specrepp expr
))
1828 (cons (strip-lineinfo-op (car expr
)) (mapcar #'strip-lineinfo
(cdr expr
)))))
1830 ;; If something in the operator looks like debugging stuff, remove it.
1831 ;; It is assumed here that debugging stuff is a list comprising an integer and a string
1832 ;; (and maybe other stuff, which is ignored).
1834 (defun strip-lineinfo-op (maxima-op)
1835 (remove-if #'(lambda (x) (and (consp x
) (integerp (first x
)) (stringp (second x
)))) maxima-op
))