Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20140528202054

Diff

Diff from 1.192 to:

Annotations

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

Annotated File View

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