📄 jcf-parse.c
字号:
/* Parser for Java(TM) .class files. Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.Java and all Java-based marks are trademarks or registered trademarksof Sun Microsystems, Inc. in the United States and other countries.The Free Software Foundation is independent of Sun Microsystems, Inc. *//* Written by Per Bothner <bothner@cygnus.com> */#include "config.h"#include "system.h"#include "tree.h"#include "obstack.h"#include "flags.h"#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)#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)))#define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \ do { \ unsigned char save; unsigned char *text; \ JCF_FILL (JCF, (LENGTH)+1); /* Make sure we read 1 byte beyond string. */ \ text = (JCF)->read_ptr; \ save = text[LENGTH]; \ text[LENGTH] = 0; \ (JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \ text[LENGTH] = save; \ JCF_SKIP (JCF, LENGTH); } while (0)#include "jcf.h"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;/* 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;/* 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));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. */voidset_source_filename (jcf, index) JCF *jcf; int index;{ tree sfname_id = get_name_constant (jcf, index); char *sfname = IDENTIFIER_POINTER (sfname_id); if (input_filename != NULL) { int old_len = strlen (input_filename); int new_len = IDENTIFIER_LENGTH (sfname_id); /* Use the current input_filename (derived from the class name) if it has a directory prefix, but otherwise matches sfname. */ if (old_len > new_len && strcmp (sfname, input_filename + old_len - new_len) == 0 && (input_filename[old_len - new_len - 1] == '/' || input_filename[old_len - new_len - 1] == '\\')) return; } input_filename = sfname; DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname; if (current_class == main_class) main_input_filename = input_filename;}#define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX)#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \{ tree super_class = SUPER==0 ? NULL_TREE : get_class_constant (jcf, SUPER); \ current_class = give_name_to_class (jcf, THIS); \ set_super_info (ACCESS_FLAGS, current_class, super_class, INTERFACES_COUNT);}#define HANDLE_CLASS_INTERFACE(INDEX) \ add_interface (current_class, get_class_constant (jcf, INDEX))#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \{ int sig_index = SIGNATURE; \ current_field = add_field (current_class, get_name_constant (jcf, NAME), \ parse_signature (jcf, sig_index), ACCESS_FLAGS); \ set_java_signature (TREE_TYPE (current_field), JPOOL_UTF (jcf, sig_index)); }#define HANDLE_END_FIELDS() \ (current_field = NULL_TREE)#define HANDLE_CONSTANTVALUE(INDEX) \{ tree constant; int index = INDEX; \ 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); \ } \ else \ constant = get_constant (jcf, index); \ set_constant_value (current_field, constant); }#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ (current_method = add_method (current_class, ACCESS_FLAGS, \ get_name_constant (jcf, NAME), \ get_name_constant (jcf, SIGNATURE)), \ DECL_LOCALVARIABLES_OFFSET (current_method) = 0, \ DECL_LINENUMBERS_OFFSET (current_method) = 0)#define HANDLE_END_METHODS() \{ tree handle_type = CLASS_TO_HANDLE_TYPE (current_class); \ if (handle_type != current_class) layout_type (handle_type); }#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \{ DECL_MAX_STACK (current_method) = (MAX_STACK); \ DECL_MAX_LOCALS (current_method) = (MAX_LOCALS); \ DECL_CODE_LENGTH (current_method) = (CODE_LENGTH); \ DECL_CODE_OFFSET (current_method) = JCF_TELL (jcf); }#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \{ int n = (COUNT); \ DECL_LOCALVARIABLES_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ JCF_SKIP (jcf, n * 10); }#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \{ int n = (COUNT); \ 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;treeparse_signature (jcf, sig_index) JCF *jcf; int sig_index;{ if (sig_index <= 0 || sig_index >= JPOOL_SIZE(jcf) || JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8) fatal ("invalid field/method signature"); else { return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index), JPOOL_UTF_LENGTH (jcf, sig_index)); }}voidinit_lex (){ /* Make identifier nodes long enough for the language-specific slots. */ set_identifier_size (sizeof (struct lang_identifier));}voidset_yydebug (value) int value;{ yydebug = value;}treeget_constant (jcf, index) JCF *jcf; int index;{ tree value; int tag; if (index <= 0 || index >= JPOOL_SIZE(jcf)) goto bad; tag = JPOOL_TAG (jcf, index); if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) return (tree) jcf->cpool.data[index]; push_obstacks (&permanent_obstack, &permanent_obstack); switch (tag) { case CONSTANT_Integer: { jint num = JPOOL_INT(jcf, index); value = build_int_2 (num, num < 0 ? -1 : 0); TREE_TYPE (value) = int_type_node; break; } case CONSTANT_Long: { jint num = JPOOL_INT (jcf, index); HOST_WIDE_INT lo, hi; lshift_double (num, 0, 32, 64, &lo, &hi, 0); num = JPOOL_INT (jcf, index+1); add_double (lo, hi, num, 0, &lo, &hi); value = build_int_2 (lo, hi); TREE_TYPE (value) = long_type_node; force_fit_type (value, 0); break; }#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT case CONSTANT_Float: { jint num = JPOOL_INT(jcf, index); REAL_VALUE_TYPE d;#ifdef REAL_ARITHMETIC d = REAL_VALUE_FROM_TARGET_SINGLE (num);#else union { float f; jint i; } u; u.i = num; d = u.f;#endif value = build_real (float_type_node, d); break; } case CONSTANT_Double: { HOST_WIDE_INT num[2]; REAL_VALUE_TYPE d; HOST_WIDE_INT lo, hi; num[0] = JPOOL_INT (jcf, index); lshift_double (num[0], 0, 32, 64, &lo, &hi, 0); num[0] = JPOOL_INT (jcf, index+1); add_double (lo, hi, num[0], 0, &lo, &hi); if (FLOAT_WORDS_BIG_ENDIAN) { num[0] = hi; num[1] = lo; } else { num[0] = lo; num[1] = hi; }#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; }#endif value = build_real (double_type_node, d); break; }#endif /* TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT */ case CONSTANT_String: { extern struct obstack *expression_obstack; tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); char *utf8_ptr = IDENTIFIER_POINTER (name); unsigned char *str_ptr; int utf8_len = IDENTIFIER_LENGTH (name); unsigned char *str = (unsigned char*)utf8_ptr; int i = utf8_len; int str_len; /* Count the number of Unicode characters in the string, while checking for a malformed Utf8 string. */ for (str_len = 0; i > 0; str_len++) { int char_len = UT8_CHAR_LENGTH (*str); if (char_len < 0 || char_len > 2 || char_len > i) fatal ("bad string constant"); str += char_len; i -= char_len; } 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); str_ptr = (unsigned char *) TREE_STRING_POINTER (value); str = (unsigned char*)utf8_ptr; for (i = 0; i < str_len; i++) { int char_value; int char_len = UT8_CHAR_LENGTH (*str); switch (char_len) { case 1: char_value = *str++; break; case 2: char_value = *str++ & 0x1F; char_value = (char_value << 6) | (*str++ & 0x3F); break; case 3: char_value = *str_ptr++ & 0x0F; char_value = (char_value << 6) | (*str++ & 0x3F); char_value = (char_value << 6) | (*str++ & 0x3F); break; default: goto bad; } if (BYTES_BIG_ENDIAN) { *str_ptr++ = char_value >> 8; *str_ptr++ = char_value & 0xFF; } else { *str_ptr++ = char_value & 0xFF; *str_ptr++ = char_value >> 8; } } } break; default: goto bad; } pop_obstacks (); JPOOL_TAG(jcf, index) = tag | CONSTANT_ResolvedFlag; jcf->cpool.data [index] = (jword) value; return value; bad: fatal ("bad value constant type %d, index %d", JPOOL_TAG( jcf, index ), index);}treeget_name_constant (jcf, index) JCF *jcf; int index;{ tree name = get_constant (jcf, index); if (TREE_CODE (name) != IDENTIFIER_NODE) fatal ("bad nameandtype index %d", index); return name;}static treegive_name_to_class (jcf, i) JCF *jcf; int i;{ if (i <= 0 || i >= JPOOL_SIZE(jcf) || JPOOL_TAG (jcf, i) != CONSTANT_Class) fatal ("bad class index %d", i); else { tree this_class; int j = JPOOL_USHORT1 (jcf, i); /* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */ tree class_name = unmangle_classname (JPOOL_UTF_DATA (jcf, j), JPOOL_UTF_LENGTH (jcf, j)); this_class = lookup_class (class_name); input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class)); lineno = 0; if (main_input_filename == NULL && jcf == main_jcf) main_input_filename = input_filename; jcf->cpool.data[i] = (jword) this_class; JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; return this_class; }}/* Get the class of the CONSTANT_Class whose constant pool index is I. */treeget_class_constant (JCF *jcf , int i){ tree type; if (i <= 0 || i >= JPOOL_SIZE(jcf) || (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class) fatal ("bad class index %d", i); if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass) { 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); int nlength = JPOOL_UTF_LENGTH (jcf, name_index); if (name[0] == '[') /* Handle array "classes". */ type = TREE_TYPE (parse_signature_string (name, nlength)); else { tree cname = unmangle_classname (name, nlength); type = lookup_class (cname); } jcf->cpool.data[i] = (jword) type; JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; } else type = (tree) jcf->cpool.data[i]; return type;}voidDEFUN(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 define the class it is supposed to.) */intread_class (name) tree name;{ JCF this_jcf, *jcf; tree save_current_class = current_class; char *save_input_filename = input_filename; JCF *save_current_jcf = current_jcf; 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), &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); } else current_jcf = jcf; if (current_jcf->java_source) jcf_parse_source (); else { java_parser_context_save_global (); java_push_parser_context (); input_filename = current_jcf->filename; jcf_parse (current_jcf); java_pop_parser_context (0); java_parser_context_restore_global (); } if (!current_jcf->seen_in_zip) JCF_FINISH (current_jcf); pop_obstacks (); current_class = save_current_class; input_filename = save_input_filename; current_jcf = save_current_jcf; if (current_jcf->read_state) fseek (current_jcf->read_state, saved_pos, SEEK_SET); return 1;}/* 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. *//* Replace calls to load_class by having callers call read_class directly
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -