forked from lwhjp/building-lisp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathread.c
148 lines (120 loc) · 2.74 KB
/
read.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
#include "lisp.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int lex(const char *str, const char **start, const char **end)
{
const char *ws = " \t\n";
const char *delim = "(); \t\n";
const char *prefix = "()\'`";
str += strspn(str, ws);
if (str[0] == '\0') {
*start = *end = NULL;
return Error_Syntax;
}
*start = str;
if (strchr(prefix, str[0]) != NULL)
*end = str + 1;
else if (str[0] == ',')
*end = str + (str[1] == '@' ? 2 : 1);
else if (str[0] == ';') {
str = strchr(str, '\n');
if (!str) {
*start = *end = NULL;
return Error_Syntax;
}
return lex(str, start, end);
} else
*end = str + strcspn(str, delim);
return Error_OK;
}
int parse_simple(const char *start, const char *end, Atom *result)
{
char *buf, *p;
/* Is it an integer? */
long val = strtol(start, &p, 10);
if (p == end) {
result->type = AtomType_Integer;
result->value.integer = val;
return Error_OK;
}
/* NIL or symbol */
buf = malloc(end - start + 1);
p = buf;
while (start != end)
*p++ = toupper(*start), ++start;
*p = '\0';
if (strcmp(buf, "NIL") == 0)
*result = nil;
else
*result = make_sym(buf);
free(buf);
return Error_OK;
}
int read_list(const char *start, const char **end, Atom *result)
{
Atom p;
*end = start;
p = *result = nil;
for (;;) {
const char *token;
Atom item;
Error err;
err = lex(*end, &token, end);
if (err)
return err;
if (token[0] == ')')
return Error_OK;
if (token[0] == '.' && *end - token == 1) {
/* Improper list */
if (nilp(p))
return Error_Syntax;
err = read_expr(*end, end, &item);
if (err)
return err;
cdr(p) = item;
/* Read the closing ')' */
err = lex(*end, &token, end);
if (!err && token[0] != ')')
err = Error_Syntax;
return err;
}
err = read_expr(token, end, &item);
if (err)
return err;
if (nilp(p)) {
/* First item */
*result = cons(item, nil);
p = *result;
} else {
cdr(p) = cons(item, nil);
p = cdr(p);
}
}
}
int read_expr(const char *input, const char **end, Atom *result)
{
const char *token;
Error err;
err = lex(input, &token, end);
if (err)
return err;
if (token[0] == '(') {
return read_list(*end, end, result);
} else if (token[0] == ')') {
return Error_Syntax;
} else if (token[0] == '\'') {
*result = cons(make_sym("QUOTE"), cons(nil, nil));
return read_expr(*end, end, &car(cdr(*result)));
} else if (token[0] == '`') {
*result = cons(make_sym("QUASIQUOTE"), cons(nil, nil));
return read_expr(*end, end, &car(cdr(*result)));
} else if (token[0] == ',') {
*result = cons(make_sym(
token[1] == '@' ? "UNQUOTE-SPLICING" : "UNQUOTE"),
cons(nil, nil));
return read_expr(*end, end, &car(cdr(*result)));
} else {
return parse_simple(token, *end, result);
}
}