Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121019120900

Diff

Diff from 1.180 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/cc/cpp/cpp.c

Annotated File View

plunky
1.180
1 /*      $Id: cpp.c,v 1.180 2012/10/19 12:09:00 plunky Exp $     */
ragge
1.1
2
3 /*
ragge
1.109
4  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
ragge
1.1
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*
29  * The C preprocessor.
30  * This code originates from the V6 preprocessor with some additions
31  * from V7 cpp, and at last ansi/c99 support.
32  */
pj
1.23
33
ragge
1.74
34 #include "config.h"
pj
1.23
35
ragge
1.108
36 #include <sys/stat.h>
ragge
1.1
37
38 #include <fcntl.h>
gmcgarry
1.81
39 #ifdef HAVE_UNISTD_H
ragge
1.1
40 #include <unistd.h>
gmcgarry
1.81
41 #endif
ragge
1.1
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
ragge
1.9
46 #include <time.h>
ragge
1.1
47
ragge
1.74
48 #include "compat.h"
ragge
1.1
49 #include "cpp.h"
plunky
1.156
50 #include "cpy.h"
ragge
1.1
51
gmcgarry
1.130
52 #ifndef S_ISDIR
53 #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
54 #endif
55
ragge
1.126
56 #define SBSIZE  1000000
ragge
1.1
57
plunky
1.168
58 static const char versstr[] = "PCC preprocessor version " VERSSTR "\n";
59
ragge
1.1
60 static usch     sbf[SBSIZE];
61 /* C command */
62
63 int tflag;      /* traditional cpp syntax */
plunky
1.134
64 #ifdef PCC_DEBUG
ragge
1.1
65 int dflag;      /* debug printouts */
plunky
1.135
66 static void imp(const char *);
67 static void prline(const usch *s);
68 static void prrep(const usch *s);
ragge
1.36
69 #define DPRINT(x) if (dflag) printf x
70 #define DDPRINT(x) if (dflag > 1) printf x
plunky
1.135
71 #define IMP(x) if (dflag > 1) imp(x)
ragge
1.36
72 #else
73 #define DPRINT(x)
74 #define DDPRINT(x)
plunky
1.135
75 #define IMP(x)
ragge
1.1
76 #endif
ragge
1.36
77
ragge
1.51
78 int ofd;
ragge
1.56
79 usch outbuf[CPPBUF];
ragge
1.97
80 int obufpistty;
ragge
1.151
81 int CflagMflagdMflagPflagMPflag;
82 usch *Mfile, *MPfile, *Mxfile;
ragge
1.53
83 struct initar *initar;
ragge
1.117
84 int readmaclastoch;
plunky
1.173
85 int defining;
ragge
1.1
86
ragge
1.10
87 /* include dirs */
88 struct incs {
89         struct incs *next;
ragge
1.39
90         usch *dir;
ragge
1.108
91         dev_t dev;
92         ino_t ino;
ragge
1.20
93 } *incdir[2];
ragge
1.10
94
ragge
1.1
95 static struct symtab *filloc;
96 static struct symtab *linloc;
ragge
1.65
97 static struct symtab *pragloc;
ragge
1.10
98 int     trulvl;
99 int     flslvl;
100 int     elflvl;
101 int     elslvl;
102 usch *stringbuf = sbf;
ragge
1.1
103
104 /*
105  * Macro replacement list syntax:
106  * - For object-type macros, replacement strings are stored as-is.
107  * - For function-type macros, macro args are substituted for the
108  *   character WARN followed by the argument number.
ragge
1.12
109  * - The value element points to the end of the string, to simplify
110  *   pushback onto the input queue.
ragge
1.1
111  * 
ragge
1.12
112  * The first character (from the end) in the replacement list is
113  * the number of arguments:
ragge
1.37
114  *   VARG  - ends with ellipsis, next char is argcount without ellips.
ragge
1.1
115  *   OBJCT - object-type macro
116  *   0     - empty parenthesis, foo()
117  *   1->   - number of args.
ragge
1.109
118  *
119  * WARN is used:
120  *      - in stored replacement lists to tell that an argument comes
121  *      - When expanding replacement lists to tell that the list ended.
ragge
1.116
122  *
123  * To ensure that an already expanded identifier won't get expanded
124  * again a EBLOCK char + its number is stored directly before any 
125  * expanded identifier.
ragge
1.1
126  */
127
128 /* args for lookup() */
129 #define FIND    0
130 #define ENTER   1
131
plunky
1.166
132 /*
133  * No-replacement array.  If a macro is found and exists in this array
134  * then no replacement shall occur.  This is a stack.
135  */
136 struct symtab *norep[RECMAX];   /* Symbol table index table */
137 int norepptr = 1;                       /* Top of index table */
138 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
139 int bidx;                       /* Top of bptr stack */
140
ragge
1.112
141 static int readargs(struct symtab *spconst usch **args);
ragge
1.116
142 static void exparg(int);
ragge
1.112
143 static void subarg(struct symtab *spconst usch **argsint);
plunky
1.143
144 static void flbuf(void);
145 static void usage(void);
146 static usch *xstrdup(const usch *str);
ragge
1.108
147 static void addidir(char *idirstruct incs **ww);
plunky
1.178
148 static void vsheap(const char *, va_list);
ragge
1.1
149
150 int
151 main(int argcchar **argv)
152 {
ragge
1.53
153         struct initar *it;
ragge
1.26
154         struct symtab *nl;
155         register int ch;
ragge
1.103
156         const usch *fn1, *fn2;
ragge
1.15
157
ragge
1.94
158 #ifdef TIMING
159         struct timeval t1t2;
160
161         (void)gettimeofday(&t1NULL);
162 #endif
163
ragge
1.151
164         while ((ch = getopt(argcargv"CD:d:I:i:MPS:tU:Vvx:")) != -1) {
ragge
1.1
165                 switch (ch) {
ragge
1.22
166                 case 'C'/* Do not discard comments */
167                         Cflag++;
168                         break;
169
plunky
1.142
170                 case 'D'/* define something */
ragge
1.53
171                 case 'i'/* include */
172                 case 'U'/* undef */
ragge
1.58
173                         /* XXX should not need malloc() here */
174                         if ((it = malloc(sizeof(struct initar))) == NULL)
175                                 error("couldn't apply -%c %s"choptarg);
ragge
1.53
176                         it->type = ch;
177                         it->str = optarg;
178                         it->next = initar;
179                         initar = it;
ragge
1.7
180                         break;
181
plunky
1.142
182                 case 'd':
plunky
1.144
183                         while (*optarg) {
184                                 switch(*optarg) {
185                                 case 'M'/* display macro definitions */
186                                         dMflag = 1;
187                                         Mflag = 1;
188                                         break;
189
190                                 default/* ignore others */
191                                         break;
192                                 }
193                                 optarg++;
plunky
1.142
194                         }
195                         break;
196
197                 case 'I':
198                 case 'S':
199                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
200                         break;
201
ragge
1.51
202                 case 'M'/* Generate dependencies for make */
203                         Mflag++;
204                         break;
205
gmcgarry
1.85
206                 case 'P'/* Inhibit generation of line numbers */
207                         Pflag++;
208                         break;
209
plunky
1.142
210                 case 't':
211                         tflag = 1;
ragge
1.7
212                         break;
213
plunky
1.134
214 #ifdef PCC_DEBUG
ragge
1.64
215                 case 'V':
ragge
1.18
216                         dflag++;
ragge
1.1
217                         break;
218 #endif
ragge
1.64
219                 case 'v':
plunky
1.174
220                         xwrite(2versstrsizeof(versstr) - 1);
ragge
1.64
221                         break;
ragge
1.1
222
ragge
1.151
223                 case 'x':
224                         if (strcmp(optarg"MP") == 0) {
225                                 MPflag++;
226                         } else if (strncmp(optarg"MT,"3) == 0 ||
227                             strncmp(optarg"MQ,"3) == 0) {
228                                 usch *cp, *fn;
229                                 fn = stringbuf;
230                                 for (cp = (usch *)&optarg[3]; *cpcp++) {
231                                         if (*cp == '$' && optarg[1] == 'Q')
232                                                 savch('$');
233                                         savch(*cp);
234                                 }
plunky
1.152
235                                 savstr((const usch *)""); 
ragge
1.151
236                                 if (Mxfile) { savch(' '); savstr(Mxfile); }
237                                 savch(0);
238                                 Mxfile = fn;
239                         } else
240                                 usage();
241                         break;
242
ragge
1.37
243                 case '?':
plunky
1.142
244                 default:
ragge
1.37
245                         usage();
ragge
1.1
246                 }
plunky
1.142
247         }
248
ragge
1.1
249         argc -= optind;
250         argv += optind;
251
ragge
1.103
252         filloc = lookup((const usch *)"__FILE__"ENTER);
253         linloc = lookup((const usch *)"__LINE__"ENTER);
ragge
1.114
254         filloc->value = linloc->value = stringbuf;
255         savch(OBJCT);
256
257         /* create a complete macro for pragma */
ragge
1.103
258         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.114
259         savch(0);
ragge
1.115
260         savstr((const usch *)"_Pragma(");
ragge
1.114
261         savch(0);
262         savch(WARN);
263         savch(')');
264         pragloc->value = stringbuf;
265         savch(1);
ragge
1.15
266
ragge
1.12
267         if (tflag == 0) {
268                 time_t t = time(NULL);
ragge
1.39
269                 usch *n = (usch *)ctime(&t);
ragge
1.12
270
271                 /*
272                  * Manually move in the predefined macros.
273                  */
ragge
1.103
274                 nl = lookup((const usch *)"__TIME__"ENTER);
ragge
1.13
275                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
276                 savch(OBJCT);
277                 nl->value = stringbuf-1;
278
ragge
1.103
279                 nl = lookup((const usch *)"__DATE__"ENTER);
ragge
1.13
280                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
281                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
282                 nl->value = stringbuf-1;
283
ragge
1.103
284                 nl = lookup((const usch *)"__STDC__"ENTER);
ragge
1.13
285                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
286                 nl->value = stringbuf-1;
ragge
1.73
287
ragge
1.103
288                 nl = lookup((const usch *)"__STDC_VERSION__"ENTER);
289                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
ragge
1.73
290                 nl->value = stringbuf-1;
ragge
1.12
291         }
ragge
1.1
292
ragge
1.60
293         if (Mflag && !dMflag) {
ragge
1.51
294                 usch *c;
295
296                 if (argc < 1)
297                         error("-M and no infile");
298                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
299                         c = (usch *)argv[0];
300                 else
301                         c++;
302                 Mfile = stringbuf;
303                 savstr(c); savch(0);
ragge
1.151
304                 if (MPflag) {
305                         MPfile = stringbuf;
306                         savstr(c); savch(0);
307                 }
308                 if (Mxfile)
309                         Mfile = Mxfile;
ragge
1.51
310                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
311                         error("-M and no extension: ");
312                 c[1] = 'o';
313                 c[2] = 0;
314         }
315
ragge
1.26
316         if (argc == 2) {
plunky
1.180
317                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC0666)) < 0)
ragge
1.37
318                         error("Can't creat %s"argv[1]);
ragge
1.26
319         } else
ragge
1.37
320                 ofd = 1/* stdout */
321         istty = isatty(ofd);
ragge
1.26
322
ragge
1.102
323         if (argc && strcmp(argv[0], "-")) {
324                 fn1 = fn2 = (usch *)argv[0];
325         } else {
326                 fn1 = NULL;
ragge
1.103
327                 fn2 = (const usch *)"";
ragge
1.102
328         }
329         if (pushfile(fn1fn20NULL))
ragge
1.26
330                 error("cannot open %s"argv[0]);
331
ragge
1.37
332         flbuf();
333         close(ofd);
ragge
1.94
334 #ifdef TIMING
335         (void)gettimeofday(&t2NULL);
336         t2.tv_sec -= t1.tv_sec;
337         t2.tv_usec -= t1.tv_usec;
338         if (t2.tv_usec < 0) {
339                 t2.tv_usec += 1000000;
340                 t2.tv_sec -= 1;
341         }
342         fprintf(stderr"cpp total time: %ld s %ld us\n",
plunky
1.159
343              (long)t2.tv_sec, (long)t2.tv_usec);
ragge
1.94
344 #endif
ragge
1.37
345         return 0;
ragge
1.26
346 }
347
ragge
1.108
348 static void
349 addidir(char *idirstruct incs **ww)
350 {
351         struct incs *w;
352         struct stat st;
353
plunky
1.163
354         if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
ragge
1.108
355                 return/* ignore */
356         if (*ww != NULL) {
357                 for (w = *www->nextw = w->next) {
plunky
1.145
358 #ifdef os_win32
gmcgarry
1.131
359                         if (strcmp(w->diridir) == 0)
360                                 return;
361 #else
ragge
1.108
362                         if (w->dev == st.st_dev && w->ino == st.st_ino)
363                                 return;
gmcgarry
1.131
364 #endif
ragge
1.108
365                 }
plunky
1.145
366 #ifdef os_win32
gmcgarry
1.131
367                 if (strcmp(w->diridir) == 0)
368                         return;
369 #else
ragge
1.108
370                 if (w->dev == st.st_dev && w->ino == st.st_ino)
371                         return;
gmcgarry
1.131
372 #endif
ragge
1.108
373                 ww = &w->next;
374         }
375         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
376                 error("couldn't add path %s"idir);
377         w->dir = (usch *)idir;
378         w->dev = st.st_dev;
379         w->ino = st.st_ino;
380         *ww = w;
381 }
382
ragge
1.1
383 void
plunky
1.143
384 line(void)
ragge
1.9
385 {
ragge
1.37
386         static usch *lbuf;
387         static int llen;
ragge
1.97
388         usch *p;
ragge
1.9
389         int c;
390
ragge
1.97
391         if ((c = yylex()) != NUMBER)
ragge
1.9
392                 goto bad;
gmcgarry
1.100
393         ifiles->lineno = (int)(yylval.node.nd_val - 1);
ragge
1.9
394
ragge
1.97
395         if ((c = yylex()) == '\n')
ragge
1.37
396                 return;
ragge
1.97
397
398         if (c != STRING)
ragge
1.9
399                 goto bad;
ragge
1.97
400
plunky
1.160
401         p = yytext;
plunky
1.158
402         if (*p++ == 'L')
ragge
1.97
403                 p++;
404         c = strlen((char *)p);
plunky
1.158
405         p[c - 1] = '\0';
ragge
1.37
406         if (llen < c) {
plunky
1.136
407                 /* XXX may lose heap space */
ragge
1.37
408                 lbuf = stringbuf;
409                 stringbuf += c;
410                 llen = c;
plunky
1.158
411                 if (stringbuf >= &sbf[SBSIZE]) {
412                         stringbuf = sbf/* need space to write error message */
413                         error("line filename exceeds buffer size");
414                 }
ragge
1.37
415         }
plunky
1.158
416         memcpy(lbufpc);
ragge
1.37
417         ifiles->fname = lbuf;
ragge
1.97
418         if (yylex() == '\n')
419                 return;
ragge
1.9
420
421 bad:    error("bad line directive");
422 }
423
ragge
1.10
424 /*
ragge
1.102
425  * Search for and include next file.
426  * Return 1 on success.
427  */
428 static int
ragge
1.103
429 fsrch(const usch *fnint idxstruct incs *w)
ragge
1.102
430 {
431         int i;
432
433         for (i = idxi < 2i++) {
434                 if (i > idx)
435                         w = incdir[i];
436                 for (; ww = w->next) {
437                         usch *nm = stringbuf;
438
439                         savstr(w->dir); savch('/');
440                         savstr(fn); savch(0);
441                         if (pushfile(nmfniw->next) == 0)
442                                 return 1;
443                         stringbuf = nm;
444                 }
445         }
446         return 0;
447 }
448
ragge
1.132
449 static void
450 prem(void)
451 {
452         error("premature EOF");
453 }
454
ragge
1.102
455 /*
ragge
1.10
456  * Include a file. Include order:
ragge
1.20
457  * - For <...> files, first search -I directories, then system directories.
458  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
459  */
ragge
1.9
460 void
plunky
1.143
461 include(void)
ragge
1.3
462 {
ragge
1.101
463         struct symtab *nl;
ragge
1.10
464         usch *osp;
ragge
1.62
465         usch *fn, *safefn;
gmcgarry
1.133
466         int c;
ragge
1.3
467
ragge
1.37
468         if (flslvl)
469                 return;
ragge
1.10
470         osp = stringbuf;
ragge
1.97
471
ragge
1.101
472         while ((c = sloscan()) == WSPACE)
473                 ;
474         if (c == IDENT) {
475                 /* sloscan() will not expand idents */
plunky
1.160
476                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.101
477                         goto bad;
ragge
1.112
478                 if (kfind(nl))
479                         unpstr(stringbuf);
480                 else
481                         unpstr(nl->namep);
ragge
1.101
482                 stringbuf = osp;
483                 c = yylex();
484         }
485         if (c != STRING && c != '<')
ragge
1.3
486                 goto bad;
487
ragge
1.97
488         if (c == '<') {
ragge
1.10
489                 fn = stringbuf;
ragge
1.97
490                 while ((c = sloscan()) != '>' && c != '\n') {
ragge
1.105
491                         if (c == '\n'/* XXX check - cannot reach */
ragge
1.10
492                                 goto bad;
plunky
1.160
493                         savstr(yytext);
ragge
1.10
494                 }
495                 savch('\0');
ragge
1.97
496                 while ((c = sloscan()) == WSPACE)
ragge
1.37
497                         ;
ragge
1.132
498                 if (c == 0)
499                         prem();
ragge
1.37
500                 if (c != '\n')
501                         goto bad;
ragge
1.62
502                 safefn = fn;
ragge
1.3
503         } else {
ragge
1.20
504                 usch *nm = stringbuf;
505
ragge
1.116
506                 yytext[strlen((char *)yytext)-1] = 0;
plunky
1.161
507                 fn = &yytext[1];
ragge
1.20
508                 /* first try to open file relative to previous file */
ragge
1.53
509                 /* but only if it is not an absolute path */
510                 if (*fn != '/') {
511                         savstr(ifiles->orgfn);
512                         if ((stringbuf =
513                             (usch *)strrchr((char *)nm'/')) == NULL)
514                                 stringbuf = nm;
515                         else
516                                 stringbuf++;
517                 }
ragge
1.62
518                 safefn = stringbuf;
ragge
1.20
519                 savstr(fn); savch(0);
ragge
1.97
520                 c = yylex();
ragge
1.132
521                 if (c == 0)
522                         prem();
ragge
1.37
523                 if (c != '\n')
524                         goto bad;
ragge
1.102
525                 if (pushfile(nmsafefn0NULL) == 0)
ragge
1.97
526                         goto okret;
plunky
1.136
527                 /* XXX may lose stringbuf space */
ragge
1.10
528         }
529
ragge
1.102
530         if (fsrch(safefn0incdir[0]))
531                 goto okret;
ragge
1.10
532
ragge
1.62
533         error("cannot find '%s'"safefn);
ragge
1.37
534         /* error() do not return */
ragge
1.3
535
536 bad:    error("bad include");
ragge
1.37
537         /* error() do not return */
ragge
1.97
538 okret:
539         prtline();
ragge
1.37
540 }
541
ragge
1.102
542 void
plunky
1.143
543 include_next(void)
ragge
1.102
544 {
ragge
1.105
545         struct symtab *nl;
546         usch *osp;
547         usch *fn;
548         int c;
549
ragge
1.107
550         if (flslvl)
551                 return;
ragge
1.105
552         osp = stringbuf;
553         while ((c = sloscan()) == WSPACE)
554                 ;
555         if (c == IDENT) {
556                 /* sloscan() will not expand idents */
plunky
1.160
557                 if ((nl = lookup(yytextFIND)) == NULL)
ragge
1.105
558                         goto bad;
ragge
1.112
559                 if (kfind(nl))
560                         unpstr(stringbuf);
561                 else
562                         unpstr(nl->namep);
ragge
1.105
563                 stringbuf = osp;
564                 c = yylex();
565         }
566         if (c != STRING && c != '<')
567                 goto bad;
568
569         fn = stringbuf;
570         if (c == STRING) {
plunky
1.161
571                 savstr(&yytext[1]);
ragge
1.105
572                 stringbuf[-1] = 0;
573         } else { /* < > */
574                 while ((c = sloscan()) != '>') {
575                         if (c == '\n')
576                                 goto bad;
plunky
1.160
577                         savstr(yytext);
ragge
1.105
578                 }
579                 savch('\0');
580         }
581         while ((c = sloscan()) == WSPACE)
582                 ;
583         if (c != '\n')
584                 goto bad;
585
586         if (fsrch(fnifiles->idxifiles->incs) == 0)
587                 error("cannot find '%s'"fn);
588         prtline();
589         return;
590
591 bad:    error("bad include");
592         /* error() do not return */
ragge
1.102
593 }
594
ragge
1.37
595 static int
596 definp(void)
597 {
598         int c;
599
600         do
ragge
1.97
601                 c = sloscan();
ragge
1.37
602         while (c == WSPACE);
603         return c;
ragge
1.3
604 }
605
ragge
1.80
606 void
ragge
1.79
607 getcmnt(void)
608 {
609         int c;
610
plunky
1.160
611         savstr(yytext);
ragge
1.104
612         savch(cinput()); /* Lost * */
ragge
1.79
613         for (;;) {
614                 c = cinput();
615                 if (c == '*') {
616                         c = cinput();
617                         if (c == '/') {
ragge
1.103
618                                 savstr((const usch *)"*/");
ragge
1.79
619                                 return;
620                         }
621                         cunput(c);
622                         c = '*';
623                 }
624                 savch(c);
625         }
626 }
627
628 /*
629  * Compare two replacement lists, taking in account comments etc.
630  */
631 static int
ragge
1.103
632 cmprepl(const usch *oconst usch *n)
ragge
1.79
633 {
634         for (; *oo--, n--) {
635                 /* comment skip */
636                 if (*o == '/' && o[-1] == '*') {
637                         while (*o != '*' || o[-1] != '/')
638                                 o--;
639                         o -= 2;
640                 }
641                 if (*n == '/' && n[-1] == '*') {
642                         while (*n != '*' || n[-1] != '/')
643                                 n--;
644                         n -= 2;
645                 }
646                 while (*o == ' ' || *o == '\t')
647                         o--;
648                 while (*n == ' ' || *n == '\t')
649                         n--;
650                 if (*o != *n)
651                         return 1;
652         }
653         return 0;
654 }
655
ragge
1.97
656 static int
657 isell(void)
658 {
659         int ch;
660
661         if ((ch = cinput()) != '.') {
662                 cunput(ch);
663                 return 0;
664         }
665         if ((ch = cinput()) != '.') {
666                 cunput(ch);
667                 cunput('.');
668                 return 0;
669         }
670         return 1;
671 }
672
ragge
1.3
673 void
plunky
1.143
674 define(void)
ragge
1.1
675 {
676         struct symtab *np;
ragge
1.112
677         usch *args[MAXARGS+1], *ubuf, *sbeg;
ragge
1.15
678         int ciredef;
ragge
1.1
679         int mkstr = 0narg = -1;
ragge
1.37
680         int ellips = 0;
ragge
1.128
681 #ifdef GCC_COMPAT
ragge
1.86
682         usch *gccvari = NULL;
ragge
1.91
683         int wascon;
ragge
1.86
684 #endif
ragge
1.1
685
ragge
1.37
686         if (flslvl)
687                 return;
ragge
1.97
688         if (sloscan() != WSPACE || sloscan() != IDENT)
ragge
1.37
689                 goto bad;
ragge
1.36
690
plunky
1.160
691         np = lookup(yytextENTER);
ragge
1.15
692         redef = np->value != NULL;
ragge
1.1
693
ragge
1.138
694         defining = readmac = 1;
ragge
1.15
695         sbeg = stringbuf;
ragge
1.97
696         if ((c = sloscan()) == '(') {
ragge
1.1
697                 narg = 0;
698                 /* function-like macros, deal with identifiers */
ragge
1.72
699                 c = definp();
ragge
1.37
700                 for (;;) {
ragge
1.1
701                         if (c == ')')
702                                 break;
ragge
1.97
703                         if (c == '.' && isell()) {
ragge
1.37
704                                 ellips = 1;
705                                 if (definp() != ')')
706                                         goto bad;
707                                 break;
708                         }
709                         if (c == IDENT) {
ragge
1.72
710                                 /* make sure there is no arg of same name */
711                                 for (i = 0i < nargi++)
ragge
1.116
712                                         if (!strcmp((char *) args[i], (char *)yytext))
ragge
1.72
713                                                 error("Duplicate macro "
714                                                   "parameter \"%s\""yytext);
ragge
1.112
715                                 if (narg == MAXARGS)
716                                         error("Too many macro args");
ragge
1.90
717                                 args[narg++] = xstrdup(yytext);
ragge
1.72
718                                 if ((c = definp()) == ',') {
719                                         if ((c = definp()) == ')')
720                                                 goto bad;
ragge
1.37
721                                         continue;
ragge
1.72
722                                 }
ragge
1.128
723 #ifdef GCC_COMPAT
ragge
1.97
724                                 if (c == '.' && isell()) {
ragge
1.86
725                                         if (definp() != ')')
726                                                 goto bad;
727                                         gccvari = args[--narg];
728                                         break;
729                                 }
730 #endif
ragge
1.37
731                                 if (c == ')')
732                                         break;
733                         }
734                         goto bad;
ragge
1.1
735                 }
ragge
1.97
736                 c = sloscan();
ragge
1.36
737         } else if (c == '\n') {
ragge
1.8
738                 /* #define foo */
ragge
1.36
739                 ;
ragge
1.132
740         } else if (c == 0) {
741                 prem();
ragge
1.1
742         } else if (c != WSPACE)
ragge
1.37
743                 goto bad;
ragge
1.1
744
ragge
1.31
745         while (c == WSPACE)
ragge
1.97
746                 c = sloscan();
ragge
1.1
747
ragge
1.72
748         /* replacement list cannot start with ## operator */
ragge
1.97
749         if (c == '#') {
750                 if ((c = sloscan()) == '#')
751                         goto bad;
752                 savch('\0');
ragge
1.128
753 #ifdef GCC_COMPAT
ragge
1.97
754                 wascon = 0;
755 #endif
756                 goto in2;
757         }
ragge
1.72
758
ragge
1.1
759         /* parse replacement-list, substituting arguments */
760         savch('\0');
ragge
1.36
761         while (c != '\n') {
ragge
1.128
762 #ifdef GCC_COMPAT
ragge
1.91
763                 wascon = 0;
764 loop:
765 #endif
ragge
1.1
766                 switch (c) {
767                 case WSPACE:
768                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
769                         ubuf = stringbuf;
plunky
1.160
770                         savstr(yytext);
ragge
1.97
771                         c = sloscan();
772                         if (c == '#') {
773                                 if ((c = sloscan()) != '#')
774                                         goto in2;
ragge
1.2
775                                 stringbuf = ubuf;
ragge
1.1
776                                 savch(CONC);
ragge
1.97
777                                 if ((c = sloscan()) == WSPACE)
778                                         c = sloscan();
ragge
1.128
779 #ifdef GCC_COMPAT
ragge
1.91
780                                 if (c == '\n')
781                                         break;
782                                 wascon = 1;
783                                 goto loop;
784 #endif
ragge
1.1
785                         }
786                         continue;
787
ragge
1.97
788                 case '#':
789                         c = sloscan();
790                         if (c == '#') {
791                                 /* concat op */
792                                 savch(CONC);
793                                 if ((c = sloscan()) == WSPACE)
794                                         c = sloscan();
ragge
1.128
795 #ifdef GCC_COMPAT
ragge
1.97
796                                 if (c == '\n')
797                                         break;
798                                 wascon = 1;
799                                 goto loop;
ragge
1.91
800 #else
ragge
1.97
801                                 continue;
ragge
1.91
802 #endif
ragge
1.97
803                         } 
804 in2:                    if (narg < 0) {
ragge
1.1
805                                 /* no meaning in object-type macro */
806                                 savch('#');
ragge
1.97
807                                 continue;
ragge
1.1
808                         }
809                         /* remove spaces between # and arg */
810                         savch(SNUFF);
ragge
1.97
811                         if (c == WSPACE)
812                                 c = sloscan(); /* whitespace, ignore */
ragge
1.1
813                         mkstr = 1;
ragge
1.116
814                         if (c == IDENT && strcmp((char *)yytext"__VA_ARGS__") == 0)
ragge
1.37
815                                 continue;
ragge
1.1
816
817                         /* FALLTHROUGH */
818                 case IDENT:
ragge
1.116
819                         if (strcmp((char *)yytext"__VA_ARGS__") == 0) {
ragge
1.97
820                                 if (ellips == 0)
821                                         error("unwanted %s"yytext);
ragge
1.128
822 #ifdef GCC_COMPAT
823                                 savch(wascon ? GCCARG : VARG);
824 #else
ragge
1.97
825                                 savch(VARG);
ragge
1.128
826 #endif
827
ragge
1.97
828                                 savch(WARN);
829                                 if (mkstr)
830                                         savch(SNUFF), mkstr = 0;
831                                 break;
832                         }
ragge
1.1
833                         if (narg < 0)
834                                 goto id/* just add it if object */
835                         /* check if its an argument */
836                         for (i = 0i < nargi++)
ragge
1.116
837                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
ragge
1.1
838                                         break;
839                         if (i == narg) {
ragge
1.128
840 #ifdef GCC_COMPAT
ragge
1.87
841                                 if (gccvari &&
ragge
1.116
842                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
ragge
1.91
843                                         savch(wascon ? GCCARG : VARG);
ragge
1.86
844                                         savch(WARN);
845                                         if (mkstr)
846                                                 savch(SNUFF), mkstr = 0;
847                                         break;
848                                 }
849 #endif
ragge
1.1
850                                 if (mkstr)
851                                         error("not argument");
852                                 goto id;
853                         }
854                         savch(i);
855                         savch(WARN);
856                         if (mkstr)
857                                 savch(SNUFF), mkstr = 0;
858                         break;
859
ragge
1.79
860                 case CMNT/* save comments */
861                         getcmnt();
862                         break;
863
ragge
1.132
864                 case 0:
865                         prem();
866
ragge
1.1
867                 default:
plunky
1.160
868 id:                     savstr(yytext);
ragge
1.1
869                         break;
870                 }
ragge
1.97
871                 c = sloscan();
ragge
1.1
872         }
ragge
1.138
873         defining = readmac = 0;
ragge
1.20
874         /* remove trailing whitespace */
875         while (stringbuf > sbeg) {
876                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
877                         stringbuf--;
ragge
1.72
878                 /* replacement list cannot end with ## operator */
879                 else if (stringbuf[-1] == CONC)
880                         goto bad;
ragge
1.20
881                 else
882                         break;
883         }
ragge
1.128
884 #ifdef GCC_COMPAT
ragge
1.86
885         if (gccvari) {
886                 savch(narg);
887                 savch(VARG);
888         } else
889 #endif
ragge
1.37
890         if (ellips) {
891                 savch(narg);
892                 savch(VARG);
893         } else
894                 savch(narg < 0 ? OBJCT : narg);
ragge
1.118
895         if (redef && ifiles->idx != SYSINC) {
ragge
1.119
896                 if (cmprepl(np->valuestringbuf-1)) {
897                         sbeg = stringbuf;