Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20110603154245

Diff

Diff from 1.134 to:

Annotations

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

Annotated File View

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