Skip to main content

with-standard-io-syntax

with-standard-io-syntax Macro

Syntax:

with-standard-io-syntax {form}* → {result}*

Arguments and Values:

forms—an implicit progn.

results—the values returned by the forms.

Description:

Within the dynamic extent of the body of forms, all reader/printer control variables, including any implementation-defined ones not specified by this standard, are bound to values that produce standard read/print behavior. The values for the variables specified by this standard are listed in Figure 23–1.

|Variable Value|

| :- |

|

*package* The CL-USER package

*print-array* t

*print-base* 10

*print-case* :upcase

*print-circle* nil

*print-escape* t

*print-gensym* t

*print-length* nil

*print-level* nil

*print-lines* nil

*print-miser-width* nil

*print-pprint-dispatch* The standard pprint dispatch table *print-pretty* nil

*print-radix* nil

*print-readably* t

*print-right-margin* nil

*read-base* 10

*read-default-float-format* single-float

*read-eval* t

*read-suppress* nil

*readtable* The standard readtable

|

Figure 23–1. Values of standard control variables

Examples:

 
(with-open-file (file pathname :direction :output)
(with-standard-io-syntax
(print data file)))
;;; ... Later, in another Lisp:
(with-open-file (file pathname :direction :input)
(with-standard-io-syntax
(setq data (read file))))


*∗***read-base***∗ Variable*

Value Type:

a radix .

Initial Value:

10.

Description:

Controls the interpretation of tokens by read as being integers or ratios.

The value of *read-base*, called the current input base, is the radix in which integers and ratios are to be read by the Lisp reader . The parsing of other numeric types (e.g., floats) is not affected by this option.

The effect of *read-base* on the reading of any particular rational number can be locally overridden by explicit use of the #O, #X, #B, or #nR syntax or by a trailing decimal point.

Examples:

(dotimes (i 6) 
(let ((\*read-base\* (+ 10. i)))
(let ((object (read-from-string "(\\DAD DAD |BEE| BEE 123. 123)")))
(print (list \*read-base\* object)))))
(10 (DAD DAD BEE BEE 123 123))
(11 (DAD DAD BEE BEE 123 146))
(12 (DAD DAD BEE BEE 123 171))
(13 (DAD DAD BEE BEE 123 198))
(14 (DAD 2701 BEE BEE 123 227))
(15 (DAD 3088 BEE 2699 123 258))
→ NIL

Notes:

Altering the input radix can be useful when reading data files in special formats.

Expanded Reference: with-standard-io-syntax

Basic usage

with-standard-io-syntax establishes a dynamic environment where all reader and printer control variables are bound to their standard values. This guarantees portable, reproducible read/print behavior.

(with-standard-io-syntax
(list *read-base*
*read-default-float-format*
*read-eval*
*read-suppress*
*print-base*
*print-case*))
=> (10 SINGLE-FLOAT T NIL 10 :UPCASE)

Ensuring round-trip consistency for data serialization

The primary use case is to ensure that objects printed under standard syntax can be read back reliably, even if the surrounding environment has customized reader/printer settings.

;; Even with a modified environment, with-standard-io-syntax
;; ensures standard behavior for serialization
(let ((*print-base* 16)
(*read-base* 16))
(with-standard-io-syntax
(let ((str (prin1-to-string 255)))
(list str (read-from-string str)))))
=> ("255" 255)

Writing and reading data files

A common pattern is to use with-standard-io-syntax when writing data to a file and reading it back, ensuring the data survives across different Lisp sessions with potentially different settings.

;; Writing data
;; (with-open-file (out pathname :direction :output)
;; (with-standard-io-syntax
;; (print data out)))

;; Reading data back
;; (with-open-file (in pathname :direction :input)
;; (with-standard-io-syntax
;; (setq data (read in))))

;; Simulated with string streams:
(let ((data '(hello 42 "world" 3.14)))
(let ((str (with-standard-io-syntax
(prin1-to-string data))))
(with-standard-io-syntax
(read-from-string str))))
=> (HELLO 42 "world" 3.14)
=> 62

The readtable is bound to the standard readtable

Inside with-standard-io-syntax, *readtable* is bound to the standard readtable, so any custom reader macros in effect outside the form are not active.

(let ((*readtable* (copy-readtable)))
(set-macro-character #\!
(lambda (s c) (declare (ignore s c)) 'bang))
;; Inside with-standard-io-syntax, ! is a normal constituent
(with-standard-io-syntax
(with-input-from-string (s "!test")
(symbol-name (read s)))))
=> "!TEST"

Package is bound to CL-USER

Inside the form, *package* is bound to the CL-USER package.

(in-package :cl-user)
(with-standard-io-syntax
(package-name *package*))
=> "COMMON-LISP-USER"