@@ -159,28 +159,125 @@ most-negative-fixnum = ~s."
159
159
; ACL2 CHARACTERS
160
160
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
161
161
162
- ; At one time we read the legal ACL2 characters from a string in a file, so
163
- ; that we could be confident that we know exactly what they are. But if
164
- ; code-char is not a function, then we lose anyhow, because we have defined it
165
- ; in ACL2. And if code-char is a function, then we can do our checking without
166
- ; having to get the characters from a file, the idea being that the range of
167
- ; code-char on {0,1,...,255} is exactly the set of legal ACL2 characters.
168
-
169
- ; Note that this issue is orthogonal to the problem of ensuring that #\c is
170
- ; read in as the same character in different ACL2 sessions, for any ACL2
171
- ; character c. (Even #\Newline is potentially problematic, as its char-code is
172
- ; 10 in most Common Lisps but is 13 in MCL!) Because of the latter issue, our
173
- ; story about ACL2 could include a caveat that certified books may only be
174
- ; soundly loaded into the same Lisp image in which they were certified. When
175
- ; we say ``same lisp image'' we don't mean the same exact process necessarily,
176
- ; but rather simply an invocation of the same saved image. Another reason for
177
- ; such a caveat, independent of the character-reading issue, is that different
178
- ; saved images may be tied into different compilers, thus making the object
179
- ; files of the books incompatible.
180
-
181
- ; However, we believe that we can prevent the most serious assaults on
182
- ; soundness due to implementation dependencies, simply by making notes in the
183
- ; version string, state global 'acl2-version; see :DOC version.
162
+ ; It is difficult or impossible to ensure that #\c is read in as the same
163
+ ; character in different ACL2 sessions, for any ACL2 character c. (Even
164
+ ; #\Newline is potentially problematic, as its char-code is 10 in most Common
165
+ ; Lisps but is 13 in [now-obsolete] MCL!) Thus, the soundness of ACL2 rests on
166
+ ; a caveat that all books are certified using the same Lisp image. When we say
167
+ ; ``same lisp image'' we don't mean the same exact process necessarily, but
168
+ ; rather, an invocation of the same saved image. Another reason for such a
169
+ ; caveat, independent of the character-reading issue, is that different saved
170
+ ; images may be tied into different compilers, thus making the object files of
171
+ ; the books incompatible.
172
+
173
+ ; Nevertheless, it would of course be nice if all host Lisp implementations of
174
+ ; ACL2 actually do agree on character and string constants provided by the Lisp
175
+ ; reader (based on *acl2-readtable*). Our first check is intended to address
176
+ ; this point, by providing some confidence that the host Lisp has an ASCII
177
+ ; character set. As explained above, we only intend soundness in the case that
178
+ ; all books are certified from scratch using the same host Lisp, and we do not
179
+ ; actually assume ASCII characters -- more precisely, we do not assume any
180
+ ; particular values for code-char and code-char -- so this check is not really
181
+ ; necessary, except for a claim about ASCII characters in "Precise Description
182
+ ; of the ACL2 Logic", which should perhaps be removed. However, as of January
183
+ ; 2012 we seem to be able to make the following check in all supported Lisps,
184
+ ; at least on our Linux and Mac OS platforms. It should be sound for users to
185
+ ; comment out this check, but with the understanding that ACL2 is taking
186
+ ; whatever the Lisp reader (using *acl2-readtable*) gives it.
187
+
188
+ (let ((filename " acl2-characters" ))
189
+
190
+ ; Why do we read from a separate file, rather than just saving the relevant
191
+ ; characters in the present file? For example, it may seem reasonable to use a
192
+ ; trusted host Lisp to obtain an alist by evaluating the following expression.
193
+
194
+ ; (loop for i from 0 to 255 do (princ (cons i (code-char i))))
195
+
196
+ ; Could the resulting the alist be placed into this file and used for the check
197
+ ; below?
198
+
199
+ ; We run into a problem right away with that approach because of Control-D.
200
+ ; For example, try this
201
+
202
+ ; (princ (cons 4 (code-char 4)))
203
+
204
+ ; and then try quoting the output and reading it back in. Or,
205
+ ; try evaluating the following.
206
+
207
+ ; (read-from-string (format nil "~a" (code-char 4)))
208
+
209
+ ; We have seen an error in both cases.
210
+
211
+ ; So instead, we originally generated the file acl2-characters as follows,
212
+ ; using an ACL2 image based on CCL.
213
+
214
+ ; (with-open-file (str "acl2-characters" :direction :output)
215
+ ; (loop for i from 0 to 255
216
+ ; do (write-char (code-char i) str)))
217
+
218
+ (with-open-file
219
+ (str filename :direction :input
220
+
221
+ ; In SBCL and CLISP we have found the need to specify :external-format in order
222
+ ; to avoid errors. Note that (for example) in our SBCL,
223
+ ; (stream-external-format *terminal-io*) evaluates to (:UTF-8 :REPLACEMENT
224
+ ; #\REPLACEMENT_CHARACTER).
225
+
226
+ #+ (or clisp sbcl) :external-format
227
+ #+ sbcl :iso-8859-1
228
+ #+ clisp
229
+ ; The following came from
230
+ ; http://en.wikibooks.org/wiki/Common_Lisp/Advanced_topics/Files_and_Directories
231
+ ; in January 2012.
232
+ (ext :make-encoding :charset ' charset:iso-8859-1
233
+ :line-terminator :unix ))
234
+ (loop for i from 0 to 255
235
+
236
+ ; The function legal-acl2-character-p, called in bad-lisp-objectp for
237
+ ; characters and strings, checks that the char-code of any character that is
238
+ ; read must be between 0 and 255.
239
+
240
+ do (let ((temp (read-char str)))
241
+ (when #- clisp (not (eql (char-code temp) i))
242
+
243
+ ; In CLISP we find character 10 (Newline) at position 13 (expected Return).
244
+ ; Perhaps this has something to do CLISP's attempt to comply with the CL
245
+ ; HyperSpec Section 13.1.8, "Treatment of Newline during Input and Output".
246
+ ; But something is amiss. Consider for example the following log (with some
247
+ ; output edited in the case of the first two forms, but no editing of output
248
+ ; for the third form).
249
+
250
+ ; ACL2 [RAW LISP]> (with-open-file (str "tmp" :direction :output)
251
+ ; (write-char (code-char 13) str))
252
+ ; #\Return
253
+ ; ACL2 [RAW LISP]> (with-open-file (str "tmp" :direction :input)
254
+ ; (equal (read-char str) (code-char 10)))
255
+ ; T
256
+ ; ACL2 [RAW LISP]> (format nil "~a" (code-char 13))
257
+ ; "
258
+ ; ACL2 [RAW LISP]>
259
+
260
+ ; So our check for CLISP is incomplete, but as explained in the comment just
261
+ ; above this check, we can live with that.
262
+
263
+ #+ clisp
264
+ (and (not (eql (char-code temp) i))
265
+ (not (eql i 13 )))
266
+ (error " Bad character in file ~s : character ~s at position ~s ."
267
+ filename (char-code temp) i))))))
268
+
269
+ ; The check just above does not say anything about the five character names
270
+ ; that we support (see acl2-read-character-string), as described in :doc
271
+ ; characters; so we add suitable checks on these here.
272
+
273
+ (loop for pair in (pairlis ' (#\Space #\Tab #\Newline #\Page #\Rubout )
274
+ ' (32 9 10 12 127 ))
275
+ do (let* ((ch (car pair))
276
+ (code (cdr pair))
277
+ (val (char-code ch)))
278
+ (or (eql val code)
279
+ (error " (char-code ~s ) evaluated to ~s (expected ~s )."
280
+ ch val code))))
184
281
185
282
; Test that all purportedly standard characters are standard, and vice versa.
186
283
0 commit comments