2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
27 ** Module for calling LSL checker.
31 ** Massachusetts Institute of Technology
34 # include "splintMacros.nf"
38 # include "lslgrammar.h"
40 # include "lslscanline.h"
41 # include "lsltokentable.h"
42 # include "lslparse.h"
46 /*@dependent@*/ /*@null@*/ lslOp g_importedlslOp
= NULL
;
47 bool g_lslParsingTraits
= FALSE
;
49 static void invokeLSL (cstring p_infile
, cstring p_outfile
, bool p_deletep
);
52 parseSignatures (cstring infile
)
54 inputStream sourceFile
;
55 ltoken
*id
= (ltoken
*) dmalloc (sizeof (*id
));
59 *id
= LSLInsertToken (LST_SIMPLEID
, lsymbol_fromString (infile
), 0, FALSE
);
60 ltoken_setFileName (*id
, infile
);
61 ltoken_setLine (*id
, 0);
62 ltoken_setCol (*id
, 0);
64 sourceFile
= inputStream_create (infile
, cstring_undefined
, FALSE
);
66 if (!inputStream_getPath (context_getLarchPath (), sourceFile
))
69 (message ("LSL signature parsing: can't find file %s containing trait",
70 inputStream_fileName (sourceFile
)));
74 inputStream_free (sourceFile
);
78 if (!inputStream_open (sourceFile
))
81 (cstring_makeLiteral ("LSL parsing: can't open file containing trait"));
84 inputStream_free (sourceFile
);
89 g_lslParsingTraits
= TRUE
;
90 LSLScanReset (sourceFile
);
91 LSLReportEolTokens (FALSE
);
95 /* symtable_dump (symtab, stdout, TRUE); */
96 g_lslParsingTraits
= FALSE
;
98 (void) inputStream_close (sourceFile
);
99 inputStream_free (sourceFile
);
108 parseOpLine (cstring fname
, cstring line
)
110 inputStream sourceFile
;
113 sourceFile
= inputStream_fromString (fname
, line
);
115 if (check (inputStream_open (sourceFile
)))
117 LSLScanReset (sourceFile
);
118 LSLReportEolTokens (FALSE
); /* 0 by default, lslParsingTraits = 0; */
121 ** lsl parsing and importing .lcs files are expected to be mutually
124 ** lslparse sets importedlslOp
127 status
= (lslparse () != 0);
131 lclplainfatalerror (message ("Error in parsing line: %s", line
));
134 (void) inputStream_close (sourceFile
);
137 inputStream_free (sourceFile
);
139 llassert (g_importedlslOp
!= NULL
);
140 return (lslOp_copy (g_importedlslOp
));
144 processTraitSortId (lsymbol sortid
)
146 lsymbol out
= lsymbol_sortFromType (g_symtab
, sortid
);
148 { /* may be a new sort */
149 (void) sort_fromLsymbol (sortid
);
154 /* formerly from check.c module */
156 static /*@only@*/ cstring
157 printTypeName2 (typeNameNode n
)
159 cstring s
= cstring_undefined
;
164 if (n
!= (typeNameNode
) 0)
168 /* does not process opForm renaming, pass on to LSL
169 and hope that it works for now. */
170 typeNamePack p
= n
->typename
;
172 llassert (p
!= NULL
);
174 /* get the LCL type, assume LCL type has already been mentioned. */
175 lclSort
= lclTypeSpecNode2sort (p
->type
);
176 lclSort
= sort_getUnderlying (lclSort
);
177 /* lclsource = LCLSLScanSource (); */
178 if (!sort_isValidSort (lclSort
))
180 err
= lclTypeSpecNode_errorToken (p
->type
);
181 /* errorShowPoint (inputStream_thisLine (lclsource), ltoken_getCol (err)); */
182 lclerror (err
, message ("Unrecognized type in uses: %q",
183 typeNameNode_unparse (n
)));
188 ** Below is necessary because this is one place where an LCL mutable
189 ** type name is mapped directly into its value sort, not obj sort.
190 ** Allows us to support only one qualifying "obj", rather
191 ** than "val" as well.
194 lclSort
= typeExpr2ptrSort (lclSort
, p
->abst
);
195 lclSort
= sort_makeVal (lclSort
);
198 ** Check that lclSort is not a HOFSort ...
199 ** Propagation of HOFSort should stop here.
202 if (sort_isHOFSortKind (lclSort
))
204 err
= lclTypeSpecNode_errorToken (p
->type
);
209 ("LCL uses cannot handle higher-order types"));
212 lclSort
= sort_makeObj (lclSort
);
215 lclSort = sort_makeVal (lclSort);
218 sn
= sort_lookup (lclSort
);
219 s
= cstring_copy (cstring_fromChars (lsymbol_toChars (sn
->name
)));
220 /* s = string_paste (s, AbstDeclaratorNode_unparse (p->abst)); */
225 /* s = OpFormNode_unparse (n->opform); */
230 cstring_makeLiteral ("Attempt to rename operator with uses: "
231 "use LSL includes renaming facility"));
242 static /*@only@*/ cstring
243 replaceNode_unparseAlt (replaceNode x
)
245 cstring s
= cstring_undefined
;
247 if (x
!= (replaceNode
) 0)
249 s
= printTypeName2 (x
->typename
);
250 s
= cstring_concatChars (s
, " for ");
254 s
= cstring_concatFree1 (s
, ltoken_unparse (x
->content
.ctype
));
258 s
= cstring_concatFree (s
, nameNode_unparse (x
->content
.renamesortname
.name
));
259 s
= cstring_concatFree (s
,
260 sigNode_unparse (x
->content
.renamesortname
.signature
));
267 static /*@only@*/ cstring
268 replaceNodeList_unparseAlt (replaceNodeList x
)
270 cstring s
= cstring_undefined
;
273 replaceNodeList_elements (x
, i
)
277 s
= replaceNode_unparseAlt (i
);
282 s
= message ("%q, %q", s
, replaceNode_unparseAlt (i
));
284 } end_replaceNodeList_elements
;
289 static /*@only@*/ cstring
290 printNameList2 (typeNameNodeList x
)
292 /* printing a list of typeNameNode's, not nameNode's */
294 cstring s
= cstring_undefined
;
296 typeNameNodeList_elements (x
, i
)
300 s
= printTypeName2 (i
);
305 s
= message ("%q, %q", s
, printTypeName2 (i
));
307 } end_typeNameNodeList_elements
;
312 static /*@only@*/ cstring
313 printRenamingNode2 (renamingNode x
)
315 cstring s
= cstring_undefined
;
317 if (x
!= (renamingNode
) 0)
321 replaceNodeList r
= x
->content
.replace
;
322 s
= replaceNodeList_unparseAlt (r
);
326 nameAndReplaceNode n
= x
->content
.name
;
327 bool printComma
= TRUE
;
328 if (typeNameNodeList_size (n
->namelist
) == 0)
332 s
= printNameList2 (n
->namelist
);
334 if (replaceNodeList_isDefined (n
->replacelist
) &&
335 replaceNodeList_size (n
->replacelist
) != 0)
337 s
= cstring_appendChar (s
, ',');
338 s
= cstring_appendChar (s
, ' ');
340 s
= cstring_concatFree (s
, replaceNodeList_unparseAlt (n
->replacelist
));
346 static /*@only@*/ cstring
347 printTraitRefList2 (traitRefNodeList x
) /*@*/
349 cstring s
= cstring_undefined
;
351 traitRefNodeList_elements (x
, i
)
353 s
= message ("%qincludes (%q)", s
, printRawLeaves2 (i
->traitid
));
357 s
= message ("%q(%q)", s
, printRenamingNode2 (i
->rename
));
360 s
= message ("%q\n", s
);
361 } end_traitRefNodeList_elements
;
367 callLSL (/*@unused@*/ cstring specfile
, /*@only@*/ cstring text
)
369 /* specfile is the name of the LCL file that contains "uses"
370 Create an intermediate file named
371 specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_IN_SUFFIX>.
372 put text in the file, run lsl on it and direct
373 output to specfile_<TEMP_LSL_SUFFIX>.<TEMP_LSL_OUT_SUFFIX>.
374 specfile can be a full pathname.
375 Note: LSL does not support traitnames that are pathnames, only
385 infile
= fileTable_fileName (fileTable_addTempFile (context_fileTable (), FILE_LSLTEMP
, fileId_invalid
));
386 inptr
= fileTable_createTempFile (context_fileTable (), infile
, FALSE
);
391 llfatalerror (message ("Unable to write intermediate file: %s",
395 nopath
= fileLib_removePath (infile
);
396 noext
= fileLib_removeAnyExtension (nopath
);
398 fprintf (inptr
, "%s : trait\n", cstring_toCharsSafe (noext
));
400 cstring_free (noext
);
401 cstring_free (nopath
);
403 fprintf (inptr
, "%s", cstring_toCharsSafe (text
));
404 check (fileTable_closeFile (context_fileTable (), inptr
));
406 /* the default is to delete the input file */
408 outfile
= fileTable_fileName (fileTable_addTempFile (context_fileTable (), FILE_LSLTEMP
, fileId_invalid
));
409 invokeLSL (infile
, outfile
, context_getFlag (FLG_KEEP
));
413 static void invokeLSL (cstring infile
, cstring outfile
, bool deletep
)
415 /* run lsl on infile and leave result in outfile */
420 cstring returnPath
= cstring_undefined
;
423 ** Ensures that outfile can be written into, should find a better
427 outptr
= fileTable_createTempFile (context_fileTable (), outfile
, FALSE
);
432 llfatalerror (message ("Unable to write intermediate file: %s",
436 check (fileTable_closeFile (context_fileTable (), outptr
));
438 /* set call to the right command */
439 status
= osd_getExePath (cstring_makeLiteralTemp (getenv ("PATH")),
440 cstring_makeLiteralTemp ("lsl"),
444 if (status
== OSD_FILEFOUND
)
446 call
= message ("%s -syms %s > %s", returnPath
, infile
, outfile
);
448 /* before calling, make sure old file is removed */
449 (void) osd_unlink (outfile
);
451 callstatus
= osd_system (call
);
455 if (callstatus
!= CALL_SUCCESS
)
458 ** lsl errors: call lsl again without -syms, sending output to stdout
460 cstring syscal
= message ("%s %s", returnPath
, infile
);
461 (void) osd_system (syscal
);
462 cstring_free (syscal
);
464 llfatalerror (cstring_makeLiteral ("LSL trait used contains errors."));
468 /* Now parse the LSL output and store info in symbol table */
469 callstatus
= parseSignatures (cstring_copy (outfile
));
474 if (!context_getFlag (FLG_KEEP
))
476 /* delete temporary files */
479 (void) osd_unlink (infile
);
482 (void) osd_unlink (outfile
);
487 else if (status
== OSD_FILENOTFOUND
)
490 (cstring_makeLiteral ("Cannot find LSL checker: check your command search path."));
492 else /* must be (status == OSD_PATHTOOLONG) */
494 lclfatalbug ("invokeLSL: lsl plus directory from search path is too long");
498 /* callLSL ("MySet", "includes Set (CC for C, EE for E)"); */
501 readlsignatures (interfaceNode n
)
503 /* assume n->kind = usesKIND */
504 callLSL (g_currentSpec
, printTraitRefList2 (n
->content
.uses
));