Stream 在公共lisp中更改默认读取器

Stream 在公共lisp中更改默认读取器,stream,common-lisp,reader,reader-macro,Stream,Common Lisp,Reader,Reader Macro,我编写了一些函数,可以替换common lisp的函数read (defun my-read (stream &rest args) (declare (ignore args)) (funcall (my-get-macro-character (read-char stream)))) 有没有办法将此函数用作默认读卡器?您不能重新定义内置函数1,但您可以定义一个包,该包隐藏了cl:read,并定义了一个新函数my:read,因此当您使用该包时,它看起来像是默认的read函数

我编写了一些函数,可以替换common lisp的函数
read

(defun my-read (stream &rest args)
  (declare (ignore args))
  (funcall (my-get-macro-character (read-char stream))))

有没有办法将此函数用作默认读卡器?

您不能重新定义内置函数1,但您可以定义一个包,该包隐藏了cl:read,并定义了一个新函数my:read,因此当您使用该包时,它看起来像是默认的read函数。例如,类似这样的事情:

CL-USER> (defpackage #:my-package 
           (:use "COMMON-LISP")
           (:shadow #:read)
           (:export #:read))
;=> #<PACKAGE "MY-PACKAGE">

CL-USER> (defun my-package:read (&rest args)
           (declare (ignore args))
           42)
;=> MY-PACKAGE:READ

CL-USER> (defpackage #:another-package
           (:use #:my-package "COMMON-LISP")
           (:shadowing-import-from #:my-package #:read))
;=> #<PACKAGE "ANOTHER-PACKAGE">

CL-USER> (in-package #:another-package)
;=> #<PACKAGE "ANOTHER-PACKAGE">

ANOTHER-PACKAGE> (read)
;=> 42
(defun replace-default-read-behavior (rt fn)
  (loop for c across 
        " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
        do (set-macro-character c fn t rt)))

(defun my-parser (stream char)
  (format t "custom read: ~A~A" char (read-line stream)))

(defun my-get-macro-character (char)
  (declare (ignore char))
  #'my-parser)

(defun my-read (stream char)
  (funcall (my-get-macro-character char) stream char))

(defvar *my-readtable* (copy-readtable ()))

(replace-default-read-behavior *my-readtable* #'my-read)

(let ((*readtable* *my-readtable*))
  (read-from-string "foo"))
custom read: foo  ; printed
NIL               ; returned
3
CL-USER>(defpackage#:我的包
(:使用“COMMON-LISP”)
(:阴影#:读取)
(:导出#:读取))
;=> #
CL-USER>(卸载我的包:读取(&rest参数)
(声明(忽略args))
42)
;=> MY-PACKAGE:阅读
CL-USER>(defpackage#):另一个包
(:use#:我的包“COMMON-LISP”)
(:阴影从#:我的包#:读取导入))
;=> #
CL-USER>(包中#:另一个包)
;=> #
另一个软件包>(已读)
;=> 42

  • 实际上,正如在注释中一样,尽管它是未定义的行为(请参阅),但通常有一些方法可以重新定义一些常见的Lisp函数,例如,在SBCL中,您可以使用解锁软件包,如中所示。CLISP有。其他实现可能具有类似的功能

  • 一种方法是对可读表中的所有“有效”输入字符使用
    设置宏字符。(如果您只接受ASCII输入,这是可以的,但我不知道它是否适用于完整的Unicode。)

    大概是这样的:

    CL-USER> (defpackage #:my-package 
               (:use "COMMON-LISP")
               (:shadow #:read)
               (:export #:read))
    ;=> #<PACKAGE "MY-PACKAGE">
    
    CL-USER> (defun my-package:read (&rest args)
               (declare (ignore args))
               42)
    ;=> MY-PACKAGE:READ
    
    CL-USER> (defpackage #:another-package
               (:use #:my-package "COMMON-LISP")
               (:shadowing-import-from #:my-package #:read))
    ;=> #<PACKAGE "ANOTHER-PACKAGE">
    
    CL-USER> (in-package #:another-package)
    ;=> #<PACKAGE "ANOTHER-PACKAGE">
    
    ANOTHER-PACKAGE> (read)
    ;=> 42
    
    (defun replace-default-read-behavior (rt fn)
      (loop for c across 
            " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
            do (set-macro-character c fn t rt)))
    
    (defun my-parser (stream char)
      (format t "custom read: ~A~A" char (read-line stream)))
    
    (defun my-get-macro-character (char)
      (declare (ignore char))
      #'my-parser)
    
    (defun my-read (stream char)
      (funcall (my-get-macro-character char) stream char))
    
    (defvar *my-readtable* (copy-readtable ()))
    
    (replace-default-read-behavior *my-readtable* #'my-read)
    
    (let ((*readtable* *my-readtable*))
      (read-from-string "foo"))
    custom read: foo  ; printed
    NIL               ; returned
    3
    
    (取消替换默认读取行为(rt fn)
    (c的循环
    “!\”——/0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^`ABCDEFGHIJKLMNOPQRSTUVWXYZ{124;}”
    do(设置宏字符c fn t rt)))
    (卸载我的解析器(流字符)
    (格式t“自定义读取:~A~A”字符(读取行流)))
    (取消我的get宏字符(字符)
    (声明(忽略字符))
    #'我的解析器)
    (取消我的读取(流字符)
    (funcall(我的获取宏字符字符)stream char)
    (defvar*my readtable*(copy readtable()))
    (替换默认读取行为*my readtable*#'my-read)
    (让((*可读表**我的可读表*)
    (从字符串“foo”读取)
    自定义阅读:foo;打印
    零;返回
    3.
    
    请注意,标准不允许重新定义标准函数,但许多/大多数实际实现都有一种特定于实现的方法来重新定义标准函数。这对于更改默认读取器以读取主file@cl-porky11我不知道你说的“主文件”到底是什么意思“。如果您在某个地方有这样的定义,那么您需要做的就是在该文件的顶部添加
    (在package#:my package中)
    。我也考虑过这个解决方案,但它不适用于非标准字符,在某些情况下可能会出现问题。”。(你忘了字符串中的新行)@cl-porky11同意。最坏的情况是,意外的字符可能会导致您的程序在静默状态下出现错误。如果您调整
    my read
    以接收整个输入,您可以放宽要求,即输入的第一个字符必须是您期望的字符。这仍然不能令人满意,但我不知道有什么更好的方法可以做到。简短的回答:不,至少不能随身携带。诸如
    load
    compile file
    之类的操作可能会使读取器内联,或者它们可能引用内部读取器定义,例如,绕过可选/关键参数处理开销。