]> andersk Git - splint.git/blame - src/lslparse.c
Updating to use the LEnsures and LRequires instead of the ensures requires so
[splint.git] / src / lslparse.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
3** Copyright (C) 1994-2000 University of Virginia,
4** Massachusetts Institute of Technology
5**
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.
10**
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.
15**
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.
19**
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
23*/
24/*
25** lslparse.c
26**
27** Module for calling LSL checker.
28**
29** AUTHOR:
30** Yang Meng Tan,
31** Massachusetts Institute of Technology
32*/
33
34# include "lclintMacros.nf"
35# include "llbasic.h"
36# include "lclscan.h"
37# include "signature.h"
38# include "signature2.h"
39# include "scan.h"
40# include "scanline.h"
41# include "syntable.h"
42# include "tokentable.h"
43# include "lslinit.h"
44# include "lslparse.h"
45# include "llmain.h"
46
47/*@+ignorequals@*/
48
49/*@dependent@*/ /*@null@*/ lslOp g_importedlslOp = NULL;
50bool g_lslParsingTraits = FALSE;
51
52static void invokeLSL (char *p_infile, char *p_outfile, bool p_deletep);
53
54int
55parseSignatures (cstring infile)
56{
57 char *cinfile = cstring_toCharsSafe (infile);
58 tsource *sourceFile;
59 ltoken *id = (ltoken *) dmalloc (sizeof (*id));
60 int status = 0;
61
62 /* parse traits */
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);
67
68 sourceFile = tsource_create (cinfile, "", FALSE);
69
70 if (!tsource_getPath (cstring_toCharsSafe (context_getLarchPath ()), sourceFile))
71 {
72 lclplainerror
73 (message ("LSL signature parsing: can't find file %s containing trait",
74 cstring_fromChars (tsource_fileName (sourceFile))));
75 status = 1;
76
77 sfree (id);
78 tsource_free (sourceFile);
79 return status;
80 }
81
82 if (!tsource_open (sourceFile))
83 {
84 lclplainerror
85 (cstring_makeLiteral ("LSL parsing: can't open file containing trait"));
86 status = 2;
87 sfree (id);
88 tsource_free (sourceFile);
89
90 return status;
91 }
92
93 lsldebug = 0;
94 g_lslParsingTraits = TRUE;
95 LSLScanReset (sourceFile);
96 LSLReportEolTokens (FALSE);
97
98 status = lslparse ();
99
100 /* symtable_dump (symtab, stdout, TRUE); */
101 g_lslParsingTraits = FALSE;
102
103 (void) tsource_close (sourceFile);
104 tsource_free (sourceFile);
105
106 sfree (id);
107
108
109 return status;
110}
111
112/*@only@*/ lslOp
113parseOpLine (char *fname, char *line)
114{
115 tsource *sourceFile;
116 bool status;
117
118 sourceFile = tsource_fromString (fname, line);
119
120 if (check (tsource_open (sourceFile)))
121 {
122 LSLScanReset (sourceFile);
123 LSLReportEolTokens (FALSE); /* 0 by default, lslParsingTraits = 0; */
124
125 /*
126 ** lsl parsing and importing .lcs files are expected to be mutually
127 ** exclusive.
128 **
129 ** lslparse sets importedlslOp
130 */
131
132 status = (lslparse () != 0);
133
134 if (status)
135 {
136 lclplainfatalerror (message ("Error in parsing line: %s",
137 cstring_fromChars (line)));
138 }
139
140 (void) tsource_close (sourceFile);
141 }
142
143 tsource_free (sourceFile);
144
145 llassert (g_importedlslOp != NULL);
146 return (lslOp_copy (g_importedlslOp));
147}
148
149lsymbol
150processTraitSortId (lsymbol sortid)
151{
152 lsymbol out = lsymbol_sortFromType (g_symtab, sortid);
153 if (out == sortid)
154 { /* may be a new sort */
155 (void) sort_fromLsymbol (sortid);
156 }
157 return out;
158}
159
160/* formerly from check.c module */
161
162static /*@only@*/ cstring
163printTypeName2 (typeNameNode n)
164{
165 cstring s = cstring_undefined;
166 sortNode sn;
167 lsymbol lclSort;
168 ltoken err;
169
170 if (n != (typeNameNode) 0)
171 {
172 if (n->isTypeName)
173 {
174 /* does not process opForm renaming, pass on to LSL
175 and hope that it works for now. */
176 typeNamePack p = n->typename;
177
178 llassert (p != NULL);
179
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))
185 {
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)));
190 }
191 else
192 {
193 /*
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.
198 */
199
200 lclSort = typeExpr2ptrSort (lclSort, p->abst);
201 lclSort = sort_makeVal (lclSort);
202
203 /*
204 ** Check that lclSort is not a HOFSort ...
205 ** Propagation of HOFSort should stop here.
206 */
207
208 if (sort_isHOFSortKind (lclSort))
209 {
210 err = lclTypeSpecNode_errorToken (p->type);
211
212 lclfatalerror
213 (err,
214 cstring_makeLiteral
215 ("LCL uses cannot handle higher-order types"));
216 }
217 if (p->isObj)
218 lclSort = sort_makeObj (lclSort);
219
220 /* if (!p->isObj) {
221 lclSort = sort_makeVal (lclSort);
222 } */
223
224 sn = sort_lookup (lclSort);
225 s = cstring_copy (cstring_fromChars (lsymbol_toChars (sn.name)));
226 /* s = string_paste (s, AbstDeclaratorNode_unparse (p->abst)); */
227 }
228 }
229 else
230 {
231 /* s = OpFormNode_unparse (n->opform); */
232 if (n->opform != 0)
233 {
234 lclfatalerror
235 (n->opform->tok,
236 cstring_makeLiteral ("Attempt to rename operator with uses: "
237 "use LSL includes renaming facility"));
238 }
239 else
240 {
241 BADEXIT;
242 }
243 }
244 }
245 return s;
246}
247
248static /*@only@*/ cstring
249replaceNode_unparseAlt (replaceNode x)
250{
251 cstring s = cstring_undefined;
252
253 if (x != (replaceNode) 0)
254 {
255 s = printTypeName2 (x->typename);
256 s = cstring_concatChars (s, " for ");
257
258 if (x->isCType)
259 {
260 s = cstring_concatFree1 (s, ltoken_unparse (x->content.ctype));
261 }
262 else
263 {
264 s = cstring_concatFree (s, nameNode_unparse (x->content.renamesortname.name));
265 s = cstring_concatFree (s,
266 sigNode_unparse (x->content.renamesortname.signature));
267 }
268 }
269
270 return s;
271}
272
273static /*@only@*/ cstring
274replaceNodeList_unparseAlt (replaceNodeList x)
275{
276 cstring s = cstring_undefined;
277 bool first = TRUE;
278
279 replaceNodeList_elements (x, i)
280 {
281 if (first)
282 {
283 s = replaceNode_unparseAlt (i);
284 first = FALSE;
285 }
286 else
287 {
288 s = message ("%q, %q", s, replaceNode_unparseAlt (i));
289 }
290 } end_replaceNodeList_elements;
291
292 return s;
293}
294
295static /*@only@*/ cstring
296printNameList2 (typeNameNodeList x)
297{
298 /* printing a list of typeNameNode's, not nameNode's */
299 bool first = TRUE;
300 cstring s = cstring_undefined;
301
302 typeNameNodeList_elements (x, i)
303 {
304 if (first)
305 {
306 s = printTypeName2 (i);
307 first = FALSE;
308 }
309 else
310 {
311 s = message ("%q, %q", s, printTypeName2 (i));
312 }
313 } end_typeNameNodeList_elements;
314
315 return s;
316}
317
318static /*@only@*/ cstring
319printRenamingNode2 (renamingNode x)
320{
321 cstring s = cstring_undefined;
322
323 if (x != (renamingNode) 0)
324 {
325 if (x->is_replace)
326 {
327 replaceNodeList r = x->content.replace;
328 s = replaceNodeList_unparseAlt (r);
329 }
330 else
331 {
332 nameAndReplaceNode n = x->content.name;
333 bool printComma = TRUE;
334 if (typeNameNodeList_size (n->namelist) == 0)
335 {
336 printComma = FALSE;
337 }
338 s = printNameList2 (n->namelist);
339 if (printComma)
340 if (replaceNodeList_isDefined (n->replacelist) &&
341 replaceNodeList_size (n->replacelist) != 0)
342 {
343 s = cstring_appendChar (s, ',');
344 s = cstring_appendChar (s, ' ');
345 }
346 s = cstring_concatFree (s, replaceNodeList_unparseAlt (n->replacelist));
347 }
348 }
349 return s;
350}
351
352static /*@only@*/ cstring
353printTraitRefList2 (traitRefNodeList x)
354{
355 cstring s = cstring_undefined;
356
357 traitRefNodeList_elements (x, i)
358 {
359 s = message ("%qincludes (%q)", s, printRawLeaves2 (i->traitid));
360
361 if (i->rename != 0)
362 {
363 s = message ("%q(%q)", s, printRenamingNode2 (i->rename));
364 }
365 s = message ("%q\n", s);
366 } end_traitRefNodeList_elements;
367
368 return s;
369}
370
371void
372callLSL (/*@unused@*/ char *specfile, /*@only@*/ char *text)
373{
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
381 symbols.
382 */
383
384 char *infile, *outfile;
385 char *tmp1, *tmp2;
386 FILE *inptr;
387
388 infile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
389
390 inptr = fopen (infile, "w");
391
392 if (inptr == NULL)
393 {
394 /* fopen fails */
395 llfatalerror (message ("Unable to write intermediate file: %s",
396 cstring_fromChars (infile)));
397 }
398
399 tmp1 = removePath (infile);
400 tmp2 = removeAnyExtension (tmp1);
401
402 fprintf (inptr, "%s : trait\n", tmp2);
403 sfree (tmp1);
404 sfree (tmp2);
405
406 fprintf (inptr, "%s", text);
407 check (fclose (inptr) == 0);
408
409 /* the default is to delete the input file */
410
411 outfile = cstring_toCharsSafe (fileName (fileTable_addltemp (context_fileTable ())));
412 invokeLSL (infile, outfile, context_getFlag (FLG_KEEP));
413 sfree (text);
414}
415
416static void invokeLSL (char *infile, char *outfile, bool deletep)
417{
418 /* run lsl on infile and leave result in outfile */
419 FILE *outptr;
420 filestatus status;
421 int callstatus;
422 cstring call;
423 char *returnPath = NULL;
424
425 /*
426 ** Ensures that outfile can be written into, should find a better
427 ** way to do this.
428 */
429
430 outptr = fopen (outfile, "w");
431
432 if (outptr == NULL)
433 {
434 /* fopen fails */
435 llfatalerror (message ("Unable to write intermediate file: %s",
436 cstring_fromChars (outfile)));
437 }
438
439 check (fclose (outptr) == 0);
440
441 /* set call to the right command */
442 status = osd_getExePath ("PATH", "lsl", &returnPath);
443
444
445 if (status == OSD_FILEFOUND)
446 {
447 call = message ("%s -syms %s > %s", cstring_fromChars (returnPath),
448 cstring_fromChars (infile), cstring_fromChars (outfile));
449
450 /* before calling, make sure old file is removed */
451 (void) osd_unlink (outfile);
452
453 callstatus = osd_system (cstring_toCharsSafe (call));
454
455 cstring_free (call);
456
457 if (callstatus != CALL_SUCCESS)
458 {
459 /*
460 ** lsl errors: call lsl again without -syms, sending output to stdout
461 */
462 cstring syscal = message ("%s %s", cstring_fromChars (returnPath),
463 cstring_fromChars (infile));
464
465 (void) osd_system (cstring_toCharsSafe (syscal));
466 cstring_free (syscal);
467
468 llfatalerror (cstring_makeLiteral ("LSL trait used contains errors."));
469 }
470 else
471 { /* ok, go ahead */
472 /* Now parse the LSL output and store info in symbol table */
473 callstatus = parseSignatures (cstring_fromChars (outfile));
474
475 if (callstatus == 0)
476 {
477 /* all went well */
478 if (!context_getFlag (FLG_KEEP))
479 {
480 /* delete temporary files */
481 if (deletep)
482 {
483 (void) osd_unlink (infile);
484 }
485
486 (void) osd_unlink (outfile);
487 }
488 }
489 }
490 }
491 else if (status == OSD_FILENOTFOUND)
492 {
493 llfatalerror
494 (cstring_makeLiteral ("Cannot find LSL checker: check your command search path."));
495 }
496 else /* must be (status == OSD_PATHTOOLONG) */
497 {
498 lclfatalbug ("invokeLSL: lsl plus directory from search path is too long");
499 }
500}
501
502/* callLSL ("MySet", "includes Set (CC for C, EE for E)"); */
503
504void
505readlsignatures (interfaceNode n)
506{
507 /* assume n->kind = usesKIND */
508 char *content;
509
510 content = cstring_toCharsSafe (printTraitRefList2 (n->content.uses));
511 callLSL (cstring_toCharsSafe (g_currentSpec), content);
512}
This page took 0.115823 seconds and 5 git commands to generate.