Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20120926182717

Diff

Diff from 1.157 to:

Annotations

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

Annotated File View

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