(defvar *digits* '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\. #\/))
(defun read-rational (stream char)
"read all decimals as rationals"
(let ((this-char nil)
(result (position char *digits*))
(n 0)
(position-of-dot nil)
(position-of-slash nil))
(loop while (member (peek-char nil stream) *digits*) do
(setf this-char (read-char stream))
(cond ((eql this-char #\.)
(setf position-of-dot n))
((eql this-char #\/)
(setf position-of-slash n))
(t
(setf result (+ (* 10 result) (position this-char *digits*)))))
(incf n))
(cond ((and position-of-dot position-of-slash)
(error "Cannot read number with both . and / characters in it"))
(position-of-dot
(/ result (expt 10 (- n position-of-dot 1))))
(position-of-slash
(multiple-value-bind (x y) (truncate result (expt 10 (- n position-of-slash 1)))
(/ x y)))
(t
result))))
(mapcar (lambda (c)
(set-macro-character c #'read-rational))
(remove #\/ (remove #\. *digits*)))