| [4005] | 1 | ;;; -*- Mode: Lisp -*-
 | 
|---|
| [642] | 2 | #|
 | 
|---|
 | 3 |   *--------------------------------------------------------------------------*
 | 
|---|
 | 4 |   |  Copyright (C) 1994, Marek Rychlik (e-mail: rychlik@math.arizona.edu)    |
 | 
|---|
 | 5 |   |    Department of Mathematics, University of Arizona, Tucson, AZ 85721    |
 | 
|---|
 | 6 |   |                                                                          |
 | 
|---|
 | 7 |   | Everyone is permitted to copy, distribute and modify the code in this    |
 | 
|---|
 | 8 |   | directory, as long as this copyright note is preserved verbatim.         |
 | 
|---|
 | 9 |   *--------------------------------------------------------------------------*
 | 
|---|
 | 10 | |#
 | 
|---|
 | 11 | 
 | 
|---|
 | 12 | (defpackage "INFIX-PRINTER"
 | 
|---|
 | 13 |   (:use "COMMON-LISP"
 | 
|---|
 | 14 |         "INFIX"                         ;for operator-lessp
 | 
|---|
 | 15 |         )
 | 
|---|
| [685] | 16 |   (:export infix-print infix-print-to-string infix-print-to-stream))
 | 
|---|
| [642] | 17 | 
 | 
|---|
 | 18 | (in-package "INFIX-PRINTER")
 | 
|---|
 | 19 | 
 | 
|---|
 | 20 | (proclaim '(optimize (speed 0) (space 0) (safety 3) (debug 3)))
 | 
|---|
 | 21 | 
 | 
|---|
 | 22 | (defun infix-print-separated-list (lst sep stream op print-level
 | 
|---|
| [4413] | 23 |                                    &optional 
 | 
|---|
 | 24 |                                      (alt-op nil) 
 | 
|---|
 | 25 |                                      (alt-sep alt-op)
 | 
|---|
| [642] | 26 |                                    &aux
 | 
|---|
| [4412] | 27 |                                      (beg t)
 | 
|---|
 | 28 |                                      (count 0)
 | 
|---|
 | 29 |                                      true-sep)
 | 
|---|
| [4414] | 30 |   "Print a list LST using SEP as separator, to stream STREAM. Every
 | 
|---|
 | 31 | argument is printed usin OP as main operator. PRINT-LEVEL is used to
 | 
|---|
 | 32 | control printing nested expressions as expected: subexpressions at
 | 
|---|
 | 33 | level exceeding PRINT-LEVEL are printed as ellipsis. The argument BEG
 | 
|---|
 | 34 | indicates whether this is the start of a sequence of arguments with
 | 
|---|
 | 35 | the main operator OP.  The argument ALT-OP, if not NIL, replaces
 | 
|---|
 | 36 | operator OP for list elements beyond the first one. Similarly, ALT-SEP
 | 
|---|
 | 37 | replaces SEP for list elements beyond the first one."
 | 
|---|
| [4403] | 38 | 
 | 
|---|
| [642] | 39 |   (cond
 | 
|---|
 | 40 |    ((endp lst) nil)
 | 
|---|
 | 41 | 
 | 
|---|
 | 42 |    ;; Handle *print-level* 
 | 
|---|
 | 43 |    ((and (numberp *print-level*)
 | 
|---|
 | 44 |          (> print-level *print-level*))
 | 
|---|
 | 45 |     (format stream "#"))
 | 
|---|
 | 46 | 
 | 
|---|
 | 47 |    (t
 | 
|---|
 | 48 |     (dolist (arg lst)
 | 
|---|
| [4420] | 49 | 
 | 
|---|
| [4401] | 50 |       ;;(format t "Processing arg: ~S~%" arg)
 | 
|---|
| [4420] | 51 |       (setf true-sep sep)
 | 
|---|
| [4412] | 52 | 
 | 
|---|
| [642] | 53 |       (incf count)
 | 
|---|
| [4412] | 54 |           
 | 
|---|
| [4418] | 55 |       ;; The following code handles unary minus
 | 
|---|
| [4409] | 56 |       ;; Thus:
 | 
|---|
 | 57 |       ;; (+ x (- y z)) --> X + Y - Z
 | 
|---|
 | 58 |       ;; (+ x (- y)) --> X - Y
 | 
|---|
| [642] | 59 |       (when (and alt-op
 | 
|---|
 | 60 |                  (> count 1)
 | 
|---|
 | 61 |                  (consp arg)
 | 
|---|
| [4408] | 62 |                  (endp (cddr arg))
 | 
|---|
| [642] | 63 |                  (eq alt-op (car arg)))
 | 
|---|
| [4418] | 64 |         (psetf arg     (cadr arg) 
 | 
|---|
 | 65 |                alt-sep nil)
 | 
|---|
 | 66 |         ;;(format t "Arg changed: ~S, true-sep: ~S~%" arg true-sep)
 | 
|---|
| [4403] | 67 |         )
 | 
|---|
| [4402] | 68 | 
 | 
|---|
| [4408] | 69 | 
 | 
|---|
| [4415] | 70 |       (cond
 | 
|---|
 | 71 |         (beg 
 | 
|---|
 | 72 |          (setf beg nil))
 | 
|---|
 | 73 |         (t 
 | 
|---|
 | 74 |          (format stream "~a" true-sep)))
 | 
|---|
| [642] | 75 |       
 | 
|---|
 | 76 |       ;; If *print-length* exceeded, print ellipsis
 | 
|---|
 | 77 |       (when (and (numberp *print-length*) (> count *print-length*))
 | 
|---|
 | 78 |         (format stream "...")
 | 
|---|
 | 79 |         (return-from infix-print-separated-list (values)))
 | 
|---|
 | 80 |       
 | 
|---|
| [4421] | 81 |       (infix-print-to-stream arg stream op print-level)
 | 
|---|
 | 82 | 
 | 
|---|
 | 83 |       )))
 | 
|---|
| [642] | 84 |   (values))
 | 
|---|
 | 85 | 
 | 
|---|
 | 86 | (defun infix-print-arg-list (lst stream print-level)
 | 
|---|
 | 87 |   "Print a comma-separated list."
 | 
|---|
 | 88 |   (infix-print-separated-list lst '\, stream '\, print-level))
 | 
|---|
 | 89 | 
 | 
|---|
| [681] | 90 | (defun infix-print-to-stream (expr &optional (stream t) (op nil) (print-level 0))
 | 
|---|
| [642] | 91 |   "Print an expression EXPR in infix notation to stream STREAM.
 | 
|---|
 | 92 | If OP is not nil, the expression is parenthesized if its operator
 | 
|---|
| [683] | 93 | has lower precedence than OP. Returns (VALUES)." 
 | 
|---|
| [642] | 94 |   (cond 
 | 
|---|
 | 95 |     ;; Handle *print-level*
 | 
|---|
| [4405] | 96 |     ((and (numberp *print-level*)
 | 
|---|
 | 97 |           (> print-level *print-level*))
 | 
|---|
 | 98 |      (format stream "#"))
 | 
|---|
| [642] | 99 | 
 | 
|---|
| [4405] | 100 |     ;; Null expression is an error
 | 
|---|
 | 101 |     ((null expr)
 | 
|---|
 | 102 |      (error "Null expression."))
 | 
|---|
| [642] | 103 | 
 | 
|---|
| [4405] | 104 |     ;; Atoms are printed using ~A format directive
 | 
|---|
 | 105 |     ((atom expr)
 | 
|---|
 | 106 |      (format stream "~a" expr))
 | 
|---|
| [642] | 107 |    
 | 
|---|
| [4405] | 108 |     ;; Check if the operator of this expression has lower precedence
 | 
|---|
 | 109 |     ;; than the surrounding operator, and parenthesize if necessary
 | 
|---|
 | 110 |     ((and op 
 | 
|---|
 | 111 |           (operator-lessp (car expr) op))
 | 
|---|
 | 112 |      (format stream "(")
 | 
|---|
 | 113 |      (infix-print expr stream nil (1+ print-level))
 | 
|---|
 | 114 |      (format stream ")"))
 | 
|---|
| [642] | 115 | 
 | 
|---|
| [4405] | 116 |     ;; Unary minus needs special handling
 | 
|---|
 | 117 |     ((and (eq (car expr) '-) (endp (cddr expr)))
 | 
|---|
 | 118 |      (format stream "-")
 | 
|---|
| [4415] | 119 | 
 | 
|---|
| [4405] | 120 |      ;; Print the second element in product context
 | 
|---|
 | 121 |      (infix-print (cadr expr) stream '* (1+ print-level)))
 | 
|---|
| [642] | 122 | 
 | 
|---|
| [4405] | 123 |     ;; All other operators
 | 
|---|
 | 124 |     (t 
 | 
|---|
 | 125 |      (case (car expr)
 | 
|---|
| [642] | 126 | 
 | 
|---|
| [4405] | 127 |        ;; Arithmetic operators
 | 
|---|
 | 128 |        ((+ - * /)
 | 
|---|
 | 129 |         (infix-print-separated-list
 | 
|---|
 | 130 |          (cdr expr)                     
 | 
|---|
 | 131 |          (car expr)                     
 | 
|---|
 | 132 |          stream
 | 
|---|
 | 133 |          (car expr)                     
 | 
|---|
 | 134 |          (1+ print-level)               
 | 
|---|
 | 135 |          (cond ((eq (car expr) '+) '-)
 | 
|---|
 | 136 |                ((eq (car expr) '-) '-)
 | 
|---|
| [4417] | 137 |                ((eq (car expr) '*) '/)
 | 
|---|
 | 138 |                ((eq (car expr) '/) '/)
 | 
|---|
| [4405] | 139 |                (t nil))))
 | 
|---|
| [642] | 140 | 
 | 
|---|
| [4405] | 141 |        ;; Exponentials
 | 
|---|
 | 142 |        (expt
 | 
|---|
 | 143 |         (unless (= (length (cdr expr)) 2)
 | 
|---|
 | 144 |           (error "expt must take 2 arguments."))
 | 
|---|
 | 145 |         (infix-print-separated-list
 | 
|---|
 | 146 |          (cdr expr)
 | 
|---|
 | 147 |          '^
 | 
|---|
 | 148 |          stream
 | 
|---|
 | 149 |          '^
 | 
|---|
 | 150 |          (1+ print-level)))
 | 
|---|
| [642] | 151 | 
 | 
|---|
| [4405] | 152 |        ;; Assuming function call
 | 
|---|
 | 153 |        (otherwise               
 | 
|---|
 | 154 |         (cond
 | 
|---|
| [4400] | 155 | 
 | 
|---|
| [4405] | 156 |           ;; Handle array references
 | 
|---|
 | 157 |           ((eq (car expr) 'aref)
 | 
|---|
 | 158 |            ;; Special syntax for subscripted variables
 | 
|---|
 | 159 |            ;; consistent with the infix package.
 | 
|---|
 | 160 |            (format stream "~a[" (cadr expr))
 | 
|---|
 | 161 |            (infix-print-separated-list (cddr expr) '\, stream '\, (1+ print-level))
 | 
|---|
 | 162 |            (format stream "]"))
 | 
|---|
| [4400] | 163 | 
 | 
|---|
| [4405] | 164 |           ;; Handle lists
 | 
|---|
 | 165 |           ((and (symbolp (car expr))
 | 
|---|
 | 166 |                 (string= (symbol-name (car expr)) "["))
 | 
|---|
 | 167 |            (format stream "[")
 | 
|---|
 | 168 |            (infix-print-separated-list (cdr expr) '\, stream '\, (1+ print-level))
 | 
|---|
 | 169 |            (format stream "]"))
 | 
|---|
| [4400] | 170 | 
 | 
|---|
| [4405] | 171 |           ;; Handle generic function call syntax
 | 
|---|
 | 172 |           (t
 | 
|---|
 | 173 |            (format stream "~a(" (car expr))
 | 
|---|
 | 174 |            (infix-print-arg-list (cdr expr) stream (1+ print-level))
 | 
|---|
 | 175 |            (format stream ")")))))))
 | 
|---|
| [642] | 176 |   (values))
 | 
|---|
| [678] | 177 | 
 | 
|---|
| [680] | 178 | (defun infix-print-to-string (expr &optional (op nil) (print-level 0)
 | 
|---|
 | 179 |                               &aux (fstr (make-array '(0) :element-type 'base-char
 | 
|---|
 | 180 |                                                      :fill-pointer 0 :adjustable t)))
 | 
|---|
| [692] | 181 |   "Print an expression EXPR in infix notation to a string.  If OP is
 | 
|---|
 | 182 | not nil, the expression is parenthesized if its operator has lower
 | 
|---|
 | 183 | precedence than OP. Returns the string containing the printed
 | 
|---|
 | 184 | expression."
 | 
|---|
| [678] | 185 |   (with-output-to-string (s fstr)
 | 
|---|
| [682] | 186 |     (infix-print-to-stream expr s op print-level))
 | 
|---|
| [678] | 187 |   fstr)
 | 
|---|
| [681] | 188 | 
 | 
|---|
 | 189 | (defun infix-print (expr &optional (stream t) (op nil) (print-level 0))
 | 
|---|
| [688] | 190 |   "Print an expression EXPR in infix notation to stream STREAM or to
 | 
|---|
 | 191 | string if (NULL STREAM).  If OP is not nil, the expression is
 | 
|---|
 | 192 | parenthesized if its operator has lower precedence than OP. Returns
 | 
|---|
| [690] | 193 | the string containing the printed expression, or (VALUES) if (NULL
 | 
|---|
 | 194 | STREAM) is true."
 | 
|---|
| [682] | 195 |   (cond 
 | 
|---|
 | 196 |     ((null stream)
 | 
|---|
 | 197 |      (infix-print-to-string expr op print-level))
 | 
|---|
| [686] | 198 |     (t (infix-print-to-stream expr stream op print-level))))
 | 
|---|