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

lslparse.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 ** lslparse.c
00026 **
00027 ** Module for calling LSL checker.
00028 **
00029 **  AUTHOR:
00030 **      Yang Meng Tan,
00031 **         Massachusetts Institute of Technology
00032 */
00033 
00034 # include "lclintMacros.nf"
00035 # include "llbasic.h"
00036 # include "lclscan.h"
00037 # include "signature.h"
00038 # include "signature2.h"
00039 # include "scan.h"
00040 # include "scanline.h"
00041 # include "syntable.h"
00042 # include "tokentable.h"
00043 # include "lslinit.h"
00044 # include "lslparse.h"
00045 # include "llmain.h"
00046 
00047 /*@+ignorequals@*/
00048 
00049 /*@dependent@*/ /*@null@*/ lslOp g_importedlslOp = NULL;
00050 bool g_lslParsingTraits = FALSE;
00051 
00052 static void invokeLSL (char *p_infile, char *p_outfile, bool p_deletep);
00053 
00054 int
00055 parseSignatures (cstring infile)
00056 {
00057   char *cinfile = cstring_toCharsSafe (infile);
00058   tsource *sourceFile;
00059   ltoken *id = (ltoken *) dmalloc (sizeof (*id));
00060   int status = 0;
00061 
00062   /* parse traits */
00063   *id = LSLInsertToken (LST_SIMPLEID, lsymbol_fromChars (cinfile), 0, FALSE);
00064   ltoken_setFileName (*id, cinfile);
00065   ltoken_setLine (*id, 0);
00066   ltoken_setCol (*id, 0);
00067 
00068   sourceFile = tsource_create (cinfile, "", FALSE);
00069 
00070   if (!tsource_getPath (cstring_toCharsSafe (context_getLarchPath ()), sourceFile))
00071     {
00072       lclplainerror 
00073         (message ("LSL signature parsing: can't find file %s containing trait",
00074                   cstring_fromChars (tsource_fileName (sourceFile))));
00075       status = 1;
00076 
00077       sfree (id);
00078       tsource_free (sourceFile);
00079       return status;
00080     }
00081 
00082   if (!tsource_open (sourceFile))
00083     {
00084       lclplainerror 
00085         (cstring_makeLiteral ("LSL parsing: can't open file containing trait"));
00086       status = 2;
00087       sfree (id);
00088       tsource_free (sourceFile);
00089 
00090       return status;
00091     }
00092 
00093   lsldebug = 0;
00094   g_lslParsingTraits = TRUE;
00095   LSLScanReset (sourceFile);
00096   LSLReportEolTokens (FALSE);
00097 
00098   status = lslparse ();
00099 
00100   /* symtable_dump (symtab, stdout, TRUE); */
00101   g_lslParsingTraits = FALSE;
00102 
00103   (void) tsource_close (sourceFile);
00104   tsource_free (sourceFile);
00105 
00106   sfree (id);
00107 
00108   
00109   return status;
00110 }
00111 
00112 /*@only@*/ lslOp
00113 parseOpLine (char *fname, char *line)
00114 {
00115   tsource *sourceFile;
00116   bool status;
00117 
00118   sourceFile = tsource_fromString (fname, line);
00119   
00120   if (check (tsource_open (sourceFile)))
00121     {
00122       LSLScanReset (sourceFile);
00123       LSLReportEolTokens (FALSE); /* 0 by default, lslParsingTraits = 0; */
00124       
00125       /*
00126       ** lsl parsing and importing .lcs files are expected to be mutually
00127       ** exclusive. 
00128       **
00129       ** lslparse sets importedlslOp
00130       */
00131       
00132       status = (lslparse () != 0);
00133       
00134       if (status)
00135         {
00136           lclplainfatalerror (message ("Error in parsing line: %s", 
00137                                        cstring_fromChars (line)));
00138         }
00139       
00140       (void) tsource_close (sourceFile);
00141     }
00142 
00143   tsource_free (sourceFile);
00144   
00145   llassert (g_importedlslOp != NULL);
00146   return (lslOp_copy (g_importedlslOp));
00147 }
00148 
00149 lsymbol
00150 processTraitSortId (lsymbol sortid)
00151 {
00152   lsymbol out = lsymbol_sortFromType (g_symtab, sortid);
00153   if (out == sortid)
00154     { /* may be a new sort */
00155       (void) sort_fromLsymbol (sortid);
00156     }
00157   return out;
00158 }
00159 
00160 /* formerly from check.c module */
00161 
00162 static /*@only@*/ cstring
00163 printTypeName2 (typeNameNode n)
00164 {
00165   cstring s = cstring_undefined;
00166   sortNode sn;
00167   lsymbol lclSort;
00168   ltoken err;
00169 
00170   if (n != (typeNameNode) 0)
00171     {
00172       if (n->isTypeName)
00173         {
00174           /* does not process opForm renaming, pass on to LSL
00175              and hope that it works for now. */
00176           typeNamePack p = n->typename;
00177 
00178           llassert (p != NULL);
00179 
00180           /* get the LCL type, assume LCL type has already been mentioned. */
00181           lclSort = lclTypeSpecNode2sort (p->type);
00182           lclSort = sort_getUnderlying (lclSort);
00183           /* lclsource = LCLSLScanSource (); */
00184           if (!sort_isValidSort (lclSort))
00185             {
00186               err = lclTypeSpecNode_errorToken (p->type);
00187               /* errorShowPoint (tsource_thisLine (lclsource), ltoken_getCol (err)); */
00188               lclerror (err, message ("Unrecognized type in uses: %q", 
00189                                       typeNameNode_unparse (n)));
00190             }
00191           else
00192             {
00193               /* 
00194               ** Below is necessary because this is one place where an LCL mutable
00195               ** type name is mapped directly into its value sort, not obj sort.
00196               ** Allows us to support only one qualifying "obj", rather
00197               ** than "val" as well. 
00198               */
00199               
00200               lclSort = typeExpr2ptrSort (lclSort, p->abst);
00201               lclSort = sort_makeVal (lclSort);
00202               
00203               /*
00204               ** Check that lclSort is not a HOFSort ...
00205               ** Propagation of HOFSort should stop here.  
00206               */
00207 
00208               if (sort_isHOFSortKind (lclSort))
00209                 {
00210                   err = lclTypeSpecNode_errorToken (p->type);
00211                   
00212                   lclfatalerror
00213                     (err, 
00214                      cstring_makeLiteral 
00215                      ("LCL uses cannot handle higher-order types"));
00216                 }
00217               if (p->isObj)
00218                 lclSort = sort_makeObj (lclSort);
00219               
00220               /*        if (!p->isObj) {
00221                         lclSort = sort_makeVal (lclSort);
00222                         } */
00223               
00224               sn = sort_lookup (lclSort);
00225               s = cstring_copy (cstring_fromChars (lsymbol_toChars (sn.name)));
00226               /* s = string_paste (s, AbstDeclaratorNode_unparse (p->abst)); */
00227             }
00228         }
00229       else
00230         {
00231           /* s = OpFormNode_unparse (n->opform); */
00232           if (n->opform != 0)
00233             {
00234               lclfatalerror 
00235                 (n->opform->tok,
00236                  cstring_makeLiteral ("Attempt to rename operator with uses: "
00237                                      "use LSL includes renaming facility"));
00238             }
00239           else
00240             {           
00241               BADEXIT;
00242             }
00243         }
00244     }
00245   return s;
00246 }
00247 
00248 static /*@only@*/ cstring
00249 replaceNode_unparseAlt (replaceNode x)
00250 {
00251   cstring s = cstring_undefined;
00252 
00253   if (x != (replaceNode) 0)
00254     {
00255       s = printTypeName2 (x->typename);
00256       s = cstring_concatChars (s, " for ");
00257 
00258       if (x->isCType)
00259         {
00260           s = cstring_concatFree1 (s, ltoken_unparse (x->content.ctype));
00261         }
00262       else
00263         {
00264           s = cstring_concatFree (s, nameNode_unparse (x->content.renamesortname.name));
00265           s = cstring_concatFree (s, 
00266                                   sigNode_unparse (x->content.renamesortname.signature));
00267         }
00268     }
00269 
00270   return s;
00271 }
00272 
00273 static /*@only@*/ cstring
00274 replaceNodeList_unparseAlt (replaceNodeList x)
00275 {
00276   cstring s = cstring_undefined;
00277   bool first = TRUE;
00278 
00279   replaceNodeList_elements (x, i)
00280     {
00281       if (first)
00282         {
00283           s = replaceNode_unparseAlt (i);
00284           first = FALSE;
00285         }
00286       else
00287         {
00288           s = message ("%q, %q", s, replaceNode_unparseAlt (i));
00289         }
00290     } end_replaceNodeList_elements;
00291 
00292   return s;
00293 }
00294 
00295 static /*@only@*/ cstring
00296 printNameList2 (typeNameNodeList x)
00297 {
00298   /* printing a list of typeNameNode's, not nameNode's */
00299   bool first = TRUE;
00300   cstring s = cstring_undefined;
00301 
00302   typeNameNodeList_elements (x, i)
00303   {
00304     if (first)
00305       {
00306         s = printTypeName2 (i);
00307         first = FALSE;
00308       }
00309     else
00310       {
00311         s = message ("%q, %q", s, printTypeName2 (i));
00312       }
00313     } end_typeNameNodeList_elements; 
00314 
00315   return s;
00316 }
00317 
00318 static /*@only@*/ cstring
00319 printRenamingNode2 (renamingNode x)
00320 {
00321   cstring s = cstring_undefined;
00322 
00323   if (x != (renamingNode) 0)
00324     {
00325       if (x->is_replace)
00326         {
00327           replaceNodeList r = x->content.replace;
00328           s = replaceNodeList_unparseAlt (r);
00329         }
00330       else
00331         {
00332           nameAndReplaceNode n = x->content.name;
00333           bool printComma = TRUE;
00334           if (typeNameNodeList_size (n->namelist) == 0)
00335             {
00336               printComma = FALSE;
00337             }
00338           s = printNameList2 (n->namelist);
00339           if (printComma)
00340             if (replaceNodeList_isDefined (n->replacelist) &&
00341                 replaceNodeList_size (n->replacelist) != 0)
00342               {
00343                 s = cstring_appendChar (s, ',');
00344                 s = cstring_appendChar (s, ' ');
00345               }
00346           s = cstring_concatFree (s, replaceNodeList_unparseAlt (n->replacelist));
00347         }
00348     }
00349   return s;
00350 }
00351 
00352 static /*@only@*/ cstring
00353 printTraitRefList2 (traitRefNodeList x)
00354 {
00355   cstring s = cstring_undefined;
00356 
00357   traitRefNodeList_elements (x, i)
00358   {
00359     s = message ("%qincludes (%q)", s, printRawLeaves2 (i->traitid));
00360 
00361     if (i->rename != 0)
00362       {
00363         s = message ("%q(%q)", s, printRenamingNode2 (i->rename));
00364       }
00365     s = message ("%q\n", s);
00366   } end_traitRefNodeList_elements;
00367 
00368   return s;
00369 }
00370 
00371 void
00372 callLSL (/*@unused@*/ char *specfile, /*@only@*/ char *text)
00373 {
00374   /* specfile is the name of the LCL file that contains "uses"
00375      Create an intermediate file named
00376      specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_IN_SUFFIX>.
00377      put text in the file, run lsl on it and direct
00378      output to specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_OUT_SUFFIX>.
00379      specfile can be a full pathname.
00380      Note: LSL does not support traitnames that are pathnames, only
00381      symbols. 
00382      */
00383 
00384   char *infile, *outfile;
00385   char *tmp1, *tmp2;
00386   FILE *inptr;
00387 
00388   infile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
00389   
00390   inptr = fopen (infile, "w");
00391   
00392   if (inptr == NULL)
00393     {
00394       /* fopen fails */
00395       llfatalerror (message ("Unable to write intermediate file: %s", 
00396                              cstring_fromChars (infile)));
00397     }
00398   
00399   tmp1 = removePath (infile);
00400   tmp2 = removeAnyExtension (tmp1);
00401 
00402   fprintf (inptr, "%s : trait\n", tmp2);
00403   sfree (tmp1);
00404   sfree (tmp2);
00405 
00406   fprintf (inptr, "%s", text);
00407   check (fclose (inptr) == 0);
00408 
00409   /* the default is to delete the input file */
00410 
00411   outfile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
00412   invokeLSL (infile, outfile, context_getFlag (FLG_KEEP));
00413   sfree (text);
00414 }
00415 
00416 static void invokeLSL (char *infile, char *outfile, bool deletep)
00417 {
00418   /* run lsl on infile and leave result in outfile */
00419   FILE *outptr;
00420   filestatus status;
00421   int callstatus;
00422   cstring call;
00423   char *returnPath = NULL;
00424   
00425   /*
00426   ** Ensures that outfile can be written into, should find a better
00427   ** way to do this. 
00428   */
00429   
00430   outptr = fopen (outfile, "w");
00431 
00432   if (outptr == NULL)
00433     {                   
00434       /* fopen fails */
00435       llfatalerror (message ("Unable to write intermediate file: %s", 
00436                              cstring_fromChars (outfile)));
00437     }
00438   
00439   check (fclose (outptr) == 0);
00440 
00441   /* set call to the right command */
00442   status = osd_getExePath ("PATH", "lsl", &returnPath);
00443     
00444 
00445   if (status == OSD_FILEFOUND)
00446     {
00447       call = message ("%s -syms %s > %s", cstring_fromChars (returnPath), 
00448                       cstring_fromChars (infile), cstring_fromChars (outfile));
00449       
00450       /* before calling, make sure old file is removed */
00451       (void) osd_unlink (outfile);
00452 
00453       callstatus = osd_system (cstring_toCharsSafe (call));
00454       
00455       cstring_free (call);
00456 
00457       if (callstatus != CALL_SUCCESS)
00458         {
00459           /*
00460           ** lsl errors: call lsl again without -syms, sending output to stdout
00461           */
00462           cstring syscal = message ("%s %s", cstring_fromChars (returnPath), 
00463                                     cstring_fromChars (infile));
00464 
00465           (void) osd_system (cstring_toCharsSafe (syscal));
00466           cstring_free (syscal);
00467 
00468           llfatalerror (cstring_makeLiteral ("LSL trait used contains errors.")); 
00469         }
00470       else
00471         {                       /* ok, go ahead */
00472          /* Now parse the LSL output and store info in symbol table */
00473           callstatus = parseSignatures (cstring_fromChars (outfile));
00474 
00475           if (callstatus == 0)
00476             {   
00477               /* all went well */
00478               if (!context_getFlag (FLG_KEEP))
00479                 {
00480                   /* delete temporary files */
00481                   if (deletep)
00482                     {
00483                       (void) osd_unlink (infile);
00484                     }
00485                   
00486                   (void) osd_unlink (outfile);
00487                 }
00488             }
00489         }
00490     }
00491   else if (status == OSD_FILENOTFOUND)
00492     {
00493       llfatalerror 
00494         (cstring_makeLiteral ("Cannot find LSL checker: check your command search path."));
00495     }
00496   else                          /* must be (status == OSD_PATHTOOLONG) */
00497     {
00498       lclfatalbug ("invokeLSL: lsl plus directory from search path is too long");
00499     }
00500 }
00501 
00502 /* callLSL ("MySet", "includes Set (CC for C, EE for E)");  */
00503 
00504 void
00505 readlsignatures (interfaceNode n)
00506 {
00507   /* assume n->kind = usesKIND */
00508   char *content;
00509   
00510   content = cstring_toCharsSafe (printTraitRefList2 (n->content.uses));
00511   callLSL (cstring_toCharsSafe (g_currentSpec), content);
00512 }

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