Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20110830201221

Diff

Diff from 1.143 to:

Annotations

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

Annotated File View

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