Advertisement
Guest User

Untitled

a guest
Aug 19th, 2017
463
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 5.35 KB | None | 0 0
  1. ;;;
  2. ;;; #"-reader - read in extended C style strings using #"..."# read-macro
  3. ;;;
  4. ;;; This code allows you to enter extended C style strings with escape
  5. ;;; sequences, such as:
  6. ;;;
  7. ;;; #"Hello,\tWorld\n"#
  8. ;;;
  9. ;;; Supported are \a, \b, \f, \r, \n, \v, \nnn (up to 3 digits) and
  10. ;;; \xn... (unlimited length until non-hex char) escapes.  
  11. ;;;
  12. ;;; Adds \d (decimal), \B (binary) and \o (octal) formatters of
  13. ;;; unspecified length (use non-base char or "" to terminate sequence
  14. ;;; if needed, ie.  #"\B11100abc" or #"\xabc""def"#).
  15. ;;;
  16. ;;; Allowed are C style string concatenation using ".*".  In between the ""
  17. ;;; characters you can have:
  18. ;;; - any non-visible char (whitespace, newlines, etc)
  19. ;;; - line comments starting with a ;
  20. ;;; - block comments enclosed in #| |#
  21. ;;; - expressions, which are evaluated and their string represenation
  22. ;;;   is embdded in the output string (like CL-INTERPOL)
  23. ;;;
  24. ;;; For example:
  25. ;;;
  26. ;;; * (defun x () "the value of x")
  27. ;;; * #"abc| " (x) #| call x |# " |def"#
  28. ;;; "abc| the value of x |def"
  29. ;;; * (defparameter y "the value of y")
  30. ;;; * #"abc| "y" |def"#
  31. ;;; "abc| the value of y |def"
  32. ;;;
  33. ;;; The read macro number paramter is used to set the initial buffer size
  34. ;;; and expansion parameter (default 16 characters).  For example:
  35. ;;;
  36. ;;; * #1024"output: " (a-function-that-returns-a-really-long-string) #"
  37. ;;;
  38. ;;; This will initially allocate 1024 chars for the internal string
  39. ;;; buffer, and then when this is filled, will allocate another 1024
  40. ;;; chars, etc, etc.  This saves on reallocations for long strings but
  41. ;;; otherwise does not affect operation.
  42. ;;;
  43. ;;; Bugs:
  44. ;;; - doesn't like you to use macro characters in between " characters
  45. ;;; - tested on SBCL 1.0.47, doesn't work with clisp yet
  46. ;;;
  47. ;;; Author: Burton Samograd <kruhft@gmail.com>
  48. ;;; Date: May 22, 2011
  49. ;;; License: Public Domain
  50.  
  51. (defun |#"-reader| (stream subchar arg)
  52.  (declare (ignore subchar))
  53.  (let* ((sb-size (if arg arg 16))
  54.      (sb (make-array sb-size
  55.             :element-type 'standard-char
  56.             :adjustable t
  57.             :fill-pointer 0))
  58.     (chars nil))
  59.    (catch 'end-of-string
  60.      (do ((c (read-char stream) (read-char stream)))
  61.       (nil) ; loop until return
  62.     (if (char= c #\")
  63.         ;; we saw a ", so deal with reading whitespace, comments and expressions
  64.         (do ((c2 (peek-char nil stream) (peek-char nil stream)))
  65.         (nil) ; loop until return
  66.           (case c2
  67.         ((#\  #\Tab #\Newline #\Return #\Bel #\Backspace #\Page #\Vt) ; invisible char
  68.          (read-char))
  69.         (#\; (read-char stream) ; read ; line comment
  70.              (do ((c3 (read-char stream) (read-char stream)))
  71.              ((char= c3 #\Newline))))
  72.         (#\# (read-char stream)
  73.              (if (char= (peek-char nil stream) #\|)
  74.              ; read #| |# comment
  75.              (progn
  76.                (read-char stream)
  77.                (do ((c3 (read-char stream) (read-char stream)))
  78.                    (nil)
  79.                  (if (char= c3 #\|)
  80.                  (let ((c4 (peek-char nil stream)))
  81.                    (when (char= c4 #\#)
  82.                        (read-char stream)
  83.                        (return))))))
  84.              (throw 'end-of-string nil))) ; found end maker "#
  85.         (#\" (read-char stream) ; found next "
  86.              (setq c (read-char stream))
  87.              (return))
  88.         (otherwise
  89.          ;; found expression in the middle of "" sequence
  90.          ;; find textual representation and put it in the buffer
  91.          (map nil (lambda (c) (vector-push-extend c sb sb-size))
  92.               (format nil "~A" (eval (read stream))))))))
  93.     (if (char= c #\\) ; if we see a \ escaped char
  94.         (progn
  95.           (let ((c2 (read-char stream)))
  96.         (labels ((read-upto-n-char-radix-stream (stream radix &optional (max-digits -1))
  97.                ;; read in up to max-digit string of radix, or unlimited digits
  98.                ;; up to non-base character if max-digits is not specified
  99.                (let ((str (let (l)
  100.                     (do ((c (read-char stream) (read-char stream)))
  101.                         ((handler-case (parse-integer
  102.                                 (coerce `(,c) 'string)
  103.                                 :radix radix)
  104.                            (parse-error ()
  105.                          (unread-char c)
  106.                          t)
  107.                            (:no-error (a b)
  108.                          (declare (ignore a b))
  109.                          nil)))
  110.                       (push c l)
  111.                       (if (= (length l) max-digits)
  112.                           (return)))
  113.                     (coerce (nreverse l) 'string))))
  114.                  ; parse resulting string and return value
  115.                  (handler-case (parse-integer str :radix radix)
  116.                    (parse-error ()
  117.                  (error (format nil "#\"-reader: no digit characters after escape sequence for base ~A" radix)))))))
  118.           (setq c2 (case c2 ; convert escaped char or escape sequence
  119.                  (#\a #\Bel)
  120.                  (#\b #\Backspace)
  121.                  (#\f #\Page)
  122.                  (#\n #\Newline)
  123.                  (#\r #\Return)
  124.                  (#\t #\Tab)
  125.                  (#\v #\Vt)
  126.                  (#\B (code-char (read-upto-n-char-radix-stream stream 2)))
  127.                  (#\o (code-char (read-upto-n-char-radix-stream stream 8)))
  128.                  (#\d (code-char (read-upto-n-char-radix-stream stream 10)))
  129.                  (#\x (code-char (read-upto-n-char-radix-stream stream 16)))
  130.                  ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7) ; octal
  131.                   (unread-char c2)
  132.                   (code-char (read-upto-n-char-radix-stream stream 8 3)))
  133.                  (otherwise c2)))
  134.           (push c2 chars) ; save char
  135.           (vector-push-extend #\~ sb sb-size) ; add ~C to format specifier string
  136.           (vector-push-extend #\C sb sb-size))))
  137.         (vector-push-extend c sb sb-size)))) ; normal char, just add to string
  138.       (if chars
  139.       (apply #'format (append (list nil sb) (nreverse chars)))
  140.       sb)))
  141.  
  142. (set-dispatch-macro-character #\# #\" #'|#"-reader|)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement