Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20120727160703

Diff

Diff from 1.147 to:

Annotations

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

Annotated File View

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