Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110715105259

Diff

Diff from 1.138 to:

Annotations

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

Annotated File View

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