IO.html -- ACL2 Version 6.3

# IO

input/output facilities in ACL2

    Major Section:  ACL2 Documentation

    Example:
    (mv-let
      (channel state)
      (open-input-channel "foo.lisp" :object state)
      (mv-let (eofp obj state)
              (read-object channel state)
              (.
                .
                 (let ((state (close-input-channel channel state)))
                       (mv final-ans state))..)))

Also see file-reading-example.

For advanced ways to control printing, see print-control.

For a discussion of formatted printing, see fmt.

To control ACL2 abbreviation (``evisceration'') of objects before printing them, see set-evisc-tuple, see without-evisc, and see set-iprint.

To redirect output to a file, see output-to-file.

## Some Related Topics

- ### *STANDARD-CI* -- an ACL2 character-based analogue of CLTL's `*standard-input*`

- ### *STANDARD-CO* -- the ACL2 analogue of CLTL's `*standard-output*`

- ### *STANDARD-OI* -- an ACL2 object-based analogue of CLTL's `*standard-input*`

- ### CHARACTER-ENCODING -- how bytes are parsed into characters

- ### EVISC-TUPLE -- control suppression of details when printing

- ### EVISCERATE-HIDE-TERMS -- to print `(hide ...)` as `<hidden>`

- ### EXTERNAL-FORMAT -- See character-encoding.

- ### IPRINT -- See set-iprint.

- ### IPRINTING -- See set-iprint.

- ### OPEN-OUTPUT-CHANNEL! -- when trust tags are needed to open output channels

- ### OUTPUT-TO-FILE -- redirecting output to a file

- ### PRINC$ -- print an atom

- ### PRINT-CONTROL -- advanced controls of ACL2 printing

- ### PRINTING-TO-STRINGS -- printing to strings instead of files or standard output

- ### RESET-PRINT-CONTROL -- See print-control.

- ### SET-EVISC-TUPLE -- control suppression of details when printing

- ### SET-FMT-HARD-RIGHT-MARGIN -- set the right margin for formatted output

- ### SET-FMT-SOFT-RIGHT-MARGIN -- set the soft right margin for formatted output

- ### SET-IPRINT -- control whether abbreviated output can be read back in

- ### SET-PRINT-BASE -- control radix in which numbers are printed

- ### SET-PRINT-CASE -- control whether symbols are printed in upper case or in lower case

- ### SET-PRINT-CIRCLE -- See print-control.

- ### SET-PRINT-ESCAPE -- See print-control.

- ### SET-PRINT-LENGTH -- See print-control.

- ### SET-PRINT-LEVEL -- See print-control.

- ### SET-PRINT-LINES -- See print-control.

- ### SET-PRINT-RADIX -- control printing of the radix for numbers

- ### SET-PRINT-READABLY -- See print-control.

- ### SET-PRINT-RIGHT-MARGIN -- See print-control.

- ### WITHOUT-EVISC -- print output in full

ACL2 supports input and output facilities equivalent to a subset of those found in Common Lisp. ACL2 does not support random access to files or bidirectional streams. In Common Lisp, input and output are to or from objects of type `stream`. In ACL2, input and output are to or from objects called ``channels,'' which are actually symbols. Although a channel is a symbol, one may think of it intuitively as corresponding to a Common Lisp stream. Channels are in one of two ACL2 packages, `"ACL2-INPUT-CHANNEL"` and `"ACL2-OUTPUT-CHANNEL"`. When one ``opens'' a file one gets back a channel whose `symbol-name` is the file name passed to ``open,'' postfixed with `-n`, where `n` is a counter that is incremented every time an open or close occurs.

There are three channels which are open from the beginning and which cannot be closed:

      acl2-input-channel::standard-character-input-0
      acl2-input-channel::standard-object-input-0
      acl2-input-channel::standard-character-output-0

All three of these are really Common Lisp's `*standard-input*` or `*standard-output*`, appropriately.

For convenience, three global variables are bound to these rather tedious channel names:

      *standard-ci*
      *standard-oi*
      *standard-co*

Common Lisp permits one to open a stream for several different kinds of `io`, e.g. character or byte. ACL2 permits an additional type called ``object''. In ACL2 an ``io-type'' is a keyword, either `:character`, `:byte`, or `:object`. When one opens a file, one specifies a type, which determines the kind of io operations that can be done on the channel returned. The types `:character` and `:byte` are familiar. Type `:object` is an abstraction not found in Common Lisp. An `:object` file is a file of Lisp objects. One uses `read-object` to read from `:object` files and `print-object$` (or `print-object$-ser`) to print to `:object` files. (The reading and printing are really done with the Common Lisp `read` and `print` functions. For those familiar with `read`, we note that the `recursive-p` argument is `nil`.) The function `read-object-suppress` is logically the same as `read-object` except that `read-object-suppress` throws away the second returned value, i.e. the value that would normally be read, simply returning `(mv eof state)`; under the hood, `read-object-suppress` avoids errors, for example those caused by encountering symbols in packages unknown to ACL2.

File-names are strings. ACL2 does not support the Common Lisp type `pathname`. However, for the `file-name` argument of the output-related functions listed below, ACL2 supports a special value, `:STRING`. For this value, the channel connects (by way of a Common Lisp output string stream) to a string rather than to a file: as characters are written to the channel they can be retrieved by using `get-output-stream-string$`.

Here are the names, formals and output descriptions of the ACL2 io functions.

    Input Functions:
      (open-input-channel (file-name io-type state) (mv channel state))
      (open-input-channel-p (channel io-type state) boolean)
      (close-input-channel (channel state) state)
      (read-char$ (channel state) (mv char/nil state)) ; nil for EOF
      (peek-char$ (channel state) boolean)
      (read-byte$ (channel state) (mv byte/nil state)) ; nil for EOF
      (read-object (channel state) (mv eof-read-flg obj-read state))
      (read-object-suppress (channel state) (mv eof-read-flg state))

    Output Functions:
      (open-output-channel  (file-name io-type state) (mv channel state))
      (open-output-channel! (file-name io-type state) (mv channel state))
      (open-output-channel-p (channel io-type state) boolean)
      (close-output-channel (channel state) state)
      (princ$ (obj channel state) state)
      (write-byte$ (byte channel state) state)
      (print-object$ (obj channel state) state)
      (print-object$-ser (obj serialize-character channel state) state)
      (fms  (string alist channel state evisc-tuple) state)
      (fms! (string alist channel state evisc-tuple) state)
      (fmt  (string alist channel state evisc-tuple) (mv col state))
      (fmt! (string alist channel state evisc-tuple) (mv col state))
      (fmt1 (string alist col channel state evisc-tuple) (mv col state))
      (fmt1! (string alist col channel state evisc-tuple) (mv col state))
      (cw (string arg0 arg1 ... argn) nil)
      (get-output-stream-string$ (channel state
                                  &optional (close-p 't)
                                            (ctx ''get-output-stream-string$))
                                 (mv erp string state))

The ``formatting'' functions are particularly useful; see fmt and see cw. In particular, `cw` prints to a ``comment window'' and does not involve the ACL2 `state`, so many may find it easier to use than `fmt` and its variants. The functions `fms!`, `fmt!`, and `fmt1!` are the same as their respective functions without the ```!`,'' except that the ```!`'' functions are guaranteed to print forms that can be read back in (at a slight readability cost).

When one enters ACL2 with `(lp)`, input and output are taken from `*standard-oi*` to `*standard-co*`. Because these are synonyms for `*standard-input*` and `*standard-output*`, one can drive ACL2 io off of arbitrary Common Lisp streams, bound to `*standard-input*` and `*standard-output*` before entry to ACL2.

The macro `get-output-stream-string$` returns the string accumulated into the given channel. By default, a call of this macro closes the supplied output channel. However, a third argument is optional (default `t`), and if it evaluates to `nil` then the channel remains open. The fourth argument is an optional context, which generally evaluates to a symbol, for error reporting. The following example illustrates.

    ACL2 !>
    (mv-let
       (channel state)
       (open-output-channel :string :object state)
       (pprogn (print-object$-ser 17 nil channel state)
               (print-object$-ser '(a b (c d)) nil channel state)
               (er-let*
                 ((str1 (get-output-stream-string$
                         channel state
                         nil))) ; keep the channel open
                 (pprogn (print-object$-ser 23 nil channel state)
                         (print-object$-ser '((e f)) nil channel state)
                         (er-let* ; close the channel
                           ((str2 (get-output-stream-string$ channel state)))
                           (value (cons str1 str2)))))))
     ("
    17
    (A B (C D))" . "
    23
    ((E F))")
    ACL2 !>

Also see printing-to-strings for a discussion of formatted printing functions such as `fmt-to-string` that do not take a channel or `state` argument and return a string.

By default, symbols are printed in upper case when vertical bars are not required, as specified by Common Lisp. See set-print-case for how to get ACL2 to print symbols in lower case.

By default, numbers are printed in radix 10 (base 10). See set-print-base for how to get ACL2 to print numbers in radix 2, 8, or 16.

To see the guard of an IO function, or indeed any function, see args or call the function `guard`; but some built-in functions (including some IO functions) will print the result using the variable `STATE-STATE`. While that is logically correct, if you want to execute the guard then you should replace that variable by `STATE` and also replace each built-in function symbol of the form `xxx-p1` by corresponding function symbol `xxx-p`. Consider the following example.

    ACL2 !>:args princ$

    Function         PRINC$
    Formals:         (X CHANNEL STATE-STATE)
    Signature:       (PRINC$ * * STATE)
                     => STATE
    Guard:           (AND (OR (ACL2-NUMBERP X)
                              (CHARACTERP X)
                              (STRINGP X)
                              (SYMBOLP X))
                          (STATE-P1 STATE-STATE)
                          (SYMBOLP CHANNEL)
                          (OPEN-OUTPUT-CHANNEL-P1 CHANNEL
                                                  :CHARACTER STATE-STATE))
    Guards Verified: T
    Defun-Mode:      :logic
    Type:            (CONSP (PRINC$ X CHANNEL STATE-STATE))
    Documentation available via :DOC
     PRINC$
    ACL2 !>(untranslate (guard 'princ$ nil (w state)) t (w state))
    (AND (OR (ACL2-NUMBERP X)
             (CHARACTERP X)
             (STRINGP X)
             (SYMBOLP X))
         (STATE-P1 STATE-STATE)
         (SYMBOLP CHANNEL)
         (OPEN-OUTPUT-CHANNEL-P1 CHANNEL
                                 :CHARACTER STATE-STATE))
    ACL2 !>

If you want to execute the guard for `princ$`, then according to the suggestion above, you should consider the guard for `(princ$ x channel state)` to be as follows.

    (AND (OR (ACL2-NUMBERP X)
             (CHARACTERP X)
             (STRINGP X)
             (SYMBOLP X))
         (STATE-P STATE)
         (SYMBOLP CHANNEL)
         (OPEN-OUTPUT-CHANNEL-P CHANNEL :CHARACTER STATE))

For example, we can check the guard for a given value and channel as follows.

    ACL2 !>(let ((x 3) (channel *standard-co*))
             (AND (OR (ACL2-NUMBERP X)
                      (CHARACTERP X)
                      (STRINGP X)
                      (SYMBOLP X))
                  (STATE-P STATE)
                  (SYMBOLP CHANNEL)
                  (OPEN-OUTPUT-CHANNEL-P CHANNEL :CHARACTER STATE)))
    T
    ACL2 !>

Comment for advanced users: Function `open-output-channel!` is identical as a function to `open-output-channel`, except that the former may be called even during `make-event` expansion and `clause-processor` hints, but requires that there is an active trust tag (see defttag).

Finally, we note that the community book `books/misc/file-io.lisp` contains useful file io functions whose definitions illustrate some of the features described above.