parse.cpp

Go to the documentation of this file.
00001 /* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
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 
00029 #ifdef __WIN32__
00030   #pragma warning(disable : 4996)
00031 #endif
00032 
00033 #include "def.h"
00034 
00035 #include <string.h>
00036 
00037 extern const char  *directives[];
00038 extern inclist  maininclist;
00039 
00040 int find_includes(struct filepointer *filep, inclist *file, inclist *file_red, int recursion, bool failOK)
00041 {
00042   register char  *line;
00043   register int  type;
00044   bool recfailOK;
00045 
00046   while ((line = getline(filep))) {
00047     switch(type = deftype(line, filep, file_red, file, true)) {
00048     case IF:
00049     doif:
00050       type = find_includes(filep, file,
00051         file_red, recursion+1, failOK);
00052       while ((type == ELIF) || (type == ELIFFALSE) ||
00053              (type == ELIFGUESSFALSE))
00054         type = gobble(filep, file, file_red);
00055       if (type == ELSE)
00056         gobble(filep, file, file_red);
00057       break;
00058     case IFFALSE:
00059     case IFGUESSFALSE:
00060         doiffalse:
00061       if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
00062           recfailOK = true;
00063       else
00064           recfailOK = failOK;
00065       type = gobble(filep, file, file_red);
00066       if (type == ELSE)
00067           find_includes(filep, file,
00068             file_red, recursion+1, recfailOK);
00069       else
00070       if (type == ELIF)
00071           goto doif;
00072       else
00073       if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
00074           goto doiffalse;
00075       break;
00076     case IFDEF:
00077     case IFNDEF:
00078       if ((type == IFDEF && isdefined(line, file_red, NULL))
00079        || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
00080         debug(1,(type == IFNDEF ?
00081             "line %d: %s !def'd in %s via %s%s\n" : "",
00082             filep->f_line, line,
00083             file->i_file, file_red->i_file, ": doit"));
00084         type = find_includes(filep, file,
00085           file_red, recursion+1, failOK);
00086         while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
00087           type = gobble(filep, file, file_red);
00088         if (type == ELSE)
00089           gobble(filep, file, file_red);
00090       }
00091       else {
00092         debug(1,(type == IFDEF ?
00093             "line %d: %s !def'd in %s via %s%s\n" : "",
00094             filep->f_line, line,
00095             file->i_file, file_red->i_file, ": gobble"));
00096         type = gobble(filep, file, file_red);
00097         if (type == ELSE)
00098           find_includes(filep, file,
00099             file_red, recursion+1, failOK);
00100         else if (type == ELIF)
00101               goto doif;
00102         else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
00103               goto doiffalse;
00104       }
00105       break;
00106     case ELSE:
00107     case ELIFFALSE:
00108     case ELIFGUESSFALSE:
00109     case ELIF:
00110       if (!recursion)
00111         gobble(filep, file, file_red);
00112     case ENDIF:
00113       if (recursion)
00114         return(type);
00115     case DEFINE:
00116       define(line, file);
00117       break;
00118     case UNDEF:
00119       if (!*line) {
00120           warning("%s, line %d: incomplete undef == \"%s\"\n",
00121         file_red->i_file, filep->f_line, line);
00122           break;
00123       }
00124       undefine(line, file_red);
00125       break;
00126     case INCLUDE:
00127       add_include(filep, file, file_red, line, false, failOK);
00128       break;
00129     case INCLUDEDOT:
00130       add_include(filep, file, file_red, line, true, failOK);
00131       break;
00132     case ERROR:
00133           warning("%s: %d: %s\n", file_red->i_file,
00134          filep->f_line, line);
00135           break;
00136         
00137     case PRAGMA:
00138     case IDENT:
00139     case SCCS:
00140     case EJECT:
00141     case IMPORT:
00142       break;
00143     case -1:
00144       warning("%s", file_red->i_file);
00145       if (file_red != file)
00146           warning1(" (reading %s)", file->i_file);
00147       warning1(", line %d: unknown directive == \"%s\"\n",
00148          filep->f_line, line);
00149       break;
00150     case -2:
00151       warning("%s", file_red->i_file);
00152       if (file_red != file)
00153           warning1(" (reading %s)", file->i_file);
00154       warning1(", line %d: incomplete include == \"%s\"\n",
00155          filep->f_line, line);
00156       break;
00157     }
00158   }
00159   return(-1);
00160 }
00161 
00162 int gobble(register struct filepointer *filep, inclist *file,
00163     inclist *file_red)
00164 {
00165   register char  *line;
00166   register int  type;
00167 
00168   while ((line = getline(filep))) {
00169     switch(type = deftype(line, filep, file_red, file, false)) {
00170     case IF:
00171     case IFFALSE:
00172     case IFGUESSFALSE:
00173     case IFDEF:
00174     case IFNDEF:
00175       type = gobble(filep, file, file_red);
00176       while ((type == ELIF) || (type == ELIFFALSE) ||
00177              (type == ELIFGUESSFALSE))
00178           type = gobble(filep, file, file_red);
00179       if (type == ELSE)
00180               (void)gobble(filep, file, file_red);
00181       break;
00182     case ELSE:
00183     case ENDIF:
00184       debug(0,("%s, line %d: #%s\n",
00185         file->i_file, filep->f_line,
00186         directives[type]));
00187       return(type);
00188     case DEFINE:
00189     case UNDEF:
00190     case INCLUDE:
00191     case INCLUDEDOT:
00192     case PRAGMA:
00193     case ERROR:
00194     case IDENT:
00195     case SCCS:
00196     case EJECT:
00197     case IMPORT:
00198       break;
00199     case ELIF:
00200     case ELIFFALSE:
00201     case ELIFGUESSFALSE:
00202       return(type);
00203     case -1:
00204       warning("%s, line %d: unknown directive == \"%s\"\n",
00205         file_red->i_file, filep->f_line, line);
00206       break;
00207     }
00208   }
00209   return(-1);
00210 }
00211 
00212 /*
00213  * Decide what type of # directive this line is.
00214  */
00215 int deftype(register char  *line, register struct filepointer *filep,
00216     register inclist *file_red, register inclist *file,
00217     int parse_it)
00218 {
00219   register char  *p;
00220   char  *directive, savechar;
00221   register int  ret;
00222 
00223   /*
00224    * Parse the directive...
00225    */
00226   directive=line+1;
00227   while (*directive == ' ' || *directive == '\t')
00228     directive++;
00229 
00230   p = directive;
00231   while (*p >= 'a' && *p <= 'z')
00232     p++;
00233   savechar = *p;
00234   *p = '\0';
00235   ret = match(directive, directives);
00236   *p = savechar;
00237 
00238   /* If we don't recognize this compiler directive or we happen to just
00239    * be gobbling up text while waiting for an #endif or #elif or #else
00240    * in the case of an #elif we must check the zero_value and return an
00241    * ELIF or an ELIFFALSE.
00242    */
00243 
00244   if (ret == ELIF && !parse_it)
00245   {
00246       while (*p == ' ' || *p == '\t')
00247     p++;
00248       /*
00249        * parse an expression.
00250        */
00251       debug(0,("%s, line %d: #elif %s ",
00252        file->i_file, filep->f_line, p));
00253       ret = zero_value(p, filep, file_red);
00254       if (ret != IF)
00255       {
00256     debug(0,("false...\n"));
00257     if (ret == IFFALSE)
00258         return(ELIFFALSE);
00259     else
00260         return(ELIFGUESSFALSE);
00261       }
00262       else
00263       {
00264     debug(0,("true...\n"));
00265     return(ELIF);
00266       }
00267   }
00268 
00269   if (ret < 0 || ! parse_it)
00270     return(ret);
00271 
00272   /*
00273    * now decide how to parse the directive, and do it.
00274    */
00275   while (*p == ' ' || *p == '\t')
00276     p++;
00277   switch (ret) {
00278   case IF:
00279     /*
00280      * parse an expression.
00281      */
00282     ret = zero_value(p, filep, file_red);
00283     debug(0,("%s, line %d: %s #if %s\n",
00284        file->i_file, filep->f_line, ret?"false":"true", p));
00285     break;
00286   case IFDEF:
00287   case IFNDEF:
00288     debug(0,("%s, line %d: #%s %s\n",
00289       file->i_file, filep->f_line, directives[ret], p));
00290   case UNDEF:
00291     /*
00292      * separate the name of a single symbol.
00293      */
00294     while (isalnum(*p) || *p == '_')
00295       *line++ = *p++;
00296     *line = '\0';
00297     break;
00298   case INCLUDE:
00299     debug(2,("%s, line %d: #include %s\n",
00300       file->i_file, filep->f_line, p));
00301 
00302     /* Support ANSI macro substitution */
00303     {
00304         struct symtab *sym = isdefined(p, file_red, NULL);
00305         while (sym) {
00306       p = sym->s_value;
00307       debug(3,("%s : #includes SYMBOL %s = %s\n",
00308              file->i_incstring,
00309              sym -> s_name,
00310              sym -> s_value));
00311       /* mark file as having included a 'soft include' */
00312       file->i_included_sym = true; 
00313       sym = isdefined(p, file_red, NULL);
00314         }
00315     }
00316 
00317     /*
00318      * Separate the name of the include file.
00319      */
00320     while (*p && *p != '"' && *p != '<')
00321       p++;
00322     if (! *p)
00323       return(-2);
00324     if (*p++ == '"') {
00325       ret = INCLUDEDOT;
00326       while (*p && *p != '"')
00327         *line++ = *p++;
00328     } else
00329       while (*p && *p != '>')
00330         *line++ = *p++;
00331     *line = '\0';
00332     break;
00333   case DEFINE:
00334     /*
00335      * copy the definition back to the beginning of the line.
00336      */
00337     strcpy (line, p);
00338     break;
00339   case ELSE:
00340   case ENDIF:
00341   case ELIF:
00342   case PRAGMA:
00343   case ERROR:
00344   case IDENT:
00345   case SCCS:
00346   case EJECT:
00347   case IMPORT:
00348     debug(0,("%s, line %d: #%s\n",
00349       file->i_file, filep->f_line, directives[ret]));
00350     /*
00351      * nothing to do.
00352      */
00353     break;
00354   }
00355   return(ret);
00356 }
00357 
00358 symtab *isdefined(register char *symbol, inclist *file,
00359     inclist  **srcfile)
00360 {
00361   register struct symtab  *val;
00362 
00363   if ((val = slookup(symbol, &maininclist))) {
00364     debug(1,("%s defined on command line\n", symbol));
00365     if (srcfile != NULL) *srcfile = &maininclist;
00366     return(val);
00367   }
00368   if ((val = fdefined(symbol, file, srcfile)))
00369     return(val);
00370   debug(1,("%s not defined in %s\n", symbol, file->i_file));
00371   return(NULL);
00372 }
00373 
00374 struct symtab *fdefined(register char *symbol, inclist  *file, inclist  **srcfile)
00375 {
00376   register inclist  **ip;
00377   register struct symtab  *val;
00378   register int  i;
00379   static int  recurse_lvl = 0;
00380 
00381   if (file->i_defchecked)
00382     return(NULL);
00383   file->i_defchecked = true;
00384   if ((val = slookup(symbol, file)))
00385     debug(1,("%s defined in %s as %s\n", symbol, file->i_file, val->s_value));
00386   if (val == NULL && file->i_list)
00387     {
00388     for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
00389       if ((val = fdefined(symbol, *ip, srcfile))) {
00390         break;
00391       }
00392     }
00393   else if (val != NULL && srcfile != NULL) *srcfile = file;
00394   recurse_lvl--;
00395   file->i_defchecked = false;
00396 
00397   return(val);
00398 }
00399 
00400 /*
00401  * Return type based on if the #if expression evaluates to 0
00402  */
00403 int zero_value(register char  *exp, register struct filepointer *filep,
00404     register inclist *file_red)
00405 {
00406   if (cppsetup(exp, filep, file_red))
00407       return(IFFALSE);
00408   else
00409       return(IF);
00410 }
00411 
00412 void define(char  *def, inclist  *file)
00413 {
00414     char *val;
00415 
00416     /* Separate symbol name and its value */
00417     val = def;
00418     while (isalnum(*val) || *val == '_')
00419   val++;
00420     if (*val)
00421   *val++ = '\0';
00422     while (*val == ' ' || *val == '\t')
00423   val++;
00424 
00425     if (!*val)
00426   val = (char *)"1";
00427     define2(def, val, file);
00428 }
00429 
00430 void define2(char  *name, char  *val, inclist  *file)
00431 {
00432     int first, last, below;
00433     register struct symtab *sp = NULL, *dest;
00434 
00435     /* Make space if it's needed */
00436     if (file->i_defs == NULL)
00437     {
00438   file->i_defs = (struct symtab *)
00439       malloc(sizeof (struct symtab) * SYMTABINC);
00440   file->i_deflen = SYMTABINC;
00441   file->i_ndefs = 0;
00442     }
00443     else if (file->i_ndefs == file->i_deflen)
00444   file->i_defs = (struct symtab *)
00445       realloc(file->i_defs,
00446           sizeof(struct symtab)*(file->i_deflen+=SYMTABINC));
00447 
00448     if (file->i_defs == NULL)
00449   fatalerr("malloc()/realloc() failure in insert_defn()\n");
00450 
00451     below = first = 0;
00452     last = file->i_ndefs - 1;
00453     while (last >= first)
00454     {
00455   /* Fast inline binary search */
00456   register char *s1;
00457   register char *s2;
00458   register int middle = (first + last) / 2;
00459 
00460   /* Fast inline strchr() */
00461   s1 = name;
00462   s2 = file->i_defs[middle].s_name;
00463   while (*s1++ == *s2++)
00464       if (s2[-1] == '\0') break;
00465 
00466   /* If exact match, set sp and break */
00467   if (*--s1 == *--s2) 
00468   {
00469       sp = file->i_defs + middle;
00470       break;
00471   }
00472 
00473   /* If name > i_defs[middle] ... */
00474   if (*s1 > *s2) 
00475   {
00476       below = first;
00477       first = middle + 1;
00478   }
00479   /* else ... */
00480   else
00481   {
00482       below = last = middle - 1;
00483   }
00484     }
00485 
00486     /* Search is done.  If we found an exact match to the symbol name,
00487        just replace its s_value */
00488     if (sp != NULL)
00489     {
00490   free(sp->s_value);
00491   sp->s_value = copy(val);
00492   return;
00493     }
00494 
00495     sp = file->i_defs + file->i_ndefs++;
00496     dest = file->i_defs + below + 1;
00497     while (sp > dest)
00498     {
00499   *sp = sp[-1];
00500   sp--;
00501     }
00502     sp->s_name = copy(name);
00503     sp->s_value = copy(val);
00504 }
00505 
00506 struct symtab *slookup(register char  *symbol, register inclist  *file)
00507 {
00508   register int first = 0;
00509   register int last = file->i_ndefs - 1;
00510 
00511   if (file) while (last >= first)
00512   {
00513       /* Fast inline binary search */
00514       register char *s1;
00515       register char *s2;
00516       register int middle = (first + last) / 2;
00517 
00518       /* Fast inline strchr() */
00519       s1 = symbol;
00520       s2 = file->i_defs[middle].s_name;
00521       while (*s1++ == *s2++)
00522           if (s2[-1] == '\0') break;
00523 
00524       /* If exact match, we're done */
00525       if (*--s1 == *--s2) 
00526       {
00527           return file->i_defs + middle;
00528       }
00529 
00530       /* If symbol > i_defs[middle] ... */
00531       if (*s1 > *s2) 
00532       {
00533           first = middle + 1;
00534       }
00535       /* else ... */
00536       else
00537       {
00538           last = middle - 1;
00539       }
00540   }
00541   return(NULL);
00542 }
00543 
00544 void undefine(char  *symbol, register inclist *file)
00545 {
00546   register struct symtab *ptr;
00547   inclist *srcfile;
00548   while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
00549   {
00550       srcfile->i_ndefs--;
00551       for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
00552     *ptr = ptr[1];
00553   }
00554 }

Generated on Fri Nov 28 04:28:50 2008 for HOOPLE Libraries by  doxygen 1.5.1