]> andersk Git - splint.git/blob - src/lh.c
30fed4956d5c1d62f939772362ac8ae4bed92f32
[splint.git] / src / lh.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** lh.c
26 **
27 **  MODULE DESCRIPTION:
28 **
29 **      This module contains the I/O routines for writing out the .lh file
30 **      generated from the .lcl file.
31 **
32 **  AUTHORS:
33 **
34 **      Gary Feldman, Technical Languages and Environments, DECspec project
35 **      Yang Meng Tan, MIT.
36 **
37 **  CREATION DATE:  9 April 91
38 **
39 **      The lh.c module controls formatting policy.
40 */
41
42 # include "splintMacros.nf"
43 # include "basic.h"
44 # include "osd.h"
45 # include "lh.h"
46 # include "llmain.h"
47
48 /*@constant static char TABCH; @*/
49 # define TABCH          ' '
50
51 /*@constant static char TABINCH; @*/
52 # define TABINCH        '\t'
53
54
55 /*@private@*/ typedef struct
56 {
57   /*:open:*/ /*@dependent@*/ /*@null@*/ /*@reldef@*/ FILE *f;
58   /*@reldef@*/ cstring name;
59 } outFile;
60
61 static bool genLh;
62 static outFile LhFile;
63 static bool needIncludeBool = FALSE;
64
65 /*
66 **
67 **  FORWARD FUNCTIONS
68 **
69 */
70
71 /* static int colpos (int startcol, cstring line); */
72
73 static cstring lhTypeSpecNode (lclTypeSpecNode p_typespec);
74 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr p_x);
75 static /*@only@*/ cstring lhDeclaratorNode (declaratorNode p_x);
76
77 /*@only@*/ cstring 
78 lhFunction (lclTypeSpecNode lclTypeSpec, declaratorNode declarator)
79 {
80   cstring s;
81
82   if (!genLh)
83     return cstring_undefined;
84   
85   s = message ("extern %q %q;", lhTypeSpecNode (lclTypeSpec),
86                lhDeclaratorNode (declarator));
87   
88   return s;
89 }
90
91 static /*@only@*/ cstring
92 lhDeclaratorNode (declaratorNode x)
93 {
94   return (lhTypeExpr (x->type));
95 }
96
97 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr x)
98 {
99   cstring s = cstring_undefined; /* print out types in order of appearance in source */
100   paramNodeList params;
101   int i;
102
103   if (x != (typeExpr) 0)
104     {
105       cstring front = cstring_undefined;
106       cstring back  = cstring_undefined;
107
108       for (i = x->wrapped; i >= 1; i--)
109         {
110           front = cstring_appendChar (front, '(');
111           back  = cstring_appendChar (back, ')');
112         }
113
114       switch (x->kind)
115         {
116         case TEXPR_BASE:
117           s = message ("%q%s", s, ltoken_getRawString (x->content.base));
118           break;
119         case TEXPR_PTR:
120           s = message ("%q*%q", s, lhTypeExpr (x->content.pointer));
121           break;
122         case TEXPR_ARRAY:
123           s = message ("%q%q[%q]", s, 
124                        lhTypeExpr (x->content.array.elementtype),
125                        termNode_unparse (x->content.array.size));
126           break;
127         case TEXPR_FCN:
128           s = message ("%q%q (", s, lhTypeExpr (x->content.function.returntype));
129           params = x->content.function.args;
130
131           if (!paramNodeList_empty (params))
132             {
133               s = message ("%q%q", s, 
134                            paramNodeList_unparseComments (x->content.function.args));
135             }
136
137           s = message ("%q)", s);
138           break;
139         }
140       s = message ("%q%q%q", front, s, back);
141     }
142   else
143     {
144       s = cstring_makeLiteral ("?");
145     }
146
147   return s;
148 }
149
150 extern void
151 lhForwardStruct (ltoken t)
152 {
153   if (!genLh)
154     return;
155
156   lhOutLine (message ("struct %s;", ltoken_unparse (t)));
157 }
158
159
160 extern void
161 lhForwardUnion (ltoken t)
162 {
163   if (!genLh)
164     return;
165
166   lhOutLine (message ("union %s;", ltoken_unparse (t)));
167 }
168
169 extern /*@only@*/ cstring 
170 lhType (typeNode t)
171 {
172   if (!genLh)
173     return cstring_undefined;
174
175   if (t->kind == TK_EXPOSED)
176     {
177       exposedNode n = t->content.exposed;
178
179       if (n != (exposedNode) 0)
180         {
181           if (declaratorInvNodeList_size (n->decls) == 0)
182             {
183               /* 
184               ** Forward struct or union declaration
185               */
186
187               return (cstring_appendChar (lhTypeSpecNode (n->type), ';'));
188             }
189           else
190             {
191               cstring s = cstring_undefined;
192
193               declaratorInvNodeList_elements (n->decls, d)
194                 {
195                   cstring name = declaratorNode_unparse (d->declarator);
196                   cstring pname = declaratorNode_unparseCode (d->declarator); 
197                   
198                   s = message ("%q\n# ifndef EXPOSED_TYPE_%q\ntypedef %q %q;\n# endif\n", 
199                                s, pname, lhTypeSpecNode (n->type), name);
200                 } end_declaratorInvNodeList_elements;
201               
202               return s;
203             }
204         }
205     }
206
207   return cstring_undefined;
208 }
209
210 static /*@only@*/ cstring 
211 lhTypeSpecNode (lclTypeSpecNode typespec)
212 {
213   if (!genLh)
214     {
215       return cstring_undefined;
216     }
217
218   return (lclTypeSpecNode_unparseComments (typespec));
219 }
220
221 /*@only@*/ cstring
222 lhVarDecl (lclTypeSpecNode lclTypeSpec, initDeclNodeList initDecls,
223            qualifierKind qualifier)
224 {
225   bool first = TRUE;
226   cstring s;
227
228   if (!genLh)
229     return cstring_undefined;
230
231   s = cstring_makeLiteral ("extern");
232
233   switch (qualifier)
234     {
235     case QLF_NONE:
236       break;
237     case QLF_CONST:
238       s = message ("%q const", s);
239       break;
240     case QLF_VOLATILE:
241       s = message ("%q volatile", s);
242       break;
243     default:                    /* ignore it */
244       break;
245     }
246   
247   s = message ("%q %q ", s, lhTypeSpecNode (lclTypeSpec));
248
249   initDeclNodeList_elements (initDecls, i)
250   {
251     if (first)
252       {
253         s = message ("%q %q", s, declaratorNode_unparse (i->declarator));
254         first = FALSE;
255       }
256     else
257       {
258         s = message ("%q, %q", s, declaratorNode_unparse (i->declarator));
259       }
260   } end_initDeclNodeList_elements;
261   
262   return (message ("%q;", s));
263 }
264
265 extern void
266 lhCleanup (void)
267    /*@modifies fileSystem@*/
268 {
269   if (!genLh)
270     {
271       return;
272     }
273   else
274     {
275       llassert (LhFile.f != NULL);
276       
277       if (LhFile.f == NULL)
278         {
279           lldiagmsg (message ("Cannot open lh file for output: %s", LhFile.name));
280         }
281       else
282         {
283           check (fprintf (LhFile.f, "/* Output from %s */\n", LCL_PARSE_VERSION) > 0);
284           check (fileTable_closeFile (context_fileTable (), LhFile.f));
285           LhFile.f = NULL;
286         }
287     }
288 }
289
290 /* Write an #include of bool.h if we have't done so already.  */
291 extern void
292 lhIncludeBool (void)
293 {
294   needIncludeBool = TRUE;
295 }
296
297 void lhInit (inputStream f) /*@globals undef LhFile; @*/
298 {
299   static bool lherror = FALSE;
300   
301   genLh = context_msgLh ();
302   needIncludeBool = FALSE;
303
304   if (!genLh)
305     {
306       return;
307     }
308   
309   LhFile.name = cstring_concatFree1 (LSLRootName (inputStream_fileName (f)),
310                                      LH_EXTENSION);
311   LhFile.f = fileTable_openWriteUpdateFile (context_fileTable (), LhFile.name);
312
313   if (LhFile.f == NULL)
314     {
315       genLh = FALSE;
316       if (!lherror)
317         {
318           lclplainerror (message ("Cannot write temporary file: %s", 
319                                   LhFile.name));
320           lherror = TRUE;
321         }
322     } 
323
324
325 void lhOutLine (/*@only@*/ cstring s)
326 {
327   if (genLh)
328     {
329       llassert (LhFile.f != NULL);
330       DPRINTF (("lhOutLine: %s / %s", s, LhFile.name));
331
332       if (cstring_length (s) > 0) 
333         {
334           check (fputs (cstring_toCharsSafe (s), LhFile.f) != EOF); 
335         }
336
337       check (fputc ('\n', LhFile.f) == (int) '\n'); 
338     }
339
340   cstring_free (s);
341 }
342
343 void lhExternals (interfaceNodeList x)
344 {
345   if (genLh)
346     {
347       llassert (LhFile.f != NULL);
348
349       /*
350       ** Need to make sure all standard library includes come first.
351       */
352
353       interfaceNodeList_elements (x, el)
354         {
355           if (el->kind == INF_IMPORTS)
356             {
357               importNodeList imps = el->content.imports;
358
359               importNodeList_elements (imps, il)
360                 {
361                   if (il->kind == IMPBRACKET)
362                     {
363                       lhOutLine (message ("# include <%s.h>", 
364                                           ltoken_getRawString (il->val)));
365                     }
366                 } end_importNodeList_elements ;
367             }
368         } end_interfaceNodeList_elements;
369
370       lhOutLine (cstring_makeLiteral ("# include \"bool.h\""));
371       
372       interfaceNodeList_elements (x, el)
373         {
374           if (el->kind == INF_IMPORTS)
375             {
376               importNodeList imps = el->content.imports;
377
378               importNodeList_elements (imps, il)
379                 {
380                   if (il->kind != IMPBRACKET)
381                     {
382                       lhOutLine (message ("# include \"%s.h\"", 
383                                           ltoken_getRawString (il->val)));
384                     }
385                 } end_importNodeList_elements ;
386             }
387         } end_interfaceNodeList_elements;
388
389       lhOutLine (cstring_undefined);
390     }
391 }
392
393
394
This page took 0.053076 seconds and 3 git commands to generate.