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