OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / c-pragma.c
index 270cd20..f9bfbe7 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle #pragma, system V.4 style.  Supports #pragma weak and #pragma pack.
-   Copyright (C) 1992, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -20,6 +20,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "rtl.h"
 #include "tree.h"
 #include "except.h"
 #include "function.h"
@@ -28,147 +29,416 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "toplev.h"
 
-#ifdef HANDLE_SYSV_PRAGMA
+#ifdef HANDLE_GENERIC_PRAGMAS
 
+#ifdef HANDLE_PRAGMA_PACK
 /* When structure field packing is in effect, this variable is the
    number of bits to use as the maximum alignment.  When packing is not
    in effect, this is zero.  */
 
 extern int maximum_field_alignment;
+#endif
 
-/* File used for outputting assembler code.  */
-extern FILE *asm_out_file;
 
-/* Handle one token of a pragma directive.  TOKEN is the
-   current token, and STRING is its printable form.  */
+#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+typedef struct align_stack
+{
+  int                  alignment;
+  unsigned int         num_pushes;
+  struct align_stack * prev;
+} align_stack;
+
+static struct align_stack * alignment_stack = NULL;
+
+static int  push_alignment PROTO((int));
+static int  pop_alignment  PROTO((void));
+
+/* Push an alignment value onto the stack.  */
+static int
+push_alignment (alignment)
+     int alignment;
+{
+  switch (alignment)
+    {
+    case 0:
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+    case 16:
+      break;
+    default:
+      warning ("\
+Alignment must be a small power of two, not %d, in #pragma pack",
+              alignment);
+      return 0;
+    }
+  
+  if (alignment_stack == NULL
+      || alignment_stack->alignment != alignment)
+    {
+      align_stack * entry;
+
+      entry = (align_stack *) xmalloc (sizeof (* entry));
+
+      if (entry == NULL)
+       {
+         warning ("Out of memory pushing #pragma pack");
+         return 0;
+       }
+
+      entry->alignment  = alignment;
+      entry->num_pushes = 1;
+      entry->prev       = alignment_stack;
+      
+      alignment_stack = entry;
+
+      if (alignment < 8)
+       maximum_field_alignment = alignment * 8;
+      else
+       /* MSVC ignores alignments > 4.  */
+       maximum_field_alignment = 0;
+    }
+  else
+    alignment_stack->num_pushes ++;
+
+  return 1;
+}
+
+/* Undo a push of an alignment onto the stack.  */
+static int
+pop_alignment ()
+{
+  if (alignment_stack == NULL)
+    {
+      warning ("\
+#pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
+      return 0;
+    }
+
+  if (-- alignment_stack->num_pushes == 0)
+    {
+      align_stack * entry;
+      
+      entry = alignment_stack->prev;
+
+      if (entry == NULL || entry->alignment > 4)
+       maximum_field_alignment = 0;
+      else
+       maximum_field_alignment = entry->alignment * 8;
 
+      free (alignment_stack);
+
+      alignment_stack = entry;
+    }
+
+  return 1;
+}
+
+/* Generate 'packed' and 'aligned' attributes for decls whilst a
+   #pragma pack(push... is in effect.  */
 void
+insert_pack_attributes (node, attributes, prefix)
+     tree node;
+     tree * attributes;
+     tree * prefix;
+{
+  tree a;
+
+  /* If we are not packing, then there is nothing to do.  */
+  if (maximum_field_alignment == 0
+      || alignment_stack == NULL)
+    return;
+
+  /* We are only interested in fields.  */
+  if (TREE_CODE_CLASS (TREE_CODE (node)) != 'd'
+      || TREE_CODE (node) != FIELD_DECL)
+    return;
+
+  /* Add a 'packed' attribute.  */
+  * attributes = tree_cons (get_identifier ("packed"), NULL, * attributes);
+  
+  /* If the alignment is > 8 then add an alignment attribute as well.  */
+  if (maximum_field_alignment > 8)
+    {
+      /* If the aligned attribute is already present then do not override it.  */
+      for (a = * attributes; a; a = TREE_CHAIN (a))
+       {
+         tree name = TREE_PURPOSE (a);
+         if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
+           break;
+       }
+      
+      if (a == NULL)
+       for (a = * prefix; a; a = TREE_CHAIN (a))
+         {
+           tree name = TREE_PURPOSE (a);
+           if (strcmp (IDENTIFIER_POINTER (name), "aligned") == 0)
+             break;
+         }
+  
+      if (a == NULL)
+       {
+         * attributes = tree_cons
+             (get_identifier ("aligned"),
+              tree_cons (NULL,
+                         build_int_2 (maximum_field_alignment / 8, 0),
+                         NULL),
+              * attributes);
+       }
+    }
+
+  return;
+}
+#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
+\f
+#ifdef HANDLE_PRAGMA_WEAK
+static int add_weak PROTO((char *, char *));
+
+static int
+add_weak (name, value)
+     char * name;
+     char * value;
+{
+  struct weak_syms * weak;
+
+  weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms));
+
+  if (weak == NULL)
+    return 0;
+  
+  weak->next  = weak_decls;
+  weak->name  = name;
+  weak->value = value;
+  weak_decls  = weak;
+
+  return 1;
+}
+#endif /* HANDLE_PRAGMA_WEAK */
+\f
+/* Handle one token of a pragma directive.  TOKEN is the current token, and
+   STRING is its printable form.  Some front ends do not support generating
+   tokens, and will only pass in a STRING.  Also some front ends will reuse
+   the buffer containing STRING, so it must be copied to a local buffer if
+   it needs to be preserved.
+
+   If STRING is non-NULL, then the return value will be ignored, and there
+   will be futher calls to handle_pragma_token() in order to handle the rest of
+   the line containing the #pragma directive.  If STRING is NULL, the entire
+   line has now been presented to handle_pragma_token() and the return value
+   should be zero if the pragma flawed in some way, or if the pragma was not
+   recognised, and non-zero if it was successfully handled.  */
+
+int
 handle_pragma_token (string, token)
-     char *string;
+     char * string;
      tree token;
 {
-  static enum pragma_state state = ps_start, type;
-  static char *name;
-  static char *value;
+  static enum pragma_state state = ps_start;
+  static enum pragma_state type;
+  static char * name;
+  static char * value;
   static int align;
 
-  if (string == 0)
+  /* If we have reached the end of the #pragma directive then
+     determine what value we should return.  */
+  
+  if (string == NULL)
     {
-      if (type == ps_pack)
+      int ret_val = 0;
+
+      switch (type)
        {
+       default:
+         abort ();
+         break;
+
+       case ps_done:
+         /* The pragma was not recognised.  */
+         break;
+         
+#ifdef HANDLE_PRAGMA_PACK        
+       case ps_pack:
          if (state == ps_right)
-           maximum_field_alignment = align * 8;
+           {
+             maximum_field_alignment = align * 8;
+             ret_val = 1;
+           }
          else
            warning ("malformed `#pragma pack'");
-       }
-      else if (type == ps_weak)
-       {
+         break;
+#endif /* HANDLE_PRAGMA_PACK */
+         
+#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+       case ps_push:
+         if (state == ps_right)
+           ret_val = push_alignment (align);
+         else
+           warning ("incomplete '#pragma pack(push,<n>)'");
+         break;
+         
+       case ps_pop:
+         if (state == ps_right)
+           ret_val = pop_alignment ();
+         else
+           warning ("missing closing parenthesis in '#pragma pack(pop)'");
+         break;
+#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
+         
 #ifdef HANDLE_PRAGMA_WEAK
+       case ps_weak:
          if (HANDLE_PRAGMA_WEAK)
-           handle_pragma_weak (state, name, value);
-
+           {
+             if (state == ps_name)
+               ret_val = add_weak (name, NULL);
+             else if (state == ps_value)
+               ret_val = add_weak (name, value);
+             else
+               warning ("malformed `#pragma weak'");
+           }
+         else
+           ret_val = 1; /* Ignore the pragma.  */
+         break;
 #endif /* HANDLE_PRAGMA_WEAK */
        }
 
       type = state = ps_start;
-      return;
+      
+      return ret_val;
     }
 
+  /* If we have been given a token, but it is not an identifier,
+     or a small constant, then something has gone wrong.  */
+  if (token)
+    {
+      switch (TREE_CODE (token))
+       {
+       case IDENTIFIER_NODE:
+         break;
+         
+       case INTEGER_CST:
+         if (TREE_INT_CST_HIGH (token) != 0)
+           return 0;
+         break;
+         
+       default:
+         return 0;
+       }
+    }
+      
   switch (state)
     {
     case ps_start:
-      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
+      type = state = ps_done;
+#ifdef HANDLE_PRAGMA_PACK
+      if (strcmp (string, "pack") == 0)
+       type = state = ps_pack;
+#endif
+#ifdef HANDLE_PRAGMA_WEAK
+      if (strcmp (string, "weak") == 0)
+       type = state = ps_weak;
+#endif   
+      break;
+      
+#ifdef HANDLE_PRAGMA_WEAK
+    case ps_weak:
+      name = permalloc (strlen (string) + 1);
+      if (name == NULL)
        {
-         if (strcmp (IDENTIFIER_POINTER (token), "pack") == 0)
-           type = state = ps_pack;
-         else if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
-           type = state = ps_weak;
-         else
-           {
-             type = state = ps_done;
-
-             /* Issue a warning message if we have been asked to do so.
-                Ignoring unknown pragmas in system header file unless          
-                an explcit -Wunknown-pragmas has been given. */                
-             if (warn_unknown_pragmas > 1
-                 || (warn_unknown_pragmas && ! in_system_header))
-               warning ("ignoring pragma: %s", string);
-           }
+         warning ("Out of memory parsing #pragma weak");
+         state = ps_bad;
        }
       else
-       type = state = ps_done;
-      break;
-
-    case ps_weak:
-      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
        {
-         name = IDENTIFIER_POINTER (token);
+         strcpy (name, string);
          state = ps_name;
        }
-      else
-       state = ps_bad;
       break;
-
+      
     case ps_name:
       state = (strcmp (string, "=") ? ps_bad : ps_equals);
       break;
 
     case ps_equals:
-      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
+      value = permalloc (strlen (string) + 1);
+      if (value == NULL)
        {
-         value = IDENTIFIER_POINTER (token);
-         state = ps_value;
+         warning ("Out of memory parsing #pragma weak");
+         state = ps_bad;
        }
       else
-       state = ps_bad;
+       {
+         strcpy (value, string);
+         state = ps_value;
+       }
       break;
 
     case ps_value:
       state = ps_bad;
       break;
-
+#endif /* HANDLE_PRAGMA_WEAK */
+      
+#ifdef HANDLE_PRAGMA_PACK
     case ps_pack:
-      if (strcmp (string, "(") == 0)
-       state = ps_left;
-      else
-       state = ps_bad;
+      state = (strcmp (string, "(") ? ps_bad : ps_left);
       break;
 
     case ps_left:
-      if (token && TREE_CODE (token) == INTEGER_CST
-         && TREE_INT_CST_HIGH (token) == 0)
-       switch (TREE_INT_CST_LOW (token))
-         {
-         case 1:
-         case 2:
-         case 4:
-           align = TREE_INT_CST_LOW (token);
-           state = ps_align;
-           break;
 
-         default:
-           state = ps_bad;
-         }
-      else if (! token && strcmp (string, ")") == 0)
+      if (token && TREE_CODE(token) == INTEGER_CST) 
+       align = TREE_INT_CST_LOW(token);
+      else
+       align = atoi (string);
+      switch (align)
        {
-         align = 0;
-         state = ps_right;
+       case 1:
+       case 2:
+       case 4:
+         state = ps_align;
+         break;
+
+       case 0:
+         state = (strcmp (string, ")") ? ps_bad : ps_right);
+#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+         if (state == ps_bad)
+           {
+             if (strcmp (string, "push") == 0)
+               type = state = ps_push;
+             else if (strcmp (string, "pop") == 0)
+               type = state = ps_pop;
+           }
+#endif
+         break;
+
+       default:
+         state = ps_bad;
+         break;
        }
-      else
-       state = ps_bad;
       break;
 
+#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+    case ps_pop:
+#endif
     case ps_align:
-      if (strcmp (string, ")") == 0)
-       state = ps_right;
-      else
-       state = ps_bad;
+      state = (strcmp (string, ")") ? ps_bad : ps_right);
       break;
 
     case ps_right:
       state = ps_bad;
       break;
+#endif /* HANDLE_PRAGMA_PACK */
+
+#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+    case ps_push:
+      state = (strcmp (string, ",") ? ps_bad : ps_comma);
+      break;
 
+    case ps_comma:
+      align = atoi (string);
+      state = ps_align;
+      break;
+#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
+      
     case ps_bad:
     case ps_done:
       break;
@@ -176,5 +446,7 @@ handle_pragma_token (string, token)
     default:
       abort ();
     }
+
+  return 1;
 }
-#endif /* HANDLE_SYSV_PRAGMA */
+#endif /* HANDLE_GENERIC_PRAGMAS */