handle #ifdef, #ifndef, #else and #endif
[neatcc.git] / cpp.c
blobe37051f48669be9bfd302579cf2d62ede2641035
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] = {"/usr/include"};
104 static int nlocs = 1;
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 ? nlocs - 1 : nlocs; i >= 0; i--) {
116 char path[1 << 10];
117 char *s;
118 s = path;
119 if (locs[i]) {
120 s = putstr(s, locs[i]);
121 *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 read_tilleol(d->def);
238 static void jumpifs(int jumpelse)
240 int depth = 0;
241 while (cur < len) {
242 if (buf[cur] == '#') {
243 char cmd[NAMELEN];
244 cur++;
245 read_word(cmd);
246 if (!strcmp("else", cmd))
247 if (!depth && !jumpelse)
248 break;
249 if (!strcmp("endif", cmd))
250 if (!depth)
251 break;
252 else
253 depth--;
254 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd))
255 depth++;
257 if (buf[cur] == '/' && buf[cur + 1] == '*') {
258 jumpcomment();
259 continue;
261 if (buf[cur] == '\'' || buf[cur] == '"') {
262 jumpstr();
263 continue;
265 cur++;
269 static void cpp_cmd(void)
271 char cmd[NAMELEN];
272 cur++;
273 read_word(cmd);
274 if (!strcmp("define", cmd)) {
275 macro_define();
276 return;
278 if (!strcmp("undef", cmd)) {
279 char name[NAMELEN];
280 int idx;
281 read_word(name);
282 idx = macro_find(name);
283 if (idx != -1)
284 strcpy(macros[idx].name, "");
285 return;
287 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd)) {
288 char name[NAMELEN];
289 int not = cmd[2] == 'n';
290 read_word(name);
291 if (!not && macro_find(name) < 0 || not && macro_find(name) >= 0)
292 jumpifs(0);
293 return;
295 if (!strcmp("else", cmd)) {
296 jumpifs(1);
297 return;
299 if (!strcmp("endif", cmd))
300 return;
301 if (!strcmp("include", cmd)) {
302 char file[NAMELEN];
303 char *s, *e;
304 int fd;
305 jumpws();
306 s = buf + cur + 1;
307 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
308 memcpy(file, s, e - s);
309 file[e - s] = '\0';
310 cur += e - s + 2;
311 fd = include_find(file, *e == '>');
312 if (fd == -1)
313 return;
314 include(fd);
315 close(fd);
316 return;
320 static int macro_arg(struct macro *m, char *arg)
322 int i;
323 for (i = 0; i < m->nargs; i++)
324 if (!strcmp(arg, m->args[i]))
325 return i;
326 return -1;
329 static void macro_expand(void)
331 char name[NAMELEN];
332 char args[MAXARGS][MACROLEN];
333 int nargs;
334 struct macro *m;
335 char *dst;
336 int dstlen = 0;
337 int beg;
338 read_word(name);
339 m = &macros[macro_find(name)];
340 if (!m->isfunc) {
341 buf_new();
342 strcpy(buf, m->def);
343 len = strlen(m->def);
344 return;
346 if (buf[cur] == '(') {
347 cur++;
348 jumpws();
349 while (cur < len && buf[cur] != ')') {
350 readarg(args[nargs++]);
351 jumpws();
352 if (buf[cur] != ',')
353 break;
354 jumpws();
356 cur++;
357 m->isfunc = 1;
359 buf_new();
360 dst = buf;
361 buf = m->def;
362 len = strlen(m->def);
363 beg = cur;
364 while (cur < len) {
365 if (buf[cur] == '/' && buf[cur + 1] == '*') {
366 jumpcomment();
367 continue;
369 if (strchr("'\"", buf[cur])) {
370 jumpstr();
371 continue;
373 if (isalpha(buf[cur]) || buf[cur] == '_') {
374 int arg;
375 char word[NAMELEN];
376 read_word(word);
377 if ((arg = macro_arg(m, word)) != -1) {
378 int len = cur - beg - strlen(word);
379 char *argstr = arg > nargs ? "" : args[arg];
380 int arglen = strlen(argstr);
381 memcpy(dst + dstlen, buf + beg, len);
382 dstlen += len;
383 memcpy(dst + dstlen, argstr, arglen);
384 dstlen += arglen;
385 beg = cur;
387 continue;
389 cur++;
391 memcpy(dst + dstlen, buf + beg, len - beg);
392 dstlen += len - beg;
393 buf = dst;
394 len = dstlen;
395 cur = 0;
396 buf[len] = '\0';
399 void cpp_define(char *name, char *def)
401 char *s;
402 buf_new();
403 s = buf;
404 s = putstr(s, name);
405 *s++ = '\t';
406 s = putstr(s, def);
407 len = s - buf;
408 macro_define();
409 buf_pop();
412 static int definedword;
414 int cpp_read(char *s)
416 int old;
417 if (definedword) {
418 definedword = 0;
419 macro_expand();
421 if (cur == len) {
422 if (nbufs < 2)
423 return -1;
424 buf_pop();
426 old = cur;
427 if (buf[cur] == '#') {
428 cpp_cmd();
429 return 0;
431 while (cur < len) {
432 if (buf[cur] == '#')
433 break;
434 if (buf[cur] == '/' && buf[cur + 1] == '*') {
435 jumpcomment();
436 continue;
438 if (buf[cur] == '\'' || buf[cur] == '"') {
439 jumpstr();
440 continue;
442 if (isalpha(buf[cur]) || buf[cur] == '_') {
443 char word[NAMELEN];
444 read_word(word);
445 if (macro_find(word) != -1) {
446 cur -= strlen(word);
447 definedword = 1;
448 break;
450 continue;
452 cur++;
454 memcpy(s, buf + old, cur - old);
455 return cur - old;