OSDN Git Service

Added Java 1.1 language features.
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-parse.c
index ad0b807..09991eb 100644 (file)
@@ -1,5 +1,5 @@
 /* Parser for Java(TM) .class files.
-   Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -33,12 +33,13 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "input.h"
 #include "java-tree.h"
 #include "toplev.h"
+#include "parse.h"
 
 /* A CONSTANT_Utf8 element is converted to an IDENTIFIER_NODE at parse time. */
 #define JPOOL_UTF(JCF, INDEX) CPOOL_UTF(&(JCF)->cpool, INDEX)
 #define JPOOL_UTF_LENGTH(JCF, INDEX) IDENTIFIER_LENGTH (JPOOL_UTF (JCF, INDEX))
 #define JPOOL_UTF_DATA(JCF, INDEX) \
-  ((unsigned char*) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX)))
+  ((const unsigned char *) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX)))
 #define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \
   do { \
     unsigned char save;  unsigned char *text; \
@@ -56,10 +57,9 @@ extern struct obstack *saveable_obstack;
 extern struct obstack temporary_obstack;
 extern struct obstack permanent_obstack;
 
-/* This is true if the user specified a `.java' file on the command
-   line.  Otherwise it is 0.  FIXME: this is temporary, until our
-   .java parser is fully working.  */
-int saw_java_source = 0;
+/* Set to non-zero value in order to emit class initilization code
+   before static field references.  */
+extern int always_initialize_class_p;
 
 /* The class we are currently processing. */
 tree current_class = NULL_TREE;
@@ -76,16 +76,24 @@ static tree current_field = NULL_TREE;
 /* The METHOD_DECL for the current method.  */
 static tree current_method = NULL_TREE;
 
+/* The Java .class file that provides main_class;  the main input file. */
+static struct JCF main_jcf[1];
+
 /* Declarations of some functions used here.  */
-static tree give_name_to_class PROTO ((JCF *jcf, int index));
-void parse_zip_file_entries PROTO (());
-void process_zip_dir PROTO (());
-static void parse_source_file PROTO ((tree));
-static void jcf_parse_source PROTO ((JCF *));
+static tree give_name_to_class PARAMS ((JCF *jcf, int index));
+static void parse_zip_file_entries PARAMS ((void));
+static void process_zip_dir PARAMS ((void));
+static void parse_source_file PARAMS ((tree));
+static void jcf_parse_source PARAMS ((void));
+static int jcf_figure_file_type PARAMS ((JCF *));
+static int find_in_current_zip PARAMS ((const char *, struct JCF **));
+static void parse_class_file PARAMS ((void));
+static void set_source_filename PARAMS ((JCF *, int));
+static int predefined_filename_p PARAMS ((tree));
 
 /* Handle "SourceFile" attribute. */
 
-void
+static void
 set_source_filename (jcf, index)
      JCF *jcf;
      int index;
@@ -177,6 +185,32 @@ set_source_filename (jcf, index)
   DECL_FUNCTION_THROWS (current_method) = nreverse (list); \
 }
 
+/* Link seen inner classes to their outer context and register the
+   inner class to its outer context. They will be later loaded.  */
+#define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT)                             \
+{                                                                        \
+  int c = (count);                                                       \
+  while (c--)                                                            \
+    {                                                                    \
+      tree class = get_class_constant (jcf, JCF_readu2 (jcf));           \
+      if (!CLASS_COMPLETE_P (class))                                     \
+       {                                                                 \
+         tree outer = TYPE_NAME (get_class_constant (jcf,                \
+                                                     JCF_readu2 (jcf))); \
+         tree alias = get_name_constant (jcf, JCF_readu2 (jcf));         \
+         tree decl = TYPE_NAME (class);                                  \
+         JCF_SKIP (jcf, 2);                                              \
+         IDENTIFIER_GLOBAL_VALUE (alias) = decl;                         \
+         DECL_CONTEXT (decl) = outer;                                    \
+         DECL_INNER_CLASS_LIST (outer) =                                 \
+           tree_cons (decl, alias, DECL_INNER_CLASS_LIST (outer));       \
+         CLASS_COMPLETE_P (class) = 1;                                   \
+       }                                                                 \
+      else                                                               \
+       JCF_SKIP (jcf, 6);                                                \
+    }                                                                    \
+}
+
 #include "jcf-reader.c"
 
 static int yydebug;
@@ -296,10 +330,10 @@ get_constant (jcf, index)
       {
        extern struct obstack *expression_obstack;
        tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index));
-       char *utf8_ptr = IDENTIFIER_POINTER (name);
+       const char *utf8_ptr = IDENTIFIER_POINTER (name);
        unsigned char *str_ptr;
        int utf8_len = IDENTIFIER_LENGTH (name);
-       unsigned char *str = (unsigned char*)utf8_ptr;
+       const unsigned char *str = (const unsigned char *)utf8_ptr;
        int i = utf8_len;
        int str_len;
 
@@ -320,7 +354,7 @@ get_constant (jcf, index)
        TREE_STRING_POINTER (value)
          = obstack_alloc (expression_obstack, 2 * str_len);
        str_ptr = (unsigned char *) TREE_STRING_POINTER (value);
-       str = (unsigned char*)utf8_ptr;
+       str = (const unsigned char *)utf8_ptr;
        for (i = 0; i < str_len; i++)
          {
            int char_value;
@@ -419,7 +453,7 @@ get_class_constant (JCF *jcf , int i)
     {
       int name_index = JPOOL_USHORT1 (jcf, i);
       /* verify_constant_pool confirmed that name_index is a CONSTANT_Utf8. */
-      char *name = JPOOL_UTF_DATA (jcf, name_index);
+      const char *name = JPOOL_UTF_DATA (jcf, name_index);
       int nlength = JPOOL_UTF_LENGTH (jcf, name_index);
       if (name[0] == '[')  /* Handle array "classes". */
          type = TREE_TYPE (parse_signature_string (name, nlength));
@@ -436,22 +470,6 @@ get_class_constant (JCF *jcf , int i)
   return type;
 }
 
-void
-DEFUN(jcf_out_of_synch, (jcf),
-      JCF *jcf)
-{
-  char *source = strdup (jcf->filename);
-  int i = strlen (source);
-
-  while (source[i] != '.')
-    i--;
-
-  source [i] = '\0';
-  warning ("Class file `%s' out of synch with `%s.java'", 
-          jcf->filename, source);
-  free (source);
-}
-
 /* Read a class with the fully qualified-name NAME.
    Return 1 iff we read the requested file.
    (It is still possible we failed if the file did not
@@ -465,38 +483,32 @@ read_class (name)
   tree save_current_class = current_class;
   char *save_input_filename = input_filename;
   JCF *save_current_jcf = current_jcf;
-  long saved_pos;
+  long saved_pos = 0;
   if (current_jcf->read_state)
     saved_pos = ftell (current_jcf->read_state);
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
 
   /* Search in current zip first.  */
-  if (find_in_current_zip (IDENTIFIER_POINTER (name),
-                          IDENTIFIER_LENGTH (name), &jcf) == 0)
-    /* FIXME: until the `.java' parser is fully working, we only
-       look for a .java file when one was mentioned on the
-       command line.  This lets us test the .java parser fairly
-       easily, without compromising our ability to use the
-       .class parser without fear.  */
-    if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name),
-                    &this_jcf, saw_java_source) == 0)
-      {
-       pop_obstacks ();        /* FIXME: one pop_obstack() per function */
-       return 0;
-      }
-    else
-      {
-        this_jcf.seen_in_zip = 0;
-        current_jcf = &this_jcf;
-       if (this_jcf.outofsynch)
-         jcf_out_of_synch (current_jcf);
-      }
+  if (find_in_current_zip (IDENTIFIER_POINTER (name), &jcf) == 0)
+    {
+      if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name),
+                     &this_jcf, 1) == 0)
+       {
+         pop_obstacks ();      /* FIXME: one pop_obstack() per function */
+         return 0;
+       }
+      else
+       {
+         this_jcf.seen_in_zip = 0;
+         current_jcf = &this_jcf;
+       }
+    }
   else
     current_jcf = jcf;
 
   if (current_jcf->java_source)
-    jcf_parse_source (current_jcf);
+    jcf_parse_source ();
   else {
     java_parser_context_save_global ();
     java_push_parser_context ();
@@ -544,25 +556,13 @@ load_class (class_or_name, verbose)
     name = DECL_NAME (TYPE_NAME (class_or_name));
 
   if (read_class (name) == 0 && verbose)
-    {
-      error ("Cannot find file for class %s.",
-            IDENTIFIER_POINTER (name));
-      if (TREE_CODE (class_or_name) == RECORD_TYPE)
-       TYPE_SIZE (class_or_name) = error_mark_node;
-#if 0
-      /* FIXME: what to do here?  */
-      if (!strcmp (classpath, DEFAULT_CLASS_PATH))
-       fatal ("giving up");
-#endif
-      return;
-    }
+    fatal ("Cannot find file for class %s.", IDENTIFIER_POINTER (name));
 }
 
 /* Parse a source file when JCF refers to a source file.  */
 
-void
-jcf_parse_source (jcf)
-     JCF *jcf;
+static void
+jcf_parse_source ()
 {
   tree file;
 
@@ -591,6 +591,7 @@ jcf_parse (jcf)
      JCF* jcf;
 {
   int i, code;
+  tree current;
 
   if (jcf_parse_preamble (jcf) != 0)
     fatal ("Not a valid Java .class file.\n");
@@ -605,7 +606,8 @@ jcf_parse (jcf)
   if (main_class == NULL_TREE)
     main_class = current_class;
   if (! quiet_flag && TYPE_NAME (current_class))
-    fprintf (stderr, " class %s",
+    fprintf (stderr, " %s %s",
+            (jcf->access_flags & ACC_INTERFACE) ? "interface" : "class", 
             IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
   if (CLASS_LOADED_P (current_class))
     return;
@@ -642,26 +644,24 @@ jcf_parse (jcf)
   else
     all_class_list = tree_cons (NULL_TREE, 
                                TYPE_NAME (current_class), all_class_list );
+
+  /* And if we came accross inner classes, load them now. */
+  for (current = DECL_INNER_CLASS_LIST (TYPE_NAME (current_class)); current;
+       current = TREE_CHAIN (current))
+    load_class (DECL_NAME (TREE_PURPOSE (current)), 1);
+
   pop_obstacks ();
 }
 
 void
 init_outgoing_cpool ()
 {
-  current_constant_pool_data_ref = NULL_TREE; 
-  if (outgoing_cpool == NULL)
-    {
-      static CPool outgoing_cpool_buffer;
-      outgoing_cpool = &outgoing_cpool_buffer;
-      CPOOL_INIT(outgoing_cpool);
-    }
-  else
-    {
-      CPOOL_REINIT(outgoing_cpool);
-    }
+  current_constant_pool_data_ref = NULL_TREE;
+  outgoing_cpool = (struct CPool *)xmalloc (sizeof (struct CPool));
+  bzero (outgoing_cpool, sizeof (struct CPool));
 }
 
-void
+static void
 parse_class_file ()
 {
   tree method;
@@ -675,6 +675,10 @@ parse_class_file ()
   debug_start_source_file (input_filename);
   init_outgoing_cpool ();
 
+  /* Currently we always have to emit calls to _Jv_InitClass when
+     compiling from class files.  */
+  always_initialize_class_p = 1;
+
   for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class));
        method != NULL_TREE; method = TREE_CHAIN (method))
     {
@@ -726,7 +730,7 @@ parse_class_file ()
   if (flag_emit_class_files)
     write_classfile (current_class);
 
-  finish_class (current_class);
+  finish_class ();
 
   debug_end_source_file (save_lineno);
   input_filename = save_input_filename;
@@ -743,6 +747,8 @@ parse_source_file (file)
   /* Mark the file as parsed */
   HAS_BEEN_ALREADY_PARSED_P (file) = 1;
 
+  jcf_dependency_add_file (input_filename, 0);
+
   lang_init_source (1);                    /* Error msgs have no method prototypes */
 
   java_init_lex ();                /* Initialize the parser */
@@ -754,13 +760,27 @@ parse_source_file (file)
   java_parse_abort_on_error ();
   java_check_circular_reference (); /* Check on circular references */
   java_parse_abort_on_error ();
+  java_fix_constructors ();        /* Fix the constructors */
+  java_parse_abort_on_error ();
+  java_reorder_fields ();          /* Reorder the fields */
+}
+
+static int
+predefined_filename_p (node)
+     tree node;
+{
+  int i;
+  for (i = 0; i < predef_filenames_size; i++)
+    if (predef_filenames [i] == node)
+      return 1;
+  return 0;
 }
 
 int
 yyparse ()
 {
   int several_files = 0;
-  char *list = strdup (input_filename), *next;
+  char *list = xstrdup (input_filename), *next;
   tree node, current_file_list = NULL_TREE;
 
   do 
@@ -775,21 +795,51 @@ yyparse ()
       if (list[0]) 
        {
          char *value;
+         tree id;
+         int twice = 0;
 
          int len = strlen (list);
-         /* FIXME: this test is only needed until our .java parser is
-            fully capable.  */
-         if (len > 5 && ! strcmp (&list[len - 5], ".java"))
-           saw_java_source = 1;
 
          if (*list != '/' && several_files)
            obstack_grow (&temporary_obstack, "./", 2);
 
          obstack_grow0 (&temporary_obstack, list, len);
          value = obstack_finish (&temporary_obstack);
-         node = get_identifier (value);
-         IS_A_COMMAND_LINE_FILENAME_P (node) = 1;
-         current_file_list = tree_cons (NULL_TREE, node, current_file_list);
+
+         /* Exclude file that we see twice on the command line. For
+            all files except {Class,Error,Object,RuntimeException,String,
+            Throwable}.java we can rely on maybe_get_identifier. For
+            these files, we need to do a linear search of
+            current_file_list. This search happens only for these
+            files, presumably only when we're recompiling libgcj. */
+            
+         if ((id = maybe_get_identifier (value)))
+           {
+             if (predefined_filename_p (id))
+               {
+                 tree c;
+                 for (c = current_file_list; c; c = TREE_CHAIN (c))
+                   if (TREE_VALUE (c) == id)
+                     twice = 1;
+               }
+             else
+               twice = 1;
+           }
+
+         if (twice)
+           {
+             char *saved_input_filename = input_filename;
+             input_filename = value;
+             warning ("source file seen twice on command line and will be compiled only once.");
+             input_filename = saved_input_filename;
+           }
+         else
+           {
+             node = get_identifier (value);
+             IS_A_COMMAND_LINE_FILENAME_P (node) = 1;
+             current_file_list = tree_cons (NULL_TREE, node, 
+                                            current_file_list);
+           }
        }
       list = next;
     }
@@ -853,7 +903,7 @@ yyparse ()
 static struct ZipFileCache *localToFile;
 
 /* Process all class entries found in the zip file.  */
-void
+static void
 parse_zip_file_entries (void)
 {
   struct ZipDirectory *zdir;
@@ -869,7 +919,7 @@ parse_zip_file_entries (void)
        continue;
 
       class = lookup_class (get_identifier (ZIPDIR_FILENAME (zdir)));
-      current_jcf = TYPE_LANG_SPECIFIC (class)->jcf;
+      current_jcf = TYPE_JCF (class);
       current_class = class;
 
       if ( !CLASS_LOADED_P (class))
@@ -894,7 +944,7 @@ parse_zip_file_entries (void)
 /* Read all the entries of the zip file, creates a class and a JCF. Sets the
    jcf up for further processing and link it to the created class.  */
 
-void process_zip_dir()
+static void process_zip_dir()
 {
   int i;
   ZipDirectory *zdir;
@@ -946,17 +996,15 @@ void process_zip_dir()
       jcf->classname   = class_name;
       jcf->filename    = file_name;
 
-      TYPE_LANG_SPECIFIC (class) = 
-        (struct lang_type *) perm_calloc (1, sizeof (struct lang_type));
-      TYPE_LANG_SPECIFIC (class)->jcf = jcf;
+      TYPE_JCF (class) = jcf;
     }
 }
 
 /* Lookup class NAME and figure whether is a class already found in the current
    zip file.  */
-int
+static int
 DEFUN(find_in_current_zip, (name, length, jcf),
-      char *name AND int length AND JCF **jcf)
+      const char *name AND JCF **jcf)
 {
   JCF *local_jcf;
   tree class_name = maybe_get_identifier (name), class, icv;
@@ -970,16 +1018,16 @@ DEFUN(find_in_current_zip, (name, length, jcf),
   class = TREE_TYPE (icv);
 
   /* Doesn't have jcf specific info ? It's not ours */
-  if (!TYPE_LANG_SPECIFIC (class) || !TYPE_LANG_SPECIFIC (class)->jcf)
+  if (!TYPE_JCF (class))
     return 0;
 
-  *jcf = local_jcf = TYPE_LANG_SPECIFIC (class)->jcf;
+  *jcf = local_jcf = TYPE_JCF (class);
   fseek (local_jcf->read_state, local_jcf->zip_offset, SEEK_SET);
   return 1;
 }
 
 /* Figure what kind of file we're dealing with */
-int
+static int
 DEFUN(jcf_figure_file_type, (jcf),
       JCF *jcf)
 {
@@ -1000,7 +1048,7 @@ DEFUN(jcf_figure_file_type, (jcf),
       && !open_in_zip (jcf, input_filename, NULL, 0))
     {
       localToFile = ALLOC (sizeof (struct ZipFileCache));
-      bcopy (SeenZipFiles, localToFile, sizeof (struct ZipFileCache));
+      bcopy ((PTR) SeenZipFiles, (PTR) localToFile, sizeof (struct ZipFileCache));
       process_zip_dir ();      /* Register all the class defined there */
       return JCF_ZIP;
     }