aboutsummaryrefslogtreecommitdiff
path: root/gcc/java/jcf-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/java/jcf-parse.c')
-rw-r--r--gcc/java/jcf-parse.c390
1 files changed, 247 insertions, 143 deletions
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index cdcbcedd8e1..58dd7223fac 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -1,5 +1,5 @@
/* Parser for Java(TM) .class files.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -32,6 +32,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "java-except.h"
#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)
@@ -55,34 +57,35 @@ 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;
+
/* The class we are currently processing. */
tree current_class = NULL_TREE;
/* The class we started with. */
tree main_class = NULL_TREE;
-/* The FIELD_DECL for the current field. */
+/* List of all class DECL seen so far. */
+tree all_class_list = NULL_TREE;
+
+/* The FIELD_DECL for the current field. */
static tree current_field = NULL_TREE;
+/* The METHOD_DECL for the current method. */
static tree current_method = NULL_TREE;
+/* Declarations of some functions used here. */
static tree give_name_to_class PROTO ((JCF *jcf, int index));
-
-void parse_zip_file_entries (void);
-void process_zip_dir();
-
-/* Source file compilation declarations */
-static void parse_source_file ();
-extern int java_error_count;
-#define java_parse_abort_on_error() \
- { \
- if (java_error_count) \
- { \
- java_report_errors (); \
- java_pop_parser_context (); \
- return; \
- } \
- }
+static void parse_zip_file_entries PROTO ((void));
+static void process_zip_dir PROTO ((void));
+static void parse_source_file PROTO ((tree));
+static void jcf_parse_source PROTO ((void));
+static int jcf_figure_file_type PROTO ((JCF *));
+static int find_in_current_zip PROTO ((char *, struct JCF **));
+static void parse_class_file PROTO ((void));
/* Handle "SourceFile" attribute. */
@@ -131,7 +134,7 @@ set_source_filename (jcf, index)
#define HANDLE_CONSTANTVALUE(INDEX) \
{ tree constant; int index = INDEX; \
- if (JPOOL_TAG (jcf, index) == CONSTANT_String) { \
+ if (! flag_emit_class_files && JPOOL_TAG (jcf, index) == CONSTANT_String) { \
tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); \
constant = build_utf8_ref (name); \
} \
@@ -166,6 +169,18 @@ set_source_filename (jcf, index)
DECL_LINENUMBERS_OFFSET (current_method) = JCF_TELL (jcf) - 2; \
JCF_SKIP (jcf, n * 4); }
+#define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
+{ \
+ int n = COUNT; \
+ tree list = DECL_FUNCTION_THROWS (current_method); \
+ while (--n >= 0) \
+ { \
+ tree thrown_class = get_class_constant (jcf, JCF_readu2 (jcf)); \
+ list = tree_cons (NULL_TREE, thrown_class, list); \
+ } \
+ DECL_FUNCTION_THROWS (current_method) = nreverse (list); \
+}
+
#include "jcf-reader.c"
static int yydebug;
@@ -270,10 +285,12 @@ get_constant (jcf, index)
#ifdef REAL_ARITHMETIC
d = REAL_VALUE_FROM_TARGET_DOUBLE (num);
#else
- union { double d; jint i[2]; } u;
- u.i[0] = (jint) num[0];
- u.i[1] = (jint) num[1];
- d = u.d;
+ {
+ union { double d; jint i[2]; } u;
+ u.i[0] = (jint) num[0];
+ u.i[1] = (jint) num[1];
+ d = u.d;
+ }
#endif
value = build_real (double_type_node, d);
break;
@@ -302,6 +319,7 @@ get_constant (jcf, index)
}
value = make_node (STRING_CST);
+ TREE_TYPE (value) = build_pointer_type (string_type_node);
TREE_STRING_LENGTH (value) = 2 * str_len;
TREE_STRING_POINTER (value)
= obstack_alloc (expression_obstack, 2 * str_len);
@@ -408,7 +426,7 @@ get_class_constant (JCF *jcf , int i)
char *name = JPOOL_UTF_DATA (jcf, name_index);
int nlength = JPOOL_UTF_LENGTH (jcf, name_index);
if (name[0] == '[') /* Handle array "classes". */
- type = parse_signature_string (name, nlength);
+ type = TREE_TYPE (parse_signature_string (name, nlength));
else
{
tree cname = unmangle_classname (name, nlength);
@@ -423,22 +441,6 @@ get_class_constant (JCF *jcf , int i)
}
void
-fix_classpath ()
-{
- static char default_path[] = DEFAULT_CLASS_PATH;
-
- if (classpath == NULL)
- {
- classpath = (char *) getenv ("CLASSPATH");
- if (classpath == NULL)
- {
- warning ("CLASSPATH not set");
- classpath = default_path;
- }
- }
-}
-
-void
DEFUN(jcf_out_of_synch, (jcf),
JCF *jcf)
{
@@ -454,45 +456,37 @@ DEFUN(jcf_out_of_synch, (jcf),
free (source);
}
-/* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if
- called from the parser, otherwise it's a RECORD_TYPE node. If
- VERBOSE is 1, print error message on failure to load a class. */
+/* 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
+ define the class it is supposed to.) */
-void
-load_class (class_or_name, verbose)
- tree class_or_name;
- int verbose;
+int
+read_class (name)
+ tree name;
{
JCF this_jcf, *jcf;
- tree name = (TREE_CODE (class_or_name) == IDENTIFIER_NODE ?
- class_or_name : DECL_NAME (TYPE_NAME (class_or_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);
- if (!classpath)
- fix_classpath ();
/* Search in current zip first. */
- if (find_in_current_zip (IDENTIFIER_POINTER (name),
- IDENTIFIER_LENGTH (name), &jcf) == 0)
+ if (find_in_current_zip (IDENTIFIER_POINTER (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, 1) == 0)
+ &this_jcf, saw_java_source) == 0)
{
- if (verbose)
- {
- error ("Cannot find class file class %s.",
- IDENTIFIER_POINTER (name));
- TYPE_SIZE (class_or_name) = error_mark_node;
- if (!strcmp (classpath, DEFAULT_CLASS_PATH))
- fatal ("giving up");
- pop_obstacks (); /* FIXME: one pop_obstack() per function */
- }
- return;
+ pop_obstacks (); /* FIXME: one pop_obstack() per function */
+ return 0;
}
else
{
@@ -505,17 +499,18 @@ load_class (class_or_name, verbose)
current_jcf = jcf;
if (current_jcf->java_source)
- jcf_parse_source (current_jcf);
+ jcf_parse_source ();
else {
- int saved_lineno = lineno;
+ java_parser_context_save_global ();
+ java_push_parser_context ();
input_filename = current_jcf->filename;
jcf_parse (current_jcf);
- lineno = saved_lineno;
+ java_pop_parser_context (0);
+ java_parser_context_restore_global ();
}
if (!current_jcf->seen_in_zip)
JCF_FINISH (current_jcf);
-/* DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1;*/
pop_obstacks ();
current_class = save_current_class;
@@ -523,33 +518,77 @@ load_class (class_or_name, verbose)
current_jcf = save_current_jcf;
if (current_jcf->read_state)
fseek (current_jcf->read_state, saved_pos, SEEK_SET);
+ return 1;
}
-/* Parse a source file when JCF refers to a source file. This piece
- needs further work as far as error handling and report. */
+/* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if
+ called from the parser, otherwise it's a RECORD_TYPE node. If
+ VERBOSE is 1, print error message on failure to load a class. */
-int
-jcf_parse_source (jcf)
- JCF *jcf;
+/* Replace calls to load_class by having callers call read_class directly
+ - and then perhaps rename read_class to load_class. FIXME */
+
+void
+load_class (class_or_name, verbose)
+ tree class_or_name;
+ int verbose;
{
- java_parser_context_save_global ();
+ tree name;
+
+ /* class_or_name can be the name of the class we want to load */
+ if (TREE_CODE (class_or_name) == IDENTIFIER_NODE)
+ name = class_or_name;
+ /* In some cases, it's a dependency that we process earlier that
+ we though */
+ else if (TREE_CODE (class_or_name) == TREE_LIST)
+ name = TYPE_NAME (TREE_PURPOSE (class_or_name));
+ /* Or it's a type in the making */
+ else
+ name = DECL_NAME (TYPE_NAME (class_or_name));
- input_filename = current_jcf->filename;
- if (!(finput = fopen (input_filename, "r")))
- fatal ("input file `%s' just disappeared - jcf_parse_source",
- input_filename);
+ 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;
+ }
+}
- parse_source_file (1); /* Parse only */
- if (current_class && TREE_TYPE (current_class))
- CLASS_FROM_SOURCE_P (TREE_TYPE (current_class)) = 1;
+/* Parse a source file when JCF refers to a source file. */
- fclose (finput);
+static void
+jcf_parse_source ()
+{
+ tree file;
+
+ java_parser_context_save_global ();
+ java_push_parser_context ();
+ input_filename = current_jcf->filename;
+ file = get_identifier (input_filename);
+ if (!HAS_BEEN_ALREADY_PARSED_P (file))
+ {
+ if (!(finput = fopen (input_filename, "r")))
+ fatal ("input file `%s' just disappeared - jcf_parse_source",
+ input_filename);
+ parse_source_file (file);
+ if (fclose (finput))
+ fatal ("can't close input file `%s' stream - jcf_parse_source",
+ input_filename);
+ }
+ java_pop_parser_context (IS_A_COMMAND_LINE_FILENAME_P (file));
java_parser_context_restore_global ();
}
/* Parse the .class file JCF. */
-int
+void
jcf_parse (jcf)
JCF* jcf;
{
@@ -570,6 +609,8 @@ jcf_parse (jcf)
if (! quiet_flag && TYPE_NAME (current_class))
fprintf (stderr, " class %s",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class))));
+ if (CLASS_LOADED_P (current_class))
+ return;
CLASS_LOADED_P (current_class) = 1;
for (i = 1; i < JPOOL_SIZE(jcf); i++)
@@ -598,6 +639,11 @@ jcf_parse (jcf)
push_obstacks (&permanent_obstack, &permanent_obstack);
layout_class (current_class);
+ if (current_class == object_type_node)
+ layout_class_methods (object_type_node);
+ else
+ all_class_list = tree_cons (NULL_TREE,
+ TYPE_NAME (current_class), all_class_list );
pop_obstacks ();
}
@@ -617,13 +663,15 @@ init_outgoing_cpool ()
}
}
-void
+static void
parse_class_file ()
{
tree method;
char *save_input_filename = input_filename;
int save_lineno = lineno;
+ java_layout_seen_class_methods ();
+
input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class));
lineno = 0;
debug_start_source_file (input_filename);
@@ -679,83 +727,135 @@ parse_class_file ()
if (flag_emit_class_files)
write_classfile (current_class);
- make_class_data (current_class);
- register_class ();
- rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0);
+
+ finish_class (current_class);
debug_end_source_file (save_lineno);
input_filename = save_input_filename;
lineno = save_lineno;
}
-/* Parse a source file, as pointed by the current JCF. If PARSE_ONLY
- is non zero, we're not parsing a file found on the command line and
- we skip things related to code generation. */
+/* Parse a source file, as pointed by the current value of INPUT_FILENAME. */
static void
-parse_source_file (parse_only)
- int parse_only;
+parse_source_file (file)
+ tree file;
{
+ int save_error_count = java_error_count;
+ /* Mark the file as parsed */
+ HAS_BEEN_ALREADY_PARSED_P (file) = 1;
+
lang_init_source (1); /* Error msgs have no method prototypes */
- java_push_parser_context ();
+
java_init_lex (); /* Initialize the parser */
java_parse_abort_on_error ();
+
java_parse (); /* Parse and build partial tree nodes. */
java_parse_abort_on_error ();
java_complete_class (); /* Parse unsatisfied class decl. */
java_parse_abort_on_error ();
java_check_circular_reference (); /* Check on circular references */
java_parse_abort_on_error ();
- java_check_methods (); /* Check the methods */
- java_parse_abort_on_error ();
- java_layout_classes ();
- java_parse_abort_on_error ();
- if (!parse_only)
- {
- lang_init_source (2); /* Error msgs have method prototypes */
- java_complete_expand_methods (); /* Complete and expand method bodies */
- java_parse_abort_on_error ();
- java_expand_finals (); /* Expand and check the finals */
- java_parse_abort_on_error ();
- java_check_final (); /* Check unitialized final */
- java_parse_abort_on_error ();
- if (! flag_emit_class_files)
- emit_register_class ();
- java_report_errors (); /* Final step for this file */
- }
- if (flag_emit_class_files)
- write_classfile (current_class);
- java_pop_parser_context ();
}
int
yyparse ()
{
- /* Everything migh be enclosed within a loop processing each file after
- the other one. */
+ int several_files = 0;
+ char *list = strdup (input_filename), *next;
+ tree node, current_file_list = NULL_TREE;
- switch (jcf_figure_file_type (current_jcf))
+ do
{
- case JCF_ZIP:
- parse_zip_file_entries ();
- emit_register_class ();
- break;
- case JCF_CLASS:
- jcf_parse (current_jcf);
- parse_class_file ();
- emit_register_class ();
- break;
- case JCF_SOURCE:
- parse_source_file (0); /* Parse and generate */
- break;
+ next = strchr (list, '&');
+ if (next)
+ {
+ *next++ = '\0';
+ several_files = 1;
+ }
+
+ if (list[0])
+ {
+ char *value;
+
+ 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);
+ }
+ list = next;
}
+ while (next);
+
+ current_jcf = main_jcf;
+ current_file_list = nreverse (current_file_list);
+ for (node = current_file_list; node; node = TREE_CHAIN (node))
+ {
+ tree name = TREE_VALUE (node);
+
+ /* Skip already parsed files */
+ if (HAS_BEEN_ALREADY_PARSED_P (name))
+ continue;
+
+ /* Close previous descriptor, if any */
+ if (main_jcf->read_state && fclose (main_jcf->read_state))
+ fatal ("failed to close input file `%s' - yyparse",
+ (main_jcf->filename ? main_jcf->filename : "<unknown>"));
+
+ /* Set jcf up and open a new file */
+ JCF_ZERO (main_jcf);
+ main_jcf->read_state = fopen (IDENTIFIER_POINTER (name), "rb");
+ if (main_jcf->read_state == NULL)
+ pfatal_with_name (IDENTIFIER_POINTER (name));
+
+ /* Set new input_filename and finput */
+ finput = main_jcf->read_state;
+#ifdef IO_BUFFER_SIZE
+ setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE),
+ _IOFBF, IO_BUFFER_SIZE);
+#endif
+ input_filename = IDENTIFIER_POINTER (name);
+ main_jcf->filbuf = jcf_filbuf_from_stdio;
+
+ switch (jcf_figure_file_type (current_jcf))
+ {
+ case JCF_ZIP:
+ parse_zip_file_entries ();
+ break;
+ case JCF_CLASS:
+ jcf_parse (current_jcf);
+ parse_class_file ();
+ break;
+ case JCF_SOURCE:
+ java_push_parser_context ();
+ java_parser_context_save_global ();
+ parse_source_file (name);
+ java_parser_context_restore_global ();
+ java_pop_parser_context (1);
+ break;
+ }
+ }
+
+ java_expand_classes ();
+ if (!java_report_errors () && !flag_syntax_only)
+ emit_register_classes ();
return 0;
}
static struct ZipFileCache *localToFile;
/* Process all class entries found in the zip file. */
-void
+static void
parse_zip_file_entries (void)
{
struct ZipDirectory *zdir;
@@ -780,21 +880,23 @@ parse_zip_file_entries (void)
jcf_parse (current_jcf);
}
- input_filename = current_jcf->filename;
-
- parse_class_file ();
- FREE (current_jcf->buffer); /* No longer necessary */
- /* Note: there is a way to free this buffer right after a class seen
- in a zip file has been parsed. The idea is the set its jcf in such
- a way that buffer will be reallocated the time the code for the class
- will be generated. FIXME. */
+ if (TYPE_SIZE (current_class) != error_mark_node)
+ {
+ input_filename = current_jcf->filename;
+ parse_class_file ();
+ FREE (current_jcf->buffer); /* No longer necessary */
+ /* Note: there is a way to free this buffer right after a
+ class seen in a zip file has been parsed. The idea is the
+ set its jcf in such a way that buffer will be reallocated
+ the time the code for the class will be generated. FIXME. */
+ }
}
}
/* 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;
@@ -854,9 +956,9 @@ void process_zip_dir()
/* 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)
+ char *name AND JCF **jcf)
{
JCF *local_jcf;
tree class_name = maybe_get_identifier (name), class, icv;
@@ -879,7 +981,7 @@ DEFUN(find_in_current_zip, (name, length, jcf),
}
/* Figure what kind of file we're dealing with */
-int
+static int
DEFUN(jcf_figure_file_type, (jcf),
JCF *jcf)
{
@@ -895,7 +997,9 @@ DEFUN(jcf_figure_file_type, (jcf),
if (magic == 0xcafebabe)
return JCF_CLASS;
- if (!open_in_zip (jcf, input_filename, NULL))
+ /* FIXME: is it a system file? */
+ if (magic == (JCF_u4)ZIPMAGIC
+ && !open_in_zip (jcf, input_filename, NULL, 0))
{
localToFile = ALLOC (sizeof (struct ZipFileCache));
bcopy (SeenZipFiles, localToFile, sizeof (struct ZipFileCache));