Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002093131

Diff

Diff from 1.165 to:

Annotations

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

Annotated File View

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