/* 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.
#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; \
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;
/* 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;
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;
{
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;
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;
{
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));
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
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 ();
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;
JCF* jcf;
{
int i, code;
+ tree current;
if (jcf_parse_preamble (jcf) != 0)
fatal ("Not a valid Java .class file.\n");
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;
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;
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))
{
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;
/* 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 */
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
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;
}
static struct ZipFileCache *localToFile;
/* Process all class entries found in the zip file. */
-void
+static void
parse_zip_file_entries (void)
{
struct ZipDirectory *zdir;
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))
/* 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;
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;
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)
{
&& !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;
}