2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
27 ** Module for calling LSL checker.
31 ** Massachusetts Institute of Technology
34 # include "lclintMacros.nf"
37 # include "signature.h"
38 # include "signature2.h"
40 # include "scanline.h"
41 # include "syntable.h"
42 # include "tokentable.h"
44 # include "lslparse.h"
49 /*@dependent@*/ /*@null@*/ lslOp g_importedlslOp = NULL;
50 bool g_lslParsingTraits = FALSE;
52 static void invokeLSL (char *p_infile, char *p_outfile, bool p_deletep);
55 parseSignatures (cstring infile)
57 char *cinfile = cstring_toCharsSafe (infile);
59 ltoken *id = (ltoken *) dmalloc (sizeof (*id));
63 *id = LSLInsertToken (LST_SIMPLEID, lsymbol_fromChars (cinfile), 0, FALSE);
64 ltoken_setFileName (*id, cinfile);
65 ltoken_setLine (*id, 0);
66 ltoken_setCol (*id, 0);
68 sourceFile = tsource_create (cinfile, "", FALSE);
70 if (!tsource_getPath (cstring_toCharsSafe (context_getLarchPath ()), sourceFile))
73 (message ("LSL signature parsing: can't find file %s containing trait",
74 cstring_fromChars (tsource_fileName (sourceFile))));
78 tsource_free (sourceFile);
82 if (!tsource_open (sourceFile))
85 (cstring_makeLiteral ("LSL parsing: can't open file containing trait"));
88 tsource_free (sourceFile);
94 g_lslParsingTraits = TRUE;
95 LSLScanReset (sourceFile);
96 LSLReportEolTokens (FALSE);
100 /* symtable_dump (symtab, stdout, TRUE); */
101 g_lslParsingTraits = FALSE;
103 (void) tsource_close (sourceFile);
104 tsource_free (sourceFile);
113 parseOpLine (char *fname, char *line)
118 sourceFile = tsource_fromString (fname, line);
120 if (check (tsource_open (sourceFile)))
122 LSLScanReset (sourceFile);
123 LSLReportEolTokens (FALSE); /* 0 by default, lslParsingTraits = 0; */
126 ** lsl parsing and importing .lcs files are expected to be mutually
129 ** lslparse sets importedlslOp
132 status = (lslparse () != 0);
136 lclplainfatalerror (message ("Error in parsing line: %s",
137 cstring_fromChars (line)));
140 (void) tsource_close (sourceFile);
143 tsource_free (sourceFile);
145 llassert (g_importedlslOp != NULL);
146 return (lslOp_copy (g_importedlslOp));
150 processTraitSortId (lsymbol sortid)
152 lsymbol out = lsymbol_sortFromType (g_symtab, sortid);
154 { /* may be a new sort */
155 (void) sort_fromLsymbol (sortid);
160 /* formerly from check.c module */
162 static /*@only@*/ cstring
163 printTypeName2 (typeNameNode n)
165 cstring s = cstring_undefined;
170 if (n != (typeNameNode) 0)
174 /* does not process opForm renaming, pass on to LSL
175 and hope that it works for now. */
176 typeNamePack p = n->typename;
178 llassert (p != NULL);
180 /* get the LCL type, assume LCL type has already been mentioned. */
181 lclSort = lclTypeSpecNode2sort (p->type);
182 lclSort = sort_getUnderlying (lclSort);
183 /* lclsource = LCLSLScanSource (); */
184 if (!sort_isValidSort (lclSort))
186 err = lclTypeSpecNode_errorToken (p->type);
187 /* errorShowPoint (tsource_thisLine (lclsource), ltoken_getCol (err)); */
188 lclerror (err, message ("Unrecognized type in uses: %q",
189 typeNameNode_unparse (n)));
194 ** Below is necessary because this is one place where an LCL mutable
195 ** type name is mapped directly into its value sort, not obj sort.
196 ** Allows us to support only one qualifying "obj", rather
197 ** than "val" as well.
200 lclSort = typeExpr2ptrSort (lclSort, p->abst);
201 lclSort = sort_makeVal (lclSort);
204 ** Check that lclSort is not a HOFSort ...
205 ** Propagation of HOFSort should stop here.
208 if (sort_isHOFSortKind (lclSort))
210 err = lclTypeSpecNode_errorToken (p->type);
215 ("LCL uses cannot handle higher-order types"));
218 lclSort = sort_makeObj (lclSort);
221 lclSort = sort_makeVal (lclSort);
224 sn = sort_lookup (lclSort);
225 s = cstring_copy (cstring_fromChars (lsymbol_toChars (sn.name)));
226 /* s = string_paste (s, AbstDeclaratorNode_unparse (p->abst)); */
231 /* s = OpFormNode_unparse (n->opform); */
236 cstring_makeLiteral ("Attempt to rename operator with uses: "
237 "use LSL includes renaming facility"));
248 static /*@only@*/ cstring
249 replaceNode_unparseAlt (replaceNode x)
251 cstring s = cstring_undefined;
253 if (x != (replaceNode) 0)
255 s = printTypeName2 (x->typename);
256 s = cstring_concatChars (s, " for ");
260 s = cstring_concatFree1 (s, ltoken_unparse (x->content.ctype));
264 s = cstring_concatFree (s, nameNode_unparse (x->content.renamesortname.name));
265 s = cstring_concatFree (s,
266 sigNode_unparse (x->content.renamesortname.signature));
273 static /*@only@*/ cstring
274 replaceNodeList_unparseAlt (replaceNodeList x)
276 cstring s = cstring_undefined;
279 replaceNodeList_elements (x, i)
283 s = replaceNode_unparseAlt (i);
288 s = message ("%q, %q", s, replaceNode_unparseAlt (i));
290 } end_replaceNodeList_elements;
295 static /*@only@*/ cstring
296 printNameList2 (typeNameNodeList x)
298 /* printing a list of typeNameNode's, not nameNode's */
300 cstring s = cstring_undefined;
302 typeNameNodeList_elements (x, i)
306 s = printTypeName2 (i);
311 s = message ("%q, %q", s, printTypeName2 (i));
313 } end_typeNameNodeList_elements;
318 static /*@only@*/ cstring
319 printRenamingNode2 (renamingNode x)
321 cstring s = cstring_undefined;
323 if (x != (renamingNode) 0)
327 replaceNodeList r = x->content.replace;
328 s = replaceNodeList_unparseAlt (r);
332 nameAndReplaceNode n = x->content.name;
333 bool printComma = TRUE;
334 if (typeNameNodeList_size (n->namelist) == 0)
338 s = printNameList2 (n->namelist);
340 if (replaceNodeList_isDefined (n->replacelist) &&
341 replaceNodeList_size (n->replacelist) != 0)
343 s = cstring_appendChar (s, ',');
344 s = cstring_appendChar (s, ' ');
346 s = cstring_concatFree (s, replaceNodeList_unparseAlt (n->replacelist));
352 static /*@only@*/ cstring
353 printTraitRefList2 (traitRefNodeList x)
355 cstring s = cstring_undefined;
357 traitRefNodeList_elements (x, i)
359 s = message ("%qincludes (%q)", s, printRawLeaves2 (i->traitid));
363 s = message ("%q(%q)", s, printRenamingNode2 (i->rename));
365 s = message ("%q\n", s);
366 } end_traitRefNodeList_elements;
372 callLSL (/*@unused@*/ char *specfile, /*@only@*/ char *text)
374 /* specfile is the name of the LCL file that contains "uses"
375 Create an intermediate file named
376 specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_IN_SUFFIX>.
377 put text in the file, run lsl on it and direct
378 output to specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_OUT_SUFFIX>.
379 specfile can be a full pathname.
380 Note: LSL does not support traitnames that are pathnames, only
384 char *infile, *outfile;
388 infile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
390 inptr = fopen (infile, "w");
395 llfatalerror (message ("Unable to write intermediate file: %s",
396 cstring_fromChars (infile)));
399 tmp1 = removePath (infile);
400 tmp2 = removeAnyExtension (tmp1);
402 fprintf (inptr, "%s : trait\n", tmp2);
406 fprintf (inptr, "%s", text);
407 check (fclose (inptr) == 0);
409 /* the default is to delete the input file */
411 outfile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
412 invokeLSL (infile, outfile, context_getFlag (FLG_KEEP));
416 static void invokeLSL (char *infile, char *outfile, bool deletep)
418 /* run lsl on infile and leave result in outfile */
423 char *returnPath = NULL;
426 ** Ensures that outfile can be written into, should find a better
430 outptr = fopen (outfile, "w");
435 llfatalerror (message ("Unable to write intermediate file: %s",
436 cstring_fromChars (outfile)));
439 check (fclose (outptr) == 0);
441 /* set call to the right command */
442 status = osd_getExePath ("PATH", "lsl", &returnPath);
445 if (status == OSD_FILEFOUND)
447 call = message ("%s -syms %s > %s", cstring_fromChars (returnPath),
448 cstring_fromChars (infile), cstring_fromChars (outfile));
450 /* before calling, make sure old file is removed */
451 (void) osd_unlink (outfile);
453 callstatus = osd_system (cstring_toCharsSafe (call));
457 if (callstatus != CALL_SUCCESS)
460 ** lsl errors: call lsl again without -syms, sending output to stdout
462 cstring syscal = message ("%s %s", cstring_fromChars (returnPath),
463 cstring_fromChars (infile));
465 (void) osd_system (cstring_toCharsSafe (syscal));
466 cstring_free (syscal);
468 llfatalerror (cstring_makeLiteral ("LSL trait used contains errors."));
472 /* Now parse the LSL output and store info in symbol table */
473 callstatus = parseSignatures (cstring_fromChars (outfile));
478 if (!context_getFlag (FLG_KEEP))
480 /* delete temporary files */
483 (void) osd_unlink (infile);
486 (void) osd_unlink (outfile);
491 else if (status == OSD_FILENOTFOUND)
494 (cstring_makeLiteral ("Cannot find LSL checker: check your command search path."));
496 else /* must be (status == OSD_PATHTOOLONG) */
498 lclfatalbug ("invokeLSL: lsl plus directory from search path is too long");
502 /* callLSL ("MySet", "includes Set (CC for C, EE for E)"); */
505 readlsignatures (interfaceNode n)
507 /* assume n->kind = usesKIND */
510 content = cstring_toCharsSafe (printTraitRefList2 (n->content.uses));
511 callLSL (cstring_toCharsSafe (g_currentSpec), content);