4

I wrote some function that could replace the function read of common lisp

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

Is there a way to use this function as default reader?

1
  • 1
    Short answer: no, at least not portably. Things like load or compile-file might have the reader inlined, or they might refer to internal reader definitions, e.g. to bypass the optional/key argument handling overhead. Commented Jun 30, 2015 at 14:09

2 Answers 2

5

You can't redefine the built in functions1, but you can define a package that shadows cl:read and defines a new function my:read, so that when you use that package, it looks like it's the default read function. E.g., something like this:

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 

  1. Actually, as Rainer Joswig noted in the comments, even though it's undefined behavior (see 11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming Programs), there often are ways to redefine some of the Common Lisp function, For instance, in SBCL you can use unlock-package, as shown in redefining built-in function. CLISP has package locks. Other implementations may have similar functionality.
Sign up to request clarification or add additional context in comments.

3 Comments

Note that the standard does not allow to redefine standard functions, but many/most actual implementations have an implementation specific way to do so.
That is not useful to change default reader for reading the main file
@cl-porky11 I'm not sure exactly what you mean by "the main file". If you have a definition like this somewhere, then all you'd need to do is (in-package #:my-package) at the top of that file.
4

One approach is to use set-macro-character on all "valid" input characters in a readtable. (This is okay if you only accept ASCII input, but I don't know if it would be practical for full Unicode.)

Something like this:

(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 

2 Comments

I also thought about this solution, but it won't work for non-standard-characters, what might be a problem in some cases. (you forgot #\Newline in the string)
@cl-porky11 agreed. Worst case, unexpected characters could cause your program to silently misbehave. If you adjust my-read to ingest the entire input you can loosen the requirement to say just the first character of input has to be one you expect. That's still not satisfying, but I don't know of a better way to do it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.