Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121017103313

Diff

Diff from 1.176 to:

Annotations

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

Annotated File View

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