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