Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20110927082255

Diff

Diff from 1.145 to:

Annotations

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

Annotated File View

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