altos/scheme: Accept more escaped character constants
[fw/altos] / src / scheme / ao_scheme_read.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16 #include "ao_scheme_read.h"
17 #include <math.h>
18 #include <stdlib.h>
19
20 static const uint16_t   lex_classes[128] = {
21         IGNORE,         /* ^@ */
22         IGNORE,         /* ^A */
23         IGNORE,         /* ^B */
24         IGNORE,         /* ^C */
25         IGNORE,         /* ^D */
26         IGNORE,         /* ^E */
27         IGNORE,         /* ^F */
28         IGNORE,         /* ^G */
29         IGNORE,         /* ^H */
30         WHITE,          /* ^I */
31         WHITE,          /* ^J */
32         WHITE,          /* ^K */
33         WHITE,          /* ^L */
34         WHITE,          /* ^M */
35         IGNORE,         /* ^N */
36         IGNORE,         /* ^O */
37         IGNORE,         /* ^P */
38         IGNORE,         /* ^Q */
39         IGNORE,         /* ^R */
40         IGNORE,         /* ^S */
41         IGNORE,         /* ^T */
42         IGNORE,         /* ^U */
43         IGNORE,         /* ^V */
44         IGNORE,         /* ^W */
45         IGNORE,         /* ^X */
46         IGNORE,         /* ^Y */
47         IGNORE,         /* ^Z */
48         IGNORE,         /* ^[ */
49         IGNORE,         /* ^\ */
50         IGNORE,         /* ^] */
51         IGNORE,         /* ^^ */
52         IGNORE,         /* ^_ */
53         PRINTABLE|WHITE,        /*    */
54         PRINTABLE,              /* ! */
55         PRINTABLE|STRINGC,      /* " */
56         PRINTABLE,              /* # */
57         PRINTABLE,              /* $ */
58         PRINTABLE,              /* % */
59         PRINTABLE,              /* & */
60         PRINTABLE|SPECIAL,      /* ' */
61         PRINTABLE|SPECIAL,      /* ( */
62         PRINTABLE|SPECIAL,      /* ) */
63         PRINTABLE,              /* * */
64         PRINTABLE|SIGN,         /* + */
65         PRINTABLE|SPECIAL_QUASI,        /* , */
66         PRINTABLE|SIGN,         /* - */
67         PRINTABLE|DOTC|FLOATC,  /* . */
68         PRINTABLE,              /* / */
69         PRINTABLE|DIGIT,        /* 0 */
70         PRINTABLE|DIGIT,        /* 1 */
71         PRINTABLE|DIGIT,        /* 2 */
72         PRINTABLE|DIGIT,        /* 3 */
73         PRINTABLE|DIGIT,        /* 4 */
74         PRINTABLE|DIGIT,        /* 5 */
75         PRINTABLE|DIGIT,        /* 6 */
76         PRINTABLE|DIGIT,        /* 7 */
77         PRINTABLE|DIGIT,        /* 8 */
78         PRINTABLE|DIGIT,        /* 9 */
79         PRINTABLE,              /* : */
80         PRINTABLE|COMMENT,      /* ; */
81         PRINTABLE,              /* < */
82         PRINTABLE,              /* = */
83         PRINTABLE,              /* > */
84         PRINTABLE,              /* ? */
85         PRINTABLE,              /*  @ */
86         PRINTABLE|HEX_LETTER,   /*  A */
87         PRINTABLE|HEX_LETTER,   /*  B */
88         PRINTABLE|HEX_LETTER,   /*  C */
89         PRINTABLE|HEX_LETTER,   /*  D */
90         PRINTABLE|FLOATC|HEX_LETTER,/*  E */
91         PRINTABLE|HEX_LETTER,   /*  F */
92         PRINTABLE,              /*  G */
93         PRINTABLE,              /*  H */
94         PRINTABLE,              /*  I */
95         PRINTABLE,              /*  J */
96         PRINTABLE,              /*  K */
97         PRINTABLE,              /*  L */
98         PRINTABLE,              /*  M */
99         PRINTABLE,              /*  N */
100         PRINTABLE,              /*  O */
101         PRINTABLE,              /*  P */
102         PRINTABLE,              /*  Q */
103         PRINTABLE,              /*  R */
104         PRINTABLE,              /*  S */
105         PRINTABLE,              /*  T */
106         PRINTABLE,              /*  U */
107         PRINTABLE,              /*  V */
108         PRINTABLE,              /*  W */
109         PRINTABLE,              /*  X */
110         PRINTABLE,              /*  Y */
111         PRINTABLE,              /*  Z */
112         PRINTABLE,              /*  [ */
113         PRINTABLE,              /*  \ */
114         PRINTABLE,              /*  ] */
115         PRINTABLE,              /*  ^ */
116         PRINTABLE,              /*  _ */
117         PRINTABLE|SPECIAL_QUASI,        /*  ` */
118         PRINTABLE|HEX_LETTER,   /*  a */
119         PRINTABLE|HEX_LETTER,   /*  b */
120         PRINTABLE|HEX_LETTER,   /*  c */
121         PRINTABLE|HEX_LETTER,   /*  d */
122         PRINTABLE|FLOATC|HEX_LETTER,/*  e */
123         PRINTABLE|HEX_LETTER,   /*  f */
124         PRINTABLE,              /*  g */
125         PRINTABLE,              /*  h */
126         PRINTABLE,              /*  i */
127         PRINTABLE,              /*  j */
128         PRINTABLE,              /*  k */
129         PRINTABLE,              /*  l */
130         PRINTABLE,              /*  m */
131         PRINTABLE,              /*  n */
132         PRINTABLE,              /*  o */
133         PRINTABLE,              /*  p */
134         PRINTABLE,              /*  q */
135         PRINTABLE,              /*  r */
136         PRINTABLE,              /*  s */
137         PRINTABLE,              /*  t */
138         PRINTABLE,              /*  u */
139         PRINTABLE,              /*  v */
140         PRINTABLE,              /*  w */
141         PRINTABLE,              /*  x */
142         PRINTABLE,              /*  y */
143         PRINTABLE,              /*  z */
144         PRINTABLE,              /*  { */
145         PRINTABLE,              /*  | */
146         PRINTABLE,              /*  } */
147         PRINTABLE,              /*  ~ */
148         IGNORE,                 /*  ^? */
149 };
150
151 static int lex_unget_c;
152
153 static inline int
154 lex_get(void)
155 {
156         int     c;
157         if (lex_unget_c) {
158                 c = lex_unget_c;
159                 lex_unget_c = 0;
160         } else {
161                 c = ao_scheme_getc();
162         }
163         return c;
164 }
165
166 static inline void
167 lex_unget(int c)
168 {
169         if (c != EOF)
170                 lex_unget_c = c;
171 }
172
173 static uint16_t lex_class;
174
175 static int
176 lexc(void)
177 {
178         int     c;
179         do {
180                 c = lex_get();
181                 if (c == EOF) {
182                         c = 0;
183                         lex_class = ENDOFFILE;
184                 } else {
185                         c &= 0x7f;
186                         lex_class = lex_classes[c];
187                 }
188         } while (lex_class & IGNORE);
189         return c;
190 }
191
192 static int
193 lex_quoted(void)
194 {
195         int     c;
196         int     v;
197         int     count;
198
199         c = lex_get();
200         if (c == EOF) {
201                 lex_class = ENDOFFILE;
202                 return 0;
203         }
204         lex_class = 0;
205         c &= 0x7f;
206         switch (c) {
207         case 'a':
208                 return '\a';
209         case 'b':
210                 return '\b';
211         case 't':
212                 return '\t';
213         case 'n':
214                 return '\n';
215         case 'r':
216                 return '\r';
217         case 'f':
218                 return '\f';
219         case 'v':
220                 return '\v';
221         case '0':
222         case '1':
223         case '2':
224         case '3':
225         case '4':
226         case '5':
227         case '6':
228         case '7':
229                 v = c - '0';
230                 count = 1;
231                 while (count <= 3) {
232                         c = lex_get();
233                         if (c == EOF)
234                                 return EOF;
235                         c &= 0x7f;
236                         if (c < '0' || '7' < c) {
237                                 lex_unget(c);
238                                 break;
239                         }
240                         v = (v << 3) + c - '0';
241                         ++count;
242                 }
243                 return v;
244         default:
245                 return c;
246         }
247 }
248
249 #ifndef AO_SCHEME_TOKEN_MAX
250 #define AO_SCHEME_TOKEN_MAX     128
251 #endif
252
253 static char     token_string[AO_SCHEME_TOKEN_MAX];
254 static int32_t  token_int;
255 static int      token_len;
256
257 static inline void add_token(int c) {
258         if (c && token_len < AO_SCHEME_TOKEN_MAX - 1)
259                 token_string[token_len++] = c;
260 }
261
262 static inline void del_token(void) {
263         if (token_len > 0)
264                 token_len--;
265 }
266
267 static inline void end_token(void) {
268         token_string[token_len] = '\0';
269 }
270
271 #ifdef AO_SCHEME_FEATURE_FLOAT
272 static float    token_float;
273
274 struct namedfloat {
275         const char      *name;
276         float           value;
277 };
278
279 static const struct namedfloat namedfloats[] = {
280         { .name = "+inf.0", .value = INFINITY },
281         { .name = "-inf.0", .value = -INFINITY },
282         { .name = "+nan.0", .value = NAN },
283         { .name = "-nan.0", .value = NAN },
284 };
285
286 #define NUM_NAMED_FLOATS        (sizeof namedfloats / sizeof namedfloats[0])
287 #endif
288
289 static int
290 parse_int(int base)
291 {
292         int     cval;
293         int     c;
294
295         token_int = 0;
296         for (;;) {
297                 c = lexc();
298                 if ((lex_class & HEX_DIGIT) == 0) {
299                         lex_unget(c);
300                         end_token();
301                         return NUM;
302                 }
303                 add_token(c);
304                 if ('0' <= c && c <= '9')
305                         cval = c - '0';
306                 else
307                         cval = (c | ('a' - 'A')) - 'a' + 10;
308                 token_int = token_int * base + cval;
309         }
310         return NUM;
311 }
312
313 static int
314 _lex(void)
315 {
316         int     c;
317
318         token_len = 0;
319         for (;;) {
320                 c = lexc();
321                 if (lex_class & ENDOFFILE)
322                         return END;
323
324                 if (lex_class & WHITE)
325                         continue;
326
327                 if (lex_class & COMMENT) {
328                         while ((c = lexc()) != '\n') {
329                                 if (lex_class & ENDOFFILE)
330                                         return END;
331                         }
332                         continue;
333                 }
334
335                 if (lex_class & (SPECIAL|DOTC)) {
336                         add_token(c);
337                         end_token();
338                         switch (c) {
339                         case '(':
340                         case '[':
341                                 return OPEN;
342                         case ')':
343                         case ']':
344                                 return CLOSE;
345                         case '\'':
346                                 return QUOTE;
347                         case '.':
348                                 return DOT;
349 #ifdef AO_SCHEME_FEATURE_QUASI
350                         case '`':
351                                 return QUASIQUOTE;
352                         case ',':
353                                 c = lexc();
354                                 if (c == '@') {
355                                         add_token(c);
356                                         end_token();
357                                         return UNQUOTE_SPLICING;
358                                 } else {
359                                         lex_unget(c);
360                                         return UNQUOTE;
361                                 }
362 #endif
363                         }
364                 }
365                 if (c == '#') {
366                         c = lexc();
367                         switch (c) {
368                         case 't':
369                                 add_token(c);
370                                 end_token();
371                                 return BOOL;
372                         case 'f':
373                                 add_token(c);
374                                 end_token();
375                                 return BOOL;
376 #ifdef AO_SCHEME_FEATURE_VECTOR
377                         case '(':
378                                 return OPEN_VECTOR;
379 #endif
380                         case '\\':
381                                 for (;;) {
382                                         int alphabetic;
383                                         c = lexc();
384                                         alphabetic = (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
385                                         if (token_len == 0) {
386                                                 add_token(c);
387                                                 if (!alphabetic)
388                                                         break;
389                                         } else {
390                                                 if (alphabetic)
391                                                         add_token(c);
392                                                 else {
393                                                         lex_unget(c);
394                                                         break;
395                                                 }
396                                         }
397                                 }
398                                 end_token();
399                                 if (token_len == 1)
400                                         token_int = token_string[0];
401                                 else if (!strcmp(token_string, "space"))
402                                         token_int = ' ';
403                                 else if (!strcmp(token_string, "newline"))
404                                         token_int = '\n';
405                                 else if (!strcmp(token_string, "tab"))
406                                         token_int = '\t';
407                                 else if (!strcmp(token_string, "return"))
408                                         token_int = '\r';
409                                 else if (!strcmp(token_string, "formfeed"))
410                                         token_int = '\f';
411                                 else {
412                                         ao_scheme_error(AO_SCHEME_INVALID, "invalid character token #\\%s", token_string);
413                                         continue;
414                                 }
415                                 return NUM;
416                         case 'x':
417                                 return parse_int(16);
418                         case 'o':
419                                 return parse_int(8);
420                         case 'b':
421                                 return parse_int(2);
422                         }
423                 }
424                 if (lex_class & STRINGC) {
425                         for (;;) {
426                                 c = lexc();
427                                 if (c == '\\')
428                                         c = lex_quoted();
429                                 if (lex_class & (STRINGC|ENDOFFILE)) {
430                                         end_token();
431                                         return STRING;
432                                 }
433                                 add_token(c);
434                         }
435                 }
436                 if (lex_class & PRINTABLE) {
437 #ifdef AO_SCHEME_FEATURE_FLOAT
438                         int     isfloat = 1;
439                         int     epos = 0;
440 #endif
441                         int     hasdigit = 0;
442                         int     isneg = 0;
443                         int     isint = 1;
444
445                         token_int = 0;
446                         for (;;) {
447                                 if (!(lex_class & NUMBER)) {
448                                         isint = 0;
449 #ifdef AO_SCHEME_FEATURE_FLOAT
450                                         isfloat = 0;
451 #endif
452                                 } else {
453 #ifdef AO_SCHEME_FEATURE_FLOAT
454                                         if (!(lex_class & INTEGER))
455                                                 isint = 0;
456                                         if (token_len != epos &&
457                                             (lex_class & SIGN))
458                                         {
459                                                 isint = 0;
460                                                 isfloat = 0;
461                                         }
462 #endif
463                                         if (c == '-')
464                                                 isneg = 1;
465 #ifdef AO_SCHEME_FEATURE_FLOAT
466                                         if (c == '.' && epos != 0)
467                                                 isfloat = 0;
468                                         if (c == 'e' || c == 'E') {
469                                                 if (token_len == 0)
470                                                         isfloat = 0;
471                                                 else
472                                                         epos = token_len + 1;
473                                         }
474 #endif
475                                         if (lex_class & DIGIT) {
476                                                 hasdigit = 1;
477                                                 if (isint)
478                                                         token_int = token_int * 10 + c - '0';
479                                         }
480                                 }
481                                 add_token (c);
482                                 c = lexc ();
483                                 if ((lex_class & (NOTNAME))
484 #ifdef AO_SCHEME_FEATURE_FLOAT
485                                     && (c != '.' || !isfloat)
486 #endif
487                                         ) {
488 #ifdef AO_SCHEME_FEATURE_FLOAT
489                                         unsigned int u;
490 #endif
491 //                                      if (lex_class & ENDOFFILE)
492 //                                              clearerr (f);
493                                         lex_unget(c);
494                                         end_token ();
495                                         if (isint && hasdigit) {
496                                                 if (isneg)
497                                                         token_int = -token_int;
498                                                 return NUM;
499                                         }
500 #ifdef AO_SCHEME_FEATURE_FLOAT
501                                         if (isfloat && hasdigit) {
502                                                 token_float = strtof(token_string, NULL);
503                                                 return FLOAT;
504                                         }
505                                         for (u = 0; u < NUM_NAMED_FLOATS; u++)
506                                                 if (!strcmp(namedfloats[u].name, token_string)) {
507                                                         token_float = namedfloats[u].value;
508                                                         return FLOAT;
509                                                 }
510 #endif
511                                         return NAME;
512                                 }
513                         }
514                 }
515         }
516 }
517
518 static inline int lex(void)
519 {
520         int     parse_token = _lex();
521         RDBGI("token %d \"%s\"\n", parse_token, token_string);
522         return parse_token;
523 }
524
525 static int parse_token;
526
527 int                     ao_scheme_read_list;
528 struct ao_scheme_cons   *ao_scheme_read_cons;
529 struct ao_scheme_cons   *ao_scheme_read_cons_tail;
530 struct ao_scheme_cons   *ao_scheme_read_stack;
531 static int              ao_scheme_read_state;
532
533 #define READ_IN_QUOTE   0x01
534 #define READ_SAW_DOT    0x02
535 #define READ_DONE_DOT   0x04
536 #define READ_SAW_VECTOR 0x08
537
538 static int
539 push_read_stack(int read_state)
540 {
541         RDBGI("push read stack %p 0x%x\n", ao_scheme_read_cons, read_state);
542         RDBG_IN();
543         if (ao_scheme_read_list) {
544                 ao_scheme_read_stack = ao_scheme_cons_cons(ao_scheme_cons_poly(ao_scheme_read_cons),
545                                                        ao_scheme_cons(ao_scheme_int_poly(read_state),
546                                                                      ao_scheme_cons_poly(ao_scheme_read_stack)));
547                 if (!ao_scheme_read_stack)
548                         return 0;
549         } else
550                 ao_scheme_read_state = read_state;
551         ao_scheme_read_cons = NULL;
552         ao_scheme_read_cons_tail = NULL;
553         return 1;
554 }
555
556 static int
557 pop_read_stack(void)
558 {
559         int     read_state = 0;
560         if (ao_scheme_read_list) {
561                 ao_scheme_read_cons = ao_scheme_poly_cons(ao_scheme_read_stack->car);
562                 ao_scheme_read_stack = ao_scheme_poly_cons(ao_scheme_read_stack->cdr);
563                 read_state = ao_scheme_poly_int(ao_scheme_read_stack->car);
564                 ao_scheme_read_stack = ao_scheme_poly_cons(ao_scheme_read_stack->cdr);
565                 for (ao_scheme_read_cons_tail = ao_scheme_read_cons;
566                      ao_scheme_read_cons_tail && ao_scheme_read_cons_tail->cdr;
567                      ao_scheme_read_cons_tail = ao_scheme_poly_cons(ao_scheme_read_cons_tail->cdr))
568                         ;
569         } else {
570                 read_state = ao_scheme_read_state;
571                 ao_scheme_read_cons = NULL;
572                 ao_scheme_read_cons_tail = NULL;
573                 ao_scheme_read_stack = NULL;
574                 ao_scheme_read_state = 0;
575         }
576         RDBG_OUT();
577         RDBGI("pop read stack %p %d\n", ao_scheme_read_cons, read_state);
578         return read_state;
579 }
580
581 #ifdef AO_SCHEME_FEATURE_VECTOR
582 #define is_open(t) ((t) == OPEN || (t) == OPEN_VECTOR)
583 #else
584 #define is_open(t) ((t) == OPEN)
585 #endif
586
587 ao_poly
588 ao_scheme_read(void)
589 {
590         struct ao_scheme_atom   *atom;
591         struct ao_scheme_string *string;
592         int                     read_state;
593         ao_poly                 v = AO_SCHEME_NIL;
594
595         ao_scheme_read_list = 0;
596         read_state = 0;
597         ao_scheme_read_cons = ao_scheme_read_cons_tail = ao_scheme_read_stack = NULL;
598         for (;;) {
599                 parse_token = lex();
600                 while (is_open(parse_token)) {
601 #ifdef AO_SCHEME_FEATURE_VECTOR
602                         if (parse_token == OPEN_VECTOR)
603                                 read_state |= READ_SAW_VECTOR;
604 #endif
605                         if (!push_read_stack(read_state))
606                                 return AO_SCHEME_NIL;
607                         ao_scheme_read_list++;
608                         read_state = 0;
609                         parse_token = lex();
610                 }
611
612                 switch (parse_token) {
613                 case END:
614                 default:
615                         if (ao_scheme_read_list)
616                                 ao_scheme_error(AO_SCHEME_EOF, "unexpected end of file");
617                         return _ao_scheme_atom_eof;
618                         break;
619                 case NAME:
620                         atom = ao_scheme_atom_intern(token_string);
621                         if (atom)
622                                 v = ao_scheme_atom_poly(atom);
623                         else
624                                 v = AO_SCHEME_NIL;
625                         break;
626                 case NUM:
627                         v = ao_scheme_integer_poly(token_int);
628                         break;
629 #ifdef AO_SCHEME_FEATURE_FLOAT
630                 case FLOAT:
631                         v = ao_scheme_float_get(token_float);
632                         break;
633 #endif
634                 case BOOL:
635                         if (token_string[0] == 't')
636                                 v = _ao_scheme_bool_true;
637                         else
638                                 v = _ao_scheme_bool_false;
639                         break;
640                 case STRING:
641                         string = ao_scheme_string_new(token_string);
642                         if (string)
643                                 v = ao_scheme_string_poly(string);
644                         else
645                                 v = AO_SCHEME_NIL;
646                         break;
647                 case QUOTE:
648 #ifdef AO_SCHEME_FEATURE_QUASI
649                 case QUASIQUOTE:
650                 case UNQUOTE:
651                 case UNQUOTE_SPLICING:
652 #endif
653                         if (!push_read_stack(read_state))
654                                 return AO_SCHEME_NIL;
655                         ao_scheme_read_list++;
656                         read_state = READ_IN_QUOTE;
657                         switch (parse_token) {
658                         case QUOTE:
659                                 v = _ao_scheme_atom_quote;
660                                 break;
661 #ifdef AO_SCHEME_FEATURE_QUASI
662                         case QUASIQUOTE:
663                                 v = _ao_scheme_atom_quasiquote;
664                                 break;
665                         case UNQUOTE:
666                                 v = _ao_scheme_atom_unquote;
667                                 break;
668                         case UNQUOTE_SPLICING:
669                                 v = _ao_scheme_atom_unquote2dsplicing;
670                                 break;
671 #endif
672                         }
673                         break;
674                 case CLOSE:
675                         if (!ao_scheme_read_list) {
676                                 v = AO_SCHEME_NIL;
677                                 break;
678                         }
679                         v = ao_scheme_cons_poly(ao_scheme_read_cons);
680                         --ao_scheme_read_list;
681                         read_state = pop_read_stack();
682 #ifdef AO_SCHEME_FEATURE_VECTOR
683                         if (read_state & READ_SAW_VECTOR) {
684                                 v = ao_scheme_vector_poly(ao_scheme_list_to_vector(ao_scheme_poly_cons(v)));
685                                 read_state &= ~READ_SAW_VECTOR;
686                         }
687 #endif
688                         break;
689                 case DOT:
690                         if (!ao_scheme_read_list) {
691                                 ao_scheme_error(AO_SCHEME_INVALID, ". outside of cons");
692                                 return AO_SCHEME_NIL;
693                         }
694                         if (!ao_scheme_read_cons) {
695                                 ao_scheme_error(AO_SCHEME_INVALID, ". first in cons");
696                                 return AO_SCHEME_NIL;
697                         }
698                         read_state |= READ_SAW_DOT;
699                         continue;
700                 }
701
702                 /* loop over QUOTE ends */
703                 for (;;) {
704                         if (!ao_scheme_read_list)
705                                 return v;
706
707                         if (read_state & READ_DONE_DOT) {
708                                 ao_scheme_error(AO_SCHEME_INVALID, ". not last in cons");
709                                 return AO_SCHEME_NIL;
710                         }
711
712                         if (read_state & READ_SAW_DOT) {
713                                 read_state |= READ_DONE_DOT;
714                                 ao_scheme_read_cons_tail->cdr = v;
715                         } else {
716                                 struct ao_scheme_cons   *read = ao_scheme_cons_cons(v, AO_SCHEME_NIL);
717                                 if (!read)
718                                         return AO_SCHEME_NIL;
719
720                                 if (ao_scheme_read_cons_tail)
721                                         ao_scheme_read_cons_tail->cdr = ao_scheme_cons_poly(read);
722                                 else
723                                         ao_scheme_read_cons = read;
724                                 ao_scheme_read_cons_tail = read;
725                         }
726
727                         if (!(read_state & READ_IN_QUOTE) || !ao_scheme_read_cons->cdr)
728                                 break;
729
730                         v = ao_scheme_cons_poly(ao_scheme_read_cons);
731                         --ao_scheme_read_list;
732                         read_state = pop_read_stack();
733                 }
734         }
735         return v;
736 }