Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002093029

Diff

Diff from 1.164 to:

Annotations

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

Annotated File View

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