OSDN Git Service

36aa2c4dbaf07dfe9227c82ef23ce86d78f9e4c7
[pf3gnuchains/gcc-fork.git] / gcc / c-pragma.c
1 /* Handle #pragma, system V.4 style.  Supports #pragma weak and #pragma pack.
2    Copyright (C) 1992, 1997, 1998, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "rtl.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "defaults.h"
27 #include "c-pragma.h"
28 #include "flags.h"
29 #include "toplev.h"
30 #include "ggc.h"
31
32 #ifdef HANDLE_GENERIC_PRAGMAS
33
34 #ifdef HANDLE_PRAGMA_PACK
35 /* When structure field packing is in effect, this variable is the
36    number of bits to use as the maximum alignment.  When packing is not
37    in effect, this is zero.  */
38
39 extern int maximum_field_alignment;
40 #endif
41
42
43 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
44 typedef struct align_stack
45 {
46   int                  alignment;
47   unsigned int         num_pushes;
48   tree                 id;
49   struct align_stack * prev;
50 } align_stack;
51
52 static struct align_stack * alignment_stack = NULL;
53
54 /* If we have a "global" #pragma pack(<n>) if effect when the first
55    #pragma push(pack,<n>) is encountered, this stores the the value of 
56    maximum_field_alignment in effect.  When the final pop_alignment() 
57    happens, we restore the value to this, not to a value of 0 for
58    maximum_field_alignment.  Value is in bits. */
59 static int  default_alignment;
60
61 static int  push_alignment PROTO((int, tree));
62 static int  pop_alignment  PROTO((tree));
63
64 /* Push an alignment value onto the stack.  */
65 static int
66 push_alignment (alignment, id)
67      int alignment;
68      tree id;
69 {
70   switch (alignment)
71     {
72     case 0:
73     case 1:
74     case 2:
75     case 4:
76     case 8:
77     case 16:
78       break;
79     default:
80       warning ("\
81 Alignment must be a small power of two, not %d, in #pragma pack",
82                alignment);
83       return 0;
84     }
85   
86   if (alignment_stack == NULL
87       || alignment_stack->alignment != alignment
88       || id != NULL_TREE)
89     {
90       align_stack * entry;
91
92       entry = (align_stack *) xmalloc (sizeof (* entry));
93
94       if (entry == NULL)
95         {
96           warning ("Out of memory pushing #pragma pack");
97           return 0;
98         }
99
100       entry->alignment  = alignment;
101       entry->num_pushes = 1;
102       entry->id         = id;
103       entry->prev       = alignment_stack;
104       
105       /* The current value of maximum_field_alignment is not necessarily 
106          0 since there may be a #pragma pack(<n>) in effect; remember it 
107          so that we can restore it after the final #pragma pop(). */
108       if (alignment_stack == NULL)
109         default_alignment = maximum_field_alignment;
110       
111       alignment_stack = entry;
112
113       maximum_field_alignment = alignment * 8;
114     }
115   else
116     alignment_stack->num_pushes ++;
117
118   return 1;
119 }
120
121 /* Undo a push of an alignment onto the stack.  */
122 static int
123 pop_alignment (id)
124      tree id;
125 {
126   align_stack * entry;
127       
128   if (alignment_stack == NULL)
129     {
130       warning ("\
131 #pragma pack (pop) encountered without matching #pragma pack (push, <n>)"
132                );
133       return 0;
134     }
135
136   /* If we got an identifier, strip away everything above the target
137      entry so that the next step will restore the state just below it.  */
138   if (id)
139     {
140       for (entry = alignment_stack; entry; entry = entry->prev)
141         if (entry->id == id)
142           {
143             entry->num_pushes = 1;
144             alignment_stack = entry;
145             break;
146           }
147       if (entry == NULL)
148         warning ("\
149 #pragma pack(pop, %s) encountered without matching #pragma pack(push, %s, <n>)"
150                  , IDENTIFIER_POINTER (id), IDENTIFIER_POINTER (id));
151     }
152
153   if (-- alignment_stack->num_pushes == 0)
154     {
155       entry = alignment_stack->prev;
156
157       if (entry == NULL)
158         maximum_field_alignment = default_alignment;
159       else
160         maximum_field_alignment = entry->alignment * 8;
161
162       free (alignment_stack);
163
164       alignment_stack = entry;
165     }
166
167   return 1;
168 }
169 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
170 \f
171 /* Handle one token of a pragma directive.  TOKEN is the current token, and
172    STRING is its printable form.  Some front ends do not support generating
173    tokens, and will only pass in a STRING.  Also some front ends will reuse
174    the buffer containing STRING, so it must be copied to a local buffer if
175    it needs to be preserved.
176
177    If STRING is non-NULL, then the return value will be ignored, and there
178    will be futher calls to handle_pragma_token() in order to handle the rest of
179    the line containing the #pragma directive.  If STRING is NULL, the entire
180    line has now been presented to handle_pragma_token() and the return value
181    should be zero if the pragma flawed in some way, or if the pragma was not
182    recognised, and non-zero if it was successfully handled.  */
183
184 int
185 handle_pragma_token (string, token)
186      const char * string;
187      tree token;
188 {
189   static enum pragma_state state = ps_start;
190   static enum pragma_state type;
191 #ifdef HANDLE_PRAGMA_WEAK
192   static char * name;
193   static char * value;
194 #endif
195 #if defined(HANDLE_PRAGMA_PACK) || defined(HANDLE_PRAGMA_PACK_PUSH_POP)
196   static int align;
197 #endif
198   static tree id;
199
200   /* If we have reached the end of the #pragma directive then
201      determine what value we should return.  */
202   
203   if (string == NULL)
204     {
205       int ret_val = 0;
206
207       switch (type)
208         {
209         default:
210           abort ();
211           break;
212
213         case ps_done:
214           /* The pragma was not recognised.  */
215           break;
216           
217 #ifdef HANDLE_PRAGMA_PACK         
218         case ps_pack:
219           if (state == ps_right)
220             {
221               maximum_field_alignment = align * 8;
222 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
223               default_alignment = maximum_field_alignment;
224 #endif
225               ret_val = 1;
226             }
227           else
228             warning ("malformed `#pragma pack'");
229           break;
230 #endif /* HANDLE_PRAGMA_PACK */
231           
232 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
233         case ps_push:
234           if (state == ps_right)
235             ret_val = push_alignment (align, id);
236           else
237             warning ("malformed '#pragma pack(push[,id],<n>)'");
238           break;
239           
240         case ps_pop:
241           if (state == ps_right)
242             ret_val = pop_alignment (id);
243           else
244             warning ("malformed '#pragma pack(pop[,id])'");
245           break;
246 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
247           
248 #ifdef HANDLE_PRAGMA_WEAK
249         case ps_weak:
250           if (HANDLE_PRAGMA_WEAK)
251             {
252               if (state == ps_name)
253                 ret_val = add_weak (name, NULL);
254               else if (state == ps_value)
255                 ret_val = add_weak (name, value);
256               else
257                 warning ("malformed `#pragma weak'");
258             }
259           else
260             ret_val = 1; /* Ignore the pragma.  */
261           break;
262 #endif /* HANDLE_PRAGMA_WEAK */
263
264         case ps_poison:
265           ret_val = 1;
266           break;
267         }
268
269       type = state = ps_start;
270       id = NULL_TREE;
271       
272       return ret_val;
273     }
274
275   /* If we have been given a token, but it is not an identifier,
276      or a small constant, then something has gone wrong.  */
277   if (token)
278     {
279       switch (TREE_CODE (token))
280         {
281         case IDENTIFIER_NODE:
282           break;
283           
284         case INTEGER_CST:
285           if (TREE_INT_CST_HIGH (token) != 0)
286             return 0;
287           break;
288           
289         default:
290           return 0;
291         }
292     }
293       
294   switch (state)
295     {
296     case ps_start:
297       type = state = ps_done;
298 #ifdef HANDLE_PRAGMA_PACK
299       if (strcmp (string, "pack") == 0)
300         type = state = ps_pack;
301 #endif
302 #ifdef HANDLE_PRAGMA_WEAK
303       if (strcmp (string, "weak") == 0)
304         type = state = ps_weak;
305 #endif
306       if (strcmp (string, "poison") == 0)
307         type = state = ps_poison;
308       break;
309
310 #ifdef HANDLE_PRAGMA_WEAK
311     case ps_weak:
312       name = permalloc (strlen (string) + 1);
313       if (name == NULL)
314         {
315           warning ("Out of memory parsing #pragma weak");
316           state = ps_bad;
317         }
318       else
319         {
320           strcpy (name, string);
321           state = ps_name;
322         }
323       break;
324       
325     case ps_name:
326       state = (strcmp (string, "=") ? ps_bad : ps_equals);
327       break;
328
329     case ps_equals:
330       value = permalloc (strlen (string) + 1);
331       if (value == NULL)
332         {
333           warning ("Out of memory parsing #pragma weak");
334           state = ps_bad;
335         }
336       else
337         {
338           strcpy (value, string);
339           state = ps_value;
340         }
341       break;
342
343     case ps_value:
344       state = ps_bad;
345       break;
346 #endif /* HANDLE_PRAGMA_WEAK */
347       
348 #ifdef HANDLE_PRAGMA_PACK
349     case ps_pack:
350       state = (strcmp (string, "(") ? ps_bad : ps_left);
351       break;
352
353     case ps_left:
354
355       if (token == NULL_TREE)
356         {
357           /* #pragma pack () resets packing rules to their
358              defaults.  */
359           if (strcmp (string, ")") == 0)
360             {
361               align = 0;
362               state = ps_right;
363             }
364           else
365             state = ps_bad;
366         }
367       else if (TREE_CODE (token) == INTEGER_CST)
368         goto handle_align;
369
370 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
371       else if (TREE_CODE (token) == IDENTIFIER_NODE)
372         {
373           if (strcmp (string, "push") == 0)
374             type = state = ps_push;
375           else if (strcmp (string, "pop") == 0)
376             type = state = ps_pop;
377           else
378             state = ps_bad;
379         }
380 #endif
381       else
382         state = ps_bad;
383       break;
384
385     handle_align:
386       align = TREE_INT_CST_LOW (token);
387       switch (align)
388         {
389         case 1:
390         case 2:
391         case 4:
392         case 8:
393         case 16:
394           state = ps_align;
395           break;
396
397         default:
398           state = ps_bad;
399           break;
400         }
401       break;
402
403     case ps_align:
404       state = (strcmp (string, ")") ? ps_bad : ps_right);
405       break;
406
407     case ps_right:
408       state = ps_bad;
409       break;
410 #endif /* HANDLE_PRAGMA_PACK */
411
412 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
413     case ps_push:
414       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma);
415       break;
416
417     case ps_pushid:
418       state = (strcmp (string, ",") ? ps_bad : ps_pushcomma2);
419       break;
420
421     case ps_pushcomma:
422       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
423         {
424           id = token;
425           state = ps_pushid;
426           break;
427         }
428
429       /* else fall through */
430     case ps_pushcomma2:
431       if (token && TREE_CODE (token) == INTEGER_CST)
432         goto handle_align;
433       else
434         state = ps_bad;
435       break;
436
437     case ps_pop:
438       if (strcmp (string, ",") == 0)
439         state = ps_popcomma;
440       else
441         state = (strcmp (string, ")") ? ps_bad : ps_right);
442       break;
443
444     case ps_popcomma:
445       if (token && TREE_CODE (token) == IDENTIFIER_NODE)
446         {
447           id = token;
448           state = ps_align;
449         }
450       else
451         state = ps_bad;
452       break;
453 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
454
455     case ps_poison:
456       if (token && TREE_CODE (token) != IDENTIFIER_NODE)
457         state = ps_bad;
458       break;
459
460     case ps_bad:
461     case ps_done:
462       break;
463
464     default:
465       abort ();
466     }
467
468   return 1;
469 }
470 #endif /* HANDLE_GENERIC_PRAGMAS */
471 \f
472 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
473 static void
474 mark_align_stack (p)
475     void *p;
476 {
477   align_stack *a = *(align_stack **) p;
478
479   while (a)
480     {
481       ggc_mark_tree (a->id);
482       a = a->prev;
483     }
484 }
485 #endif
486
487 void
488 init_pragma ()
489 {
490 #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
491   ggc_add_root (&alignment_stack, 1, sizeof(alignment_stack),
492                 mark_align_stack);
493 #endif
494 }