Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20140528085242

Diff

Diff from 1.191 to:

Annotations

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

Annotated File View

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