Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002094010

Diff

Diff from 1.167 to:

Annotations

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

Annotated File View

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