Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

lh.c

Go to the documentation of this file.
00001 /*
00002 ** LCLint - annotation-assisted static program checker
00003 ** Copyright (C) 1994-2000 University of Virginia,
00004 **         Massachusetts Institute of Technology
00005 **
00006 ** This program is free software; you can redistribute it and/or modify it
00007 ** under the terms of the GNU General Public License as published by the
00008 ** Free Software Foundation; either version 2 of the License, or (at your
00009 ** option) any later version.
00010 ** 
00011 ** This program is distributed in the hope that it will be useful, but
00012 ** WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 ** General Public License for more details.
00015 ** 
00016 ** The GNU General Public License is available from http://www.gnu.org/ or
00017 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018 ** MA 02111-1307, USA.
00019 **
00020 ** For information on lclint: lclint-request@cs.virginia.edu
00021 ** To report a bug: lclint-bug@cs.virginia.edu
00022 ** For more information: http://lclint.cs.virginia.edu
00023 */
00024 /*
00025 ** lh.c
00026 **
00027 **  MODULE DESCRIPTION:
00028 **
00029 **      This module contains the I/O routines for writing out the .lh file
00030 **      generated from the .lcl file.
00031 **
00032 **  AUTHORS:
00033 **
00034 **      Gary Feldman, Technical Languages and Environments, DECspec project
00035 **      Yang Meng Tan, MIT.
00036 **
00037 **  CREATION DATE:  9 April 91
00038 **
00039 **      The lh.c module controls formatting policy.
00040 */
00041 
00042 # include "lclintMacros.nf"
00043 # include "llbasic.h"
00044 # include "osd.h"
00045 # include "herald.h"
00046 # include "lh.h"
00047 # include "llmain.h"
00048 
00049 /*@constant static char TABCH; @*/
00050 # define TABCH          '\1'
00051 
00052 /*@constant static char TABINCH; @*/
00053 # define TABINCH        '\2'
00054 
00055 /*@constant static char TABOUTCH; @*/
00056 # define TABOUTCH       '\3'
00057 
00058 /*@constant static observer char *LHTMP_SUFFIX; @*/
00059 # define LHTMP_SUFFIX ".lh_tmp"
00060 
00061 /*
00062   # define TAB                  fputc (TABCH,   LhFile.f);
00063   # define TABIN                fputc (TABINCH,         LhFile.f);
00064   # define TABOUT               fputc (TABOUTCH, LhFile.f);
00065 */
00066 
00067 typedef struct
00068 {
00069   /*@dependent@*/ /*@null@*/ /*@reldef@*/ FILE *f;
00070   /*@reldef@*/ char *name;
00071 } outFile;
00072 
00073 static bool genLh;
00074 static outFile LhFile;
00075 static bool needIncludeBool = FALSE;
00076 
00077 /*
00078 **
00079 **  FORWARD FUNCTIONS
00080 **
00081 */
00082 
00083 /* static int colpos (int startcol, cstring line); */
00084 
00085 static cstring lhTypeSpecNode (lclTypeSpecNode p_typespec);
00086 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr p_x);
00087 static /*@only@*/ cstring lhDeclaratorNode (declaratorNode p_x);
00088 
00089 static /*@dependent@*/ /*@null@*/ FILE *out_open (char *name, char *suffix) /*@modifies fileSystem@*/
00090 {
00091   char *fullname = (char *)
00092     mstring_create (size_toInt (strlen (name) + strlen (suffix)));
00093   FILE *ret;
00094 
00095   strcpy (fullname, name);
00096   strcat (fullname, suffix);
00097   ret = fopen (fullname, "w+");
00098   sfree (fullname);
00099   return ret;
00100 }
00101 
00102 /*@only@*/ cstring 
00103 lhFunction (lclTypeSpecNode lclTypeSpec, declaratorNode declarator)
00104 {
00105   cstring s;
00106 
00107   if (!genLh)
00108     return cstring_undefined;
00109   
00110   s = message ("extern %q\1%q;", lhTypeSpecNode (lclTypeSpec),
00111                lhDeclaratorNode (declarator));
00112   
00113   return s;
00114 }
00115 
00116 static /*@only@*/ cstring
00117 lhDeclaratorNode (declaratorNode x)
00118 {
00119   return (lhTypeExpr (x->type));
00120 }
00121 
00122 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr x)
00123 {
00124   cstring s = cstring_undefined; /* print out types in order of appearance in source */
00125   paramNodeList params;
00126   int i;
00127 
00128   if (x != (typeExpr) 0)
00129     {
00130       cstring front = cstring_undefined;
00131       cstring back  = cstring_undefined;
00132 
00133       for (i = x->wrapped; i >= 1; i--)
00134         {
00135           front = cstring_appendChar (front, '(');
00136           back  = cstring_appendChar (back, ')');
00137         }
00138 
00139       switch (x->kind)
00140         {
00141         case TEXPR_BASE:
00142           s = message ("%q%s", s, ltoken_getRawString (x->content.base));
00143           break;
00144         case TEXPR_PTR:
00145           s = message ("%q*%q", s, lhTypeExpr (x->content.pointer));
00146           break;
00147         case TEXPR_ARRAY:
00148           s = message ("%q%q[%q]", s, 
00149                        lhTypeExpr (x->content.array.elementtype),
00150                        termNode_unparse (x->content.array.size));
00151           break;
00152         case TEXPR_FCN:
00153           s = message ("%q%q (", s, lhTypeExpr (x->content.function.returntype));
00154           params = x->content.function.args;
00155 
00156           if (!paramNodeList_empty (params))
00157             {
00158               s = message ("%q%q", s, 
00159                            paramNodeList_unparseComments (x->content.function.args));
00160             }
00161 
00162           s = message ("%q)", s);
00163           break;
00164         }
00165       s = message ("%q%q%q", front, s, back);
00166     }
00167   else
00168     {
00169       s = cstring_makeLiteral ("?");
00170     }
00171 
00172   return s;
00173 }
00174 
00175 extern void
00176 lhForwardStruct (ltoken t)
00177 {
00178   if (!genLh)
00179     return;
00180 
00181   lhOutLine (message ("struct %s;", ltoken_unparse (t)));
00182 }
00183 
00184 
00185 extern void
00186 lhForwardUnion (ltoken t)
00187 {
00188   if (!genLh)
00189     return;
00190 
00191   lhOutLine (message ("union %s;", ltoken_unparse (t)));
00192 }
00193 
00194 extern /*@only@*/ cstring 
00195 lhType (typeNode t)
00196 {
00197   if (!genLh)
00198     return cstring_undefined;
00199 
00200   if (t->kind == TK_EXPOSED)
00201     {
00202       exposedNode n = t->content.exposed;
00203 
00204       if (n != (exposedNode) 0)
00205         {
00206           if (declaratorInvNodeList_size (n->decls) == 0)
00207             {
00208               /* 
00209               ** Forward struct or union declaration
00210               */
00211 
00212               return (cstring_appendChar (lhTypeSpecNode (n->type), ';'));
00213             }
00214           else
00215             {
00216               cstring s = cstring_undefined;
00217 
00218               declaratorInvNodeList_elements (n->decls, d)
00219                 {
00220                   cstring name = declaratorNode_unparse (d->declarator);
00221                   cstring pname = declaratorNode_unparseCode (d->declarator); 
00222                   
00223                   s = message ("%q\n# ifndef EXPOSED_TYPE_%q\ntypedef %q %q;\n# endif\n", 
00224                                s, pname, lhTypeSpecNode (n->type), name);
00225                 } end_declaratorInvNodeList_elements;
00226               
00227               return s;
00228             }
00229         }
00230     }
00231 
00232   return cstring_undefined;
00233 }
00234 
00235 static /*@only@*/ cstring 
00236 lhTypeSpecNode (lclTypeSpecNode typespec)
00237 {
00238   if (!genLh)
00239     {
00240       return cstring_undefined;
00241     }
00242 
00243   return (lclTypeSpecNode_unparseComments (typespec));
00244 }
00245 
00246 /*@only@*/ cstring
00247 lhVarDecl (lclTypeSpecNode lclTypeSpec, initDeclNodeList initDecls,
00248            qualifierKind qualifier)
00249 {
00250   bool first = TRUE;
00251   cstring s;
00252 
00253   if (!genLh)
00254     return cstring_undefined;
00255 
00256   s = cstring_makeLiteral ("extern");
00257 
00258   switch (qualifier)
00259     {
00260     case QLF_NONE:
00261       break;
00262     case QLF_CONST:
00263       s = message ("%q const", s);
00264       break;
00265     case QLF_VOLATILE:
00266       s = message ("%q volatile", s);
00267       break;
00268     default:                    /* ignore it */
00269       break;
00270     }
00271   
00272   s = message ("%q %q\1", s, lhTypeSpecNode (lclTypeSpec));
00273 
00274   initDeclNodeList_elements (initDecls, i)
00275   {
00276     if (first)
00277       {
00278         s = message ("%q %q", s, declaratorNode_unparse (i->declarator));
00279         first = FALSE;
00280       }
00281     else
00282       {
00283         s = message ("%q, %q", s, declaratorNode_unparse (i->declarator));
00284       }
00285   } end_initDeclNodeList_elements;
00286   
00287   return (message ("%q;", s));
00288 }
00289 
00290 extern void
00291 lhCleanup (void)
00292    /*@modifies fileSystem@*/
00293 {
00294   if (!genLh)
00295     {
00296       return;
00297     }
00298   else
00299     {
00300       FILE *f;
00301       int c, col = 0, tabcol = 0;
00302       char *fullname;
00303 
00304       
00305       fullname = mstring_create 
00306         (size_toInt (strlen (LhFile.name) + strlen (LHTMP_SUFFIX)));
00307 
00308       f = out_open (LhFile.name, LH_SUFFIX);
00309       llassert (LhFile.f != NULL);
00310 
00311       strcpy (fullname, LhFile.name);
00312       strcat (fullname, LHTMP_SUFFIX);
00313 
00314       if (f == NULL)
00315         {
00316           lldiagmsg (message ("Cannot open lh file for output: %s", 
00317                               cstring_fromChars (fullname)));
00318         }
00319       else
00320         {
00321           fprintf (f, "/* Output from %s */\n", LCL_PARSE_VERSION);
00322 
00323           rewind (LhFile.f);
00324 
00325           while (EOF != (c = getc (LhFile.f)))
00326             {
00327               switch (c)
00328                 {
00329                 case TABCH:
00330                   if (col == 0)
00331                     {
00332                       if (tabcol > 0)
00333                         fprintf (f, "%*s", tabcol, "");
00334                     }
00335                   else
00336                     {
00337                       check (fputc (' ', f) == (int) ' ');
00338                     }
00339                   /*@switchbreak@*/ break;
00340                   
00341                 case TABINCH:
00342                   tabcol += 4;
00343                   /*@switchbreak@*/ break;
00344                   
00345                 case TABOUTCH:
00346                   tabcol -= 4;
00347                   /*@switchbreak@*/ break;
00348                   
00349                 case '\n':
00350                   col = 0;
00351                   check (fputc (c, f) == (int) c);
00352                   /*@switchbreak@*/ break;
00353                   
00354                 default:
00355                   col++;
00356                   check (fputc (c, f) == (int) c);
00357                   /*@switchbreak@*/ break;
00358                 }
00359             }
00360 
00361           check (fclose (f) == 0);
00362           check (fclose (LhFile.f) == 0);
00363 
00364           (void) osd_unlink (fullname);
00365           LhFile.f = NULL;
00366         }
00367       
00368       sfree (fullname);
00369     }
00370 }
00371 
00372 /* Write an #include of bool.h if we have't done so already.  */
00373 extern void
00374 lhIncludeBool (void)
00375 {
00376   needIncludeBool = TRUE;
00377 }
00378 
00379 /*
00380 **++
00381 **  FUNCTIONAL DESCRIPTION:
00382 **
00383 **      Initialize the .lh file processing.
00384 **
00385 **  FORMAL PARAMETERS:
00386 **
00387 **      source * f: The source file, from which we compute the name of
00388 **      the .lh file.
00389 **
00390 **      bool outputLh: If true, produce a .lh file, otherwise don't.
00391 **
00392 **  RETURN VALUE:
00393 **
00394 **      None
00395 **
00396 **  SIDE EFFECTS:
00397 **
00398 **      The .lh file may be opened.
00399 **
00400 **
00401 **--
00402 */
00403 
00404 void lhInit (tsource * f) /*@globals undef LhFile; @*/
00405 {
00406   static bool lherror = FALSE;
00407   
00408   genLh = context_msgLh ();
00409   needIncludeBool = FALSE;
00410 
00411   if (!genLh)
00412     {
00413       return;
00414     }
00415   
00416   LhFile.name = LSLRootName (tsource_fileName (f));
00417   LhFile.f = out_open (LhFile.name, LHTMP_SUFFIX);
00418 
00419   if (LhFile.f == NULL)
00420     {
00421       genLh = FALSE;
00422       if (!lherror)
00423         {
00424           lclplainerror (message ("Cannot write .lh file: %s.lh", 
00425                                   cstring_fromChars (LhFile.name)));
00426           lherror = TRUE;
00427         }
00428     } 
00429 } 
00430 
00431 void lhOutLine (/*@only@*/ cstring s)
00432 {
00433   if (genLh)
00434     {
00435       llassert (LhFile.f != NULL);
00436 
00437       if (cstring_length (s) > 0) 
00438         {
00439           check (fputs (cstring_toCharsSafe (s), LhFile.f) != EOF); 
00440         }
00441 
00442       check (fputc ('\n', LhFile.f) == (int) '\n'); 
00443     }
00444 
00445   cstring_free (s);
00446 }
00447 
00448 void lhExternals (interfaceNodeList x)
00449 {
00450   if (genLh)
00451     {
00452       llassert (LhFile.f != NULL);
00453 
00454       /*
00455       ** Need to make sure all standard library includes come first.
00456       */
00457 
00458       interfaceNodeList_elements (x, el)
00459         {
00460           if (el->kind == INF_IMPORTS)
00461             {
00462               importNodeList imps = el->content.imports;
00463 
00464               importNodeList_elements (imps, il)
00465                 {
00466                   if (il->kind == IMPBRACKET)
00467                     {
00468                       lhOutLine (message ("# include <%s.h>", 
00469                                           ltoken_getRawString (il->val)));
00470                     }
00471                 } end_importNodeList_elements ;
00472             }
00473         } end_interfaceNodeList_elements;
00474 
00475       lhOutLine (cstring_makeLiteral ("# include \"bool.h\""));
00476       
00477       interfaceNodeList_elements (x, el)
00478         {
00479           if (el->kind == INF_IMPORTS)
00480             {
00481               importNodeList imps = el->content.imports;
00482 
00483               importNodeList_elements (imps, il)
00484                 {
00485                   if (il->kind != IMPBRACKET)
00486                     {
00487                       lhOutLine (message ("# include \"%s.h\"", 
00488                                           ltoken_getRawString (il->val)));
00489                     }
00490                 } end_importNodeList_elements ;
00491             }
00492         } end_interfaceNodeList_elements;
00493 
00494       lhOutLine (cstring_undefined);
00495     }
00496 }
00497 
00498 
00499 

Generated at Fri Nov 3 18:57:42 2000 for LCLint by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000