1
/* $XConsortium: parse.c /main/33 1996/12/04 10:11:28 swick $ */
4
Copyright (c) 1993, 1994 X Consortium
6
Permission is hereby granted, free of charge, to any person obtaining a copy
7
of this software and associated documentation files (the "Software"), to deal
8
in the Software without restriction, including without limitation the rights
9
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
copies of the Software, and to permit persons to whom the Software is
11
furnished to do so, subject to the following conditions:
13
The above copyright notice and this permission notice shall be included in
14
all copies or substantial portions of the Software.
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
Except as contained in this notice, the name of the X Consortium shall not be
24
used in advertising or otherwise to promote the sale, use or other dealings
25
in this Software without prior written authorization from the X Consortium.
31
extern char *directives[];
32
extern struct inclist maininclist;
33
extern boolean show_where_not;
36
static int gobble( struct filepointer *filep,
38
struct inclist *file_red);
39
static int deftype( char *line,
40
struct filepointer *filep,
41
struct inclist *file_red,
44
static struct symtab **fdefined( char *symbol,
46
struct inclist **srcfile);
47
static int zero_value( char *exp,
48
struct filepointer *filep,
49
struct inclist *file_red);
51
static struct symtab **slookup( char *symbol, struct inclist *file);
53
static int merge2defines( struct inclist *file1, struct inclist *file2);
54
static void undefine( char *symbol, struct inclist *file);
55
static int match(char *str, char **list);
56
static void add_include(struct filepointer *filep,
58
struct inclist *file_red,
65
static struct symtab **fdefined();
66
static int zero_value();
67
static struct symtab **slookup();
68
static int merge2defines();
69
static void undefine();
71
static void add_include();
75
/*-------------------------------------------------------------------------*/
76
static int gobble(filep, file, file_red)
77
register struct filepointer *filep;
78
struct inclist *file, *file_red;
83
while ((line = getline(filep))) {
84
switch(type = deftype(line, filep, file_red, file, FALSE)) {
90
type = gobble(filep, file, file_red);
91
while ((type == ELIF) || (type == ELIFFALSE) ||
92
(type == ELIFGUESSFALSE))
93
type = gobble(filep, file, file_red);
95
(void)gobble(filep, file, file_red);
99
debug(0,("%s, line %d: #%s\n",
100
file->i_file, filep->f_line,
118
warning("%s, line %d: unknown directive == \"%s\"\n",
119
file_red->i_file, filep->f_line, line);
127
/*---------------------------------------------------------------------------
128
Decide what type of # directive this line is.
129
----------------------------------------------------------------------------*/
130
static int deftype (line, filep, file_red, file, parse_it)
132
register struct filepointer *filep;
133
register struct inclist *file_red, *file;
137
char *directive, savechar;
141
* Parse the directive...
144
while (*directive == ' ' || *directive == '\t')
148
while (*p >= 'a' && *p <= 'z')
152
ret = match(directive, directives);
155
/* If we don't recognize this compiler directive or we happen to just
156
* be gobbling up text while waiting for an #endif or #elif or #else
157
* in the case of an #elif we must check the zero_value and return an
158
* ELIF or an ELIFFALSE.
161
if (ret == ELIF && !parse_it)
163
while (*p == ' ' || *p == '\t')
166
* parse an expression.
168
debug(0,("%s, line %d: #elif %s ",
169
file->i_file, filep->f_line, p));
170
ret = zero_value(p, filep, file_red);
173
debug(0,("false...\n"));
177
return(ELIFGUESSFALSE);
181
debug(0,("true...\n"));
186
if (ret < 0 || ! parse_it)
190
* now decide how to parse the directive, and do it.
192
while (*p == ' ' || *p == '\t')
197
* parse an expression.
199
ret = zero_value(p, filep, file_red);
200
debug(0,("%s, line %d: %s #if %s\n",
201
file->i_file, filep->f_line, ret?"false":"true", p));
205
debug(0,("%s, line %d: #%s %s\n",
206
file->i_file, filep->f_line, directives[ret], p));
209
* separate the name of a single symbol.
211
while (isalnum(*p) || *p == '_')
216
debug(2,("%s, line %d: #include %s\n",
217
file->i_file, filep->f_line, p));
219
/* Support ANSI macro substitution */
221
struct symtab **sym = isdefined(p, file_red, NULL);
224
debug(3,("%s : #includes SYMBOL %s = %s\n",
228
/* mark file as having included a 'soft include' */
229
file->i_flags |= INCLUDED_SYM;
230
sym = isdefined(p, file_red, NULL);
235
* Separate the name of the include file.
237
while (*p && *p != '"' && *p != '<')
243
while (*p && *p != '"')
246
while (*p && *p != '>')
252
* copy the definition back to the beginning of the line.
264
debug(0,("%s, line %d: #%s\n",
265
file->i_file, filep->f_line, directives[ret]));
274
/*-------------------------------------------------------------------------*/
275
static struct symtab **fdefined(symbol, file, srcfile)
276
register char *symbol;
277
struct inclist *file;
278
struct inclist **srcfile;
280
register struct inclist **ip;
281
register struct symtab **val;
283
static int recurse_lvl = 0;
285
if (file->i_flags & DEFCHECKED)
287
file->i_flags |= DEFCHECKED;
288
if ((val = slookup(symbol, file)))
289
debug(1,("%s defined in %s as %s\n",
290
symbol, file->i_file, (*val)->s_value));
291
if (val == NULL && file->i_list)
293
for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
294
if (file->i_merged[i]==FALSE) {
295
val = fdefined(symbol, *ip, srcfile);
296
if ((*ip)->i_flags & FINISHED) {
297
merge2defines(file,*ip);
298
file->i_merged[i]=TRUE;
300
if (val!=NULL) break;
303
else if (val != NULL && srcfile != NULL) *srcfile = file;
305
file->i_flags &= ~DEFCHECKED;
310
/*-------------------------------------------------------------------------*/
311
struct symtab **isdefined(symbol, file, srcfile)
312
register char *symbol;
313
struct inclist *file;
314
struct inclist **srcfile;
316
register struct symtab **val;
318
if ((val = slookup(symbol, &maininclist))) {
319
debug(1,("%s defined on command line\n", symbol));
320
if (srcfile != NULL) *srcfile = &maininclist;
323
if ((val = fdefined(symbol, file, srcfile)))
325
debug(1,("%s not defined in %s\n", symbol, file->i_file));
329
/*---------------------------------------------------------------------------
330
Return type based on if the #if expression evaluates to 0
331
----------------------------------------------------------------------------*/
332
static int zero_value(exp, filep, file_red)
334
register struct filepointer *filep;
335
register struct inclist *file_red;
337
if (cppsetup(exp, filep, file_red))
343
/*-------------------------------------------------------------------------*/
344
void define2(name, val, file)
346
struct inclist *file;
348
int first, last, below;
349
register struct symtab **sp = NULL, **dest;
352
/* Make space if it's needed */
353
if (file->i_defs == NULL)
355
file->i_defs = (struct symtab **)
356
malloc(sizeof (struct symtab*) * SYMTABINC);
359
else if (!(file->i_ndefs % SYMTABINC))
360
file->i_defs = (struct symtab **)
361
realloc(file->i_defs,
362
sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC));
364
if (file->i_defs == NULL)
365
fatalerr("malloc()/realloc() failure in insert_defn()\n");
368
last = file->i_ndefs - 1;
369
while (last >= first)
371
/* Fast inline binary search */
374
register int middle = (first + last) / 2;
376
/* Fast inline strchr() */
378
s2 = file->i_defs[middle]->s_name;
379
while (*s1++ == *s2++)
380
if (s2[-1] == '\0') break;
382
/* If exact match, set sp and break */
385
sp = file->i_defs + middle;
389
/* If name > i_defs[middle] ... */
398
below = last = middle - 1;
402
/* Search is done. If we found an exact match to the symbol name,
403
just replace its s_value */
406
free((*sp)->s_value);
407
(*sp)->s_value = copy(val);
411
sp = file->i_defs + file->i_ndefs++;
412
dest = file->i_defs + below + 1;
418
stab = (struct symtab *) malloc(sizeof (struct symtab));
420
fatalerr("malloc()/realloc() failure in insert_defn()\n");
422
stab->s_name = copy(name);
423
stab->s_value = copy(val);
427
/*-------------------------------------------------------------------------*/
428
void define(def, file)
430
struct inclist *file;
434
/* Separate symbol name and its value */
436
while (isalnum(*val) || *val == '_')
440
while (*val == ' ' || *val == '\t')
445
define2(def, val, file);
448
/*-------------------------------------------------------------------------*/
449
static struct symtab **slookup(symbol, file)
450
register char *symbol;
451
register struct inclist *file;
453
register int first = 0;
454
register int last = file->i_ndefs - 1;
456
if (file) while (last >= first)
458
/* Fast inline binary search */
461
register int middle = (first + last) / 2;
463
/* Fast inline strchr() */
465
s2 = file->i_defs[middle]->s_name;
466
while (*s1++ == *s2++)
467
if (s2[-1] == '\0') break;
469
/* If exact match, we're done */
472
return file->i_defs + middle;
475
/* If symbol > i_defs[middle] ... */
489
/*-------------------------------------------------------------------------*/
490
static int merge2defines(file1, file2)
491
struct inclist *file1;
492
struct inclist *file2;
494
if ((file1!=NULL) && (file2!=NULL))
497
int last1 = file1->i_ndefs - 1;
500
int last2 = file2->i_ndefs - 1;
503
struct symtab** i_defs = NULL;
504
int deflen=file1->i_ndefs+file2->i_ndefs;
508
/* make sure deflen % SYMTABINC == 0 is still true */
509
deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC;
510
i_defs=(struct symtab**)
511
malloc(deflen*sizeof(struct symtab*));
512
if (i_defs==NULL) return 0;
515
while ((last1 >= first1) && (last2 >= first2))
517
char *s1=file1->i_defs[first1]->s_name;
518
char *s2=file2->i_defs[first2]->s_name;
520
if (strcmp(s1,s2) < 0)
521
i_defs[first++]=file1->i_defs[first1++];
522
else if (strcmp(s1,s2) > 0)
523
i_defs[first++]=file2->i_defs[first2++];
526
i_defs[first++]=file2->i_defs[first2++];
530
while (last1 >= first1)
532
i_defs[first++]=file1->i_defs[first1++];
534
while (last2 >= first2)
536
i_defs[first++]=file2->i_defs[first2++];
539
if (file1->i_defs) free(file1->i_defs);
540
file1->i_defs=i_defs;
541
file1->i_ndefs=first;
548
/*-------------------------------------------------------------------------*/
549
static void undefine(symbol, file)
551
register struct inclist *file;
553
register struct symtab **ptr;
554
struct inclist *srcfile;
555
while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
558
for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
563
/*-------------------------------------------------------------------------*/
564
int find_includes(filep, file, file_red, recursion, failOK)
565
struct filepointer *filep;
566
struct inclist *file, *file_red;
574
while ((line = getline(filep))) {
575
switch(type = deftype(line, filep, file_red, file, TRUE)) {
578
type = find_includes(filep, file,
579
file_red, recursion+1, failOK);
580
while ((type == ELIF) || (type == ELIFFALSE) ||
581
(type == ELIFGUESSFALSE))
582
type = gobble(filep, file, file_red);
584
gobble(filep, file, file_red);
589
if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
593
type = gobble(filep, file, file_red);
595
find_includes(filep, file,
596
file_red, recursion+1, recfailOK);
601
if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
606
if ((type == IFDEF &&
607
isdefined(line, file_red, (struct inclist **) NULL))
608
|| (type == IFNDEF &&
609
!isdefined(line, file_red, (struct inclist **) NULL))) {
610
debug(1,(type == IFNDEF ?
611
"line %d: %s !def'd in %s via %s%s\n" : "",
613
file->i_file, file_red->i_file, ": doit"));
614
type = find_includes(filep, file,
615
file_red, recursion+1, failOK);
616
while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
617
type = gobble(filep, file, file_red);
619
gobble(filep, file, file_red);
622
debug(1,(type == IFDEF ?
623
"line %d: %s !def'd in %s via %s%s\n" : "",
625
file->i_file, file_red->i_file, ": gobble"));
626
type = gobble(filep, file, file_red);
628
find_includes(filep, file,
629
file_red, recursion+1, failOK);
630
else if (type == ELIF)
632
else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
641
gobble(filep, file, file_red);
650
warning("%s, line %d: incomplete undef == \"%s\"\n",
651
file_red->i_file, filep->f_line, line);
654
undefine(line, file_red);
658
add_include(filep, file, file_red, line, FALSE, failOK);
661
add_include(filep, file, file_red, line, TRUE, failOK);
664
warning("%s: %d: %s\n", file_red->i_file,
665
filep->f_line, line);
674
warning("%s", file_red->i_file);
675
if (file_red != file)
676
warning1(" (reading %s)", file->i_file);
677
warning1(", line %d: unknown directive == \"%s\"\n",
678
filep->f_line, line);
681
warning("%s", file_red->i_file);
682
if (file_red != file)
683
warning1(" (reading %s)", file->i_file);
684
warning1(", line %d: incomplete include == \"%s\"\n",
685
filep->f_line, line);
689
file->i_flags |= FINISHED;
693
/*-------------------------------------------------------------------------*/
694
static int match(str, list)
695
register char *str, **list;
699
for (i=0; *list; i++, list++)
700
if (strcmp(str, *list) == 0)
705
/*-------------------------------------------------------------------------*/
706
static void add_include(filep, file, file_red, include, dot, failOK)
707
struct filepointer *filep;
708
struct inclist *file, *file_red;
713
register struct inclist *newfile;
714
register struct filepointer *content;
717
* First decide what the pathname of this include file really is.
719
newfile = inc_path(file->i_file, include, dot);
720
if (newfile == NULL) {
723
if (file != file_red)
724
warning("%s (reading %s, line %d): ",
725
file_red->i_file, file->i_file, filep->f_line);
727
warning("%s, line %d: ", file->i_file, filep->f_line);
728
warning1("cannot find include file \"%s\"\n", include);
729
show_where_not = TRUE;
730
newfile = inc_path(file->i_file, include, dot);
731
show_where_not = FALSE;
735
included_by(file, newfile);
736
if (!(newfile->i_flags & SEARCHED)) {
737
newfile->i_flags |= SEARCHED;
738
content = getfile(newfile->i_file);
739
find_includes(content, newfile, file_red, 0, failOK);