Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002155006

Diff

Diff from 1.168 to:

Annotations

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

Annotated File View

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