Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121108111403

Diff

Diff from 1.187 to:

Annotations

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

Annotated File View

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