parse.c

Go to the documentation of this file.
00001 /* $XConsortium: parse.c /main/33 1996/12/04 10:11:28 swick $ */
00002 /*
00003 
00004 Copyright (c) 1993, 1994  X Consortium
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 Except as contained in this notice, the name of the X Consortium shall not be
00024 used in advertising or otherwise to promote the sale, use or other dealings
00025 in this Software without prior written authorization from the X Consortium.
00026 
00027 */
00028 /* $XFree86: xc/config/makedepend/parse.c,v 1.3 1997/01/12 10:39:45 dawes Exp $ */
00029 
00030 #include "def.h"
00031 
00032 extern char *directives[];
00033 extern struct inclist maininclist;
00034 
00035 extern int deftype(char *line, struct filepointer *filep,
00036                       struct inclist *file_red, struct inclist *file,
00037                       int parse_it);
00038 extern int match(char *str, char **list);
00039 extern int zero_value(char *exp, struct filepointer *filep,
00040                          struct inclist *file_red);
00041 extern int merge2defines(struct inclist *file1, struct inclist *file2);
00042 extern int cppsetup(char *line, struct filepointer *filep,
00043                        struct inclist *inc);
00044 extern void add_include(struct filepointer *filep, struct inclist *file,
00045                            struct inclist *file_red, char *include,
00046                            boolean dot, boolean failOK);
00047 
00048 
00049 
00050 int
00051 gobble(filep, file, file_red)
00052 register struct filepointer *filep;
00053 struct inclist  *file, *file_red;
00054 {
00055    register char *line;
00056    register int type;
00057 
00058    while ((line = rgetline(filep))) {
00059       switch (type = deftype(line, filep, file_red, file, FALSE)) {
00060          case IF:
00061          case IFFALSE:
00062          case IFGUESSFALSE:
00063          case IFDEF:
00064          case IFNDEF:
00065             type = gobble(filep, file, file_red);
00066             while ((type == ELIF) || (type == ELIFFALSE) ||
00067                    (type == ELIFGUESSFALSE))
00068                type = gobble(filep, file, file_red);
00069             if (type == ELSE)
00070                (void)gobble(filep, file, file_red);
00071             break;
00072          case ELSE:
00073          case ENDIF:
00074             debug(0, ("%s, line %d: #%s\n",
00075                       file->i_file, filep->f_line,
00076                       directives[type]));
00077             return(type);
00078          case DEFINE:
00079          case UNDEF:
00080          case INCLUDE:
00081          case INCLUDEDOT:
00082          case PRAGMA:
00083          case ERROR:
00084          case IDENT:
00085          case SCCS:
00086          case EJECT:
00087          case WARNING:
00088             break;
00089          case ELIF:
00090          case ELIFFALSE:
00091          case ELIFGUESSFALSE:
00092             return(type);
00093          case -1:
00094             warning("%s, line %d: unknown directive == \"%s\"\n",
00095                     file_red->i_file, filep->f_line, line);
00096             break;
00097       }
00098    }
00099    return(-1);
00100 }
00101 
00102 /* copy from to to, where from and to might overlap */
00103 static void inplace_strcpy(char* to, const char* from)
00104 {
00105    while (*from)
00106       *to++ = *from++;
00107    *to = *from;
00108 }
00109 
00110 /*
00111  * Decide what type of # directive this line is.
00112  */
00113 int deftype(line, filep, file_red, file, parse_it)
00114 register char *line;
00115 register struct filepointer *filep;
00116 register struct inclist *file_red, *file;
00117 int parse_it;
00118 {
00119    register char *p;
00120    char *directive, savechar;
00121    register int ret;
00122 
00123    /*
00124     * Parse the directive...
00125     */
00126    directive = line + 1;
00127    while (*directive == ' ' || *directive == '\t')
00128       directive++;
00129 
00130    p = directive;
00131    while (*p >= 'a' && *p <= 'z')
00132       p++;
00133    savechar = *p;
00134    *p = '\0';
00135    ret = match(directive, directives);
00136    *p = savechar;
00137 
00138    /* If we don't recognize this compiler directive or we happen to just
00139     * be gobbling up text while waiting for an #endif or #elif or #else
00140     * in the case of an #elif we must check the zero_value and return an
00141     * ELIF or an ELIFFALSE.
00142     */
00143 
00144    if (ret == ELIF && !parse_it) {
00145       while (*p == ' ' || *p == '\t')
00146          p++;
00147       /*
00148        * parse an expression.
00149        */
00150       debug(0, ("%s, line %d: #elif %s ",
00151                 file->i_file, filep->f_line, p));
00152       ret = zero_value(p, filep, file_red);
00153       if (ret != IF) {
00154          debug(0, ("false...\n"));
00155          if (ret == IFFALSE)
00156             return(ELIFFALSE);
00157          else
00158             return(ELIFGUESSFALSE);
00159       } else {
00160          debug(0, ("true...\n"));
00161          return(ELIF);
00162       }
00163    }
00164 
00165    if (ret < 0 || ! parse_it)
00166       return(ret);
00167 
00168    /*
00169     * now decide how to parse the directive, and do it.
00170     */
00171    while (*p == ' ' || *p == '\t')
00172       p++;
00173    switch (ret) {
00174       case IF:
00175          /*
00176           * parse an expression.
00177           */
00178          ret = zero_value(p, filep, file_red);
00179          debug(0, ("%s, line %d: %s #if %s\n",
00180                    file->i_file, filep->f_line, ret ? "false" : "true", p));
00181          break;
00182       case IFDEF:
00183       case IFNDEF:
00184          debug(0, ("%s, line %d: #%s %s\n",
00185                    file->i_file, filep->f_line, directives[ret], p));
00186       case UNDEF:
00187          /*
00188           * separate the name of a single symbol.
00189           */
00190          while (isalnum((int)*p) || *p == '_')
00191             *line++ = *p++;
00192          *line = '\0';
00193          break;
00194       case INCLUDE:
00195          debug(2, ("%s, line %d: #include %s\n",
00196                    file->i_file, filep->f_line, p));
00197 
00198          /* Support ANSI macro substitution */
00199          {
00200             struct symtab **sym = isdefined(p, file_red, NULL);
00201             while (sym) {
00202                p = (*sym)->s_value;
00203                debug(3, ("%s : #includes SYMBOL %s = %s\n",
00204                          file->i_incstring,
00205                          (*sym) -> s_name,
00206                          (*sym) -> s_value));
00207                /* mark file as having included a 'soft include' */
00208                file->i_flags |= INCLUDED_SYM;
00209                sym = isdefined(p, file_red, NULL);
00210             }
00211          }
00212 
00213          /*
00214           * Separate the name of the include file.
00215           */
00216          while (*p && *p != '"' && *p != '<')
00217             p++;
00218          if (! *p)
00219             return(-2);
00220          if (*p++ == '"') {
00221             ret = INCLUDEDOT;
00222             while (*p && *p != '"')
00223                *line++ = *p++;
00224          } else
00225             while (*p && *p != '>')
00226                *line++ = *p++;
00227          *line = '\0';
00228          break;
00229       case DEFINE:
00230          /*
00231           * copy the definition back to the beginning of the line.
00232           */
00233          inplace_strcpy(line, p);
00234          break;
00235       case ELSE:
00236       case ENDIF:
00237       case ELIF:
00238       case PRAGMA:
00239       case ERROR:
00240       case IDENT:
00241       case SCCS:
00242       case EJECT:
00243       case WARNING:
00244          debug(0, ("%s, line %d: #%s\n",
00245                    file->i_file, filep->f_line, directives[ret]));
00246          /*
00247           * nothing to do.
00248           */
00249          break;
00250    }
00251    return(ret);
00252 }
00253 
00254 struct symtab **fdefined(symbol, file, srcfile)
00255          register char *symbol;
00256 struct inclist *file;
00257 struct inclist **srcfile;
00258 {
00259    register struct inclist **ip;
00260    register struct symtab **val;
00261    register int i;
00262    static int recurse_lvl = 0;
00263 
00264    if (file->i_flags & DEFCHECKED)
00265       return(NULL);
00266    file->i_flags |= DEFCHECKED;
00267    if ((val = slookup(symbol, file))) {
00268       debug(1, ("%s defined in %s as %s\n",
00269                 symbol, file->i_file, (*val)->s_value));
00270    }
00271    if (val == NULL && file->i_list) {
00272       for (ip = file->i_list, i = 0; i < file->i_listlen; i++, ip++)
00273          if (file->i_merged[i] == FALSE) {
00274             val = fdefined(symbol, *ip, srcfile);
00275             if ((*ip)->i_flags & FINISHED) {
00276                merge2defines(file, *ip);
00277                file->i_merged[i] = TRUE;
00278             }
00279             if (val != NULL) break;
00280          }
00281    } else if (val != NULL && srcfile != NULL) *srcfile = file;
00282    recurse_lvl--;
00283    file->i_flags &= ~DEFCHECKED;
00284 
00285    return(val);
00286 }
00287 
00288 struct symtab **isdefined(symbol, file, srcfile)
00289          register char *symbol;
00290 struct inclist *file;
00291 struct inclist **srcfile;
00292 {
00293    register struct symtab **val;
00294 
00295    if ((val = slookup(symbol, &maininclist))) {
00296       debug(1, ("%s defined on command line\n", symbol));
00297       if (srcfile != NULL) *srcfile = &maininclist;
00298       return(val);
00299    }
00300    if ((val = fdefined(symbol, file, srcfile)))
00301       return(val);
00302    debug(1, ("%s not defined in %s\n", symbol, file->i_file));
00303    return(NULL);
00304 }
00305 
00306 /*
00307  * Return type based on if the #if expression evaluates to 0
00308  */
00309 int
00310 zero_value(exp, filep, file_red)
00311 register char *exp;
00312 register struct filepointer *filep;
00313 register struct inclist *file_red;
00314 {
00315    if (cppsetup(exp, filep, file_red))
00316       return(IFFALSE);
00317    else
00318       return(IF);
00319 }
00320 
00321 void
00322 define2(name, val, file)
00323 char *name, *val;
00324 struct inclist *file;
00325 {
00326    int first, last, below;
00327    register struct symtab **sp = NULL, **dest;
00328    struct symtab *stab;
00329 
00330    /* Make space if it's needed */
00331    if (file->i_defs == NULL) {
00332       file->i_defs = (struct symtab **)
00333                      malloc(sizeof(struct symtab*) * SYMTABINC);
00334       file->i_ndefs = 0;
00335    } else if (!(file->i_ndefs % SYMTABINC))
00336       file->i_defs = (struct symtab **)
00337                      realloc(file->i_defs,
00338                              sizeof(struct symtab*) * (file->i_ndefs + SYMTABINC));
00339 
00340    if (file->i_defs == NULL)
00341       fatalerr("malloc()/realloc() failure in insert_defn()\n");
00342 
00343    below = first = 0;
00344    last = file->i_ndefs - 1;
00345    while (last >= first) {
00346       /* Fast inline binary search */
00347       register char *s1;
00348       register char *s2;
00349       register int middle = (first + last) / 2;
00350 
00351       /* Fast inline strchr() */
00352       s1 = name;
00353       s2 = file->i_defs[middle]->s_name;
00354       while (*s1++ == *s2++)
00355          if (s2[-1] == '\0') break;
00356 
00357       /* If exact match, set sp and break */
00358       if (*--s1 == *--s2) {
00359          sp = file->i_defs + middle;
00360          break;
00361       }
00362 
00363       /* If name > i_defs[middle] ... */
00364       if (*s1 > *s2) {
00365          below = first;
00366          first = middle + 1;
00367       }
00368       /* else ... */
00369       else {
00370          below = last = middle - 1;
00371       }
00372    }
00373 
00374    /* Search is done.  If we found an exact match to the symbol name,
00375       just replace its s_value */
00376    if (sp != NULL) {
00377       free((*sp)->s_value);
00378       (*sp)->s_value = copy(val);
00379       return;
00380    }
00381 
00382    sp = file->i_defs + file->i_ndefs++;
00383    dest = file->i_defs + below + 1;
00384    while (sp > dest) {
00385       *sp = sp[-1];
00386       sp--;
00387    }
00388    stab = (struct symtab *) malloc(sizeof(struct symtab));
00389    if (stab == NULL)
00390       fatalerr("malloc()/realloc() failure in insert_defn()\n");
00391 
00392    stab->s_name = copy(name);
00393    stab->s_value = copy(val);
00394    *sp = stab;
00395 }
00396 
00397 void
00398 define(def, file)
00399 char *def;
00400 struct inclist *file;
00401 {
00402    char *val;
00403 
00404    /* Separate symbol name and its value */
00405    val = def;
00406    while (isalnum((int)*val) || *val == '_')
00407       val++;
00408    if (*val)
00409       *val++ = '\0';
00410    while (*val == ' ' || *val == '\t')
00411       val++;
00412 
00413    if (!*val)
00414       val = "1";
00415    define2(def, val, file);
00416 }
00417 
00418 struct symtab **slookup(symbol, file)
00419          register char *symbol;
00420 register struct inclist *file;
00421 {
00422    register int first = 0;
00423    register int last = file->i_ndefs - 1;
00424 
00425    while (last >= first) {
00426       /* Fast inline binary search */
00427       register char *s1;
00428       register char *s2;
00429       register int middle = (first + last) / 2;
00430 
00431       /* Fast inline strchr() */
00432       s1 = symbol;
00433       s2 = file->i_defs[middle]->s_name;
00434       while (*s1++ == *s2++)
00435          if (s2[-1] == '\0') break;
00436 
00437       /* If exact match, we're done */
00438       if (*--s1 == *--s2) {
00439          return file->i_defs + middle;
00440       }
00441 
00442       /* If symbol > i_defs[middle] ... */
00443       if (*s1 > *s2) {
00444          first = middle + 1;
00445       }
00446       /* else ... */
00447       else {
00448          last = middle - 1;
00449       }
00450    }
00451    return(NULL);
00452 }
00453 
00454 int merge2defines(file1, file2)
00455 struct inclist *file1;
00456 struct inclist *file2;
00457 {
00458    if ((file1 != NULL) && (file2 != NULL)) {
00459       int first1 = 0;
00460       int last1 = file1->i_ndefs - 1;
00461 
00462       int first2 = 0;
00463       int last2 = file2->i_ndefs - 1;
00464 
00465       int first = 0;
00466       struct symtab** i_defs = NULL;
00467       int deflen = file1->i_ndefs + file2->i_ndefs;
00468 
00469       if (deflen > 0) {
00470          /* make sure deflen % SYMTABINC == 0 is still true */
00471          deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC;
00472          i_defs = (struct symtab**)malloc(deflen * sizeof(struct symtab*));
00473       }
00474       if (i_defs == NULL) return 0;
00475 
00476       while ((last1 >= first1) && (last2 >= first2)) {
00477          char *s1 = file1->i_defs[first1]->s_name;
00478          char *s2 = file2->i_defs[first2]->s_name;
00479 
00480          if (strcmp(s1, s2) < 0)
00481             i_defs[first++] = file1->i_defs[first1++];
00482          else if (strcmp(s1, s2) > 0)
00483             i_defs[first++] = file2->i_defs[first2++];
00484          else { /* equal */
00485             i_defs[first++] = file2->i_defs[first2++];
00486             first1++;
00487          }
00488       }
00489       while (last1 >= first1) {
00490          i_defs[first++] = file1->i_defs[first1++];
00491       }
00492       while (last2 >= first2) {
00493          i_defs[first++] = file2->i_defs[first2++];
00494       }
00495 
00496       if (file1->i_defs) free(file1->i_defs);
00497       file1->i_defs = i_defs;
00498       file1->i_ndefs = first;
00499 
00500       return 1;
00501    }
00502    return 0;
00503 }
00504 
00505 void
00506 undefine(symbol, file)
00507 char *symbol;
00508 register struct inclist *file;
00509 {
00510    register struct symtab **ptr;
00511    struct inclist *srcfile;
00512    while ((ptr = isdefined(symbol, file, &srcfile)) != NULL) {
00513       srcfile->i_ndefs--;
00514       for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
00515          *ptr = ptr[1];
00516    }
00517 }
00518 
00519 void
00520 undefine_all(file)
00521 register struct inclist *file;
00522 {
00523    register struct symtab **ptr;
00524 
00525    for (ptr = file->i_defs; ptr < file->i_defs + file->i_ndefs; ptr++)
00526       *ptr = 0;
00527    /* should delete it instead? */
00528    file->i_ndefs = 0;
00529 }
00530 
00531 int
00532 find_includes(filep, file, file_red, recursion, failOK)
00533 struct filepointer *filep;
00534 struct inclist  *file, *file_red;
00535 int   recursion;
00536 boolean   failOK;
00537 {
00538    register char *line;
00539    register int type;
00540    boolean recfailOK;
00541 
00542    while ((line = rgetline(filep))) {
00543       switch (type = deftype(line, filep, file_red, file, TRUE)) {
00544          case IF:
00545 doif:
00546             type = find_includes(filep, file,
00547                                  file_red, recursion + 1, failOK);
00548             while ((type == ELIF) || (type == ELIFFALSE) ||
00549                    (type == ELIFGUESSFALSE))
00550                type = gobble(filep, file, file_red);
00551             if (type == ELSE)
00552                gobble(filep, file, file_red);
00553             break;
00554          case IFFALSE:
00555          case IFGUESSFALSE:
00556 doiffalse:
00557             if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
00558                recfailOK = TRUE;
00559             else
00560                recfailOK = failOK;
00561             type = gobble(filep, file, file_red);
00562             if (type == ELSE)
00563                find_includes(filep, file,
00564                              file_red, recursion + 1, recfailOK);
00565             else
00566                if (type == ELIF)
00567                   goto doif;
00568                else
00569                   if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
00570                      goto doiffalse;
00571             break;
00572          case IFDEF:
00573          case IFNDEF:
00574             if ((type == IFDEF && isdefined(line, file_red, (struct inclist**)0))
00575                   || (type == IFNDEF && !isdefined(line, file_red, (struct inclist **)0))) {
00576                debug(1, (type == IFNDEF ?
00577                          "line %d: %s !def'd in %s via %s%s\n" : "",
00578                          filep->f_line, line,
00579                          file->i_file, file_red->i_file, ": doit"));
00580                type = find_includes(filep, file,
00581                                     file_red, recursion + 1, failOK);
00582                while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
00583                   type = gobble(filep, file, file_red);
00584                if (type == ELSE)
00585                   gobble(filep, file, file_red);
00586             } else {
00587                debug(1, (type == IFDEF ?
00588                          "line %d: %s !def'd in %s via %s%s\n" : "",
00589                          filep->f_line, line,
00590                          file->i_file, file_red->i_file, ": gobble"));
00591                type = gobble(filep, file, file_red);
00592                if (type == ELSE)
00593                   find_includes(filep, file,
00594                                 file_red, recursion + 1, failOK);
00595                else if (type == ELIF)
00596                   goto doif;
00597                else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
00598                   goto doiffalse;
00599             }
00600             break;
00601          case ELSE:
00602          case ELIFFALSE:
00603          case ELIFGUESSFALSE:
00604          case ELIF:
00605             if (!recursion)
00606                gobble(filep, file, file_red);
00607             /* fallthrough */
00608          case ENDIF:
00609             if (recursion)
00610                return(type);
00611             /* fallthrough */
00612          case DEFINE:
00613             define(line, file);
00614             break;
00615          case UNDEF:
00616             if (!*line) {
00617                warning("%s, line %d: incomplete undef == \"%s\"\n",
00618                        file_red->i_file, filep->f_line, line);
00619                break;
00620             }
00621             undefine(line, file_red);
00622             break;
00623          case INCLUDE:
00624             add_include(filep, file, file_red, line, FALSE, failOK);
00625             break;
00626          case INCLUDEDOT:
00627             add_include(filep, file, file_red, line, TRUE, failOK);
00628             break;
00629          case ERROR:
00630          case WARNING:
00631             warning("%s: %d: %s\n", file_red->i_file,
00632                     filep->f_line, line);
00633             break;
00634 
00635          case PRAGMA:
00636          case IDENT:
00637          case SCCS:
00638          case EJECT:
00639             break;
00640          case - 1:
00641             warning("%s", file_red->i_file);
00642             if (file_red != file)
00643                warning1(" (reading %s)", file->i_file);
00644             warning1(", line %d: unknown directive == \"%s\"\n",
00645                      filep->f_line, line);
00646             break;
00647          case - 2:
00648             warning("%s", file_red->i_file);
00649             if (file_red != file)
00650                warning1(" (reading %s)", file->i_file);
00651             warning1(", line %d: incomplete include == \"%s\"\n",
00652                      filep->f_line, line);
00653             break;
00654       }
00655    }
00656    file->i_flags |= FINISHED;
00657    return(-1);
00658 }

Generated on Tue Jul 5 14:10:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1