support #undef NAME
[neatcc.git] / cpp.c
blobc4cd9b8742ae14658d18a7540e555538abb42b16
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include "tok.h"
8 static char *buf;
9 static int len;
10 static int cur;
12 #define MAXDEFS (1 << 10)
13 #define MACROLEN (1 << 10)
14 #define MAXARGS (1 << 5)
16 static struct macro {
17 char name[NAMELEN];
18 char def[MACROLEN];
19 char args[MAXARGS][NAMELEN];
20 int nargs;
21 int isfunc;
22 } macros[MAXDEFS];
23 static int nmacros;
25 #define MAXBUFS (1 << 3)
27 static struct buf {
28 char buf[BUFSIZE];
29 int len;
30 int cur;
31 } bufs[MAXBUFS];
32 static int nbufs;
34 static void buf_new(void)
36 if (nbufs) {
37 bufs[nbufs - 1].cur = cur;
38 bufs[nbufs - 1].len = len;
40 nbufs++;
41 cur = 0;
42 len = 0;
43 buf = bufs[nbufs - 1].buf;
46 static void buf_pop(void)
48 nbufs--;
49 if (nbufs) {
50 cur = bufs[nbufs - 1].cur;
51 len = bufs[nbufs - 1].len;
52 buf = bufs[nbufs - 1].buf;
56 static void include(int fd)
58 int n = 0;
59 buf_new();
60 while ((n = read(fd, buf + len, BUFSIZE - len)) > 0)
61 len += n;
64 void cpp_init(int fd)
66 include(fd);
69 static void jumpws(void)
71 while (cur < len && isspace(buf[cur]))
72 cur++;
75 static void read_word(char *dst)
77 jumpws();
78 while (cur < len && isalnum(buf[cur]) || buf[cur] == '_')
79 *dst++ = buf[cur++];
80 *dst = '\0';
83 static void read_tilleol(char *dst)
85 while (cur < len && buf[cur] != '\n')
86 if (buf[cur] == '\\')
87 cur += 2;
88 else
89 *dst++ = buf[cur++];
90 *dst = '\0';
93 static char *putstr(char *d, char *s)
95 while (*s)
96 *d++ = *s++;
97 *d = '\0';
98 return d;
101 #define MAXLOCS (1 << 10)
103 static char *locs[MAXLOCS] = {".", NULL, "/usr/include"};
104 static int nlocs = 3;
106 void cpp_addpath(char *s)
108 locs[nlocs++] = s;
111 static int include_find(char *name, int std)
113 int i;
114 int fd;
115 for (i = std ? 1 : 0; i < nlocs; i++) {
116 char path[1 << 10];
117 char *s;
118 if (!locs[i] && *name != '/')
119 continue;
120 s = putstr(path, locs[i]);
121 if (locs[i])
122 *s++ = '/';
123 s = putstr(s, name);
124 fd = open(path, O_RDONLY);
125 if (fd != -1)
126 return fd;
128 return -1;
131 static void jumpstr(void)
133 if (buf[cur] == '\'') {
134 while (cur < len && buf[++cur] != '\'')
135 if (buf[cur] == '\\')
136 cur++;
137 cur++;
138 return;
140 if (buf[cur] == '"') {
141 while (cur < len && buf[++cur] != '"')
142 if (buf[cur] == '\\')
143 cur++;
144 cur++;
145 return;
149 static void jumpcomment(void)
151 while (++cur < len) {
152 if (buf[cur] == '*' && buf[cur + 1] == '/') {
153 cur += 2;
154 break;
159 static void readarg(char *s)
161 int depth = 0;
162 int beg = cur;
163 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
164 switch (buf[cur]) {
165 case '(':
166 case '[':
167 case '{':
168 cur++;
169 depth++;
170 break;
171 case ')':
172 case ']':
173 case '}':
174 cur++;
175 depth--;
176 break;
177 case '\'':
178 case '"':
179 jumpstr();
180 break;
181 default:
182 if (buf[cur] == '/' && buf[cur + 1] == '*')
183 jumpcomment();
184 else
185 cur++;
188 memcpy(s, buf + beg, cur - beg);
189 s[cur - beg] = '\0';
192 static int macro_find(char *name)
194 int i;
195 for (i = 0; i < nmacros; i++)
196 if (!strcmp(name, macros[i].name))
197 return i;
198 return -1;
201 static int macro_new(char *name)
203 int i;
204 for (i = 0; i < nmacros; i++) {
205 if (!strcmp(name, macros[i].name))
206 return i;
207 if (!*macros[i].name) {
208 strcpy(macros[i].name, name);
209 return i;
212 strcpy(macros[nmacros++].name, name);
213 return nmacros - 1;
216 static void macro_define(void)
218 char name[NAMELEN];
219 struct macro *d;
220 read_word(name);
221 d = &macros[macro_new(name)];
222 d->isfunc = 0;
223 if (buf[cur++] == '(') {
224 jumpws();
225 while (cur < len && buf[cur] != ')') {
226 readarg(d->args[d->nargs++]);
227 jumpws();
228 if (buf[cur] != ',')
229 break;
230 jumpws();
232 d->isfunc = 1;
233 cur++;
235 jumpws();
236 read_tilleol(d->def);
239 static void cpp_cmd(void)
241 char cmd[NAMELEN];
242 cur++;
243 read_word(cmd);
244 if (!strcmp("define", cmd)) {
245 macro_define();
246 return;
248 if (!strcmp("undef", cmd)) {
249 char name[NAMELEN];
250 int idx;
251 read_word(name);
252 idx = macro_find(name);
253 if (idx != -1)
254 strcpy(macros[idx].name, "");
255 return;
257 if (!strcmp("include", cmd)) {
258 char file[NAMELEN];
259 char *s, *e;
260 int fd;
261 jumpws();
262 s = buf + cur + 1;
263 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
264 memcpy(file, s, e - s);
265 file[e - s] = '\0';
266 cur += e - s + 2;
267 fd = include_find(file, *e == '>');
268 if (fd == -1)
269 return;
270 include(fd);
271 close(fd);
272 return;
276 static int macro_arg(struct macro *m, char *arg)
278 int i;
279 for (i = 0; i < m->nargs; i++)
280 if (!strcmp(arg, m->args[i]))
281 return i;
282 return -1;
285 static void macro_expand(void)
287 char name[NAMELEN];
288 char args[MAXARGS][MACROLEN];
289 int nargs;
290 struct macro *m;
291 char *dst;
292 int dstlen = 0;
293 int beg;
294 read_word(name);
295 m = &macros[macro_find(name)];
296 if (!m->isfunc) {
297 buf_new();
298 strcpy(buf, m->def);
299 len = strlen(m->def);
300 return;
302 if (buf[cur] == '(') {
303 cur++;
304 jumpws();
305 while (cur < len && buf[cur] != ')') {
306 readarg(args[nargs++]);
307 jumpws();
308 if (buf[cur] != ',')
309 break;
310 jumpws();
312 cur++;
313 m->isfunc = 1;
315 buf_new();
316 dst = buf;
317 buf = m->def;
318 len = strlen(m->def);
319 beg = cur;
320 while (cur < len) {
321 if (buf[cur] == '/' && buf[cur + 1] == '*') {
322 jumpcomment();
323 continue;
325 if (strchr("'\"", buf[cur])) {
326 jumpstr();
327 continue;
329 if (isalpha(buf[cur]) || buf[cur] == '_') {
330 int arg;
331 char word[NAMELEN];
332 read_word(word);
333 if ((arg = macro_arg(m, word)) != -1) {
334 int len = cur - beg - strlen(word);
335 char *argstr = arg > nargs ? "" : args[arg];
336 int arglen = strlen(argstr);
337 memcpy(dst + dstlen, buf + beg, len);
338 dstlen += len;
339 memcpy(dst + dstlen, argstr, arglen);
340 dstlen += arglen;
341 beg = cur;
343 continue;
345 cur++;
347 memcpy(dst + dstlen, buf + beg, len - beg);
348 dstlen += len - beg;
349 buf = dst;
350 len = dstlen;
351 cur = 0;
352 buf[len] = '\0';
355 void cpp_define(char *name, char *def)
357 char *s;
358 buf_new();
359 s = buf;
360 s = putstr(s, name);
361 *s++ = '\t';
362 s = putstr(s, def);
363 len = s - buf;
364 macro_define();
365 buf_pop();
368 static int definedword;
370 int cpp_read(char *s)
372 int old;
373 if (definedword) {
374 definedword = 0;
375 macro_expand();
377 if (cur == len) {
378 if (nbufs < 2)
379 return -1;
380 buf_pop();
382 old = cur;
383 if (buf[cur] == '#') {
384 cpp_cmd();
385 return 0;
387 while (cur < len) {
388 if (buf[cur] == '#')
389 break;
390 if (buf[cur] == '/' && buf[cur + 1] == '*') {
391 jumpcomment();
392 continue;
394 if (buf[cur] == '\'' || buf[cur] == '"') {
395 jumpstr();
396 continue;
398 if (isalpha(buf[cur]) || buf[cur] == '_') {
399 char word[NAMELEN];
400 read_word(word);
401 if (macro_find(word) != -1) {
402 cur -= strlen(word);
403 definedword = 1;
404 break;
406 continue;
408 cur++;
410 memcpy(s, buf + old, cur - old);
411 return cur - old;