2
* Copyright (c) 2002 by The XFree86 Project, Inc.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* Except as contained in this notice, the name of the XFree86 Project shall
23
* not be used in advertising or otherwise to promote the sale, use or other
24
* dealings in this Software without prior written authorization from the
27
* Author: Paulo César Pereira de Andrade
30
/* $XFree86: xc/programs/xedit/lisp/read.c,v 1.36tsi Exp $ */
33
#include "lisp/read.h"
34
#include "lisp/package.h"
35
#include "lisp/write.h"
39
/* This should be visible only in read.c, but if an error is generated,
40
* the current code in write.c will print it as #<ERROR> */
41
#define LABEL_BIT_COUNT 8
42
#define LABEL_BIT_MASK 0xff
43
#define MAX_LABEL_VALUE ((1L << (sizeof(long) * 8 - 9)) - 1)
44
#define READLABEL(label) \
45
(LispObj*)(((label) << LABEL_BIT_COUNT) | READLABEL_MASK)
46
#define READLABELP(object) \
47
(((unsigned long)(object) & LABEL_BIT_MASK) == READLABEL_MASK)
48
#define READLABEL_VALUE(object) \
49
((long)(object) >> LABEL_BIT_COUNT)
51
#define READ_ENTER() \
52
LispObj *read__stream = SINPUT; \
53
int read__line = LispGetLine(read__stream)
54
#define READ_ERROR0(format) \
55
LispReadError(read__stream, read__line, format)
56
#define READ_ERROR1(format, arg1) \
57
LispReadError(read__stream, read__line, format, arg1)
58
#define READ_ERROR2(format, arg1, arg2) \
59
LispReadError(read__stream, read__line, format, arg1, arg2)
61
#define READ_ERROR_EOF() READ_ERROR0("unexpected end of input")
62
#define READ_ERROR_FIXNUM() READ_ERROR0("number is not a fixnum")
63
#define READ_ERROR_INVARG() READ_ERROR0("invalid argument")
66
# define finite(x) isfinite(x)
72
typedef struct _object_info {
73
long label; /* the read label of this object */
74
LispObj *object; /* the resulting object */
75
long num_circles; /* references to object before it was completely read */
78
typedef struct _read_info {
79
int level; /* level of open parentheses */
81
int nodot; /* flag set when reading a "special" list */
83
int discard; /* flag used when reading an unavailable feature */
85
long circle_count; /* if non zero, must resolve some labels */
87
/* information for #<number>= and #<number># */
91
/* could use only the objects field as all circular data is known,
92
* but check every object so that circular/shared references generated
93
* by evaluations would not cause an infinite loop at read time */
101
static LispObj *LispReadChar(LispBuiltin*, int);
103
static int LispGetLine(LispObj*);
105
#define PRINTF_FORMAT __attribute__ ((format (printf, 3, 4)))
107
#define PRINTF_FORMAT /**/
109
static void LispReadError(LispObj*, int, char*, ...);
111
static void LispReadFixCircle(LispObj*, read_info*);
112
static LispObj *LispReadLabelCircle(LispObj*, read_info*);
113
static int LispReadCheckCircle(LispObj*, read_info*);
114
static LispObj *LispDoRead(read_info*);
115
static int LispSkipWhiteSpace(void);
116
static LispObj *LispReadList(read_info*);
117
static LispObj *LispReadQuote(read_info*);
118
static LispObj *LispReadBackquote(read_info*);
119
static LispObj *LispReadCommaquote(read_info*);
120
static LispObj *LispReadObject(int, read_info*);
121
static LispObj *LispParseAtom(char*, char*, int, int, LispObj*, int);
122
static LispObj *LispParseNumber(char*, int, LispObj*, int);
123
static int StringInRadix(char*, int, int);
124
static int AtomSeparator(int, int, int);
125
static LispObj *LispReadVector(read_info*);
126
static LispObj *LispReadMacro(read_info*);
127
static LispObj *LispReadFunction(read_info*);
128
static LispObj *LispReadRational(int, read_info*);
129
static LispObj *LispReadCharacter(read_info*);
130
static void LispSkipComment(void);
131
static LispObj *LispReadEval(read_info*);
132
static LispObj *LispReadComplex(read_info*);
133
static LispObj *LispReadPathname(read_info*);
134
static LispObj *LispReadStruct(read_info*);
135
static LispObj *LispReadMacroArg(read_info*);
136
static LispObj *LispReadArray(long, read_info*);
137
static LispObj *LispReadFeature(int, read_info*);
138
static LispObj *LispEvalFeature(LispObj*);
143
static char *Char_Nul[] = {"Null", "Nul", NULL};
144
static char *Char_Soh[] = {"Soh", NULL};
145
static char *Char_Stx[] = {"Stx", NULL};
146
static char *Char_Etx[] = {"Etx", NULL};
147
static char *Char_Eot[] = {"Eot", NULL};
148
static char *Char_Enq[] = {"Enq", NULL};
149
static char *Char_Ack[] = {"Ack", NULL};
150
static char *Char_Bel[] = {"Bell", "Bel", NULL};
151
static char *Char_Bs[] = {"Backspace", "Bs", NULL};
152
static char *Char_Tab[] = {"Tab", NULL};
153
static char *Char_Nl[] = {"Newline", "Nl", "Lf", "Linefeed", NULL};
154
static char *Char_Vt[] = {"Vt", NULL};
155
static char *Char_Np[] = {"Page", "Np", NULL};
156
static char *Char_Cr[] = {"Return", "Cr", NULL};
157
static char *Char_Ff[] = {"So", "Ff", NULL};
158
static char *Char_Si[] = {"Si", NULL};
159
static char *Char_Dle[] = {"Dle", NULL};
160
static char *Char_Dc1[] = {"Dc1", NULL};
161
static char *Char_Dc2[] = {"Dc2", NULL};
162
static char *Char_Dc3[] = {"Dc3", NULL};
163
static char *Char_Dc4[] = {"Dc4", NULL};
164
static char *Char_Nak[] = {"Nak", NULL};
165
static char *Char_Syn[] = {"Syn", NULL};
166
static char *Char_Etb[] = {"Etb", NULL};
167
static char *Char_Can[] = {"Can", NULL};
168
static char *Char_Em[] = {"Em", NULL};
169
static char *Char_Sub[] = {"Sub", NULL};
170
static char *Char_Esc[] = {"Escape", "Esc", NULL};
171
static char *Char_Fs[] = {"Fs", NULL};
172
static char *Char_Gs[] = {"Gs", NULL};
173
static char *Char_Rs[] = {"Rs", NULL};
174
static char *Char_Us[] = {"Us", NULL};
175
static char *Char_Sp[] = {"Space", "Sp", NULL};
176
static char *Char_Del[] = {"Rubout", "Del", "Delete", NULL};
178
LispCharInfo LispChars[256] = {
212
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
213
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
214
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
215
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
216
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
217
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
218
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
219
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
220
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
221
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
222
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
223
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
225
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
226
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
227
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
228
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
229
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
230
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
231
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
232
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
233
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
234
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
235
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
236
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
237
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
238
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
239
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
240
{NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
244
Atom_id Sand, Sor, Snot;
251
Lisp_Read(LispBuiltin *builtin)
253
read &optional input-stream eof-error-p eof-value recursive-p
258
LispObj *input_stream, *eof_error_p, *eof_value;
260
eof_value = ARGUMENT(2);
261
eof_error_p = ARGUMENT(1);
262
input_stream = ARGUMENT(0);
264
if (input_stream == UNSPEC)
266
else if (input_stream != NIL) {
267
CHECK_STREAM(input_stream);
268
else if (!input_stream->data.stream.readable)
269
LispDestroy("%s: stream %s is not readable",
270
STRFUN(builtin), STROBJ(input_stream));
271
LispPushInput(input_stream);
273
else if (CONSP(lisp__data.input_list)) {
274
input_stream = STANDARD_INPUT;
275
LispPushInput(input_stream);
278
if (eof_value == UNSPEC)
282
if (input_stream != NIL)
283
LispPopInput(input_stream);
285
if (result == NULL) {
286
if (eof_error_p != NIL)
287
LispDestroy("%s: EOF reading stream %s",
288
STRFUN(builtin), STROBJ(input_stream));
297
LispReadChar(LispBuiltin *builtin, int nohang)
301
LispObj *input_stream, *eof_error_p, *eof_value;
303
eof_value = ARGUMENT(2);
304
eof_error_p = ARGUMENT(1);
305
input_stream = ARGUMENT(0);
307
if (input_stream == UNSPEC)
309
else if (input_stream != NIL) {
310
CHECK_STREAM(input_stream);
313
input_stream = lisp__data.input;
315
if (eof_value == UNSPEC)
320
if (input_stream->data.stream.readable) {
321
LispFile *file = NULL;
323
switch (input_stream->data.stream.type) {
324
case LispStreamStandard:
326
file = FSTREAMP(input_stream);
329
file = IPSTREAMP(input_stream);
331
case LispStreamString:
332
character = LispSgetc(SSTREAMP(input_stream));
338
if (file->available || file->offset < file->length)
339
character = LispFgetc(file);
341
if (nohang && !file->nonblock) {
342
if (fcntl(file->descriptor, F_SETFL, O_NONBLOCK) < 0)
343
LispDestroy("%s: fcntl(%d): %s",
344
STRFUN(builtin), file->descriptor,
348
else if (!nohang && file->nonblock) {
349
if (fcntl(file->descriptor, F_SETFL, 0) < 0)
350
LispDestroy("%s: fcntl(%d): %s",
351
STRFUN(builtin), file->descriptor,
358
if (read(file->descriptor, &ch, 1) == 1)
360
else if (errno == EAGAIN)
361
return (NIL); /* XXX no character available */
366
character = LispFgetc(file);
371
LispDestroy("%s: stream %s is unreadable",
372
STRFUN(builtin), STROBJ(input_stream));
374
if (character == EOF) {
375
if (eof_error_p != NIL)
376
LispDestroy("%s: EOF reading stream %s",
377
STRFUN(builtin), STROBJ(input_stream));
382
return (SCHAR(character));
386
Lisp_ReadChar(LispBuiltin *builtin)
388
read-char &optional input-stream eof-error-p eof-value recursive-p
391
return (LispReadChar(builtin, 0));
395
Lisp_ReadCharNoHang(LispBuiltin *builtin)
397
read-char-no-hang &optional input-stream eof-error-p eof-value recursive-p
400
return (LispReadChar(builtin, 1));
404
Lisp_ReadLine(LispBuiltin *builtin)
406
read-line &optional input-stream eof-error-p eof-value recursive-p
411
LispObj *result, *status = NIL;
413
LispObj *input_stream, *eof_error_p, *eof_value;
415
eof_value = ARGUMENT(2);
416
eof_error_p = ARGUMENT(1);
417
input_stream = ARGUMENT(0);
419
if (input_stream == UNSPEC)
421
else if (input_stream == NIL)
422
input_stream = STANDARD_INPUT;
424
CHECK_STREAM(input_stream);
427
if (eof_value == UNSPEC)
434
if (!input_stream->data.stream.readable)
435
LispDestroy("%s: stream %s is unreadable",
436
STRFUN(builtin), STROBJ(input_stream));
437
if (input_stream->data.stream.type == LispStreamString) {
438
char *start, *end, *ptr;
440
if (SSTREAMP(input_stream)->input >=
441
SSTREAMP(input_stream)->length) {
442
if (eof_error_p != NIL)
443
LispDestroy("%s: EOS found reading %s",
444
STRFUN(builtin), STROBJ(input_stream));
451
start = SSTREAMP(input_stream)->string +
452
SSTREAMP(input_stream)->input;
453
end = SSTREAMP(input_stream)->string +
454
SSTREAMP(input_stream)->length;
455
/* Search for a newline */
456
for (ptr = start; *ptr != '\n' && ptr < end; ptr++)
460
else if (!SSTREAMP(input_stream)->binary)
461
++SSTREAMP(input_stream)->line;
462
length = ptr - start;
463
string = LispMalloc(length + 1);
464
memcpy(string, start, length);
465
string[length] = '\0';
466
result = LSTRING2(string, length);
467
/* macro LSTRING2 does not make a copy of it's arguments, and
468
* calls LispMused on it. */
469
SSTREAMP(input_stream)->input += length + (status == NIL);
471
else /*if (input_stream->data.stream.type == LispStreamFile ||
472
input_stream->data.stream.type == LispStreamStandard ||
473
input_stream->data.stream.type == LispStreamPipe)*/ {
476
if (input_stream->data.stream.type == LispStreamPipe)
477
file = IPSTREAMP(input_stream);
479
file = FSTREAMP(input_stream);
481
if (file->nonblock) {
482
if (fcntl(file->descriptor, F_SETFL, 0) < 0)
483
LispDestroy("%s: fcntl: %s",
484
STRFUN(builtin), strerror(errno));
489
ch = LispFgetc(file);
493
if (eof_error_p != NIL)
494
LispDestroy("%s: EOF found reading %s",
495
STRFUN(builtin), STROBJ(input_stream));
505
else if ((length % 64) == 0)
506
string = LispRealloc(string, length + 64);
507
string[length++] = ch;
510
if ((length % 64) == 0)
511
string = LispRealloc(string, length + 1);
512
string[length] = '\0';
513
result = LSTRING2(string, length);
531
LispObj *result, *code = COD;
533
info.level = info.nodot = info.discard = 0;
534
info.circle_count = 0;
536
info.num_objects = 0;
538
result = LispDoRead(&info);
540
/* fix circular/shared lists, note that this is done when returning to
541
* the toplevel, so, if some circular/shared reference was evaluated,
542
* it should have generated an expected error */
543
if (info.num_objects) {
544
if (info.circle_count) {
546
info.num_circles = 0;
547
LispReadFixCircle(result, &info);
548
if (info.num_circles)
549
LispFree(info.circles);
551
LispFree(info.objects);
554
if (result == EOLIST)
555
READ_ERROR0("object cannot start with #\\)");
556
else if (result == DOT)
557
READ_ERROR0("dot allowed only on lists");
559
if (result != NULL && POINTERP(result)) {
563
COD = CONS(COD, result);
570
LispGetLine(LispObj *stream)
574
if (STREAMP(stream)) {
575
switch (stream->data.stream.type) {
576
case LispStreamStandard:
578
if (!FSTREAMP(stream)->binary)
579
line = FSTREAMP(stream)->line;
582
if (!IPSTREAMP(stream)->binary)
583
line = IPSTREAMP(stream)->line;
585
case LispStreamString:
586
if (!SSTREAMP(stream)->binary)
587
line = SSTREAMP(stream)->line;
593
else if (stream == NIL && !Stdin->binary)
600
LispReadError(LispObj *stream, int line, char *fmt, ...)
602
char string[128], *buffer_string;
603
LispObj *buffer = LSTRINGSTREAM("", STREAM_READ | STREAM_WRITE, 0);
608
vsnprintf(string, sizeof(string), fmt, ap);
611
LispFwrite(Stderr, "*** Reading ", 12);
612
LispWriteObject(buffer, stream);
613
buffer_string = LispGetSstring(SSTREAMP(buffer), &length);
614
LispFwrite(Stderr, buffer_string, length);
615
LispFwrite(Stderr, " at line ", 9);
617
LispFwrite(Stderr, "?\n", 2);
621
sprintf(str, "%d\n", line);
622
LispFputs(Stderr, str);
625
LispDestroy("READ: %s", string);
629
LispReadFixCircle(LispObj *object, read_info *info)
634
switch (OBJECT_TYPE(object)) {
638
cons = object, object = CDR(object)) {
639
if (READLABELP(CAR(object)))
640
CAR(object) = LispReadLabelCircle(CAR(object), info);
641
else if (LispReadCheckCircle(object, info))
644
LispReadFixCircle(CAR(object), info);
646
if (READLABELP(object))
647
CDR(cons) = LispReadLabelCircle(object, info);
652
if (READLABELP(object->data.array.list))
653
object->data.array.list =
654
LispReadLabelCircle(object->data.array.list, info);
655
else if (!LispReadCheckCircle(object, info)) {
656
object = object->data.array.list;
661
if (READLABELP(object->data.struc.fields))
662
object->data.struc.fields =
663
LispReadLabelCircle(object->data.struc.fields, info);
664
else if (!LispReadCheckCircle(object, info)) {
665
object = object->data.struc.fields;
670
case LispBackquote_t:
671
case LispFunctionQuote_t:
672
if (READLABELP(object->data.quote))
674
LispReadLabelCircle(object->data.quote, info);
676
object = object->data.quote;
681
if (READLABELP(object->data.comma.eval))
682
object->data.comma.eval =
683
LispReadLabelCircle(object->data.comma.eval, info);
685
object = object->data.comma.eval;
690
if (READLABELP(object->data.lambda.code))
691
object->data.lambda.code =
692
LispReadLabelCircle(object->data.lambda.code, info);
693
else if (!LispReadCheckCircle(object, info)) {
694
object = object->data.lambda.code;
704
LispReadLabelCircle(LispObj *label, read_info *info)
706
long i, value = READLABEL_VALUE(label);
708
for (i = 0; i < info->num_objects; i++)
709
if (info->objects[i].label == value)
710
return (info->objects[i].object);
712
LispDestroy("READ: internal error");
718
LispReadCheckCircle(LispObj *object, read_info *info)
722
for (i = 0; i < info->num_circles; i++)
723
if (info->circles[i] == object)
726
if ((info->num_circles % 16) == 0)
727
info->circles = LispRealloc(info->circles, sizeof(LispObj*) *
728
(info->num_circles + 16));
729
info->circles[info->num_circles++] = object;
735
LispDoRead(read_info *info)
738
int ch = LispSkipWhiteSpace();
742
object = LispReadList(info);
745
for (ch = LispGet(); ch != EOF && ch != '\n'; ch = LispGet()) {
755
object = LispReadQuote(info);
758
object = LispReadBackquote(info);
761
object = LispReadCommaquote(info);
764
object = LispReadMacro(info);
768
object = LispReadObject(0, info);
776
LispReadMacro(read_info *info)
779
LispObj *result = NULL;
784
result = LispReadVector(info);
787
result = LispReadFunction(info);
791
result = LispReadRational(2, info);
795
result = LispReadRational(8, info);
799
result = LispReadRational(16, info);
802
result = LispReadCharacter(info);
806
result = LispDoRead(info);
808
case '.': /* eval when compiling */
809
case ',': /* eval when loading */
810
result = LispReadEval(info);
814
result = LispReadComplex(info);
818
result = LispReadPathname(info);
822
result = LispReadStruct(info);
825
result = LispReadFeature(1, info);
828
result = LispReadFeature(0, info);
831
/* Uninterned symbol */
832
result = LispReadObject(1, info);
837
result = LispReadMacroArg(info);
839
else if (!info->discard)
840
READ_ERROR1("undefined dispatch macro character #%c", ch);
848
LispReadMacroArg(read_info *info)
851
LispObj *result = NIL;
855
/* skip leading zeros */
856
while (ch = LispGet(), ch != EOF && isdigit(ch) && ch == '0')
862
/* if ch is not a number the argument was zero */
872
if (len + 1 >= sizeof(stk))
878
integer = strtol(stk, &str, 10);
879
/* number is positive because sign is not processed here */
880
if (*str || errno == ERANGE || integer > MOST_POSITIVE_FIXNUM)
890
/* LispReadArray and LispReadList expect
891
* the '(' being already read */
892
if ((ch = LispSkipWhiteSpace()) != '(') {
894
return (ch == EOF ? NULL : NIL);
895
READ_ERROR0("bad array specification");
897
result = LispReadVector(info);
900
result = LispReadArray(integer, info);
904
result = LispReadRational(integer, info);
907
if (integer > MAX_LABEL_VALUE)
909
if (!info->discard) {
910
long num_objects = info->num_objects;
912
/* check for duplicated label */
913
for (i = 0; i < info->num_objects; i++) {
914
if (info->objects[i].label == integer)
915
READ_ERROR1("label #%ld# defined more than once",
918
info->objects = LispRealloc(info->objects,
919
sizeof(object_info) *
921
/* if this label is referenced it is a shared/circular object */
922
info->objects[num_objects].label = integer;
923
info->objects[num_objects].object = NULL;
924
info->objects[num_objects].num_circles = 0;
926
result = LispDoRead(info);
927
if (READLABELP(result) && READLABEL_VALUE(result) == integer)
928
READ_ERROR2("incorrect syntax #%ld= #%ld#",
930
/* any reference to it now is not shared/circular */
931
info->objects[num_objects].object = result;
934
result = LispDoRead(info);
937
if (integer > MAX_LABEL_VALUE)
939
if (!info->discard) {
941
for (i = 0; i < info->num_objects; i++) {
942
if (info->objects[i].label == integer) {
943
result = info->objects[i].object;
944
if (result == NULL) {
945
++info->objects[i].num_circles;
946
++info->circle_count;
947
result = READLABEL(integer);
952
if (i == info->num_objects)
953
READ_ERROR1("undefined label #%ld#", integer);
958
READ_ERROR1("undefined dispatch macro character #%c", ch);
966
LispSkipWhiteSpace(void)
971
while (ch = LispGet(), isspace(ch) && ch != EOF)
974
while (ch = LispGet(), ch != '\n' && ch != EOF)
986
/* any data in the format '(' FORM ')' is read here */
988
LispReadList(read_info *info)
992
LispObj *result, *cons, *object;
997
object = LispDoRead(info);
998
if (object == EOLIST) {
1005
READ_ERROR0("illegal start of dotted list");
1007
result = cons = CONS(object, NIL);
1009
/* make sure GC will not release data being read */
1012
while ((object = LispDoRead(info)) != EOLIST) {
1015
if (object == DOT) {
1016
if (info->nodot == info->level)
1017
READ_ERROR0("dotted list not allowed");
1018
/* this is a dotted list */
1020
READ_ERROR0("more than one . in list");
1025
/* only one object after a dot */
1027
READ_ERROR0("more than one object after . in list");
1028
RPLACD(cons, object);
1031
RPLACD(cons, CONS(object, NIL));
1037
/* this will happen if last list element was a dot */
1039
READ_ERROR0("illegal end of dotted list");
1048
LispReadQuote(read_info *info)
1051
LispObj *quote = LispDoRead(info), *result;
1053
if (INVALIDP(quote))
1054
READ_ERROR_INVARG();
1056
result = QUOTE(quote);
1062
LispReadBackquote(read_info *info)
1065
LispObj *backquote = LispDoRead(info), *result;
1067
if (INVALIDP(backquote))
1068
READ_ERROR_INVARG();
1070
result = BACKQUOTE(backquote);
1076
LispReadCommaquote(read_info *info)
1079
LispObj *comma, *result;
1080
int atlist = LispGet();
1084
else if (atlist != '@' && atlist != '.')
1087
comma = LispDoRead(info);
1090
comma = LispDoRead(info);
1092
if (INVALIDP(comma))
1093
READ_ERROR_INVARG();
1095
result = COMMA(comma, atlist == '@' || atlist == '.');
1101
* Read anything that is not readily identifiable by it's first character
1102
* and also put the code for reading atoms, numbers and strings together.
1105
LispReadObject(int unintern, read_info *info)
1109
char stk[128], *string, *package, *symbol;
1110
int ch, length, backslash, size, quote, unreadable, collon;
1112
package = symbol = string = stk;
1114
backslash = quote = unreadable = collon = 0;
1118
if (unintern && (ch == ':' || ch == '"'))
1119
READ_ERROR0("syntax error after #:");
1120
else if (ch == '"' || ch == '|')
1122
else if (ch == '\\') {
1123
unreadable = backslash = 1;
1124
string[length++] = ch;
1126
else if (ch == ':') {
1128
string[length++] = ch;
1129
symbol = string + 1;
1134
string[length++] = ch;
1139
/* read remaining data */
1145
/* if quote, file ended with an open quoted object */
1152
else if (ch == '\0')
1156
backslash = !backslash;
1158
/* only remove backslashs from strings */
1167
else if (ch == quote)
1169
else if (!quote && !backslash) {
1172
else if (isspace(ch))
1174
else if (AtomSeparator(ch, 0, 0)) {
1178
else if (ch == ':') {
1180
(collon == (1 - unintern) && symbol == string + length)) {
1182
symbol = string + length + 1;
1185
READ_ERROR0("too many collons");
1189
if (length + 2 >= size) {
1190
if (string == stk) {
1192
string = LispMalloc(size);
1193
strcpy(string, stk);
1197
string = LispRealloc(string, size);
1199
symbol = string + (symbol - package);
1202
string[length++] = ch;
1205
if (info->discard) {
1209
return (ch == EOF ? NULL : NIL);
1212
string[length] = '\0';
1216
READ_ERROR0("syntax error after #:");
1217
object = UNINTERNED_ATOM(string);
1220
else if (quote == '"')
1221
object = LSTRING(string, length);
1223
else if (quote == '|' || (unreadable && !collon)) {
1224
/* Set unreadable field, this atom needs quoting to be read back */
1225
object = ATOM(string);
1226
object->data.atom->unreadable = 1;
1230
/* Package specified in object name */
1234
object = LispParseAtom(package, symbol,
1235
collon == 2, unreadable,
1236
read__stream, read__line);
1239
/* Check some common symbols */
1240
else if (length == 1 && string[0] == 'T')
1244
else if (length == 1 && string[0] == '.')
1248
else if (length == 3 &&
1249
string[0] == 'N' && string[1] == 'I' && string[2] == 'L')
1253
else if (isdigit(string[0]) || string[0] == '.' ||
1254
((string[0] == '-' || string[0] == '+') && string[1]))
1255
/* Looks like a number */
1256
object = LispParseNumber(string, 10, read__stream, read__line);
1260
object = ATOM(string);
1269
LispParseAtom(char *package, char *symbol, int intern, int unreadable,
1270
LispObj *read__stream, int read__line)
1272
LispObj *object = NULL, *thepackage = NULL;
1273
LispPackage *pack = NULL;
1276
/* Until NIL and T be treated as normal symbols */
1277
if (symbol[0] == 'N' && symbol[1] == 'I' &&
1278
symbol[2] == 'L' && symbol[3] == '\0')
1280
if (symbol[0] == 'T' && symbol[1] == '\0')
1282
unreadable = !LispCheckAtomString(symbol);
1285
/* If package is empty, it is a keyword */
1286
if (package[0] == '\0') {
1287
thepackage = lisp__data.keyword;
1288
pack = lisp__data.key;
1292
/* Else, search it in the package list */
1293
thepackage = LispFindPackageFromString(package);
1295
if (thepackage == NIL)
1296
READ_ERROR1("the package %s is not available", package);
1298
pack = thepackage->data.package.package;
1301
if (pack == lisp__data.pack && intern) {
1302
/* Redundant package specification, since requesting a
1303
* intern symbol, create it if does not exist */
1305
object = ATOM(symbol);
1307
object->data.atom->unreadable = 1;
1310
else if (intern || pack == lisp__data.key) {
1311
/* Symbol is created, or just fetched from the specified package */
1313
LispPackage *savepack;
1314
LispObj *savepackage = PACKAGE;
1316
/* Remember curent package */
1317
savepack = lisp__data.pack;
1319
/* Temporarily set another package */
1320
lisp__data.pack = pack;
1321
PACKAGE = thepackage;
1323
/* Get the object pointer */
1324
if (pack == lisp__data.key)
1325
object = KEYWORD(LispDoGetAtom(symbol, 0)->string);
1327
object = ATOM(symbol);
1329
object->data.atom->unreadable = 1;
1331
/* Restore current package */
1332
lisp__data.pack = savepack;
1333
PACKAGE = savepackage;
1337
/* Symbol must exist (and be extern) in the specified package */
1342
i = STRHASH(symbol);
1343
atom = pack->atoms[i];
1345
if (strcmp(atom->string, symbol) == 0) {
1346
object = atom->object;
1353
/* No object found */
1354
if (object == NULL || object->data.atom->ext == 0)
1355
READ_ERROR2("no extern symbol %s in package %s", symbol, package);
1362
LispParseNumber(char *str, int radix, LispObj *read__stream, int read__line)
1372
if (radix < 2 || radix > 36)
1373
READ_ERROR1("radix %d is not in the range 2 to 36", radix);
1378
ratio = strchr(str, '/');
1380
/* check if looks like a correctly specified ratio */
1381
if (ratio[1] == '\0' || strchr(ratio + 1, '/') != NULL)
1384
/* ratio must point to an integer in radix base */
1387
else if (radix == 10) {
1391
/* check if it is a floating point number */
1393
if (*ptr == '-' || *ptr == '+')
1395
else if (*ptr == '.') {
1403
/* ignore it if last char is a dot */
1404
if (ptr[1] == '\0') {
1410
else if (!isdigit(*ptr))
1417
if (dot) /* if dot, it is default float */
1420
case 'E': case 'S': case 'F': case 'D': case 'L':
1425
return (ATOM(str)); /* syntax error */
1428
/* if type set, it is not an integer specification */
1435
if (*ptr == '+' || *ptr == '-')
1437
while (*ptr && isdigit(*ptr))
1446
dfloat = strtod(str, NULL);
1447
if (!finite(dfloat))
1448
READ_ERROR0("floating point overflow");
1450
return (DFLOAT(dfloat));
1454
/* check if correctly specified in the given radix */
1455
len = strlen(str) - 1;
1456
if (!ratio && radix != 10 && str[len] == '.')
1459
if (ratio || radix != 10) {
1460
if (!StringInRadix(str, radix, 1)) {
1465
if (ratio && !StringInRadix(ratio, radix, 0)) {
1475
integer = strtol(str, NULL, radix);
1477
/* if does not fit in a long */
1478
if (errno == ERANGE &&
1479
((*str == '-' && integer == LONG_MIN) ||
1480
(*str != '-' && integer == LONG_MAX))) {
1481
bignum = LispMalloc(sizeof(mpi));
1483
mpi_setstr(bignum, str, radix);
1487
if (ratio && integer != 0) {
1491
denominator = strtol(ratio, NULL, radix);
1492
if (denominator == 0)
1493
READ_ERROR0("divide by zero");
1495
if (bignum == NULL) {
1496
if (integer == MINSLONG ||
1497
(denominator == LONG_MAX && errno == ERANGE)) {
1498
bigratio = LispMalloc(sizeof(mpr));
1500
mpi_seti(mpr_num(bigratio), integer);
1501
mpi_setstr(mpr_den(bigratio), ratio, radix);
1505
bigratio = LispMalloc(sizeof(mpr));
1507
mpi_set(mpr_num(bigratio), bignum);
1510
mpi_setstr(mpr_den(bigratio), ratio, radix);
1514
mpr_canonicalize(bigratio);
1515
if (mpi_fiti(mpr_num(bigratio)) &&
1516
mpi_fiti(mpr_den(bigratio))) {
1517
integer = mpi_geti(mpr_num(bigratio));
1518
denominator = mpi_geti(mpr_den(bigratio));
1519
mpr_clear(bigratio);
1521
if (denominator == 1)
1522
number = INTEGER(integer);
1524
number = RATIO(integer, denominator);
1527
number = BIGRATIO(bigratio);
1530
long num = integer, den = denominator, rest;
1535
if ((rest = den % num) == 0)
1544
if (denominator < 0) {
1546
denominator = -denominator;
1548
if (denominator == 1)
1549
number = INTEGER(integer);
1551
number = RATIO(integer, denominator);
1555
number = BIGNUM(bignum);
1557
number = INTEGER(integer);
1563
StringInRadix(char *str, int radix, int skip_sign)
1565
if (skip_sign && (*str == '-' || *str == '+'))
1568
if (*str >= '0' && *str <= '9') {
1569
if (*str - '0' >= radix)
1572
else if (*str >= 'A' && *str <= 'Z') {
1573
if (radix <= 10 || *str - 'A' + 10 >= radix)
1585
AtomSeparator(int ch, int check_space, int check_backslash)
1587
if (check_space && isspace(ch))
1589
if (check_backslash && ch == '\\')
1591
return (strchr("(),\";'`#|,", ch) != NULL);
1595
LispReadVector(read_info *info)
1598
int nodot = info->nodot;
1600
info->nodot = info->level + 1;
1601
objects = LispReadList(info);
1602
info->nodot = nodot;
1607
return (VECTOR(objects));
1611
LispReadFunction(read_info *info)
1614
int nodot = info->nodot;
1617
info->nodot = info->level + 1;
1618
function = LispDoRead(info);
1619
info->nodot = nodot;
1624
if (INVALIDP(function))
1625
READ_ERROR_INVARG();
1626
else if (CONSP(function)) {
1627
if (CAR(function) != Olambda)
1628
READ_ERROR_INVARG();
1630
return (FUNCTION_QUOTE(function));
1632
else if (!SYMBOLP(function))
1633
READ_ERROR_INVARG();
1635
return (FUNCTION_QUOTE(function));
1639
LispReadRational(int radix, read_info *info)
1644
char stk[128], *str;
1652
if (ch == EOF || isspace(ch))
1654
else if (AtomSeparator(ch, 0, 1)) {
1658
else if (islower(ch))
1660
if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') &&
1661
ch != '+' && ch != '-' && ch != '/') {
1665
READ_ERROR1("bad character %c for rational number", ch);
1667
if (len + 1 >= size) {
1670
str = LispMalloc(size);
1671
strcpy(str + 1, stk + 1);
1675
str = LispRealloc(str, size);
1681
if (info->discard) {
1685
return (ch == EOF ? NULL : NIL);
1690
number = LispParseNumber(str, radix, read__stream, read__line);
1694
if (!RATIONALP(number))
1695
READ_ERROR0("bad rational number specification");
1701
LispReadCharacter(read_info *info)
1719
else if (ch != '-' && !isalnum(ch)) {
1723
if (len + 1 < sizeof(stk))
1731
for (c = ch = 0; ch <= ' ' && !found; ch++) {
1732
for (names = LispChars[ch].names; *names; names++)
1733
if (strcasecmp(*names, stk) == 0) {
1740
for (names = LispChars[0177].names; *names; names++)
1741
if (strcasecmp(*names, stk) == 0) {
1751
READ_ERROR1("unkwnown character %s", stk);
1761
LispSkipComment(void)
1776
if (ch == '#' && --comm == 0)
1785
LispReadEval(read_info *info)
1788
int nodot = info->nodot;
1791
info->nodot = info->level + 1;
1792
code = LispDoRead(info);
1793
info->nodot = nodot;
1799
READ_ERROR_INVARG();
1801
return (EVAL(code));
1805
LispReadComplex(read_info *info)
1809
int nodot = info->nodot;
1810
LispObj *number, *arguments;
1812
info->nodot = info->level + 1;
1813
arguments = LispDoRead(info);
1814
info->nodot = nodot;
1820
if (INVALIDP(arguments) || !CONSP(arguments))
1821
READ_ERROR_INVARG();
1823
GC_PROTECT(arguments);
1824
number = APPLY(Ocomplex, arguments);
1831
LispReadPathname(read_info *info)
1835
int nodot = info->nodot;
1836
LispObj *path, *arguments;
1838
info->nodot = info->level + 1;
1839
arguments = LispDoRead(info);
1840
info->nodot = nodot;
1846
if (INVALIDP(arguments))
1847
READ_ERROR_INVARG();
1849
GC_PROTECT(arguments);
1850
path = APPLY1(Oparse_namestring, arguments);
1857
LispReadStruct(read_info *info)
1861
int len, nodot = info->nodot;
1862
char stk[128], *str;
1863
LispObj *struc, *fields;
1865
info->nodot = info->level + 1;
1866
fields = LispDoRead(info);
1867
info->nodot = nodot;
1873
if (INVALIDP(fields) || !CONSP(fields) || !SYMBOLP(CAR(fields)))
1874
READ_ERROR_INVARG();
1878
len = strlen(ATOMID(CAR(fields)));
1880
if (len + 6 > sizeof(stk))
1881
str = LispMalloc(len + 6);
1884
sprintf(str, "MAKE-%s", ATOMID(CAR(fields)));
1885
RPLACA(fields, ATOM(str));
1888
struc = APPLY(Omake_struct, fields);
1894
/* XXX This is broken, needs a rewritten as soon as true vector/arrays be
1897
LispReadArray(long dimensions, read_info *info)
1902
int nodot = info->nodot;
1903
LispObj *arguments, *initial, *dim, *cons, *array, *data;
1905
info->nodot = info->level + 1;
1906
data = LispDoRead(info);
1907
info->nodot = nodot;
1914
READ_ERROR_INVARG();
1916
initial = Kinitial_contents;
1922
for (count = 0, array = data; count < dimensions; count++) {
1927
READ_ERROR0("bad array for given dimension");
1931
for (length = 0; CONSP(item); item = CDR(item), length++)
1935
dim = cons = CONS(FIXNUM(length), NIL);
1939
RPLACD(cons, CONS(FIXNUM(length), NIL));
1945
arguments = CONS(dim, CONS(initial, CONS(data, NIL)));
1946
GC_PROTECT(arguments);
1947
array = APPLY(Omake_array, arguments);
1954
LispReadFeature(int with, read_info *info)
1958
LispObj *feature = LispDoRead(info);
1964
if (INVALIDP(feature))
1965
READ_ERROR_INVARG();
1967
/* paranoia check, features must be a list, possibly empty */
1968
if (!CONSP(FEATURES) && FEATURES != NIL)
1969
READ_ERROR1("%s is not a list", STROBJ(FEATURES));
1971
status = LispEvalFeature(feature);
1975
return (LispDoRead(info));
1977
/* need to use the field discard because the following expression
1978
* may be #.FORM or #,FORM or any other form that may generate
1984
return (LispDoRead(info));
1988
return (LispDoRead(info));
1994
return (LispDoRead(info));
1998
* A very simple eval loop with AND, NOT, and OR functions for testing
1999
* the available features.
2002
LispEvalFeature(LispObj *feature)
2008
if (CONSP(feature)) {
2009
LispObj *function = CAR(feature), *arguments = CDR(feature);
2011
if (!SYMBOLP(function))
2012
READ_ERROR1("bad feature test function %s", STROBJ(function));
2013
if (!CONSP(arguments))
2014
READ_ERROR1("bad feature test arguments %s", STROBJ(arguments));
2015
test = ATOMID(function);
2017
for (; CONSP(arguments); arguments = CDR(arguments)) {
2018
if (LispEvalFeature(CAR(arguments)) == NIL)
2023
else if (test == Sor) {
2024
for (; CONSP(arguments); arguments = CDR(arguments)) {
2025
if (LispEvalFeature(CAR(arguments)) == T)
2030
else if (test == Snot) {
2031
if (CONSP(CDR(arguments)))
2032
READ_ERROR0("too many arguments to NOT");
2034
return (LispEvalFeature(CAR(arguments)) == NIL ? T : NIL);
2037
READ_ERROR1("unimplemented feature test function %s", test);
2040
if (KEYWORDP(feature))
2041
feature = feature->data.quote;
2042
else if (!SYMBOLP(feature))
2043
READ_ERROR1("bad feature specification %s", STROBJ(feature));
2045
test = ATOMID(feature);
2047
for (object = FEATURES; CONSP(object); object = CDR(object)) {
2048
/* paranoia check, elements in the feature list must ge keywords */
2049
if (!KEYWORDP(CAR(object)))
2050
READ_ERROR1("%s is not a keyword", STROBJ(CAR(object)));
2051
if (ATOMID(CAR(object)) == test)
2055
/* unknown feature */