-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreader.c
154 lines (131 loc) · 3.46 KB
/
reader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lilscheme.h"
int issymbolstart(int);
int issymbol(int);
int ReadNextNonSpace(FILE*);
Handle ReadNextObject(FILE*);
Handle ReadNumber(FILE*);
Handle ReadSymbol(FILE*);
Handle ReadList(FILE*);
Handle ReadQuoted(FILE*);
Handle ReadVector(FILE*);
// TODO: allow reading from a string, not just a file
// options: fmemopen(3), a Scheme-like port abstraction, wacky HAL stuff
// TODO: handle EOFs properly
// disable garbage collection while reading
Handle ReadObject(FILE *input) {
DisableGC();
Handle o = ReadNextObject(input);
EnableGC();
return o;
}
Handle ReadNextObject(FILE *input) {
int c;
c = ReadNextNonSpace(input);
if (ferror(input)) panic("EOF or read error in reader");
if (feof(input)) return nil;
ungetc(c, input);
if (isdigit(c)) return ReadNumber(input);
if (issymbolstart(c)) return ReadSymbol(input);
if (c == '(') return ReadList(input);
if (c == '\'') return ReadQuoted(input);
if (c == '#') return ReadVector(input);
// TODO: quasiquote/unquote
// control isn't supposed to fall through to here
fprintf(stderr, "c = %d ('%c')\n", c, (char)c);
panic("reader doesn't understand that");
return nil;
}
// TODO: hex, scientific notation, floating point
Handle ReadNumber(FILE *input) {
char buffer[32];
int idx = 0;
int c = 0;
while (c=fgetc(input), isdigit(c)) {
if (idx >= 31) break; // clumsy
buffer[idx++] = (char)c;
}
ungetc(c, input);
buffer[idx] = '\0';
int result = atoi(buffer);
return CreateInteger(result);
}
int matches(int c, const char *ds) {
while (*ds != '\0') {
if (c == *ds) return 1;
ds++;
}
return 0;
}
int issymbolstart(int c) {
const char* SYM_CHARS = "!$%&*+-./:<=>?@^_~";
return isalpha(c) || matches(c, SYM_CHARS);
}
int issymbol(int c) {
return issymbolstart(c) || isdigit(c);
}
Handle ReadSymbol(FILE *input) {
char buffer[64];
int idx = 0;
int c = 0;
while (c=fgetc(input), issymbol(c)) {
if (idx >= 63) break; // clumsy termination
buffer[idx++] = (char)c;
}
ungetc(c, input);
buffer[idx] = '\0';
return CreateSymbol(buffer);
}
Handle ReadList(FILE *input) {
Handle head, tail, next;
Handle item;
int c;
fgetc(input); //discard left parenthesis
if ((c = fgetc(input)) == ')') {
// let's say that the empty list is nil for now
return nil;
}
else ungetc(c, input);
item = ReadNextObject(input);
head = CreateCons(item, nil);
tail = head;
while ((c = ReadNextNonSpace(input)) != ')') {
if (feof(input)) panic("list not closed");
ungetc(c, input);
item = ReadNextObject(input);
next = CreateCons(item, nil);
SetCdr(tail, next);
tail = next;
}
return head;
}
Handle ReadQuoted(FILE *input) {
fgetc(input); // discard quote tick
Handle o = ReadNextObject(input);
// 'o -> (quote o)
return CreateCons(CreateSymbol("quote"),
CreateCons(o,
nil));
}
int ReadNextNonSpace(FILE *input) {
int c;
do {
c = fgetc(input);
} while (isspace(c));
return c;
}
// XXX: concise, but inefficient implementation
Handle ReadVector(FILE *input) {
fgetc(input); // discard hash sign
Handle intermed = ReadNextObject(input);
if (DEREF(intermed)->type != TYPE_CONS){
// not a list
panic("reader doesn't understand that");
return nil;
}
Handle v = VectorFromList(intermed);
return v;
}