]> andersk Git - splint.git/blob - src/lh.c
Renamed lclintMacros.nf splintMacros.nf
[splint.git] / src / lh.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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: splint@cs.virginia.edu
21 ** To report a bug: splint-bug@cs.virginia.edu
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 "llbasic.h"
44 # include "osd.h"
45 # include "lh.h"
46 # include "llmain.h"
47
48 /*@constant static char TABCH; @*/
49 # define TABCH          '\1'
50
51 /*@constant static char TABINCH; @*/
52 # define TABINCH        '\2'
53
54 /*@constant static char TABOUTCH; @*/
55 # define TABOUTCH       '\3'
56
57 /*
58   # define TAB                  fputc (TABCH,   LhFile.f);
59   # define TABIN                fputc (TABINCH,         LhFile.f);
60   # define TABOUT               fputc (TABOUTCH, LhFile.f);
61 */
62
63 /*@private@*/ typedef struct
64 {
65   /*:open:*/ /*@dependent@*/ /*@null@*/ /*@reldef@*/ FILE *f;
66   /*@reldef@*/ cstring name;
67 } outFile;
68
69 static bool genLh;
70 static outFile LhFile;
71 static bool needIncludeBool = FALSE;
72
73 /*
74 **
75 **  FORWARD FUNCTIONS
76 **
77 */
78
79 /* static int colpos (int startcol, cstring line); */
80
81 static cstring lhTypeSpecNode (lclTypeSpecNode p_typespec);
82 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr p_x);
83 static /*@only@*/ cstring lhDeclaratorNode (declaratorNode p_x);
84
85 static /*:open:*/ /*@dependent@*/ /*@null@*/ FILE *out_open (cstring name, cstring suffix)
86      /*@modifies fileSystem@*/
87 {
88   cstring fullname = cstring_concat (name, suffix);
89   FILE *ret = fileTable_openFile (context_fileTable (), fullname, "w+");
90   cstring_free (fullname);
91   return ret;
92 }
93
94 /*@only@*/ cstring 
95 lhFunction (lclTypeSpecNode lclTypeSpec, declaratorNode declarator)
96 {
97   cstring s;
98
99   if (!genLh)
100     return cstring_undefined;
101   
102   s = message ("extern %q\1%q;", lhTypeSpecNode (lclTypeSpec),
103                lhDeclaratorNode (declarator));
104   
105   return s;
106 }
107
108 static /*@only@*/ cstring
109 lhDeclaratorNode (declaratorNode x)
110 {
111   return (lhTypeExpr (x->type));
112 }
113
114 static /*@only@*/ cstring lhTypeExpr (/*@null@*/ typeExpr x)
115 {
116   cstring s = cstring_undefined; /* print out types in order of appearance in source */
117   paramNodeList params;
118   int i;
119
120   if (x != (typeExpr) 0)
121     {
122       cstring front = cstring_undefined;
123       cstring back  = cstring_undefined;
124
125       for (i = x->wrapped; i >= 1; i--)
126         {
127           front = cstring_appendChar (front, '(');
128           back  = cstring_appendChar (back, ')');
129         }
130
131       switch (x->kind)
132         {
133         case TEXPR_BASE:
134           s = message ("%q%s", s, ltoken_getRawString (x->content.base));
135           break;
136         case TEXPR_PTR:
137           s = message ("%q*%q", s, lhTypeExpr (x->content.pointer));
138           break;
139         case TEXPR_ARRAY:
140           s = message ("%q%q[%q]", s, 
141                        lhTypeExpr (x->content.array.elementtype),
142                        termNode_unparse (x->content.array.size));
143           break;
144         case TEXPR_FCN:
145           s = message ("%q%q (", s, lhTypeExpr (x->content.function.returntype));
146           params = x->content.function.args;
147
148           if (!paramNodeList_empty (params))
149             {
150               s = message ("%q%q", s, 
151                            paramNodeList_unparseComments (x->content.function.args));
152             }
153
154           s = message ("%q)", s);
155           break;
156         }
157       s = message ("%q%q%q", front, s, back);
158     }
159   else
160     {
161       s = cstring_makeLiteral ("?");
162     }
163
164   return s;
165 }
166
167 extern void
168 lhForwardStruct (ltoken t)
169 {
170   if (!genLh)
171     return;
172
173   lhOutLine (message ("struct %s;", ltoken_unparse (t)));
174 }
175
176
177 extern void
178 lhForwardUnion (ltoken t)
179 {
180   if (!genLh)
181     return;
182
183   lhOutLine (message ("union %s;", ltoken_unparse (t)));
184 }
185
186 extern /*@only@*/ cstring 
187 lhType (typeNode t)
188 {
189   if (!genLh)
190     return cstring_undefined;
191
192   if (t->kind == TK_EXPOSED)
193     {
194       exposedNode n = t->content.exposed;
195
196       if (n != (exposedNode) 0)
197         {
198           if (declaratorInvNodeList_size (n->decls) == 0)
199             {
200               /* 
201               ** Forward struct or union declaration
202               */
203
204               return (cstring_appendChar (lhTypeSpecNode (n->type), ';'));
205             }
206           else
207             {
208               cstring s = cstring_undefined;
209
210               declaratorInvNodeList_elements (n->decls, d)
211                 {
212                   cstring name = declaratorNode_unparse (d->declarator);
213                   cstring pname = declaratorNode_unparseCode (d->declarator); 
214                   
215                   s = message ("%q\n# ifndef EXPOSED_TYPE_%q\ntypedef %q %q;\n# endif\n", 
216                                s, pname, lhTypeSpecNode (n->type), name);
217                 } end_declaratorInvNodeList_elements;
218               
219               return s;
220             }
221         }
222     }
223
224   return cstring_undefined;
225 }
226
227 static /*@only@*/ cstring 
228 lhTypeSpecNode (lclTypeSpecNode typespec)
229 {
230   if (!genLh)
231     {
232       return cstring_undefined;
233     }
234
235   return (lclTypeSpecNode_unparseComments (typespec));
236 }
237
238 /*@only@*/ cstring
239 lhVarDecl (lclTypeSpecNode lclTypeSpec, initDeclNodeList initDecls,
240            qualifierKind qualifier)
241 {
242   bool first = TRUE;
243   cstring s;
244
245   if (!genLh)
246     return cstring_undefined;
247
248   s = cstring_makeLiteral ("extern");
249
250   switch (qualifier)
251     {
252     case QLF_NONE:
253       break;
254     case QLF_CONST:
255       s = message ("%q const", s);
256       break;
257     case QLF_VOLATILE:
258       s = message ("%q volatile", s);
259       break;
260     default:                    /* ignore it */
261       break;
262     }
263   
264   s = message ("%q %q\1", s, lhTypeSpecNode (lclTypeSpec));
265
266   initDeclNodeList_elements (initDecls, i)
267   {
268     if (first)
269       {
270         s = message ("%q %q", s, declaratorNode_unparse (i->declarator));
271         first = FALSE;
272       }
273     else
274       {
275         s = message ("%q, %q", s, declaratorNode_unparse (i->declarator));
276       }
277   } end_initDeclNodeList_elements;
278   
279   return (message ("%q;", s));
280 }
281
282 extern void
283 lhCleanup (void)
284    /*@modifies fileSystem@*/
285 {
286   if (!genLh)
287     {
288       return;
289     }
290   else
291     {
292       FILE *f;
293       int c, col = 0, tabcol = 0;
294       cstring fullname;
295
296       f = out_open (LhFile.name, LH_EXTENSION);
297       llassert (LhFile.f != NULL);
298       
299       fullname = cstring_concat (LhFile.name, LHTMP_EXTENSION);
300
301       if (f == NULL)
302         {
303           /*@i25534  check this!  does it report the right filename? */
304           lldiagmsg (message ("Cannot open lh file for output: %s", 
305                               fullname));
306         }
307       else
308         {
309           fprintf (f, "/* Output from %s */\n", LCL_PARSE_VERSION);
310
311           rewind (LhFile.f);
312
313           while (EOF != (c = getc (LhFile.f)))
314             {
315               switch (c)
316                 {
317                 case TABCH:
318                   if (col == 0)
319                     {
320                       if (tabcol > 0)
321                         fprintf (f, "%*s", tabcol, "");
322                     }
323                   else
324                     {
325                       check (fputc (' ', f) == (int) ' ');
326                     }
327                   /*@switchbreak@*/ break;
328                   
329                 case TABINCH:
330                   tabcol += 4;
331                   /*@switchbreak@*/ break;
332                   
333                 case TABOUTCH:
334                   tabcol -= 4;
335                   /*@switchbreak@*/ break;
336                   
337                 case '\n':
338                   col = 0;
339                   check (fputc (c, f) == (int) c);
340                   /*@switchbreak@*/ break;
341                   
342                 default:
343                   col++;
344                   check (fputc (c, f) == (int) c);
345                   /*@switchbreak@*/ break;
346                 }
347             }
348
349           check (fileTable_closeFile (context_fileTable (), f));
350           check (fileTable_closeFile (context_fileTable (), LhFile.f));
351
352           (void) osd_unlink (fullname);
353           LhFile.f = NULL;
354         }
355       
356       cstring_free (fullname);
357     }
358 }
359
360 /* Write an #include of bool.h if we have't done so already.  */
361 extern void
362 lhIncludeBool (void)
363 {
364   needIncludeBool = TRUE;
365 }
366
367 /*
368 **++
369 **  FUNCTIONAL DESCRIPTION:
370 **
371 **      Initialize the .lh file processing.
372 **
373 **  FORMAL PARAMETERS:
374 **
375 **      source * f: The source file, from which we compute the name of
376 **      the .lh file.
377 **
378 **      bool outputLh: If true, produce a .lh file, otherwise don't.
379 **
380 **  RETURN VALUE:
381 **
382 **      None
383 **
384 **  SIDE EFFECTS:
385 **
386 **      The .lh file may be opened.
387 **
388 **
389 **--
390 */
391
392 void lhInit (inputStream  f) /*@globals undef LhFile; @*/
393 {
394   static bool lherror = FALSE;
395   
396   genLh = context_msgLh ();
397   needIncludeBool = FALSE;
398
399   if (!genLh)
400     {
401       return;
402     }
403   
404   LhFile.name = LSLRootName (inputStream_fileName (f));
405   LhFile.f = out_open (LhFile.name, LHTMP_EXTENSION);
406
407   if (LhFile.f == NULL)
408     {
409       genLh = FALSE;
410       if (!lherror)
411         {
412           lclplainerror (message ("Cannot write temporary %s file: %s%s", 
413                                   LH_EXTENSION,
414                                   LhFile.name,
415                                   LHTMP_EXTENSION));
416           lherror = TRUE;
417         }
418     } 
419
420
421 void lhOutLine (/*@only@*/ cstring s)
422 {
423   if (genLh)
424     {
425       llassert (LhFile.f != NULL);
426
427       if (cstring_length (s) > 0) 
428         {
429           check (fputs (cstring_toCharsSafe (s), LhFile.f) != EOF); 
430         }
431
432       check (fputc ('\n', LhFile.f) == (int) '\n'); 
433     }
434
435   cstring_free (s);
436 }
437
438 void lhExternals (interfaceNodeList x)
439 {
440   if (genLh)
441     {
442       llassert (LhFile.f != NULL);
443
444       /*
445       ** Need to make sure all standard library includes come first.
446       */
447
448       interfaceNodeList_elements (x, el)
449         {
450           if (el->kind == INF_IMPORTS)
451             {
452               importNodeList imps = el->content.imports;
453
454               importNodeList_elements (imps, il)
455                 {
456                   if (il->kind == IMPBRACKET)
457                     {
458                       lhOutLine (message ("# include <%s.h>", 
459                                           ltoken_getRawString (il->val)));
460                     }
461                 } end_importNodeList_elements ;
462             }
463         } end_interfaceNodeList_elements;
464
465       lhOutLine (cstring_makeLiteral ("# include \"bool.h\""));
466       
467       interfaceNodeList_elements (x, el)
468         {
469           if (el->kind == INF_IMPORTS)
470             {
471               importNodeList imps = el->content.imports;
472
473               importNodeList_elements (imps, il)
474                 {
475                   if (il->kind != IMPBRACKET)
476                     {
477                       lhOutLine (message ("# include \"%s.h\"", 
478                                           ltoken_getRawString (il->val)));
479                     }
480                 } end_importNodeList_elements ;
481             }
482         } end_interfaceNodeList_elements;
483
484       lhOutLine (cstring_undefined);
485     }
486 }
487
488
489
This page took 1.173561 seconds and 5 git commands to generate.