* read.c (scm_read): Don't assume that scm_cur_inp is always open.
[bpt/guile.git] / libguile / read.c
1 /* Copyright (C) 1995,1996,1997, 1999 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41 \f
42
43 #include <stdio.h>
44 #include "_scm.h"
45 #include "chars.h"
46 #include "genio.h"
47 #include "eval.h"
48 #include "unif.h"
49 #include "keywords.h"
50 #include "alist.h"
51 #include "srcprop.h"
52 #include "hashtab.h"
53 #include "hash.h"
54
55 #include "read.h"
56
57 \f
58
59 SCM_SYMBOL (scm_keyword_prefix, "prefix");
60
61 scm_option scm_read_opts[] = {
62 { SCM_OPTION_BOOLEAN, "copy", 0,
63 "Copy source code expressions." },
64 { SCM_OPTION_BOOLEAN, "positions", 0,
65 "Record positions of source code expressions." },
66 { SCM_OPTION_BOOLEAN, "case-insensitive", 0,
67 "Convert symbols to lower case."},
68 { SCM_OPTION_SCM, "keywords", SCM_BOOL_F,
69 "Style of keyword recognition: #f or 'prefix"}
70 };
71
72 SCM_PROC (s_read_options, "read-options-interface", 0, 1, 0, scm_read_options);
73
74 SCM
75 scm_read_options (setting)
76 SCM setting;
77 {
78 SCM ans = scm_options (setting,
79 scm_read_opts,
80 SCM_N_READ_OPTIONS,
81 s_read_options);
82 if (SCM_COPY_SOURCE_P)
83 SCM_RECORD_POSITIONS_P = 1;
84 return ans;
85 }
86
87 /* An association list mapping extra hash characters to procedures. */
88 static SCM *scm_read_hash_procedures;
89
90 SCM_PROC (s_read, "read", 0, 1, 0, scm_read);
91
92 SCM
93 scm_read (port)
94 SCM port;
95 {
96 int c;
97 SCM tok_buf, copy;
98
99 if (SCM_UNBNDP (port))
100 port = scm_cur_inp;
101 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port),
102 port,
103 SCM_ARG1,
104 s_read);
105
106 c = scm_flush_ws (port, (char *) NULL);
107 if (EOF == c)
108 return SCM_EOF_VAL;
109 scm_ungetc (c, port);
110
111 tok_buf = scm_makstr (30L, 0);
112 return scm_lreadr (&tok_buf, port, &copy);
113 }
114
115
116
117 char *
118 scm_grow_tok_buf (tok_buf)
119 SCM * tok_buf;
120 {
121 scm_vector_set_length_x (*tok_buf, SCM_MAKINUM (2 * SCM_LENGTH (*tok_buf)));
122 return SCM_CHARS (*tok_buf);
123 }
124
125
126
127 int
128 scm_flush_ws (port, eoferr)
129 SCM port;
130 const char *eoferr;
131 {
132 register int c;
133 while (1)
134 switch (c = scm_getc (port))
135 {
136 case EOF:
137 goteof:
138 if (eoferr)
139 scm_wta (SCM_UNDEFINED, "end of file in ", eoferr);
140 return c;
141 case ';':
142 lp:
143 switch (c = scm_getc (port))
144 {
145 case EOF:
146 goto goteof;
147 default:
148 goto lp;
149 case SCM_LINE_INCREMENTORS:
150 break;
151 }
152 break;
153 case SCM_LINE_INCREMENTORS:
154 case SCM_SINGLE_SPACES:
155 case '\t':
156 break;
157 default:
158 return c;
159 }
160 }
161
162
163
164 int
165 scm_casei_streq (s1, s2)
166 char * s1;
167 char * s2;
168 {
169 while (*s1 && *s2)
170 if (scm_downcase((int)*s1) != scm_downcase((int)*s2))
171 return 0;
172 else
173 {
174 ++s1;
175 ++s2;
176 }
177 return !(*s1 || *s2);
178 }
179
180
181 /* recsexpr is used when recording expressions
182 * constructed by read:sharp.
183 */
184 #ifndef DEBUG_EXTENSIONS
185 #define recsexpr(obj, line, column, filename) (obj)
186 #else
187 static SCM recsexpr SCM_P ((SCM obj, int line, int column, SCM filename));
188
189 static SCM
190 recsexpr (obj, line, column, filename)
191 SCM obj;
192 int line;
193 int column;
194 SCM filename;
195 {
196 if (SCM_IMP (obj) || SCM_NCONSP(obj))
197 return obj;
198 {
199 SCM tmp = obj, copy;
200 /* If this sexpr is visible in the read:sharp source, we want to
201 keep that information, so only record non-constant cons cells
202 which haven't previously been read by the reader. */
203 if (SCM_FALSEP (scm_whash_lookup (scm_source_whash, obj)))
204 {
205 if (SCM_COPY_SOURCE_P)
206 {
207 copy = scm_cons (recsexpr (SCM_CAR (obj), line, column, filename),
208 SCM_UNDEFINED);
209 while (SCM_NIMP (tmp = SCM_CDR (tmp)) && SCM_CONSP (tmp))
210 {
211 SCM_SETCDR (copy, scm_cons (recsexpr (SCM_CAR (tmp),
212 line,
213 column,
214 filename),
215 SCM_UNDEFINED));
216 copy = SCM_CDR (copy);
217 }
218 SCM_SETCDR (copy, tmp);
219 }
220 else
221 {
222 recsexpr (SCM_CAR (obj), line, column, filename);
223 while (SCM_NIMP (tmp = SCM_CDR (tmp)) && SCM_CONSP (tmp))
224 recsexpr (SCM_CAR (tmp), line, column, filename);
225 copy = SCM_UNDEFINED;
226 }
227 scm_whash_insert (scm_source_whash,
228 obj,
229 scm_make_srcprops (line,
230 column,
231 filename,
232 copy,
233 SCM_EOL));
234 }
235 return obj;
236 }
237 }
238 #endif
239
240 /* Consume an SCSH-style block comment. Assume that we've already
241 read the initial `#!', and eat characters until we get a
242 newline/exclamation-point/sharp-sign/newline sequence. */
243
244 static void
245 skip_scsh_block_comment (port)
246 SCM port;
247 {
248 /* Is this portable? Dear God, spare me from the non-eight-bit
249 characters. But is it tasteful? */
250 long history = 0;
251
252 for (;;)
253 {
254 int c = scm_getc (port);
255
256 if (c == EOF)
257 scm_wta (SCM_UNDEFINED,
258 "unterminated `#! ... !#' comment", "read");
259 history = ((history << 8) | (c & 0xff)) & 0xffffffff;
260
261 /* Were the last four characters read "\n!#\n"? */
262 if (history == (('\n' << 24) | ('!' << 16) | ('#' << 8) | '\n'))
263 return;
264 }
265 }
266
267 static SCM
268 scm_get_hash_procedure SCM_P ((int c));
269
270 static char s_list[]="list";
271
272 SCM
273 scm_lreadr (tok_buf, port, copy)
274 SCM *tok_buf;
275 SCM port;
276 SCM *copy;
277 {
278 int c;
279 scm_sizet j;
280 SCM p;
281
282 tryagain:
283 c = scm_flush_ws (port, s_read);
284 tryagain_no_flush_ws:
285 switch (c)
286 {
287 case EOF:
288 return SCM_EOF_VAL;
289
290 case '(':
291 return SCM_RECORD_POSITIONS_P
292 ? scm_lreadrecparen (tok_buf, port, s_list, copy)
293 : scm_lreadparen (tok_buf, port, s_list, copy);
294 case ')':
295 scm_wta (SCM_UNDEFINED, "unexpected \")\"", "read");
296 goto tryagain;
297
298 case '\'':
299 p = scm_sym_quote;
300 goto recquote;
301 case '`':
302 p = scm_sym_quasiquote;
303 goto recquote;
304 case ',':
305 c = scm_getc (port);
306 if ('@' == c)
307 p = scm_sym_uq_splicing;
308 else
309 {
310 scm_ungetc (c, port);
311 p = scm_sym_unquote;
312 }
313 recquote:
314 p = scm_cons2 (p,
315 scm_lreadr (tok_buf, port, copy),
316 SCM_EOL);
317 if (SCM_RECORD_POSITIONS_P)
318 scm_whash_insert (scm_source_whash,
319 p,
320 scm_make_srcprops (SCM_LINUM (port),
321 SCM_COL (port) - 1,
322 SCM_FILENAME (port),
323 SCM_COPY_SOURCE_P
324 ? (*copy = scm_cons2 (SCM_CAR (p),
325 SCM_CAR (SCM_CDR (p)),
326 SCM_EOL))
327 : SCM_UNDEFINED,
328 SCM_EOL));
329 return p;
330 case '#':
331 c = scm_getc (port);
332 switch (c)
333 {
334 case '(':
335 p = scm_lreadparen (tok_buf, port, "vector", copy);
336 return SCM_NULLP (p) ? scm_nullvect : scm_vector (p);
337
338 case 't':
339 case 'T':
340 return SCM_BOOL_T;
341 case 'f':
342 case 'F':
343 return SCM_BOOL_F;
344
345 case 'b':
346 case 'B':
347 case 'o':
348 case 'O':
349 case 'd':
350 case 'D':
351 case 'x':
352 case 'X':
353 case 'i':
354 case 'I':
355 case 'e':
356 case 'E':
357 scm_ungetc (c, port);
358 c = '#';
359 goto num;
360
361 case '!':
362 /* start of a shell script. Parse as a block comment,
363 terminated by !#, just like SCSH. */
364 skip_scsh_block_comment (port);
365 /* EOF is not an error here */
366 c = scm_flush_ws (port, (char *)NULL);
367 goto tryagain_no_flush_ws;
368
369 case '*':
370 j = scm_read_token (c, tok_buf, port, 0);
371 p = scm_istr2bve (SCM_CHARS (*tok_buf) + 1, (long) (j - 1));
372 if (SCM_NFALSEP (p))
373 return p;
374 else
375 goto unkshrp;
376
377 case '{':
378 j = scm_read_token (c, tok_buf, port, 1);
379 p = scm_intern (SCM_CHARS (*tok_buf), j);
380 return SCM_CAR (p);
381
382 case '\\':
383 c = scm_getc (port);
384 j = scm_read_token (c, tok_buf, port, 0);
385 if (j == 1)
386 return SCM_MAKICHR (c);
387 if (c >= '0' && c < '8')
388 {
389 p = scm_istr2int (SCM_CHARS (*tok_buf), (long) j, 8);
390 if (SCM_NFALSEP (p))
391 return SCM_MAKICHR (SCM_INUM (p));
392 }
393 for (c = 0; c < scm_n_charnames; c++)
394 if (scm_charnames[c]
395 && (scm_casei_streq (scm_charnames[c], SCM_CHARS (*tok_buf))))
396 return SCM_MAKICHR (scm_charnums[c]);
397 scm_wta (SCM_UNDEFINED, "unknown # object: #\\", SCM_CHARS (*tok_buf));
398
399 /* #:SYMBOL is a syntax for keywords supported in all contexts. */
400 case ':':
401 j = scm_read_token ('-', tok_buf, port, 0);
402 p = scm_intern (SCM_CHARS (*tok_buf), j);
403 return scm_make_keyword_from_dash_symbol (SCM_CAR (p));
404
405 default:
406 callshrp:
407 {
408 SCM sharp = scm_get_hash_procedure (c);
409
410 if (SCM_NIMP (sharp))
411 {
412 int line = SCM_LINUM (port);
413 int column = SCM_COL (port) - 2;
414 SCM got;
415
416 got = scm_apply (sharp,
417 SCM_MAKICHR (c),
418 scm_acons (port, SCM_EOL, SCM_EOL));
419 if (SCM_UNSPECIFIED == got)
420 goto unkshrp;
421 if (SCM_RECORD_POSITIONS_P)
422 return *copy = recsexpr (got, line, column,
423 SCM_FILENAME (port));
424 else
425 return got;
426 }
427 }
428 unkshrp:
429 scm_misc_error (s_read, "Unknown # object: %S",
430 scm_listify (SCM_MAKICHR (c), SCM_UNDEFINED));
431 }
432
433 case '"':
434 j = 0;
435 while ('"' != (c = scm_getc (port)))
436 {
437 SCM_ASSERT (EOF != c, SCM_UNDEFINED, "end of file in ", "string");
438
439 while (j + 2 >= SCM_LENGTH (*tok_buf))
440 scm_grow_tok_buf (tok_buf);
441
442 if (c == '\\')
443 switch (c = scm_getc (port))
444 {
445 case '\n':
446 continue;
447 case '0':
448 c = '\0';
449 break;
450 case 'f':
451 c = '\f';
452 break;
453 case 'n':
454 c = '\n';
455 break;
456 case 'r':
457 c = '\r';
458 break;
459 case 't':
460 c = '\t';
461 break;
462 case 'a':
463 c = '\007';
464 break;
465 case 'v':
466 c = '\v';
467 break;
468 }
469 SCM_CHARS (*tok_buf)[j] = c;
470 ++j;
471 }
472 if (j == 0)
473 return scm_nullstr;
474 SCM_CHARS (*tok_buf)[j] = 0;
475 {
476 SCM str;
477 str = scm_makfromstr (SCM_CHARS (*tok_buf), j, 0);
478 return str;
479 }
480
481 case'0':case '1':case '2':case '3':case '4':
482 case '5':case '6':case '7':case '8':case '9':
483 case '.':
484 case '-':
485 case '+':
486 num:
487 j = scm_read_token (c, tok_buf, port, 0);
488 p = scm_istring2number (SCM_CHARS (*tok_buf), (long) j, 10L);
489 if (SCM_NFALSEP (p))
490 return p;
491 if (c == '#')
492 {
493 if ((j == 2) && (scm_getc (port) == '('))
494 {
495 scm_ungetc ('(', port);
496 c = SCM_CHARS (*tok_buf)[1];
497 goto callshrp;
498 }
499 scm_wta (SCM_UNDEFINED, "unknown # object", SCM_CHARS (*tok_buf));
500 }
501 goto tok;
502
503 case ':':
504 if (SCM_KEYWORD_STYLE == scm_keyword_prefix)
505 {
506 j = scm_read_token ('-', tok_buf, port, 0);
507 p = scm_intern (SCM_CHARS (*tok_buf), j);
508 return scm_make_keyword_from_dash_symbol (SCM_CAR (p));
509 }
510 /* fallthrough */
511 default:
512 j = scm_read_token (c, tok_buf, port, 0);
513 /* fallthrough */
514
515 tok:
516 p = scm_intern (SCM_CHARS (*tok_buf), j);
517 return SCM_CAR (p);
518 }
519 }
520
521 #ifdef _UNICOS
522 _Pragma ("noopt"); /* # pragma _CRI noopt */
523 #endif
524
525 scm_sizet
526 scm_read_token (ic, tok_buf, port, weird)
527 int ic;
528 SCM *tok_buf;
529 SCM port;
530 int weird;
531 {
532 register scm_sizet j;
533 register int c;
534 register char *p;
535
536 c = (SCM_CASE_INSENSITIVE_P ? scm_downcase(ic) : ic);
537 p = SCM_CHARS (*tok_buf);
538
539 if (weird)
540 j = 0;
541 else
542 {
543 j = 0;
544 while (j + 2 >= SCM_LENGTH (*tok_buf))
545 p = scm_grow_tok_buf (tok_buf);
546 p[j] = c;
547 ++j;
548 }
549
550 while (1)
551 {
552 while (j + 2 >= SCM_LENGTH (*tok_buf))
553 p = scm_grow_tok_buf (tok_buf);
554 c = scm_getc (port);
555 switch (c)
556 {
557 case '(':
558 case ')':
559 case '"':
560 case ';':
561 case SCM_WHITE_SPACES:
562 case SCM_LINE_INCREMENTORS:
563 if (weird)
564 goto default_case;
565
566 scm_ungetc (c, port);
567 case EOF:
568 eof_case:
569 p[j] = 0;
570 return j;
571 case '\\':
572 if (!weird)
573 goto default_case;
574 else
575 {
576 c = scm_getc (port);
577 if (c == EOF)
578 goto eof_case;
579 else
580 goto default_case;
581 }
582 case '}':
583 if (!weird)
584 goto default_case;
585
586 c = scm_getc (port);
587 if (c == '#')
588 {
589 p[j] = 0;
590 return j;
591 }
592 else
593 {
594 scm_ungetc (c, port);
595 c = '}';
596 goto default_case;
597 }
598
599 default:
600 default_case:
601 {
602 c = (SCM_CASE_INSENSITIVE_P ? scm_downcase(c) : c);
603 p[j] = c;
604 ++j;
605 }
606
607 }
608 }
609 }
610
611 #ifdef _UNICOS
612 _Pragma ("opt"); /* # pragma _CRI opt */
613 #endif
614
615 SCM
616 scm_lreadparen (tok_buf, port, name, copy)
617 SCM *tok_buf;
618 SCM port;
619 char *name;
620 SCM *copy;
621 {
622 SCM tmp;
623 SCM tl;
624 SCM ans;
625 int c;
626
627 c = scm_flush_ws (port, name);
628 if (')' == c)
629 return SCM_EOL;
630 scm_ungetc (c, port);
631 if (scm_sym_dot == (tmp = scm_lreadr (tok_buf, port, copy)))
632 {
633 ans = scm_lreadr (tok_buf, port, copy);
634 closeit:
635 if (')' != (c = scm_flush_ws (port, name)))
636 scm_wta (SCM_UNDEFINED, "missing close paren", "");
637 return ans;
638 }
639 ans = tl = scm_cons (tmp, SCM_EOL);
640 while (')' != (c = scm_flush_ws (port, name)))
641 {
642 scm_ungetc (c, port);
643 if (scm_sym_dot == (tmp = scm_lreadr (tok_buf, port, copy)))
644 {
645 SCM_SETCDR (tl, scm_lreadr (tok_buf, port, copy));
646 goto closeit;
647 }
648 SCM_SETCDR (tl, scm_cons (tmp, SCM_EOL));
649 tl = SCM_CDR (tl);
650 }
651 return ans;
652 }
653
654
655 SCM
656 scm_lreadrecparen (tok_buf, port, name, copy)
657 SCM *tok_buf;
658 SCM port;
659 char *name;
660 SCM *copy;
661 {
662 register int c;
663 register SCM tmp;
664 register SCM tl, tl2 = SCM_EOL;
665 SCM ans, ans2 = SCM_EOL;
666 /* Need to capture line and column numbers here. */
667 int line = SCM_LINUM (port);
668 int column = SCM_COL (port) - 1;
669
670 c = scm_flush_ws (port, name);
671 if (')' == c)
672 return SCM_EOL;
673 scm_ungetc (c, port);
674 if (scm_sym_dot == (tmp = scm_lreadr (tok_buf, port, copy)))
675 {
676 ans = scm_lreadr (tok_buf, port, copy);
677 if (')' != (c = scm_flush_ws (port, name)))
678 scm_wta (SCM_UNDEFINED, "missing close paren", "");
679 return ans;
680 }
681 /* Build the head of the list structure. */
682 ans = tl = scm_cons (tmp, SCM_EOL);
683 if (SCM_COPY_SOURCE_P)
684 ans2 = tl2 = scm_cons (SCM_NIMP (tmp) && SCM_CONSP (tmp)
685 ? *copy
686 : tmp,
687 SCM_EOL);
688 while (')' != (c = scm_flush_ws (port, name)))
689 {
690 scm_ungetc (c, port);
691 if (scm_sym_dot == (tmp = scm_lreadr (tok_buf, port, copy)))
692 {
693 SCM_SETCDR (tl, tmp = scm_lreadr (tok_buf, port, copy));
694 if (SCM_COPY_SOURCE_P)
695 SCM_SETCDR (tl2, scm_cons (SCM_NIMP (tmp) && SCM_CONSP (tmp)
696 ? *copy
697 : tmp,
698 SCM_EOL));
699 if (')' != (c = scm_flush_ws (port, name)))
700 scm_wta (SCM_UNDEFINED, "missing close paren", "");
701 goto exit;
702 }
703 tl = SCM_SETCDR (tl, scm_cons (tmp, SCM_EOL));
704 if (SCM_COPY_SOURCE_P)
705 tl2 = SCM_SETCDR (tl2, scm_cons (SCM_NIMP (tmp) && SCM_CONSP (tmp)
706 ? *copy
707 : tmp,
708 SCM_EOL));
709 }
710 exit:
711 scm_whash_insert (scm_source_whash,
712 ans,
713 scm_make_srcprops (line,
714 column,
715 SCM_FILENAME (port),
716 SCM_COPY_SOURCE_P
717 ? *copy = ans2
718 : SCM_UNDEFINED,
719 SCM_EOL));
720 return ans;
721 }
722
723
724 \f
725
726 /* Manipulate the read-hash-procedures alist. This could be written in
727 Scheme, but maybe it will also be used by C code during initialisation. */
728 SCM_PROC (s_read_hash_extend, "read-hash-extend", 2, 0, 0, scm_read_hash_extend);
729 SCM
730 scm_read_hash_extend (chr, proc)
731 SCM chr;
732 SCM proc;
733 {
734 SCM this;
735 SCM prev;
736
737 SCM_ASSERT (SCM_ICHRP(chr), chr, SCM_ARG1, s_read_hash_extend);
738 SCM_ASSERT (SCM_FALSEP (proc) || SCM_NIMP(proc), proc, SCM_ARG2,
739 s_read_hash_extend);
740
741 /* Check if chr is already in the alist. */
742 this = *scm_read_hash_procedures;
743 prev = SCM_BOOL_F;
744 while (1)
745 {
746 if (SCM_NULLP (this))
747 {
748 /* not found, so add it to the beginning. */
749 if (SCM_NFALSEP (proc))
750 {
751 *scm_read_hash_procedures =
752 scm_cons (scm_cons (chr, proc), *scm_read_hash_procedures);
753 }
754 break;
755 }
756 if (chr == SCM_CAAR (this))
757 {
758 /* already in the alist. */
759 if (SCM_FALSEP (proc))
760 {
761 /* remove it. */
762 if (prev == SCM_BOOL_F)
763 {
764 *scm_read_hash_procedures =
765 SCM_CDR (*scm_read_hash_procedures);
766 }
767 else
768 scm_set_cdr_x (prev, SCM_CDR (this));
769 }
770 else
771 {
772 /* replace it. */
773 scm_set_cdr_x (SCM_CAR (this), proc);
774 }
775 break;
776 }
777 prev = this;
778 this = SCM_CDR (this);
779 }
780
781 return SCM_UNSPECIFIED;
782 }
783
784 /* Recover the read-hash procedure corresponding to char c. */
785 static SCM
786 scm_get_hash_procedure (c)
787 int c;
788 {
789 SCM rest = *scm_read_hash_procedures;
790
791 while (1)
792 {
793 if (SCM_NULLP (rest))
794 return SCM_BOOL_F;
795
796 if (SCM_ICHR (SCM_CAAR (rest)) == c)
797 return SCM_CDAR (rest);
798
799 rest = SCM_CDR (rest);
800 }
801 }
802
803 void
804 scm_init_read ()
805 {
806 scm_read_hash_procedures =
807 SCM_CDRLOC (scm_sysintern ("read-hash-procedures", SCM_EOL));
808
809 scm_init_opts (scm_read_options, scm_read_opts, SCM_N_READ_OPTIONS);
810 #include "read.x"
811 }