allow -Dname=val option
[neatcc/cc.git] / cpp.c
blobca359071eb504d609c5c4ab1fc4b2c67b6eb2efe
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 define {
17 char name[NAMELEN];
18 char def[MACROLEN];
19 char args[MAXARGS][NAMELEN];
20 int nargs;
21 int isfunc;
22 } defines[MAXDEFS];
23 static int ndefines;
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 void macro_define(void)
194 struct define *d = &defines[ndefines++];
195 read_word(d->name);
196 d->isfunc = 0;
197 if (buf[cur++] == '(') {
198 jumpws();
199 while (cur < len && buf[cur] != ')') {
200 readarg(d->args[d->nargs++]);
201 jumpws();
202 if (buf[cur] != ',')
203 break;
204 jumpws();
206 d->isfunc = 1;
207 cur++;
209 jumpws();
210 read_tilleol(d->def);
213 static void cpp_cmd(void)
215 char cmd[NAMELEN];
216 cur++;
217 read_word(cmd);
218 if (!strcmp("define", cmd)) {
219 macro_define();
220 return;
222 if (!strcmp("include", cmd)) {
223 char file[NAMELEN];
224 char *s, *e;
225 int fd;
226 jumpws();
227 s = buf + cur + 1;
228 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
229 memcpy(file, s, e - s);
230 file[e - s] = '\0';
231 cur += e - s + 2;
232 fd = include_find(file, *e == '>');
233 if (fd == -1)
234 return;
235 include(fd);
236 close(fd);
237 return;
241 static int macro_find(char *name)
243 int i;
244 for (i = 0; i < ndefines; i++)
245 if (!strcmp(name, defines[i].name))
246 return i;
247 return -1;
250 static int macro_arg(struct define *m, char *arg)
252 int i;
253 for (i = 0; i < m->nargs; i++)
254 if (!strcmp(arg, m->args[i]))
255 return i;
256 return -1;
259 static void macro_expand(void)
261 char name[NAMELEN];
262 char args[MAXARGS][MACROLEN];
263 int nargs;
264 struct define *m;
265 char *dst;
266 int dstlen = 0;
267 int beg;
268 read_word(name);
269 m = &defines[macro_find(name)];
270 if (!m->isfunc) {
271 buf_new();
272 strcpy(buf, m->def);
273 len = strlen(m->def);
274 return;
276 if (buf[cur] == '(') {
277 cur++;
278 jumpws();
279 while (cur < len && buf[cur] != ')') {
280 readarg(args[nargs++]);
281 jumpws();
282 if (buf[cur] != ',')
283 break;
284 jumpws();
286 cur++;
287 m->isfunc = 1;
289 buf_new();
290 dst = buf;
291 buf = m->def;
292 len = strlen(m->def);
293 beg = cur;
294 while (cur < len) {
295 if (buf[cur] == '/' && buf[cur + 1] == '*') {
296 jumpcomment();
297 continue;
299 if (strchr("'\"", buf[cur])) {
300 jumpstr();
301 continue;
303 if (isalpha(buf[cur]) || buf[cur] == '_') {
304 int arg;
305 char word[NAMELEN];
306 read_word(word);
307 if ((arg = macro_arg(m, word)) != -1) {
308 int len = cur - beg - strlen(word);
309 char *argstr = arg > nargs ? "" : args[arg];
310 int arglen = strlen(argstr);
311 memcpy(dst + dstlen, buf + beg, len);
312 dstlen += len;
313 memcpy(dst + dstlen, argstr, arglen);
314 dstlen += arglen;
315 beg = cur;
317 continue;
319 cur++;
321 memcpy(dst + dstlen, buf + beg, len - beg);
322 dstlen += len - beg;
323 buf = dst;
324 len = dstlen;
325 cur = 0;
326 buf[len] = '\0';
329 void cpp_define(char *name, char *def)
331 char *s;
332 buf_new();
333 s = buf;
334 s = putstr(s, name);
335 *s++ = '\t';
336 s = putstr(s, def);
337 len = s - buf;
338 macro_define();
339 buf_pop();
342 static int definedword;
344 int cpp_read(char *s)
346 int old;
347 if (definedword) {
348 definedword = 0;
349 macro_expand();
351 if (cur == len) {
352 if (nbufs < 2)
353 return -1;
354 buf_pop();
356 old = cur;
357 if (buf[cur] == '#') {
358 cpp_cmd();
359 return 0;
361 while (cur < len) {
362 if (buf[cur] == '#')
363 break;
364 if (buf[cur] == '/' && buf[cur + 1] == '*') {
365 jumpcomment();
366 continue;
368 if (buf[cur] == '\'' || buf[cur] == '"') {
369 jumpstr();
370 continue;
372 if (isalpha(buf[cur]) || buf[cur] == '_') {
373 char word[NAMELEN];
374 read_word(word);
375 if (macro_find(word) != -1) {
376 cur -= strlen(word);
377 definedword = 1;
378 break;
380 continue;
382 cur++;
384 memcpy(s, buf + old, cur - old);
385 return cur - old;