| /* Source code parsing and tree node generation for the GNU compiler |
| for the Java(TM) language. |
| Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 |
| Free Software Foundation, Inc. |
| Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. |
| |
| Java and all Java-based marks are trademarks or registered trademarks |
| of Sun Microsystems, Inc. in the United States and other countries. |
| The Free Software Foundation is independent of Sun Microsystems, Inc. */ |
| |
| /* This file parses java source code and issues a tree node image |
| suitable for code generation (byte code and targeted CPU assembly |
| language). |
| |
| The grammar conforms to the Java grammar described in "The Java(TM) |
| Language Specification. J. Gosling, B. Joy, G. Steele. Addison Wesley |
| 1996, ISBN 0-201-63451-1" |
| |
| The following modifications were brought to the original grammar: |
| |
| method_body: added the rule '| block SC_TK' |
| static_initializer: added the rule 'static block SC_TK'. |
| |
| Note: All the extra rules described above should go away when the |
| empty_statement rule will work. |
| |
| statement_nsi: 'nsi' should be read no_short_if. |
| |
| Some rules have been modified to support JDK1.1 inner classes |
| definitions and other extensions. */ |
| |
| %{ |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include <dirent.h> |
| #include "tree.h" |
| #include "rtl.h" |
| #include "real.h" |
| #include "obstack.h" |
| #include "toplev.h" |
| #include "pretty-print.h" |
| #include "diagnostic.h" |
| #include "flags.h" |
| #include "java-tree.h" |
| #include "jcf.h" |
| #include "lex.h" |
| #include "parse.h" |
| #include "zipfile.h" |
| #include "convert.h" |
| #include "buffer.h" |
| #include "xref.h" |
| #include "function.h" |
| #include "except.h" |
| #include "ggc.h" |
| #include "debug.h" |
| #include "tree-inline.h" |
| #include "cgraph.h" |
| #include "target.h" |
| |
| /* Local function prototypes */ |
| static char *java_accstring_lookup (int); |
| static const char *accessibility_string (int); |
| static void classitf_redefinition_error (const char *,tree, tree, tree); |
| static void variable_redefinition_error (tree, tree, tree, int); |
| static tree create_class (int, tree, tree, tree); |
| static tree create_interface (int, tree, tree); |
| static void end_class_declaration (int); |
| static tree find_field (tree, tree); |
| static tree lookup_field_wrapper (tree, tree); |
| static int duplicate_declaration_error_p (tree, tree, tree); |
| static void register_fields (int, tree, tree); |
| static tree parser_qualified_classname (tree); |
| static int parser_check_super (tree, tree, tree); |
| static int parser_check_super_interface (tree, tree, tree); |
| static void check_modifiers_consistency (int); |
| static tree lookup_cl (tree); |
| static tree lookup_java_method2 (tree, tree, int); |
| static tree method_header (int, tree, tree, tree); |
| static void fix_method_argument_names (tree ,tree); |
| static tree method_declarator (tree, tree); |
| static void parse_warning_context (tree cl, const char *gmsgid, ...); |
| #ifdef USE_MAPPED_LOCATION |
| static void issue_warning_error_from_context |
| (source_location, const char *gmsgid, va_list *); |
| #else |
| static void issue_warning_error_from_context |
| (tree, const char *gmsgid, va_list *); |
| #endif |
| static void parse_ctor_invocation_error (void); |
| static tree parse_jdk1_1_error (const char *); |
| static void complete_class_report_errors (jdep *); |
| static int process_imports (void); |
| static void read_import_dir (tree); |
| static int find_in_imports_on_demand (tree, tree); |
| static void find_in_imports (tree, tree); |
| static void check_inner_class_access (tree, tree, tree); |
| static int check_pkg_class_access (tree, tree, bool, tree); |
| static void register_package (tree); |
| static tree resolve_package (tree, tree *, tree *); |
| static tree resolve_class (tree, tree, tree, tree); |
| static void declare_local_variables (int, tree, tree); |
| static void dump_java_tree (enum tree_dump_index, tree); |
| static void source_start_java_method (tree); |
| static void source_end_java_method (void); |
| static tree find_name_in_single_imports (tree); |
| static void check_abstract_method_header (tree); |
| static tree lookup_java_interface_method2 (tree, tree); |
| static tree resolve_expression_name (tree, tree *); |
| static tree maybe_create_class_interface_decl (tree, tree, tree, tree); |
| static int check_class_interface_creation (int, int, tree, tree, tree, tree); |
| static tree patch_method_invocation (tree, tree, tree, int, int *, tree *); |
| static tree resolve_and_layout (tree, tree); |
| static tree qualify_and_find (tree, tree, tree); |
| static tree resolve_no_layout (tree, tree); |
| static int invocation_mode (tree, int); |
| static tree find_applicable_accessible_methods_list (int, tree, tree, tree); |
| static void search_applicable_methods_list (int, tree, tree, tree, tree *, tree *); |
| static tree find_most_specific_methods_list (tree); |
| static int argument_types_convertible (tree, tree); |
| static tree patch_invoke (tree, tree, tree); |
| static int maybe_use_access_method (int, tree *, tree *); |
| static tree lookup_method_invoke (int, tree, tree, tree, tree); |
| static tree register_incomplete_type (int, tree, tree, tree); |
| static tree check_inner_circular_reference (tree, tree); |
| static tree check_circular_reference (tree); |
| static tree obtain_incomplete_type (tree); |
| static tree java_complete_lhs (tree); |
| static tree java_complete_tree (tree); |
| static tree maybe_generate_pre_expand_clinit (tree); |
| static int analyze_clinit_body (tree, tree); |
| static int maybe_yank_clinit (tree); |
| static void start_complete_expand_method (tree); |
| static void java_complete_expand_method (tree); |
| static void java_expand_method_bodies (tree); |
| static int unresolved_type_p (tree, tree *); |
| static void create_jdep_list (struct parser_ctxt *); |
| static tree build_expr_block (tree, tree); |
| static tree enter_block (void); |
| static tree exit_block (void); |
| static tree lookup_name_in_blocks (tree); |
| static void maybe_absorb_scoping_blocks (void); |
| static tree build_method_invocation (tree, tree); |
| static tree build_new_invocation (tree, tree); |
| static tree build_assignment (int, int, tree, tree); |
| static tree build_binop (enum tree_code, int, tree, tree); |
| static tree patch_assignment (tree, tree); |
| static tree patch_binop (tree, tree, tree); |
| static tree build_unaryop (int, int, tree); |
| static tree build_incdec (int, int, tree, int); |
| static tree patch_unaryop (tree, tree); |
| static tree build_cast (int, tree, tree); |
| static tree build_null_of_type (tree); |
| static tree patch_cast (tree, tree); |
| static int valid_ref_assignconv_cast_p (tree, tree, int); |
| static int valid_builtin_assignconv_identity_widening_p (tree, tree); |
| static int valid_cast_to_p (tree, tree); |
| static int valid_method_invocation_conversion_p (tree, tree); |
| static tree try_builtin_assignconv (tree, tree, tree); |
| static tree try_reference_assignconv (tree, tree); |
| static tree build_unresolved_array_type (tree); |
| static int build_type_name_from_array_name (tree, tree *); |
| static tree build_array_from_name (tree, tree, tree, tree *); |
| static tree build_array_ref (int, tree, tree); |
| static tree patch_array_ref (tree); |
| #ifdef USE_MAPPED_LOCATION |
| static tree make_qualified_name (tree, tree, source_location); |
| #else |
| static tree make_qualified_name (tree, tree, int); |
| #endif |
| static tree merge_qualified_name (tree, tree); |
| static tree make_qualified_primary (tree, tree, int); |
| static int resolve_qualified_expression_name (tree, tree *, tree *, tree *); |
| static void qualify_ambiguous_name (tree); |
| static tree resolve_field_access (tree, tree *, tree *); |
| static tree build_newarray_node (tree, tree, int); |
| static tree patch_newarray (tree); |
| static tree resolve_type_during_patch (tree); |
| static tree build_this (int); |
| static tree build_wfl_wrap (tree, int); |
| static tree build_return (int, tree); |
| static tree patch_return (tree); |
| static tree maybe_access_field (tree, tree, tree); |
| static int complete_function_arguments (tree); |
| static int check_for_static_method_reference (tree, tree, tree, tree, tree); |
| static int not_accessible_p (tree, tree, tree, int); |
| static void check_deprecation (tree, tree); |
| static int class_in_current_package (tree); |
| static tree build_if_else_statement (int, tree, tree, tree); |
| static tree patch_if_else_statement (tree); |
| static tree add_stmt_to_block (tree, tree, tree); |
| static tree patch_exit_expr (tree); |
| static tree build_labeled_block (int, tree); |
| static tree finish_labeled_statement (tree, tree); |
| static tree build_bc_statement (int, int, tree); |
| static tree patch_bc_statement (tree); |
| static tree patch_loop_statement (tree); |
| static tree build_new_loop (tree); |
| static tree build_loop_body (int, tree, int); |
| static tree finish_loop_body (int, tree, tree, int); |
| static tree build_debugable_stmt (int, tree); |
| static tree finish_for_loop (int, tree, tree, tree); |
| static tree patch_switch_statement (tree); |
| static tree string_constant_concatenation (tree, tree); |
| static tree build_string_concatenation (tree, tree); |
| static tree patch_string_cst (tree); |
| static tree patch_string (tree); |
| static tree encapsulate_with_try_catch (int, tree, tree, tree); |
| #ifdef USE_MAPPED_LOCATION |
| static tree build_assertion (source_location, tree, tree); |
| #else |
| static tree build_assertion (int, tree, tree); |
| #endif |
| static tree build_try_statement (int, tree, tree); |
| static tree build_try_finally_statement (int, tree, tree); |
| static tree patch_try_statement (tree); |
| static tree patch_synchronized_statement (tree, tree); |
| static tree patch_throw_statement (tree, tree); |
| #ifdef USE_MAPPED_LOCATION |
| static void check_thrown_exceptions (source_location, tree, tree); |
| #else |
| static void check_thrown_exceptions (int, tree, tree); |
| #endif |
| static int check_thrown_exceptions_do (tree); |
| static void purge_unchecked_exceptions (tree); |
| static bool ctors_unchecked_throws_clause_p (tree); |
| static void check_concrete_throws_clauses (tree, tree, tree, tree); |
| static void check_throws_clauses (tree, tree, tree); |
| static void finish_method_declaration (tree); |
| static tree build_super_invocation (tree); |
| static int verify_constructor_circularity (tree, tree); |
| static char *constructor_circularity_msg (tree, tree); |
| static tree build_this_super_qualified_invocation (int, tree, tree, int, int); |
| static const char *get_printable_method_name (tree); |
| static tree patch_conditional_expr (tree, tree, tree); |
| static tree generate_finit (tree); |
| static tree generate_instinit (tree); |
| static tree build_instinit_invocation (tree); |
| static void fix_constructors (tree); |
| static tree build_alias_initializer_parameter_list (int, tree, tree, int *); |
| static tree craft_constructor (tree, tree); |
| static int verify_constructor_super (tree); |
| static tree create_artificial_method (tree, int, tree, tree, tree); |
| static void start_artificial_method_body (tree); |
| static void end_artificial_method_body (tree); |
| static int check_method_redefinition (tree, tree); |
| static int check_method_types_complete (tree); |
| static bool hack_is_accessible_p (tree, tree); |
| static void java_check_regular_methods (tree); |
| static void check_interface_throws_clauses (tree, tree); |
| static void java_check_abstract_methods (tree); |
| static void unreachable_stmt_error (tree); |
| static int not_accessible_field_error (tree, tree); |
| static tree find_expr_with_wfl (tree); |
| static void missing_return_error (tree); |
| static tree build_new_array_init (int, tree); |
| static tree patch_new_array_init (tree, tree); |
| static tree maybe_build_array_element_wfl (tree); |
| static int array_constructor_check_entry (tree, tree); |
| static const char *purify_type_name (const char *); |
| static tree fold_constant_for_init (tree, tree); |
| static jdeplist *reverse_jdep_list (struct parser_ctxt *); |
| static void static_ref_err (tree, tree, tree); |
| static void parser_add_interface (tree, tree, tree); |
| static void add_superinterfaces (tree, tree); |
| static tree jdep_resolve_class (jdep *); |
| static int note_possible_classname (const char *, int); |
| static void java_complete_expand_classes (void); |
| static void java_complete_expand_class (tree); |
| static void java_complete_expand_methods (tree); |
| static tree cut_identifier_in_qualified (tree); |
| static tree java_stabilize_reference (tree); |
| static tree do_unary_numeric_promotion (tree); |
| static char * operator_string (tree); |
| static tree do_merge_string_cste (tree, const char *, int, int); |
| static tree merge_string_cste (tree, tree, int); |
| static tree java_refold (tree); |
| static int java_decl_equiv (tree, tree); |
| static int binop_compound_p (enum tree_code); |
| static tree search_loop (tree); |
| static int labeled_block_contains_loop_p (tree, tree); |
| static int check_abstract_method_definitions (int, tree, tree); |
| static void java_check_abstract_method_definitions (tree); |
| static void java_debug_context_do (int); |
| static void java_parser_context_push_initialized_field (void); |
| static void java_parser_context_pop_initialized_field (void); |
| static tree reorder_static_initialized (tree); |
| static void java_parser_context_suspend (void); |
| static void java_parser_context_resume (void); |
| static int pop_current_osb (struct parser_ctxt *); |
| |
| /* JDK 1.1 work. FIXME */ |
| |
| static tree maybe_make_nested_class_name (tree); |
| static int make_nested_class_name (tree); |
| static void link_nested_class_to_enclosing (void); |
| static tree resolve_inner_class (htab_t, tree, tree *, tree *, tree); |
| static tree find_as_inner_class (tree, tree, tree); |
| static tree find_as_inner_class_do (tree, tree); |
| static int check_inner_class_redefinition (tree, tree); |
| |
| static tree build_thisn_assign (void); |
| static tree build_current_thisn (tree); |
| static tree build_access_to_thisn (tree, tree, int); |
| static tree maybe_build_thisn_access_method (tree); |
| |
| static tree build_outer_field_access (tree, tree); |
| static tree build_outer_field_access_methods (tree); |
| static tree build_outer_field_access_expr (int, tree, tree, |
| tree, tree); |
| static tree build_outer_method_access_method (tree); |
| static tree build_new_access_id (void); |
| static tree build_outer_field_access_method (tree, tree, tree, |
| tree, tree); |
| |
| static int outer_field_access_p (tree, tree); |
| static int outer_field_expanded_access_p (tree, tree *, |
| tree *, tree *); |
| static tree outer_field_access_fix (tree, tree, tree); |
| static tree build_incomplete_class_ref (int, tree); |
| static tree patch_incomplete_class_ref (tree); |
| static tree create_anonymous_class (tree); |
| static void patch_anonymous_class (tree, tree, tree); |
| static void add_inner_class_fields (tree, tree); |
| |
| static tree build_dot_class_method (tree); |
| static tree build_dot_class_method_invocation (tree, tree); |
| static void create_new_parser_context (int); |
| static tree maybe_build_class_init_for_field (tree, tree); |
| |
| static int emit_test_initialization (void **, void *); |
| |
| static char *string_convert_int_cst (tree); |
| |
| /* Number of error found so far. */ |
| int java_error_count; |
| /* Number of warning found so far. */ |
| int java_warning_count; |
| /* Tell when not to fold, when doing xrefs */ |
| int do_not_fold; |
| /* Cyclic inheritance report, as it can be set by layout_class */ |
| const char *cyclic_inheritance_report; |
| |
| /* The current parser context */ |
| struct parser_ctxt *ctxp; |
| |
| /* List of things that were analyzed for which code will be generated */ |
| struct parser_ctxt *ctxp_for_generation = NULL; |
| |
| /* binop_lookup maps token to tree_code. It is used where binary |
| operations are involved and required by the parser. RDIV_EXPR |
| covers both integral/floating point division. The code is changed |
| once the type of both operator is worked out. */ |
| |
| static const enum tree_code binop_lookup[19] = |
| { |
| PLUS_EXPR, MINUS_EXPR, MULT_EXPR, RDIV_EXPR, TRUNC_MOD_EXPR, |
| LSHIFT_EXPR, RSHIFT_EXPR, URSHIFT_EXPR, |
| BIT_AND_EXPR, BIT_XOR_EXPR, BIT_IOR_EXPR, |
| TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR, |
| EQ_EXPR, NE_EXPR, GT_EXPR, GE_EXPR, LT_EXPR, LE_EXPR, |
| }; |
| #define BINOP_LOOKUP(VALUE) \ |
| binop_lookup [((VALUE) - PLUS_TK) % ARRAY_SIZE (binop_lookup)] |
| |
| /* This is the end index for binary operators that can also be used |
| in compound assignments. */ |
| #define BINOP_COMPOUND_CANDIDATES 11 |
| |
| /* The "$L" identifier we use to create labels. */ |
| static GTY(()) tree label_id; |
| |
| /* The "StringBuffer" identifier used for the String `+' operator. */ |
| static GTY(()) tree wfl_string_buffer; |
| |
| /* The "append" identifier used for String `+' operator. */ |
| static GTY(()) tree wfl_append; |
| |
| /* The "toString" identifier used for String `+' operator. */ |
| static GTY(()) tree wfl_to_string; |
| |
| /* The "java.lang" import qualified name. */ |
| static GTY(()) tree java_lang_id; |
| |
| /* The generated `inst$' identifier used for generated enclosing |
| instance/field access functions. */ |
| static GTY(()) tree inst_id; |
| |
| /* Context and flag for static blocks */ |
| static GTY(()) tree current_static_block; |
| |
| /* The generated `write_parm_value$' identifier. */ |
| static GTY(()) tree wpv_id; |
| |
| /* The list of all packages we've seen so far */ |
| static GTY(()) tree package_list; |
| |
| /* Hold THIS for the scope of the current method decl. */ |
| static GTY(()) tree current_this; |
| |
| /* Hold a list of catch clauses list. The first element of this list is |
| the list of the catch clauses of the currently analyzed try block. */ |
| static GTY(()) tree currently_caught_type_list; |
| |
| /* This holds a linked list of all the case labels for the current |
| switch statement. It is only used when checking to see if there |
| are duplicate labels. FIXME: probably this should just be attached |
| to the switch itself; then it could be referenced via |
| `ctxp->current_loop'. */ |
| static GTY(()) tree case_label_list; |
| |
| /* Anonymous class counter. Will be reset to 1 every time a non |
| anonymous class gets created. */ |
| static int anonymous_class_counter = 1; |
| |
| static GTY(()) tree src_parse_roots[1]; |
| |
| /* All classes seen from source code */ |
| #define gclass_list src_parse_roots[0] |
| |
| /* Check modifiers. If one doesn't fit, retrieve it in its declaration |
| line and point it out. */ |
| /* Should point out the one that don't fit. ASCII/unicode, going |
| backward. FIXME */ |
| |
| #define check_modifiers(__message, __value, __mask) do { \ |
| if ((__value) & ~(__mask)) \ |
| { \ |
| size_t i, remainder = (__value) & ~(__mask); \ |
| for (i = 0; i < ARRAY_SIZE (ctxp->modifier_ctx); i++) \ |
| if ((1 << i) & remainder) \ |
| parse_error_context (ctxp->modifier_ctx [i], (__message), \ |
| java_accstring_lookup (1 << i)); \ |
| } \ |
| } while (0) |
| |
| %} |
| |
| %union { |
| tree node; |
| int sub_token; |
| struct { |
| int token; |
| #ifdef USE_MAPPED_LOCATION |
| source_location location; |
| #else |
| int location; |
| #endif |
| } operator; |
| int value; |
| } |
| |
| %{ |
| #ifdef USE_MAPPED_LOCATION |
| #define SET_EXPR_LOCATION_FROM_TOKEN(EXPR, TOKEN) \ |
| SET_EXPR_LOCATION(EXPR, (TOKEN).location) |
| #else |
| #define SET_EXPR_LOCATION_FROM_TOKEN(EXPR, TOKEN) \ |
| (EXPR_WFL_LINECOL (EXPR) = (TOKEN).location) |
| #endif |
| |
| #include "lex.c" |
| %} |
| |
| %pure_parser |
| |
| /* Things defined here have to match the order of what's in the |
| binop_lookup table. */ |
| |
| %token PLUS_TK MINUS_TK MULT_TK DIV_TK REM_TK |
| %token LS_TK SRS_TK ZRS_TK |
| %token AND_TK XOR_TK OR_TK |
| %token BOOL_AND_TK BOOL_OR_TK |
| %token EQ_TK NEQ_TK GT_TK GTE_TK LT_TK LTE_TK |
| |
| /* This maps to the same binop_lookup entry than the token above */ |
| |
| %token PLUS_ASSIGN_TK MINUS_ASSIGN_TK MULT_ASSIGN_TK DIV_ASSIGN_TK |
| %token REM_ASSIGN_TK |
| %token LS_ASSIGN_TK SRS_ASSIGN_TK ZRS_ASSIGN_TK |
| %token AND_ASSIGN_TK XOR_ASSIGN_TK OR_ASSIGN_TK |
| |
| |
| /* Modifier TOKEN have to be kept in this order. Don't scramble it */ |
| |
| %token PUBLIC_TK PRIVATE_TK PROTECTED_TK |
| %token STATIC_TK FINAL_TK SYNCHRONIZED_TK |
| %token VOLATILE_TK TRANSIENT_TK NATIVE_TK |
| %token PAD_TK ABSTRACT_TK STRICT_TK |
| %token MODIFIER_TK |
| |
| /* Keep those two in order, too */ |
| %token DECR_TK INCR_TK |
| |
| /* From now one, things can be in any order */ |
| |
| %token DEFAULT_TK IF_TK THROW_TK |
| %token BOOLEAN_TK DO_TK IMPLEMENTS_TK |
| %token THROWS_TK BREAK_TK IMPORT_TK |
| %token ELSE_TK INSTANCEOF_TK RETURN_TK |
| %token VOID_TK CATCH_TK INTERFACE_TK |
| %token CASE_TK EXTENDS_TK FINALLY_TK |
| %token SUPER_TK WHILE_TK CLASS_TK |
| %token SWITCH_TK CONST_TK TRY_TK |
| %token FOR_TK NEW_TK CONTINUE_TK |
| %token GOTO_TK PACKAGE_TK THIS_TK |
| %token ASSERT_TK |
| |
| %token BYTE_TK SHORT_TK INT_TK LONG_TK |
| %token CHAR_TK INTEGRAL_TK |
| |
| %token FLOAT_TK DOUBLE_TK FP_TK |
| |
| %token ID_TK |
| |
| %token REL_QM_TK REL_CL_TK NOT_TK NEG_TK |
| |
| %token ASSIGN_ANY_TK ASSIGN_TK |
| %token OP_TK CP_TK OCB_TK CCB_TK OSB_TK CSB_TK SC_TK C_TK DOT_TK |
| |
| %token STRING_LIT_TK CHAR_LIT_TK INT_LIT_TK FP_LIT_TK |
| %token TRUE_TK FALSE_TK BOOL_LIT_TK NULL_TK |
| |
| %type <value> modifiers MODIFIER_TK final synchronized |
| |
| %type <node> super ID_TK identifier |
| %type <node> name simple_name qualified_name |
| %type <node> type_declaration compilation_unit |
| field_declaration method_declaration extends_interfaces |
| interfaces interface_type_list |
| import_declarations package_declaration |
| type_declarations interface_body |
| interface_member_declaration constant_declaration |
| interface_member_declarations interface_type |
| abstract_method_declaration |
| %type <node> class_body_declaration class_member_declaration |
| static_initializer constructor_declaration block |
| %type <node> class_body_declarations constructor_header |
| %type <node> class_or_interface_type class_type class_type_list |
| constructor_declarator explicit_constructor_invocation |
| %type <node> dim_expr dim_exprs this_or_super throws |
| |
| %type <node> variable_declarator_id variable_declarator |
| variable_declarators variable_initializer |
| variable_initializers constructor_body |
| array_initializer |
| |
| %type <node> class_body block_end constructor_block_end |
| %type <node> statement statement_without_trailing_substatement |
| labeled_statement if_then_statement label_decl |
| if_then_else_statement while_statement for_statement |
| statement_nsi labeled_statement_nsi do_statement |
| if_then_else_statement_nsi while_statement_nsi |
| for_statement_nsi statement_expression_list for_init |
| for_update statement_expression expression_statement |
| primary_no_new_array expression primary array_type |
| array_creation_initialized array_creation_uninitialized |
| class_instance_creation_expression field_access |
| method_invocation array_access something_dot_new |
| argument_list postfix_expression while_expression |
| post_increment_expression post_decrement_expression |
| unary_expression_not_plus_minus unary_expression |
| pre_increment_expression pre_decrement_expression |
| cast_expression |
| multiplicative_expression additive_expression |
| shift_expression relational_expression |
| equality_expression and_expression |
| exclusive_or_expression inclusive_or_expression |
| conditional_and_expression conditional_or_expression |
| conditional_expression assignment_expression |
| left_hand_side assignment for_header for_begin |
| constant_expression do_statement_begin empty_statement |
| switch_statement synchronized_statement throw_statement |
| try_statement assert_statement |
| switch_expression switch_block |
| catches catch_clause catch_clause_parameter finally |
| anonymous_class_creation trap_overflow_corner_case |
| %type <node> return_statement break_statement continue_statement |
| |
| %type <operator> ASSIGN_TK MULT_ASSIGN_TK DIV_ASSIGN_TK |
| %type <operator> REM_ASSIGN_TK PLUS_ASSIGN_TK MINUS_ASSIGN_TK |
| %type <operator> LS_ASSIGN_TK SRS_ASSIGN_TK ZRS_ASSIGN_TK |
| %type <operator> AND_ASSIGN_TK XOR_ASSIGN_TK OR_ASSIGN_TK |
| %type <operator> ASSIGN_ANY_TK assignment_operator |
| %token <operator> EQ_TK GTE_TK ZRS_TK SRS_TK GT_TK LTE_TK LS_TK |
| %token <operator> BOOL_AND_TK AND_TK BOOL_OR_TK OR_TK INCR_TK PLUS_TK |
| %token <operator> DECR_TK MINUS_TK MULT_TK DIV_TK XOR_TK REM_TK NEQ_TK |
| %token <operator> NEG_TK REL_QM_TK REL_CL_TK NOT_TK LT_TK OCB_TK CCB_TK |
| %token <operator> OP_TK OSB_TK DOT_TK THROW_TK INSTANCEOF_TK |
| %type <operator> THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK |
| %type <operator> CASE_TK DEFAULT_TK TRY_TK CATCH_TK SYNCHRONIZED_TK |
| %type <operator> NEW_TK ASSERT_TK |
| |
| %type <node> method_body |
| |
| %type <node> literal INT_LIT_TK FP_LIT_TK BOOL_LIT_TK CHAR_LIT_TK |
| STRING_LIT_TK NULL_TK VOID_TK |
| |
| %type <node> IF_TK WHILE_TK FOR_TK |
| |
| %type <node> formal_parameter_list formal_parameter |
| method_declarator method_header |
| |
| %type <node> primitive_type reference_type type |
| BOOLEAN_TK INTEGRAL_TK FP_TK |
| |
| /* Added or modified JDK 1.1 rule types */ |
| %type <node> type_literals |
| |
| %% |
| /* 19.2 Production from 2.3: The Syntactic Grammar */ |
| goal: compilation_unit |
| {} |
| ; |
| |
| /* 19.3 Productions from 3: Lexical structure */ |
| literal: |
| INT_LIT_TK |
| | FP_LIT_TK |
| | BOOL_LIT_TK |
| | CHAR_LIT_TK |
| | STRING_LIT_TK |
| | NULL_TK |
| ; |
| |
| /* 19.4 Productions from 4: Types, Values and Variables */ |
| type: |
| primitive_type |
| | reference_type |
| ; |
| |
| primitive_type: |
| INTEGRAL_TK |
| | FP_TK |
| | BOOLEAN_TK |
| ; |
| |
| reference_type: |
| class_or_interface_type |
| | array_type |
| ; |
| |
| class_or_interface_type: |
| name |
| ; |
| |
| class_type: |
| class_or_interface_type /* Default rule */ |
| ; |
| |
| interface_type: |
| class_or_interface_type |
| ; |
| |
| array_type: |
| primitive_type dims |
| { |
| int osb = pop_current_osb (ctxp); |
| tree t = build_java_array_type (($1), -1); |
| while (--osb) |
| t = build_unresolved_array_type (t); |
| $$ = t; |
| } |
| | name dims |
| { |
| int osb = pop_current_osb (ctxp); |
| tree t = $1; |
| while (osb--) |
| t = build_unresolved_array_type (t); |
| $$ = t; |
| } |
| ; |
| |
| /* 19.5 Productions from 6: Names */ |
| name: |
| simple_name /* Default rule */ |
| | qualified_name /* Default rule */ |
| ; |
| |
| simple_name: |
| identifier /* Default rule */ |
| ; |
| |
| qualified_name: |
| name DOT_TK identifier |
| { $$ = make_qualified_name ($1, $3, $2.location); } |
| ; |
| |
| identifier: |
| ID_TK |
| ; |
| |
| /* 19.6: Production from 7: Packages */ |
| compilation_unit: |
| {$$ = NULL;} |
| | package_declaration |
| | import_declarations |
| | type_declarations |
| | package_declaration import_declarations |
| | package_declaration type_declarations |
| | import_declarations type_declarations |
| | package_declaration import_declarations type_declarations |
| ; |
| |
| import_declarations: |
| import_declaration |
| { |
| $$ = NULL; |
| } |
| | import_declarations import_declaration |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| type_declarations: |
| type_declaration |
| | type_declarations type_declaration |
| ; |
| |
| package_declaration: |
| PACKAGE_TK name SC_TK |
| { |
| ctxp->package = EXPR_WFL_NODE ($2); |
| register_package (ctxp->package); |
| } |
| | PACKAGE_TK error |
| {yyerror ("Missing name"); RECOVER;} |
| | PACKAGE_TK name error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| import_declaration: |
| single_type_import_declaration |
| | type_import_on_demand_declaration |
| ; |
| |
| single_type_import_declaration: |
| IMPORT_TK name SC_TK |
| { |
| tree name = EXPR_WFL_NODE ($2), last_name; |
| int i = IDENTIFIER_LENGTH (name)-1; |
| const char *last = &IDENTIFIER_POINTER (name)[i]; |
| while (last != IDENTIFIER_POINTER (name)) |
| { |
| if (last [0] == '.') |
| break; |
| last--; |
| } |
| last_name = get_identifier (++last); |
| if (IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (last_name)) |
| { |
| tree err = find_name_in_single_imports (last_name); |
| if (err && err != name) |
| parse_error_context |
| ($2, "Ambiguous class: %qs and %qs", |
| IDENTIFIER_POINTER (name), |
| IDENTIFIER_POINTER (err)); |
| else |
| REGISTER_IMPORT ($2, last_name); |
| } |
| else |
| REGISTER_IMPORT ($2, last_name); |
| } |
| | IMPORT_TK error |
| {yyerror ("Missing name"); RECOVER;} |
| | IMPORT_TK name error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| type_import_on_demand_declaration: |
| IMPORT_TK name DOT_TK MULT_TK SC_TK |
| { |
| tree name = EXPR_WFL_NODE ($2); |
| tree it; |
| /* Search for duplicates. */ |
| for (it = ctxp->import_demand_list; it; it = TREE_CHAIN (it)) |
| if (EXPR_WFL_NODE (TREE_PURPOSE (it)) == name) |
| break; |
| /* Don't import the same thing more than once, just ignore |
| duplicates (7.5.2) */ |
| if (! it) |
| { |
| read_import_dir ($2); |
| ctxp->import_demand_list = |
| chainon (ctxp->import_demand_list, |
| build_tree_list ($2, NULL_TREE)); |
| } |
| } |
| | IMPORT_TK name DOT_TK error |
| {yyerror ("'*' expected"); RECOVER;} |
| | IMPORT_TK name DOT_TK MULT_TK error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| type_declaration: |
| class_declaration |
| { end_class_declaration (0); } |
| | interface_declaration |
| { end_class_declaration (0); } |
| | empty_statement |
| | error |
| { |
| YYERROR_NOW; |
| yyerror ("Class or interface declaration expected"); |
| } |
| ; |
| |
| /* 19.7 Shortened from the original: |
| modifiers: modifier | modifiers modifier |
| modifier: any of public... */ |
| modifiers: |
| MODIFIER_TK |
| { |
| $$ = (1 << $1); |
| } |
| | modifiers MODIFIER_TK |
| { |
| int acc = (1 << $2); |
| if ($$ & acc) |
| parse_error_context |
| (ctxp->modifier_ctx [$2], "Modifier %qs declared twice", |
| java_accstring_lookup (acc)); |
| else |
| { |
| $$ |= acc; |
| } |
| } |
| ; |
| |
| /* 19.8.1 Production from $8.1: Class Declaration */ |
| class_declaration: |
| modifiers CLASS_TK identifier super interfaces |
| { create_class ($1, $3, $4, $5); } |
| class_body |
| {;} |
| | CLASS_TK identifier super interfaces |
| { create_class (0, $2, $3, $4); } |
| class_body |
| {;} |
| | modifiers CLASS_TK error |
| { yyerror ("Missing class name"); RECOVER; } |
| | CLASS_TK error |
| { yyerror ("Missing class name"); RECOVER; } |
| | CLASS_TK identifier error |
| { |
| if (!ctxp->class_err) yyerror ("'{' expected"); |
| DRECOVER(class1); |
| } |
| | modifiers CLASS_TK identifier error |
| { if (!ctxp->class_err) yyerror ("'{' expected"); RECOVER; } |
| ; |
| |
| super: |
| { $$ = NULL; } |
| | EXTENDS_TK class_type |
| { $$ = $2; } |
| | EXTENDS_TK class_type error |
| {yyerror ("'{' expected"); ctxp->class_err=1;} |
| | EXTENDS_TK error |
| {yyerror ("Missing super class name"); ctxp->class_err=1;} |
| ; |
| |
| interfaces: |
| { $$ = NULL_TREE; } |
| | IMPLEMENTS_TK interface_type_list |
| { $$ = $2; } |
| | IMPLEMENTS_TK error |
| { |
| ctxp->class_err=1; |
| yyerror ("Missing interface name"); |
| } |
| ; |
| |
| interface_type_list: |
| interface_type |
| { |
| ctxp->interface_number = 1; |
| $$ = build_tree_list ($1, NULL_TREE); |
| } |
| | interface_type_list C_TK interface_type |
| { |
| ctxp->interface_number++; |
| $$ = chainon ($1, build_tree_list ($3, NULL_TREE)); |
| } |
| | interface_type_list C_TK error |
| {yyerror ("Missing interface name"); RECOVER;} |
| ; |
| |
| class_body: |
| OCB_TK CCB_TK |
| { |
| /* Store the location of the `}' when doing xrefs */ |
| if (flag_emit_xref) |
| DECL_END_SOURCE_LINE (GET_CPC ()) = $2.location; |
| $$ = GET_CPC (); |
| } |
| | OCB_TK class_body_declarations CCB_TK |
| { |
| /* Store the location of the `}' when doing xrefs */ |
| if (flag_emit_xref) |
| DECL_END_SOURCE_LINE (GET_CPC ()) = $3.location; |
| $$ = GET_CPC (); |
| } |
| ; |
| |
| class_body_declarations: |
| class_body_declaration |
| | class_body_declarations class_body_declaration |
| ; |
| |
| class_body_declaration: |
| class_member_declaration |
| | static_initializer |
| | constructor_declaration |
| | block /* Added, JDK1.1, instance initializer */ |
| { |
| if (!IS_EMPTY_STMT ($1)) |
| { |
| TREE_CHAIN ($1) = CPC_INSTANCE_INITIALIZER_STMT (ctxp); |
| SET_CPC_INSTANCE_INITIALIZER_STMT (ctxp, $1); |
| } |
| } |
| ; |
| |
| class_member_declaration: |
| field_declaration |
| | method_declaration |
| | class_declaration /* Added, JDK1.1 inner classes */ |
| { end_class_declaration (1); } |
| | interface_declaration /* Added, JDK1.1 inner interfaces */ |
| { end_class_declaration (1); } |
| | empty_statement |
| ; |
| |
| /* 19.8.2 Productions from 8.3: Field Declarations */ |
| field_declaration: |
| type variable_declarators SC_TK |
| { register_fields (0, $1, $2); } |
| | modifiers type variable_declarators SC_TK |
| { |
| check_modifiers |
| ("Illegal modifier %qs for field declaration", |
| $1, FIELD_MODIFIERS); |
| check_modifiers_consistency ($1); |
| register_fields ($1, $2, $3); |
| } |
| ; |
| |
| variable_declarators: |
| /* Should we use build_decl_list () instead ? FIXME */ |
| variable_declarator /* Default rule */ |
| | variable_declarators C_TK variable_declarator |
| { $$ = chainon ($1, $3); } |
| | variable_declarators C_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| variable_declarator: |
| variable_declarator_id |
| { $$ = build_tree_list ($1, NULL_TREE); } |
| | variable_declarator_id ASSIGN_TK variable_initializer |
| { |
| if (java_error_count) |
| $3 = NULL_TREE; |
| $$ = build_tree_list |
| ($1, build_assignment ($2.token, $2.location, $1, $3)); |
| } |
| | variable_declarator_id ASSIGN_TK error |
| { |
| yyerror ("Missing variable initializer"); |
| $$ = build_tree_list ($1, NULL_TREE); |
| RECOVER; |
| } |
| | variable_declarator_id ASSIGN_TK variable_initializer error |
| { |
| yyerror ("';' expected"); |
| $$ = build_tree_list ($1, NULL_TREE); |
| RECOVER; |
| } |
| ; |
| |
| variable_declarator_id: |
| identifier |
| | variable_declarator_id OSB_TK CSB_TK |
| { $$ = build_unresolved_array_type ($1); } |
| | identifier error |
| {yyerror ("Invalid declaration"); DRECOVER(vdi);} |
| | variable_declarator_id OSB_TK error |
| { |
| yyerror ("']' expected"); |
| DRECOVER(vdi); |
| } |
| | variable_declarator_id CSB_TK error |
| {yyerror ("Unbalanced ']'"); DRECOVER(vdi);} |
| ; |
| |
| variable_initializer: |
| expression |
| | array_initializer |
| ; |
| |
| /* 19.8.3 Productions from 8.4: Method Declarations */ |
| method_declaration: |
| method_header |
| { |
| current_function_decl = $1; |
| if (current_function_decl |
| && TREE_CODE (current_function_decl) == FUNCTION_DECL) |
| source_start_java_method (current_function_decl); |
| else |
| current_function_decl = NULL_TREE; |
| } |
| method_body |
| { finish_method_declaration ($3); } |
| | method_header error |
| {YYNOT_TWICE yyerror ("'{' expected"); RECOVER;} |
| ; |
| |
| method_header: |
| type method_declarator throws |
| { $$ = method_header (0, $1, $2, $3); } |
| | VOID_TK method_declarator throws |
| { $$ = method_header (0, void_type_node, $2, $3); } |
| | modifiers type method_declarator throws |
| { $$ = method_header ($1, $2, $3, $4); } |
| | modifiers VOID_TK method_declarator throws |
| { $$ = method_header ($1, void_type_node, $3, $4); } |
| | type error |
| { |
| yyerror ("Invalid method declaration, method name required"); |
| RECOVER; |
| } |
| | modifiers type error |
| { |
| yyerror ("Identifier expected"); |
| RECOVER; |
| } |
| | VOID_TK error |
| { |
| yyerror ("Identifier expected"); |
| RECOVER; |
| } |
| | modifiers VOID_TK error |
| { |
| yyerror ("Identifier expected"); |
| RECOVER; |
| } |
| | modifiers error |
| { |
| yyerror ("Invalid method declaration, return type required"); |
| RECOVER; |
| } |
| ; |
| |
| method_declarator: |
| identifier OP_TK CP_TK |
| { |
| ctxp->formal_parameter_number = 0; |
| $$ = method_declarator ($1, NULL_TREE); |
| } |
| | identifier OP_TK formal_parameter_list CP_TK |
| { $$ = method_declarator ($1, $3); } |
| | method_declarator OSB_TK CSB_TK |
| { |
| SET_EXPR_LOCATION_FROM_TOKEN (wfl_operator, $2); |
| TREE_PURPOSE ($1) = |
| build_unresolved_array_type (TREE_PURPOSE ($1)); |
| parse_warning_context |
| (wfl_operator, |
| "Discouraged form of returned type specification"); |
| } |
| | identifier OP_TK error |
| {yyerror ("')' expected"); DRECOVER(method_declarator);} |
| | method_declarator OSB_TK error |
| {yyerror ("']' expected"); RECOVER;} |
| ; |
| |
| formal_parameter_list: |
| formal_parameter |
| { |
| ctxp->formal_parameter_number = 1; |
| } |
| | formal_parameter_list C_TK formal_parameter |
| { |
| ctxp->formal_parameter_number += 1; |
| $$ = chainon ($1, $3); |
| } |
| | formal_parameter_list C_TK error |
| { yyerror ("Missing formal parameter term"); RECOVER; } |
| ; |
| |
| formal_parameter: |
| type variable_declarator_id |
| { |
| $$ = build_tree_list ($2, $1); |
| } |
| | final type variable_declarator_id /* Added, JDK1.1 final parms */ |
| { |
| $$ = build_tree_list ($3, $2); |
| ARG_FINAL_P ($$) = 1; |
| } |
| | type error |
| { |
| yyerror ("Missing identifier"); RECOVER; |
| $$ = NULL_TREE; |
| } |
| | final type error |
| { |
| yyerror ("Missing identifier"); RECOVER; |
| $$ = NULL_TREE; |
| } |
| ; |
| |
| final: |
| modifiers |
| { |
| check_modifiers ("Illegal modifier %qs. Only %<final%> was expected here", |
| $1, ACC_FINAL); |
| if ($1 != ACC_FINAL) |
| MODIFIER_WFL (FINAL_TK) = build_wfl_node (NULL_TREE); |
| } |
| ; |
| |
| throws: |
| { $$ = NULL_TREE; } |
| | THROWS_TK class_type_list |
| { $$ = $2; } |
| | THROWS_TK error |
| {yyerror ("Missing class type term"); RECOVER;} |
| ; |
| |
| class_type_list: |
| class_type |
| { $$ = build_tree_list ($1, $1); } |
| | class_type_list C_TK class_type |
| { $$ = tree_cons ($3, $3, $1); } |
| | class_type_list C_TK error |
| {yyerror ("Missing class type term"); RECOVER;} |
| ; |
| |
| method_body: |
| block |
| | SC_TK { $$ = NULL_TREE; } |
| ; |
| |
| /* 19.8.4 Productions from 8.5: Static Initializers */ |
| static_initializer: |
| static block |
| { |
| TREE_CHAIN ($2) = CPC_STATIC_INITIALIZER_STMT (ctxp); |
| SET_CPC_STATIC_INITIALIZER_STMT (ctxp, $2); |
| current_static_block = NULL_TREE; |
| } |
| ; |
| |
| static: /* Test lval.sub_token here */ |
| modifiers |
| { |
| check_modifiers ("Illegal modifier %qs for static initializer", $1, ACC_STATIC); |
| /* Can't have a static initializer in an innerclass */ |
| if ($1 | ACC_STATIC && |
| GET_CPC_LIST () && !TOPLEVEL_CLASS_DECL_P (GET_CPC ())) |
| parse_error_context |
| (MODIFIER_WFL (STATIC_TK), |
| "Can't define static initializer in class %qs. Static initializer can only be defined in top-level classes", |
| IDENTIFIER_POINTER (DECL_NAME (GET_CPC ()))); |
| SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); |
| } |
| ; |
| |
| /* 19.8.5 Productions from 8.6: Constructor Declarations */ |
| constructor_declaration: |
| constructor_header |
| { |
| current_function_decl = $1; |
| source_start_java_method (current_function_decl); |
| } |
| constructor_body |
| { finish_method_declaration ($3); } |
| ; |
| |
| constructor_header: |
| constructor_declarator throws |
| { $$ = method_header (0, NULL_TREE, $1, $2); } |
| | modifiers constructor_declarator throws |
| { $$ = method_header ($1, NULL_TREE, $2, $3); } |
| ; |
| |
| constructor_declarator: |
| simple_name OP_TK CP_TK |
| { |
| ctxp->formal_parameter_number = 0; |
| $$ = method_declarator ($1, NULL_TREE); |
| } |
| | simple_name OP_TK formal_parameter_list CP_TK |
| { $$ = method_declarator ($1, $3); } |
| ; |
| |
| constructor_body: |
| /* Unlike regular method, we always need a complete (empty) |
| body so we can safely perform all the required code |
| addition (super invocation and field initialization) */ |
| block_begin constructor_block_end |
| { |
| BLOCK_EXPR_BODY ($2) = build_java_empty_stmt (); |
| $$ = $2; |
| } |
| | block_begin explicit_constructor_invocation constructor_block_end |
| { $$ = $3; } |
| | block_begin block_statements constructor_block_end |
| { $$ = $3; } |
| | block_begin explicit_constructor_invocation block_statements constructor_block_end |
| { $$ = $4; } |
| ; |
| |
| constructor_block_end: |
| block_end |
| ; |
| |
| /* Error recovery for that rule moved down expression_statement: rule. */ |
| explicit_constructor_invocation: |
| this_or_super OP_TK CP_TK SC_TK |
| { |
| $$ = build_method_invocation ($1, NULL_TREE); |
| $$ = build_debugable_stmt (EXPR_WFL_LINECOL ($1), $$); |
| $$ = java_method_add_stmt (current_function_decl, $$); |
| } |
| | this_or_super OP_TK argument_list CP_TK SC_TK |
| { |
| $$ = build_method_invocation ($1, $3); |
| $$ = build_debugable_stmt (EXPR_WFL_LINECOL ($1), $$); |
| $$ = java_method_add_stmt (current_function_decl, $$); |
| } |
| /* Added, JDK1.1 inner classes. Modified because the rule |
| 'primary' couldn't work. */ |
| | name DOT_TK SUPER_TK OP_TK argument_list CP_TK SC_TK |
| {$$ = parse_jdk1_1_error ("explicit constructor invocation"); } |
| | name DOT_TK SUPER_TK OP_TK CP_TK SC_TK |
| {$$ = parse_jdk1_1_error ("explicit constructor invocation"); } |
| ; |
| |
| this_or_super: /* Added, simplifies error diagnostics */ |
| THIS_TK |
| { |
| tree wfl = build_wfl_node (this_identifier_node); |
| SET_EXPR_LOCATION_FROM_TOKEN (wfl, $1); |
| $$ = wfl; |
| } |
| | SUPER_TK |
| { |
| tree wfl = build_wfl_node (super_identifier_node); |
| SET_EXPR_LOCATION_FROM_TOKEN (wfl, $1); |
| $$ = wfl; |
| } |
| ; |
| |
| /* 19.9 Productions from 9: Interfaces */ |
| /* 19.9.1 Productions from 9.1: Interfaces Declarations */ |
| interface_declaration: |
| INTERFACE_TK identifier |
| { create_interface (0, $2, NULL_TREE); } |
| interface_body |
| { ; } |
| | modifiers INTERFACE_TK identifier |
| { create_interface ($1, $3, NULL_TREE); } |
| interface_body |
| { ; } |
| | INTERFACE_TK identifier extends_interfaces |
| { create_interface (0, $2, $3); } |
| interface_body |
| { ; } |
| | modifiers INTERFACE_TK identifier extends_interfaces |
| { create_interface ($1, $3, $4); } |
| interface_body |
| { ; } |
| | INTERFACE_TK identifier error |
| { yyerror ("'{' expected"); RECOVER; } |
| | modifiers INTERFACE_TK identifier error |
| { yyerror ("'{' expected"); RECOVER; } |
| ; |
| |
| extends_interfaces: |
| EXTENDS_TK interface_type |
| { |
| ctxp->interface_number = 1; |
| $$ = build_tree_list ($2, NULL_TREE); |
| } |
| | extends_interfaces C_TK interface_type |
| { |
| ctxp->interface_number++; |
| $$ = chainon ($1, build_tree_list ($3, NULL_TREE)); |
| } |
| | EXTENDS_TK error |
| {yyerror ("Invalid interface type"); RECOVER;} |
| | extends_interfaces C_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| interface_body: |
| OCB_TK CCB_TK |
| { $$ = NULL_TREE; } |
| | OCB_TK interface_member_declarations CCB_TK |
| { $$ = NULL_TREE; } |
| ; |
| |
| interface_member_declarations: |
| interface_member_declaration |
| | interface_member_declarations interface_member_declaration |
| ; |
| |
| interface_member_declaration: |
| constant_declaration |
| | abstract_method_declaration |
| | class_declaration /* Added, JDK1.1 inner classes */ |
| { end_class_declaration (1); } |
| | interface_declaration /* Added, JDK1.1 inner interfaces */ |
| { end_class_declaration (1); } |
| ; |
| |
| constant_declaration: |
| field_declaration |
| ; |
| |
| abstract_method_declaration: |
| method_header SC_TK |
| { |
| check_abstract_method_header ($1); |
| current_function_decl = NULL_TREE; /* FIXME ? */ |
| } |
| | method_header error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| /* 19.10 Productions from 10: Arrays */ |
| array_initializer: |
| OCB_TK CCB_TK |
| { $$ = build_new_array_init ($1.location, NULL_TREE); } |
| | OCB_TK C_TK CCB_TK |
| { $$ = build_new_array_init ($1.location, NULL_TREE); } |
| | OCB_TK variable_initializers CCB_TK |
| { $$ = build_new_array_init ($1.location, $2); } |
| | OCB_TK variable_initializers C_TK CCB_TK |
| { $$ = build_new_array_init ($1.location, $2); } |
| ; |
| |
| variable_initializers: |
| variable_initializer |
| { |
| $$ = tree_cons (maybe_build_array_element_wfl ($1), |
| $1, NULL_TREE); |
| } |
| | variable_initializers C_TK variable_initializer |
| { |
| $$ = tree_cons (maybe_build_array_element_wfl ($3), $3, $1); |
| } |
| | variable_initializers C_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| /* 19.11 Production from 14: Blocks and Statements */ |
| block: |
| block_begin block_end |
| { $$ = $2; } |
| | block_begin block_statements block_end |
| { $$ = $3; } |
| ; |
| |
| block_begin: |
| OCB_TK |
| { enter_block (); } |
| ; |
| |
| block_end: |
| CCB_TK |
| { |
| maybe_absorb_scoping_blocks (); |
| /* Store the location of the `}' when doing xrefs */ |
| if (current_function_decl && flag_emit_xref) |
| DECL_END_SOURCE_LINE (current_function_decl) = $1.location; |
| $$ = exit_block (); |
| if (!BLOCK_SUBBLOCKS ($$)) |
| BLOCK_SUBBLOCKS ($$) = build_java_empty_stmt (); |
| } |
| ; |
| |
| block_statements: |
| block_statement |
| | block_statements block_statement |
| ; |
| |
| block_statement: |
| local_variable_declaration_statement |
| | statement |
| { java_method_add_stmt (current_function_decl, $1); } |
| | class_declaration /* Added, JDK1.1 local classes */ |
| { |
| LOCAL_CLASS_P (TREE_TYPE (GET_CPC ())) = 1; |
| end_class_declaration (1); |
| } |
| ; |
| |
| local_variable_declaration_statement: |
| local_variable_declaration SC_TK /* Can't catch missing ';' here */ |
| ; |
| |
| local_variable_declaration: |
| type variable_declarators |
| { declare_local_variables (0, $1, $2); } |
| | final type variable_declarators /* Added, JDK1.1 final locals */ |
| { declare_local_variables ($1, $2, $3); } |
| ; |
| |
| statement: |
| statement_without_trailing_substatement |
| | labeled_statement |
| | if_then_statement |
| | if_then_else_statement |
| | while_statement |
| | for_statement |
| { $$ = exit_block (); } |
| ; |
| |
| statement_nsi: |
| statement_without_trailing_substatement |
| | labeled_statement_nsi |
| | if_then_else_statement_nsi |
| | while_statement_nsi |
| | for_statement_nsi |
| { $$ = exit_block (); } |
| ; |
| |
| statement_without_trailing_substatement: |
| block |
| | empty_statement |
| | expression_statement |
| | switch_statement |
| | do_statement |
| | break_statement |
| | continue_statement |
| | return_statement |
| | synchronized_statement |
| | throw_statement |
| | try_statement |
| | assert_statement |
| ; |
| |
| empty_statement: |
| SC_TK |
| { |
| if (flag_extraneous_semicolon |
| && ! current_static_block |
| && (! current_function_decl || |
| /* Verify we're not in a inner class declaration */ |
| (GET_CPC () != TYPE_NAME |
| (DECL_CONTEXT (current_function_decl))))) |
| |
| { |
| #ifdef USE_MAPPED_LOCATION |
| SET_EXPR_LOCATION (wfl_operator, input_location); |
| #else |
| EXPR_WFL_SET_LINECOL (wfl_operator, input_line, -1); |
| #endif |
| parse_warning_context (wfl_operator, "An empty declaration is a deprecated feature that should not be used"); |
| } |
| $$ = build_java_empty_stmt (); |
| } |
| ; |
| |
| label_decl: |
| identifier REL_CL_TK |
| { |
| $$ = build_labeled_block (EXPR_WFL_LINECOL ($1), |
| EXPR_WFL_NODE ($1)); |
| pushlevel (2); |
| push_labeled_block ($$); |
| PUSH_LABELED_BLOCK ($$); |
| } |
| ; |
| |
| labeled_statement: |
| label_decl statement |
| { $$ = finish_labeled_statement ($1, $2); } |
| | identifier error |
| {yyerror ("':' expected"); RECOVER;} |
| ; |
| |
| labeled_statement_nsi: |
| label_decl statement_nsi |
| { $$ = finish_labeled_statement ($1, $2); } |
| ; |
| |
| /* We concentrate here a bunch of error handling rules that we couldn't write |
| earlier, because expression_statement catches a missing ';'. */ |
| expression_statement: |
| statement_expression SC_TK |
| { |
| /* We have a statement. Generate a WFL around it so |
| we can debug it */ |
| #ifdef USE_MAPPED_LOCATION |
| $$ = expr_add_location ($1, input_location, 1); |
| #else |
| $$ = build_expr_wfl ($1, input_filename, input_line, 0); |
| JAVA_MAYBE_GENERATE_DEBUG_INFO ($$); |
| #endif |
| /* We know we have a statement, so set the debug |
| info to be eventually generate here. */ |
| } |
| | error SC_TK |
| { |
| YYNOT_TWICE yyerror ("Invalid expression statement"); |
| DRECOVER (expr_stmt); |
| } |
| | error OCB_TK |
| { |
| YYNOT_TWICE yyerror ("Invalid expression statement"); |
| DRECOVER (expr_stmt); |
| } |
| | error CCB_TK |
| { |
| YYNOT_TWICE yyerror ("Invalid expression statement"); |
| DRECOVER (expr_stmt); |
| } |
| | this_or_super OP_TK error |
| {yyerror ("')' expected"); RECOVER;} |
| | this_or_super OP_TK CP_TK error |
| { |
| parse_ctor_invocation_error (); |
| RECOVER; |
| } |
| | this_or_super OP_TK argument_list error |
| {yyerror ("')' expected"); RECOVER;} |
| | this_or_super OP_TK argument_list CP_TK error |
| { |
| parse_ctor_invocation_error (); |
| RECOVER; |
| } |
| | name DOT_TK SUPER_TK error |
| {yyerror ("'(' expected"); RECOVER;} |
| | name DOT_TK SUPER_TK OP_TK error |
| {yyerror ("')' expected"); RECOVER;} |
| | name DOT_TK SUPER_TK OP_TK argument_list error |
| {yyerror ("')' expected"); RECOVER;} |
| | name DOT_TK SUPER_TK OP_TK argument_list CP_TK error |
| {yyerror ("';' expected"); RECOVER;} |
| | name DOT_TK SUPER_TK OP_TK CP_TK error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| statement_expression: |
| assignment |
| | pre_increment_expression |
| | pre_decrement_expression |
| | post_increment_expression |
| | post_decrement_expression |
| | method_invocation |
| | class_instance_creation_expression |
| ; |
| |
| if_then_statement: |
| IF_TK OP_TK expression CP_TK statement |
| { |
| $$ = build_if_else_statement ($2.location, $3, |
| $5, NULL_TREE); |
| } |
| | IF_TK error |
| {yyerror ("'(' expected"); RECOVER;} |
| | IF_TK OP_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | IF_TK OP_TK expression error |
| {yyerror ("')' expected"); RECOVER;} |
| ; |
| |
| if_then_else_statement: |
| IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement |
| { $$ = build_if_else_statement ($2.location, $3, $5, $7); } |
| ; |
| |
| if_then_else_statement_nsi: |
| IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement_nsi |
| { $$ = build_if_else_statement ($2.location, $3, $5, $7); } |
| ; |
| |
| switch_statement: |
| switch_expression |
| { |
| enter_block (); |
| } |
| switch_block |
| { |
| /* Make into "proper list" of COMPOUND_EXPRs. |
| I.e. make the last statement also have its own |
| COMPOUND_EXPR. */ |
| maybe_absorb_scoping_blocks (); |
| TREE_OPERAND ($1, 1) = exit_block (); |
| $$ = build_debugable_stmt (EXPR_WFL_LINECOL ($1), $1); |
| } |
| ; |
| |
| switch_expression: |
| SWITCH_TK OP_TK expression CP_TK |
| { |
| $$ = build3 (SWITCH_EXPR, NULL_TREE, $3, |
| NULL_TREE, NULL_TREE); |
| SET_EXPR_LOCATION_FROM_TOKEN ($$, $2); |
| } |
| | SWITCH_TK error |
| {yyerror ("'(' expected"); RECOVER;} |
| | SWITCH_TK OP_TK error |
| {yyerror ("Missing term or ')'"); DRECOVER(switch_statement);} |
| | SWITCH_TK OP_TK expression CP_TK error |
| {yyerror ("'{' expected"); RECOVER;} |
| ; |
| |
| /* Default assignment is there to avoid type node on switch_block |
| node. */ |
| |
| switch_block: |
| OCB_TK CCB_TK |
| { $$ = NULL_TREE; } |
| | OCB_TK switch_labels CCB_TK |
| { $$ = NULL_TREE; } |
| | OCB_TK switch_block_statement_groups CCB_TK |
| { $$ = NULL_TREE; } |
| | OCB_TK switch_block_statement_groups switch_labels CCB_TK |
| { $$ = NULL_TREE; } |
| ; |
| |
| switch_block_statement_groups: |
| switch_block_statement_group |
| | switch_block_statement_groups switch_block_statement_group |
| ; |
| |
| switch_block_statement_group: |
| switch_labels block_statements |
| ; |
| |
| switch_labels: |
| switch_label |
| | switch_labels switch_label |
| ; |
| |
| switch_label: |
| CASE_TK constant_expression REL_CL_TK |
| { |
| tree lab = build1 (CASE_EXPR, NULL_TREE, $2); |
| SET_EXPR_LOCATION_FROM_TOKEN (lab, $1); |
| java_method_add_stmt (current_function_decl, lab); |
| } |
| | DEFAULT_TK REL_CL_TK |
| { |
| tree lab = make_node (DEFAULT_EXPR); |
| SET_EXPR_LOCATION_FROM_TOKEN (lab, $1); |
| java_method_add_stmt (current_function_decl, lab); |
| } |
| | CASE_TK error |
| {yyerror ("Missing or invalid constant expression"); RECOVER;} |
| | CASE_TK constant_expression error |
| {yyerror ("':' expected"); RECOVER;} |
| | DEFAULT_TK error |
| {yyerror ("':' expected"); RECOVER;} |
| ; |
| |
| while_expression: |
| WHILE_TK OP_TK expression CP_TK |
| { |
| tree body = build_loop_body ($2.location, $3, 0); |
| $$ = build_new_loop (body); |
| } |
| ; |
| |
| while_statement: |
| while_expression statement |
| { $$ = finish_loop_body (0, NULL_TREE, $2, 0); } |
| | WHILE_TK error |
| {YYERROR_NOW; yyerror ("'(' expected"); RECOVER;} |
| | WHILE_TK OP_TK error |
| {yyerror ("Missing term and ')' expected"); RECOVER;} |
| | WHILE_TK OP_TK expression error |
| {yyerror ("')' expected"); RECOVER;} |
| ; |
| |
| while_statement_nsi: |
| while_expression statement_nsi |
| { $$ = finish_loop_body (0, NULL_TREE, $2, 0); } |
| ; |
| |
| do_statement_begin: |
| DO_TK |
| { |
| tree body = build_loop_body (0, NULL_TREE, 1); |
| $$ = build_new_loop (body); |
| } |
| /* Need error handing here. FIXME */ |
| ; |
| |
| do_statement: |
| do_statement_begin statement WHILE_TK OP_TK expression CP_TK SC_TK |
| { $$ = finish_loop_body ($4.location, $5, $2, 1); } |
| ; |
| |
| for_statement: |
| for_begin SC_TK expression SC_TK for_update CP_TK statement |
| { |
| if (CONSTANT_CLASS_P ($3)) |
| $3 = build_wfl_node ($3); |
| $$ = finish_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7); |
| } |
| | for_begin SC_TK SC_TK for_update CP_TK statement |
| { |
| $$ = finish_for_loop (0, NULL_TREE, $4, $6); |
| /* We have not condition, so we get rid of the EXIT_EXPR */ |
| LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) = |
| build_java_empty_stmt (); |
| } |
| | for_begin SC_TK error |
| {yyerror ("Invalid control expression"); RECOVER;} |
| | for_begin SC_TK expression SC_TK error |
| {yyerror ("Invalid update expression"); RECOVER;} |
| | for_begin SC_TK SC_TK error |
| {yyerror ("Invalid update expression"); RECOVER;} |
| ; |
| |
| for_statement_nsi: |
| for_begin SC_TK expression SC_TK for_update CP_TK statement_nsi |
| { $$ = finish_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7);} |
| | for_begin SC_TK SC_TK for_update CP_TK statement_nsi |
| { |
| $$ = finish_for_loop (0, NULL_TREE, $4, $6); |
| /* We have not condition, so we get rid of the EXIT_EXPR */ |
| LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) = |
| build_java_empty_stmt (); |
| } |
| ; |
| |
| for_header: |
| FOR_TK OP_TK |
| { |
| /* This scope defined for local variable that may be |
| defined within the scope of the for loop */ |
| enter_block (); |
| } |
| | FOR_TK error |
| {yyerror ("'(' expected"); DRECOVER(for_1);} |
| | FOR_TK OP_TK error |
| {yyerror ("Invalid init statement"); RECOVER;} |
| ; |
| |
| for_begin: |
| for_header for_init |
| { |
| /* We now declare the loop body. The loop is |
| declared as a for loop. */ |
| tree body = build_loop_body (0, NULL_TREE, 0); |
| $$ = build_new_loop (body); |
| FOR_LOOP_P ($$) = 1; |
| /* The loop is added to the current block the for |
| statement is defined within */ |
| java_method_add_stmt (current_function_decl, $$); |
| } |
| ; |
| for_init: /* Can be empty */ |
| { $$ = build_java_empty_stmt (); } |
| | statement_expression_list |
| { |
| /* Init statement recorded within the previously |
| defined block scope */ |
| $$ = java_method_add_stmt (current_function_decl, $1); |
| } |
| | local_variable_declaration |
| { |
| /* Local variable are recorded within the previously |
| defined block scope */ |
| $$ = NULL_TREE; |
| } |
| | statement_expression_list error |
| {yyerror ("';' expected"); DRECOVER(for_init_1);} |
| ; |
| |
| for_update: /* Can be empty */ |
| {$$ = build_java_empty_stmt ();} |
| | statement_expression_list |
| { $$ = build_debugable_stmt (BUILD_LOCATION (), $1); } |
| ; |
| |
| statement_expression_list: |
| statement_expression |
| { $$ = add_stmt_to_compound (NULL_TREE, NULL_TREE, $1); } |
| | statement_expression_list C_TK statement_expression |
| { $$ = add_stmt_to_compound ($1, NULL_TREE, $3); } |
| | statement_expression_list C_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| break_statement: |
| BREAK_TK SC_TK |
| { $$ = build_bc_statement ($1.location, 1, NULL_TREE); } |
| | BREAK_TK identifier SC_TK |
| { $$ = build_bc_statement ($1.location, 1, $2); } |
| | BREAK_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | BREAK_TK identifier error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| continue_statement: |
| CONTINUE_TK SC_TK |
| { $$ = build_bc_statement ($1.location, 0, NULL_TREE); } |
| | CONTINUE_TK identifier SC_TK |
| { $$ = build_bc_statement ($1.location, 0, $2); } |
| | CONTINUE_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | CONTINUE_TK identifier error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| return_statement: |
| RETURN_TK SC_TK |
| { $$ = build_return ($1.location, NULL_TREE); } |
| | RETURN_TK expression SC_TK |
| { $$ = build_return ($1.location, $2); } |
| | RETURN_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | RETURN_TK expression error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| throw_statement: |
| THROW_TK expression SC_TK |
| { |
| $$ = build1 (THROW_EXPR, NULL_TREE, $2); |
| SET_EXPR_LOCATION_FROM_TOKEN ($$, $1); |
| } |
| | THROW_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | THROW_TK expression error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| assert_statement: |
| ASSERT_TK expression REL_CL_TK expression SC_TK |
| { |
| $$ = build_assertion ($1.location, $2, $4); |
| } |
| | ASSERT_TK expression SC_TK |
| { |
| $$ = build_assertion ($1.location, $2, NULL_TREE); |
| } |
| | ASSERT_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | ASSERT_TK expression error |
| {yyerror ("';' expected"); RECOVER;} |
| ; |
| |
| synchronized_statement: |
| synchronized OP_TK expression CP_TK block |
| { |
| $$ = build2 (SYNCHRONIZED_EXPR, NULL_TREE, $3, $5); |
| EXPR_WFL_LINECOL ($$) = |
| EXPR_WFL_LINECOL (MODIFIER_WFL (SYNCHRONIZED_TK)); |
| } |
| | synchronized OP_TK expression CP_TK error |
| {yyerror ("'{' expected"); RECOVER;} |
| | synchronized error |
| {yyerror ("'(' expected"); RECOVER;} |
| | synchronized OP_TK error CP_TK |
| {yyerror ("Missing term"); RECOVER;} |
| | synchronized OP_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| synchronized: |
| modifiers |
| { |
| check_modifiers ( |
| "Illegal modifier %qs. Only %<synchronized%> was expected here", |
| $1, ACC_SYNCHRONIZED); |
| if ($1 != ACC_SYNCHRONIZED) |
| MODIFIER_WFL (SYNCHRONIZED_TK) = |
| build_wfl_node (NULL_TREE); |
| } |
| ; |
| |
| try_statement: |
| TRY_TK block catches |
| { $$ = build_try_statement ($1.location, $2, $3); } |
| | TRY_TK block finally |
| { $$ = build_try_finally_statement ($1.location, $2, $3); } |
| | TRY_TK block catches finally |
| { $$ = build_try_finally_statement |
| ($1.location, build_try_statement ($1.location, |
| $2, $3), $4); |
| } |
| | TRY_TK error |
| {yyerror ("'{' expected"); DRECOVER (try_statement);} |
| ; |
| |
| catches: |
| catch_clause |
| | catches catch_clause |
| { |
| TREE_CHAIN ($2) = $1; |
| $$ = $2; |
| } |
| ; |
| |
| catch_clause: |
| catch_clause_parameter block |
| { |
| java_method_add_stmt (current_function_decl, $2); |
| exit_block (); |
| $$ = $1; |
| } |
| ; |
| |
| catch_clause_parameter: |
| CATCH_TK OP_TK formal_parameter CP_TK |
| { |
| /* We add a block to define a scope for |
| formal_parameter (CCBP). The formal parameter is |
| declared initialized by the appropriate function |
| call */ |
| tree ccpb; |
| tree init; |
| if ($3) |
| { |
| ccpb = enter_block (); |
| init = build_assignment |
| (ASSIGN_TK, $2.location, TREE_PURPOSE ($3), |
| build0 (JAVA_EXC_OBJ_EXPR, ptr_type_node)); |
| declare_local_variables (0, TREE_VALUE ($3), |
| build_tree_list |
| (TREE_PURPOSE ($3), init)); |
| $$ = build1 (JAVA_CATCH_EXPR, NULL_TREE, ccpb); |
| SET_EXPR_LOCATION_FROM_TOKEN ($$, $1); |
| } |
| else |
| { |
| $$ = error_mark_node; |
| } |
| } |
| | CATCH_TK error |
| {yyerror ("'(' expected"); RECOVER; $$ = NULL_TREE;} |
| | CATCH_TK OP_TK error |
| { |
| yyerror ("Missing term or ')' expected"); |
| RECOVER; $$ = NULL_TREE; |
| } |
| | CATCH_TK OP_TK error CP_TK /* That's for () */ |
| {yyerror ("Missing term"); RECOVER; $$ = NULL_TREE;} |
| ; |
| |
| finally: |
| FINALLY_TK block |
| { $$ = $2; } |
| | FINALLY_TK error |
| {yyerror ("'{' expected"); RECOVER; } |
| ; |
| |
| /* 19.12 Production from 15: Expressions */ |
| primary: |
| primary_no_new_array |
| | array_creation_uninitialized |
| | array_creation_initialized |
| ; |
| |
| primary_no_new_array: |
| literal |
| | THIS_TK |
| { $$ = build_this ($1.location); } |
| | OP_TK expression CP_TK |
| {$$ = $2;} |
| | class_instance_creation_expression |
| | field_access |
| | method_invocation |
| | array_access |
| | type_literals |
| /* Added, JDK1.1 inner classes. Documentation is wrong |
| referring to a 'ClassName' (class_name) rule that doesn't |
| exist. Used name: instead. */ |
| | name DOT_TK THIS_TK |
| { |
| tree wfl = build_wfl_node (this_identifier_node); |
| $$ = make_qualified_primary ($1, wfl, EXPR_WFL_LINECOL ($1)); |
| } |
| | OP_TK expression error |
| {yyerror ("')' expected"); RECOVER;} |
| | name DOT_TK error |
| {yyerror ("'class' or 'this' expected" ); RECOVER;} |
| | primitive_type DOT_TK error |
| {yyerror ("'class' expected" ); RECOVER;} |
| | VOID_TK DOT_TK error |
| {yyerror ("'class' expected" ); RECOVER;} |
| ; |
| |
| type_literals: |
| name DOT_TK CLASS_TK |
| { $$ = build_incomplete_class_ref ($2.location, $1); } |
| | array_type DOT_TK CLASS_TK |
| { $$ = build_incomplete_class_ref ($2.location, $1); } |
| | primitive_type DOT_TK CLASS_TK |
| { $$ = build_incomplete_class_ref ($2.location, $1); } |
| | VOID_TK DOT_TK CLASS_TK |
| { |
| $$ = build_incomplete_class_ref ($2.location, |
| void_type_node); |
| } |
| ; |
| |
| class_instance_creation_expression: |
| NEW_TK class_type OP_TK argument_list CP_TK |
| { $$ = build_new_invocation ($2, $4); } |
| | NEW_TK class_type OP_TK CP_TK |
| { $$ = build_new_invocation ($2, NULL_TREE); } |
| | anonymous_class_creation |
| /* Added, JDK1.1 inner classes, modified to use name or |
| primary instead of primary solely which couldn't work in |
| all situations. */ |
| | something_dot_new identifier OP_TK CP_TK |
| { |
| tree ctor = build_new_invocation ($2, NULL_TREE); |
| $$ = make_qualified_primary ($1, ctor, |
| EXPR_WFL_LINECOL ($1)); |
| } |
| | something_dot_new identifier OP_TK CP_TK class_body |
| | something_dot_new identifier OP_TK argument_list CP_TK |
| { |
| tree ctor = build_new_invocation ($2, $4); |
| $$ = make_qualified_primary ($1, ctor, |
| EXPR_WFL_LINECOL ($1)); |
| } |
| | something_dot_new identifier OP_TK argument_list CP_TK class_body |
| | NEW_TK error SC_TK |
| {$$ = NULL_TREE; yyerror ("'(' expected"); DRECOVER(new_1);} |
| | NEW_TK class_type error |
| {$$ = NULL_TREE; yyerror ("'(' expected"); RECOVER;} |
| | NEW_TK class_type OP_TK error |
| {$$ = NULL_TREE; yyerror ("')' or term expected"); RECOVER;} |
| | NEW_TK class_type OP_TK argument_list error |
| {$$ = NULL_TREE; yyerror ("')' expected"); RECOVER;} |
| | something_dot_new error |
| { |
| $$ = NULL_TREE; |
| YYERROR_NOW; |
| yyerror ("Identifier expected"); |
| RECOVER; |
| } |
| | something_dot_new identifier error |
| {$$ = NULL_TREE; yyerror ("'(' expected"); RECOVER;} |
| ; |
| |
| /* Created after JDK1.1 rules originally added to |
| class_instance_creation_expression, but modified to use |
| 'class_type' instead of 'TypeName' (type_name) which is mentioned |
| in the documentation but doesn't exist. */ |
| |
| anonymous_class_creation: |
| NEW_TK class_type OP_TK argument_list CP_TK |
| { create_anonymous_class ($2); } |
| class_body |
| { |
| tree id = build_wfl_node (DECL_NAME (GET_CPC ())); |
| EXPR_WFL_LINECOL (id) = EXPR_WFL_LINECOL ($2); |
| |
| end_class_declaration (1); |
| |
| /* Now we can craft the new expression */ |
| $$ = build_new_invocation (id, $4); |
| |
| /* Note that we can't possibly be here if |
| `class_type' is an interface (in which case the |
| anonymous class extends Object and implements |
| `class_type', hence its constructor can't have |
| arguments.) */ |
| |
| /* Otherwise, the innerclass must feature a |
| constructor matching `argument_list'. Anonymous |
| classes are a bit special: it's impossible to |
| define constructor for them, hence constructors |
| must be generated following the hints provided by |
| the `new' expression. Whether a super constructor |
| of that nature exists or not is to be verified |
| later on in verify_constructor_super. |
| |
| It's during the expansion of a `new' statement |
| referring to an anonymous class that a ctor will |
| be generated for the anonymous class, with the |
| right arguments. */ |
| |
| } |
| | NEW_TK class_type OP_TK CP_TK |
| { create_anonymous_class ($2); } |
| class_body |
| { |
| tree id = build_wfl_node (DECL_NAME (GET_CPC ())); |
| EXPR_WFL_LINECOL (id) = EXPR_WFL_LINECOL ($2); |
| |
| end_class_declaration (1); |
| |
| /* Now we can craft the new expression. The |
| statement doesn't need to be remember so that a |
| constructor can be generated, since its signature |
| is already known. */ |
| $$ = build_new_invocation (id, NULL_TREE); |
| } |
| ; |
| |
| something_dot_new: /* Added, not part of the specs. */ |
| name DOT_TK NEW_TK |
| { $$ = $1; } |
| | primary DOT_TK NEW_TK |
| { $$ = $1; } |
| ; |
| |
| argument_list: |
| expression |
| { |
| $$ = tree_cons (NULL_TREE, $1, NULL_TREE); |
| ctxp->formal_parameter_number = 1; |
| } |
| | argument_list C_TK expression |
| { |
| ctxp->formal_parameter_number += 1; |
| $$ = tree_cons (NULL_TREE, $3, $1); |
| } |
| | argument_list C_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| array_creation_uninitialized: |
| NEW_TK primitive_type dim_exprs |
| { $$ = build_newarray_node ($2, $3, 0); } |
| | NEW_TK class_or_interface_type dim_exprs |
| { $$ = build_newarray_node ($2, $3, 0); } |
| | NEW_TK primitive_type dim_exprs dims |
| { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));} |
| | NEW_TK class_or_interface_type dim_exprs dims |
| { $$ = build_newarray_node ($2, $3, pop_current_osb (ctxp));} |
| | NEW_TK error CSB_TK |
| {yyerror ("'[' expected"); DRECOVER ("]");} |
| | NEW_TK error OSB_TK |
| {yyerror ("']' expected"); RECOVER;} |
| ; |
| |
| array_creation_initialized: |
| /* Added, JDK1.1 anonymous array. Initial documentation rule |
| modified */ |
| NEW_TK class_or_interface_type dims array_initializer |
| { |
| char *sig; |
| int osb = pop_current_osb (ctxp); |
| while (osb--) |
| obstack_grow (&temporary_obstack, "[]", 2); |
| obstack_1grow (&temporary_obstack, '\0'); |
| sig = obstack_finish (&temporary_obstack); |
| $$ = build3 (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE, |
| $2, get_identifier (sig), $4); |
| } |
| | NEW_TK primitive_type dims array_initializer |
| { |
| int osb = pop_current_osb (ctxp); |
| tree type = $2; |
| while (osb--) |
| type = build_java_array_type (type, -1); |
| $$ = build3 (NEW_ANONYMOUS_ARRAY_EXPR, NULL_TREE, |
| build_pointer_type (type), NULL_TREE, $4); |
| } |
| | NEW_TK error CSB_TK |
| {yyerror ("'[' expected"); DRECOVER ("]");} |
| | NEW_TK error OSB_TK |
| {yyerror ("']' expected"); RECOVER;} |
| ; |
| |
| dim_exprs: |
| dim_expr |
| { $$ = build_tree_list (NULL_TREE, $1); } |
| | dim_exprs dim_expr |
| { $$ = tree_cons (NULL_TREE, $2, $$); } |
| ; |
| |
| dim_expr: |
| OSB_TK expression CSB_TK |
| { |
| if (JNUMERIC_TYPE_P (TREE_TYPE ($2))) |
| { |
| $2 = build_wfl_node ($2); |
| TREE_TYPE ($2) = NULL_TREE; |
| } |
| EXPR_WFL_LINECOL ($2) = $1.location; |
| $$ = $2; |
| } |
| | OSB_TK expression error |
| {yyerror ("']' expected"); RECOVER;} |
| | OSB_TK error |
| { |
| yyerror ("Missing term"); |
| yyerror ("']' expected"); |
| RECOVER; |
| } |
| ; |
| |
| dims: |
| OSB_TK CSB_TK |
| { |
| int allocate = 0; |
| /* If not initialized, allocate memory for the osb |
| numbers stack */ |
| if (!ctxp->osb_limit) |
| { |
| allocate = ctxp->osb_limit = 32; |
| ctxp->osb_depth = -1; |
| } |
| /* If capacity overflown, reallocate a bigger chunk */ |
| else if (ctxp->osb_depth+1 == ctxp->osb_limit) |
| allocate = ctxp->osb_limit << 1; |
| |
| if (allocate) |
| { |
| allocate *= sizeof (int); |
| if (ctxp->osb_number) |
| ctxp->osb_number = xrealloc (ctxp->osb_number, |
| allocate); |
| else |
| ctxp->osb_number = xmalloc (allocate); |
| } |
| ctxp->osb_depth++; |
| CURRENT_OSB (ctxp) = 1; |
| } |
| | dims OSB_TK CSB_TK |
| { CURRENT_OSB (ctxp)++; } |
| | dims OSB_TK error |
| { yyerror ("']' expected"); RECOVER;} |
| ; |
| |
| field_access: |
| primary DOT_TK identifier |
| { $$ = make_qualified_primary ($1, $3, $2.location); } |
| /* FIXME - REWRITE TO: |
| { $$ = build_binop (COMPONENT_REF, $2.location, $1, $3); } */ |
| | SUPER_TK DOT_TK identifier |
| { |
| tree super_wfl = build_wfl_node (super_identifier_node); |
| SET_EXPR_LOCATION_FROM_TOKEN (super_wfl, $1); |
| $$ = make_qualified_name (super_wfl, $3, $2.location); |
| } |
| | SUPER_TK error |
| {yyerror ("Field expected"); DRECOVER (super_field_acces);} |
| ; |
| |
| method_invocation: |
| name OP_TK CP_TK |
| { $$ = build_method_invocation ($1, NULL_TREE); } |
| | name OP_TK argument_list CP_TK |
| { $$ = build_method_invocation ($1, $3); } |
| | primary DOT_TK identifier OP_TK CP_TK |
| { |
| if (TREE_CODE ($1) == THIS_EXPR) |
| $$ = build_this_super_qualified_invocation |
| (1, $3, NULL_TREE, 0, $2.location); |
| else |
| { |
| tree invok = build_method_invocation ($3, NULL_TREE); |
| $$ = make_qualified_primary ($1, invok, $2.location); |
| } |
| } |
| | primary DOT_TK identifier OP_TK argument_list CP_TK |
| { |
| if (TREE_CODE ($1) == THIS_EXPR) |
| $$ = build_this_super_qualified_invocation |
| (1, $3, $5, 0, $2.location); |
| else |
| { |
| tree invok = build_method_invocation ($3, $5); |
| $$ = make_qualified_primary ($1, invok, $2.location); |
| } |
| } |
| | SUPER_TK DOT_TK identifier OP_TK CP_TK |
| { |
| $$ = build_this_super_qualified_invocation |
| (0, $3, NULL_TREE, $1.location, $2.location); |
| } |
| | SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK |
| { |
| $$ = build_this_super_qualified_invocation |
| (0, $3, $5, $1.location, $2.location); |
| } |
| /* Screws up thing. I let it here until I'm convinced it can |
| be removed. FIXME |
| | primary DOT_TK error |
| {yyerror ("'(' expected"); DRECOVER(bad);} */ |
| | SUPER_TK DOT_TK error CP_TK |
| { yyerror ("'(' expected"); DRECOVER (method_invocation); } |
| | SUPER_TK DOT_TK error DOT_TK |
| { yyerror ("'(' expected"); DRECOVER (method_invocation); } |
| ; |
| |
| array_access: |
| name OSB_TK expression CSB_TK |
| { $$ = build_array_ref ($2.location, $1, $3); } |
| | primary_no_new_array OSB_TK expression CSB_TK |
| { $$ = build_array_ref ($2.location, $1, $3); } |
| | array_creation_initialized OSB_TK expression CSB_TK |
| { $$ = build_array_ref ($2.location, $1, $3); } |
| | name OSB_TK error |
| { |
| yyerror ("Missing term and ']' expected"); |
| DRECOVER(array_access); |
| } |
| | name OSB_TK expression error |
| { |
| yyerror ("']' expected"); |
| DRECOVER(array_access); |
| } |
| | primary_no_new_array OSB_TK error |
| { |
| yyerror ("Missing term and ']' expected"); |
| DRECOVER(array_access); |
| } |
| | primary_no_new_array OSB_TK expression error |
| { |
| yyerror ("']' expected"); |
| DRECOVER(array_access); |
| } |
| | array_creation_initialized OSB_TK error |
| { |
| yyerror ("Missing term and ']' expected"); |
| DRECOVER(array_access); |
| } |
| | array_creation_initialized OSB_TK expression error |
| { |
| yyerror ("']' expected"); |
| DRECOVER(array_access); |
| } |
| ; |
| |
| postfix_expression: |
| primary |
| | name |
| | post_increment_expression |
| | post_decrement_expression |
| ; |
| |
| post_increment_expression: |
| postfix_expression INCR_TK |
| { $$ = build_incdec ($2.token, $2.location, $1, 1); } |
| ; |
| |
| post_decrement_expression: |
| postfix_expression DECR_TK |
| { $$ = build_incdec ($2.token, $2.location, $1, 1); } |
| ; |
| |
| trap_overflow_corner_case: |
| pre_increment_expression |
| | pre_decrement_expression |
| | PLUS_TK unary_expression |
| {$$ = build_unaryop ($1.token, $1.location, $2); } |
| | unary_expression_not_plus_minus |
| | PLUS_TK error |
| {yyerror ("Missing term"); RECOVER} |
| ; |
| |
| unary_expression: |
| trap_overflow_corner_case |
| { |
| if ($1) |
| error_if_numeric_overflow ($1); |
| $$ = $1; |
| } |
| | MINUS_TK trap_overflow_corner_case |
| {$$ = build_unaryop ($1.token, $1.location, $2); } |
| | MINUS_TK error |
| {yyerror ("Missing term"); RECOVER} |
| ; |
| |
| pre_increment_expression: |
| INCR_TK unary_expression |
| {$$ = build_incdec ($1.token, $1.location, $2, 0); } |
| | INCR_TK error |
| {yyerror ("Missing term"); RECOVER} |
| ; |
| |
| pre_decrement_expression: |
| DECR_TK unary_expression |
| {$$ = build_incdec ($1.token, $1.location, $2, 0); } |
| | DECR_TK error |
| {yyerror ("Missing term"); RECOVER} |
| ; |
| |
| unary_expression_not_plus_minus: |
| postfix_expression |
| | NOT_TK unary_expression |
| {$$ = build_unaryop ($1.token, $1.location, $2); } |
| | NEG_TK unary_expression |
| {$$ = build_unaryop ($1.token, $1.location, $2); } |
| | cast_expression |
| | NOT_TK error |
| {yyerror ("Missing term"); RECOVER} |
| | NEG_TK error |
| {yyerror ("Missing term"); RECOVER} |
| ; |
| |
| cast_expression: /* Error handling here is potentially weak */ |
| OP_TK primitive_type dims CP_TK unary_expression |
| { |
| tree type = $2; |
| int osb = pop_current_osb (ctxp); |
| while (osb--) |
| type = build_java_array_type (type, -1); |
| $$ = build_cast ($1.location, type, $5); |
| } |
| | OP_TK primitive_type CP_TK unary_expression |
| { $$ = build_cast ($1.location, $2, $4); } |
| | OP_TK expression CP_TK unary_expression_not_plus_minus |
| { $$ = build_cast ($1.location, $2, $4); } |
| | OP_TK name dims CP_TK unary_expression_not_plus_minus |
| { |
| const char *ptr; |
| int osb = pop_current_osb (ctxp); |
| obstack_grow (&temporary_obstack, |
| IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)), |
| IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2))); |
| while (osb--) |
| obstack_grow (&temporary_obstack, "[]", 2); |
| obstack_1grow (&temporary_obstack, '\0'); |
| ptr = obstack_finish (&temporary_obstack); |
| EXPR_WFL_NODE ($2) = get_identifier (ptr); |
| $$ = build_cast ($1.location, $2, $5); |
| } |
| | OP_TK primitive_type OSB_TK error |
| {yyerror ("']' expected, invalid type expression");} |
| | OP_TK error |
| { |
| YYNOT_TWICE yyerror ("Invalid type expression"); RECOVER; |
| RECOVER; |
| } |
| | OP_TK primitive_type dims CP_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | OP_TK primitive_type CP_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | OP_TK name dims CP_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| multiplicative_expression: |
| unary_expression |
| | multiplicative_expression MULT_TK unary_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), |
| $2.location, $1, $3); |
| } |
| | multiplicative_expression DIV_TK unary_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | multiplicative_expression REM_TK unary_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | multiplicative_expression MULT_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | multiplicative_expression DIV_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | multiplicative_expression REM_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| additive_expression: |
| multiplicative_expression |
| | additive_expression PLUS_TK multiplicative_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | additive_expression MINUS_TK multiplicative_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | additive_expression PLUS_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | additive_expression MINUS_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| shift_expression: |
| additive_expression |
| | shift_expression LS_TK additive_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | shift_expression SRS_TK additive_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | shift_expression ZRS_TK additive_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | shift_expression LS_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | shift_expression SRS_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | shift_expression ZRS_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| relational_expression: |
| shift_expression |
| | relational_expression LT_TK shift_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | relational_expression GT_TK shift_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | relational_expression LTE_TK shift_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | relational_expression GTE_TK shift_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | relational_expression INSTANCEOF_TK reference_type |
| { $$ = build_binop (INSTANCEOF_EXPR, $2.location, $1, $3); } |
| | relational_expression LT_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | relational_expression GT_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | relational_expression LTE_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | relational_expression GTE_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | relational_expression INSTANCEOF_TK error |
| {yyerror ("Invalid reference type"); RECOVER;} |
| ; |
| |
| equality_expression: |
| relational_expression |
| | equality_expression EQ_TK relational_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | equality_expression NEQ_TK relational_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | equality_expression EQ_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| | equality_expression NEQ_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| and_expression: |
| equality_expression |
| | and_expression AND_TK equality_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | and_expression AND_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| exclusive_or_expression: |
| and_expression |
| | exclusive_or_expression XOR_TK and_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | exclusive_or_expression XOR_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| inclusive_or_expression: |
| exclusive_or_expression |
| | inclusive_or_expression OR_TK exclusive_or_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | inclusive_or_expression OR_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| conditional_and_expression: |
| inclusive_or_expression |
| | conditional_and_expression BOOL_AND_TK inclusive_or_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | conditional_and_expression BOOL_AND_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| conditional_or_expression: |
| conditional_and_expression |
| | conditional_or_expression BOOL_OR_TK conditional_and_expression |
| { |
| $$ = build_binop (BINOP_LOOKUP ($2.token), $2.location, |
| $1, $3); |
| } |
| | conditional_or_expression BOOL_OR_TK error |
| {yyerror ("Missing term"); RECOVER;} |
| ; |
| |
| conditional_expression: /* Error handling here is weak */ |
| conditional_or_expression |
| | conditional_or_expression REL_QM_TK expression REL_CL_TK conditional_expression |
| { |
| $$ = build3 (CONDITIONAL_EXPR, NULL_TREE, $1, $3, $5); |
| SET_EXPR_LOCATION_FROM_TOKEN ($$, $2); |
| } |
| | conditional_or_expression REL_QM_TK REL_CL_TK error |
| { |
| YYERROR_NOW; |
| yyerror ("Missing term"); |
| DRECOVER (1); |
| } |
| | conditional_or_expression REL_QM_TK error |
| {yyerror ("Missing term"); DRECOVER (2);} |
| | conditional_or_expression REL_QM_TK expression REL_CL_TK error |
| {yyerror ("Missing term"); DRECOVER (3);} |
| ; |
| |
| assignment_expression: |
| conditional_expression |
| | assignment |
| ; |
| |
| assignment: |
| left_hand_side assignment_operator assignment_expression |
| { $$ = build_assignment ($2.token, $2.location, $1, $3); } |
| | left_hand_side assignment_operator error |
| { |
| YYNOT_TWICE yyerror ("Missing term"); |
| DRECOVER (assign); |
| } |
| ; |
| |
| left_hand_side: |
| name |
| | field_access |
| | array_access |
| ; |
| |
| assignment_operator: |
| ASSIGN_ANY_TK |
| | ASSIGN_TK |
| ; |
| |
| expression: |
| assignment_expression |
| ; |
| |
| constant_expression: |
| expression |
| ; |
| |
| %% |
| |
| /* Helper function to retrieve an OSB count. Should be used when the |
| `dims:' rule is being used. */ |
| |
| static int |
| pop_current_osb (struct parser_ctxt *ctxp) |
| { |
| int to_return; |
| |
| if (ctxp->osb_depth < 0) |
| abort (); |
| |
| to_return = CURRENT_OSB (ctxp); |
| ctxp->osb_depth--; |
| |
| return to_return; |
| } |
| |
| |
| |
| /* This section of the code deal with save/restoring parser contexts. |
| Add mode documentation here. FIXME */ |
| |
| /* Helper function. Create a new parser context. With |
| COPY_FROM_PREVIOUS set to a nonzero value, content of the previous |
| context is copied, otherwise, the new context is zeroed. The newly |
| created context becomes the current one. */ |
| |
| static void |
| create_new_parser_context (int copy_from_previous) |
| { |
| struct parser_ctxt *new; |
| |
| new = ggc_alloc (sizeof (struct parser_ctxt)); |
| if (copy_from_previous) |
| { |
| memcpy (new, ctxp, sizeof (struct parser_ctxt)); |
| /* This flag, indicating the context saves global values, |
| should only be set by java_parser_context_save_global. */ |
| new->saved_data_ctx = 0; |
| } |
| else |
| memset (new, 0, sizeof (struct parser_ctxt)); |
| |
| new->next = ctxp; |
| ctxp = new; |
| } |
| |
| /* Create a new parser context and make it the current one. */ |
| |
| void |
| java_push_parser_context (void) |
| { |
| create_new_parser_context (0); |
| } |
| |
| void |
| java_pop_parser_context (int generate) |
| { |
| tree current; |
| struct parser_ctxt *next; |
| |
| if (!ctxp) |
| return; |
| |
| next = ctxp->next; |
| if (next) |
| { |
| input_location = ctxp->save_location; |
| current_class = ctxp->class_type; |
| } |
| |
| /* If the old and new lexers differ, then free the old one. */ |
| if (ctxp->lexer && next && ctxp->lexer != next->lexer) |
| java_destroy_lexer (ctxp->lexer); |
| |
| /* Set the single import class file flag to 0 for the current list |
| of imported things */ |
| for (current = ctxp->import_list; current; current = TREE_CHAIN (current)) |
| IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_VALUE (current)) = 0; |
| |
| /* If we pushed a context to parse a class intended to be generated, |
| we keep it so we can remember the class. What we could actually |
| do is to just update a list of class names. */ |
| if (generate) |
| { |
| ctxp->next = ctxp_for_generation; |
| ctxp_for_generation = ctxp; |
| } |
| |
| /* And restore those of the previous context */ |
| if ((ctxp = next)) /* Assignment is really meant here */ |
| for (current = ctxp->import_list; current; current = TREE_CHAIN (current)) |
| IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_VALUE (current)) = 1; |
| } |
| |
| /* Create a parser context for the use of saving some global |
| variables. */ |
| |
| void |
| java_parser_context_save_global (void) |
| { |
| if (!ctxp) |
| { |
| java_push_parser_context (); |
| ctxp->saved_data_ctx = 1; |
| } |
| |
| /* If this context already stores data, create a new one suitable |
| for data storage. */ |
| else if (ctxp->saved_data) |
| { |
| create_new_parser_context (1); |
| ctxp->saved_data_ctx = 1; |
| } |
| |
| ctxp->save_location = input_location; |
| ctxp->class_type = current_class; |
| ctxp->function_decl = current_function_decl; |
| ctxp->saved_data = 1; |
| } |
| |
| /* Restore some global variables from the previous context. Make the |
| previous context the current one. */ |
| |
| void |
| java_parser_context_restore_global (void) |
| { |
| input_location = ctxp->save_location; |
| current_class = ctxp->class_type; |
| if (wfl_operator) |
| #ifdef USE_MAPPED_LOCATION |
| SET_EXPR_LOCATION (wfl_operator, ctxp->save_location); |
| #else |
| EXPR_WFL_FILENAME_NODE (wfl_operator) = get_identifier (input_filename); |
| #endif |
| current_function_decl = ctxp->function_decl; |
| ctxp->saved_data = 0; |
| if (ctxp->saved_data_ctx) |
| java_pop_parser_context (0); |
| } |
| |
| /* Suspend vital data for the current class/function being parsed so |
| that an other class can be parsed. Used to let local/anonymous |
| classes be parsed. */ |
| |
| static void |
| java_parser_context_suspend (void) |
| { |
| /* This makes debugging through java_debug_context easier */ |
| static const char *const name = "<inner buffer context>"; |
| |
| /* Duplicate the previous context, use it to save the globals we're |
| interested in */ |
| create_new_parser_context (1); |
| ctxp->function_decl = current_function_decl; |
| ctxp->class_type = current_class; |
| |
| /* Then create a new context which inherits all data from the |
| previous one. This will be the new current context */ |
| create_new_parser_context (1); |
| |
| /* Help debugging */ |
| ctxp->next->filename = name; |
| } |
| |
| /* Resume vital data for the current class/function being parsed so |
| that an other class can be parsed. Used to let local/anonymous |
| classes be parsed. The trick is the data storing file position |
| informations must be restored to their current value, so parsing |
| can resume as if no context was ever saved. */ |
| |
| static void |
| java_parser_context_resume (void) |
| { |
| struct parser_ctxt *old = ctxp; /* This one is to be discarded */ |
| struct parser_ctxt *saver = old->next; /* This one contain saved info */ |
| struct parser_ctxt *restored = saver->next; /* This one is the old current */ |
| |
| /* We need to inherit the list of classes to complete/generate */ |
| restored->classd_list = old->classd_list; |
| restored->class_list = old->class_list; |
| |
| /* Restore the current class and function from the saver */ |
| current_class = saver->class_type; |
| current_function_decl = saver->function_decl; |
| |
| /* Retrieve the restored context */ |
| ctxp = restored; |
| |
| /* Re-installed the data for the parsing to carry on */ |
| memcpy (&ctxp->marker_begining, &old->marker_begining, |
| (size_t)(&ctxp->marker_end - &ctxp->marker_begining)); |
| } |
| |
| /* Add a new anchor node to which all statement(s) initializing static |
| and non static initialized upon declaration field(s) will be |
| linked. */ |
| |
| static void |
| java_parser_context_push_initialized_field (void) |
| { |
| tree node; |
| |
| node = build_tree_list (NULL_TREE, NULL_TREE); |
| TREE_CHAIN (node) = CPC_STATIC_INITIALIZER_LIST (ctxp); |
| CPC_STATIC_INITIALIZER_LIST (ctxp) = node; |
| |
| node = build_tree_list (NULL_TREE, NULL_TREE); |
| TREE_CHAIN (node) = CPC_INITIALIZER_LIST (ctxp); |
| CPC_INITIALIZER_LIST (ctxp) = node; |
| |
| node = build_tree_list (NULL_TREE, NULL_TREE); |
| TREE_CHAIN (node) = CPC_INSTANCE_INITIALIZER_LIST (ctxp); |
| CPC_INSTANCE_INITIALIZER_LIST (ctxp) = node; |
| } |
| |
| /* Pop the lists of initialized field. If this lists aren't empty, |
| remember them so we can use it to create and populate the finit$ |
| or <clinit> functions. */ |
| |
| static void |
| java_parser_context_pop_initialized_field (void) |
| { |
| tree stmts; |
| tree class_type = TREE_TYPE (GET_CPC ()); |
| |
| if (CPC_INITIALIZER_LIST (ctxp)) |
| { |
| stmts = CPC_INITIALIZER_STMT (ctxp); |
| CPC_INITIALIZER_LIST (ctxp) = TREE_CHAIN (CPC_INITIALIZER_LIST (ctxp)); |
| if (stmts && !java_error_count) |
| TYPE_FINIT_STMT_LIST (class_type) = reorder_static_initialized (stmts); |
| } |
| |
| if (CPC_STATIC_INITIALIZER_LIST (ctxp)) |
| { |
| stmts = CPC_STATIC_INITIALIZER_STMT (ctxp); |
| CPC_STATIC_INITIALIZER_LIST (ctxp) = |
| TREE_CHAIN (CPC_STATIC_INITIALIZER_LIST (ctxp)); |
| /* Keep initialization in order to enforce 8.5 */ |
| if (stmts && !java_error_count) |
| TYPE_CLINIT_STMT_LIST (class_type) = nreverse (stmts); |
| } |
| |
| /* JDK 1.1 instance initializers */ |
| if (CPC_INSTANCE_INITIALIZER_LIST (ctxp)) |
| { |
| stmts = CPC_INSTANCE_INITIALIZER_STMT (ctxp); |
| CPC_INSTANCE_INITIALIZER_LIST (ctxp) = |
| TREE_CHAIN (CPC_INSTANCE_INITIALIZER_LIST (ctxp)); |
| if (stmts && !java_error_count) |
| TYPE_II_STMT_LIST (class_type) = nreverse (stmts); |
| } |
| } |
| |
| static tree |
| reorder_static_initialized (tree list) |
| { |
| /* We have to keep things in order. The alias initializer have to |
| come first, then the initialized regular field, in reverse to |
| keep them in lexical order. */ |
| tree marker, previous = NULL_TREE; |
| for (marker = list; marker; previous = marker, marker = TREE_CHAIN (marker)) |
| if (TREE_CODE (marker) == TREE_LIST |
| && !TREE_VALUE (marker) && !TREE_PURPOSE (marker)) |
| break; |
| |
| /* No static initialized, the list is fine as is */ |
| if (!previous) |
| list = TREE_CHAIN (marker); |
| |
| /* No marker? reverse the whole list */ |
| else if (!marker) |
| list = nreverse (list); |
| |
| /* Otherwise, reverse what's after the marker and the new reordered |
| sublist will replace the marker. */ |
| else |
| { |
| TREE_CHAIN (previous) = NULL_TREE; |
| list = nreverse (list); |
| list = chainon (TREE_CHAIN (marker), list); |
| } |
| return list; |
| } |
| |
| /* Helper functions to dump the parser context stack. */ |
| |
| #define TAB_CONTEXT(C) \ |
| {int i; for (i = 0; i < (C); i++) fputc (' ', stderr);} |
| |
| static void |
| java_debug_context_do (int tab) |
| { |
| struct parser_ctxt *copy = ctxp; |
| while (copy) |
| { |
| TAB_CONTEXT (tab); |
| fprintf (stderr, "ctxt: 0x%0lX\n", (unsigned long)copy); |
| TAB_CONTEXT (tab); |
| fprintf (stderr, "filename: %s\n", copy->filename); |
| TAB_CONTEXT (tab); |
| fprintf (stderr, "package: %s\n", |
| (copy->package ? |
| IDENTIFIER_POINTER (copy->package) : "<none>")); |
| TAB_CONTEXT (tab); |
| fprintf (stderr, "context for saving: %d\n", copy->saved_data_ctx); |
| TAB_CONTEXT (tab); |
| fprintf (stderr, "saved data: %d\n", copy->saved_data); |
| copy = copy->next; |
| tab += 2; |
| } |
| } |
| |
| /* Dump the stacked up parser contexts. Intended to be called from a |
| debugger. */ |
| |
| void |
| java_debug_context (void) |
| { |
| java_debug_context_do (0); |
| } |
| |
| |
| |
| /* Flag for the error report routine to issue the error the first time |
| it's called (overriding the default behavior which is to drop the |
| first invocation and honor the second one, taking advantage of a |
| richer context. */ |
| static int force_error = 0; |
| |
| /* Reporting an constructor invocation error. */ |
| static void |
| parse_ctor_invocation_error (void) |
| { |
| if (DECL_CONSTRUCTOR_P (current_function_decl)) |
| yyerror ("Constructor invocation must be first thing in a constructor"); |
| else |
| yyerror ("Only constructors can invoke constructors"); |
| } |
| |
| /* Reporting JDK1.1 features not implemented. */ |
| |
| static tree |
| parse_jdk1_1_error (const char *msg) |
| { |
| sorry (": %qs JDK1.1(TM) feature", msg); |
| java_error_count++; |
| return build_java_empty_stmt (); |
| } |
| |
| static int do_warning = 0; |
| |
| void |
| yyerror (const char *msgid) |
| { |
| #ifdef USE_MAPPED_LOCATION |
| static source_location elc; |
| expanded_location xloc = expand_location (input_location); |
| int current_line = xloc.line; |
| #else |
| static java_lc elc; |
| int save_lineno; |
| int current_line = input_line; |
| #endif |
| static int prev_lineno; |
| static const char *prev_msg; |
| |
| char *remainder, *code_from_source; |
| |
| if (!force_error && prev_lineno == current_line) |
| return; |
| #ifndef USE_MAPPED_LOCATION |
| current_line = ctxp->lexer->token_start.line; |
| #endif |
| |
| /* Save current error location but report latter, when the context is |
| richer. */ |
| if (ctxp->java_error_flag == 0) |
| { |
| ctxp->java_error_flag = 1; |
| #ifdef USE_MAPPED_LOCATION |
| elc = input_location; |
| #else |
| elc = ctxp->lexer->token_start; |
| #endif |
| /* Do something to use the previous line if we're reaching the |
| end of the file... */ |
| #ifdef VERBOSE_SKELETON |
| printf ("* Error detected (%s)\n", (msgid ? msgid : "(null)")); |
| #endif |
| return; |
| } |
| |
| /* Ignore duplicate message on the same line. BTW, this is dubious. FIXME */ |
| if (!force_error && msgid == prev_msg && prev_lineno == current_line) |
| return; |
| |
| ctxp->java_error_flag = 0; |
| if (do_warning) |
| java_warning_count++; |
| else |
| java_error_count++; |
| |
| #if 0 /* FIXME */ |
| if (elc.col == 0 && msgid && msgid[1] == ';') |
| elc = ctxp->prev_line_end; |
| #endif |
| |
| prev_msg = msgid; |
| |
| #ifdef USE_MAPPED_LOCATION |
| prev_lineno = current_line; |
| code_from_source = java_get_line_col (xloc.file, current_line, xloc.column); |
| #else |
| save_lineno = input_line; |
| prev_lineno = input_line = current_line; |
| code_from_source = java_get_line_col (input_filename, current_line, |
| ctxp->lexer->token_start.col); |
| #endif |
| |
| |
| obstack_grow0 (&temporary_obstack, |
| code_from_source, strlen (code_from_source)); |
| remainder = obstack_finish (&temporary_obstack); |
| if (do_warning) |
| warning ("%s.\n%s", msgid, remainder); |
| else |
| error ("%s.\n%s", msgid, remainder); |
| |
| /* This allow us to cheaply avoid an extra 'Invalid expression |
| statement' error report when errors have been already reported on |
| the same line. This occurs when we report an error but don't have |
| a synchronization point other than ';', which |
| expression_statement is the only one to take care of. */ |
| #ifndef USE_MAPPED_LOCATION |
| input_line = save_lineno; |
| #endif |
| ctxp->prevent_ese = input_line; |
| } |
| |
| static void |
| issue_warning_error_from_context ( |
| #ifdef USE_MAPPED_LOCATION |
| source_location cl, |
| #else |
| tree cl, |
| #endif |
| const char *gmsgid, va_list *ap) |
| { |
| #ifdef USE_MAPPED_LOCATION |
| source_location saved_location = input_location; |
| expanded_location xloc = expand_location (cl); |
| #else |
| java_lc save_lc = ctxp->lexer->token_start; |
| const char *saved = ctxp->filename, *saved_input_filename; |
| #endif |
| char buffer [4096]; |
| text_info text; |
| |
| text.err_no = errno; |
| text.args_ptr = ap; |
| text.format_spec = gmsgid; |
| pp_format_text (global_dc->printer, &text); |
| strncpy (buffer, pp_formatted_text (global_dc->printer), sizeof (buffer) - 1); |
| buffer[sizeof (buffer) - 1] = '\0'; |
| pp_clear_output_area (global_dc->printer); |
| |
| force_error = 1; |
| |
| #ifdef USE_MAPPED_LOCATION |
| if (xloc.file != NULL) |
| { |
| ctxp->filename = xloc.file; |
| input_location = cl; |
| } |
| #else |
| ctxp->lexer->token_start.line = EXPR_WFL_LINENO (cl); |
| ctxp->lexer->token_start.col = (EXPR_WFL_COLNO (cl) == 0xfff ? -1 |
| : EXPR_WFL_COLNO (cl) == 0xffe ? -2 |
| : EXPR_WFL_COLNO (cl)); |
| |
| /* We have a CL, that's a good reason for using it if it contains data */ |
| if (TREE_CODE (cl) == EXPR_WITH_FILE_LOCATION && EXPR_WFL_FILENAME_NODE (cl)) |
| ctxp->filename = EXPR_WFL_FILENAME (cl); |
| saved_input_filename = input_filename; |
| input_filename = ctxp->filename; |
| #endif |
| java_error (NULL); |
| java_error (buffer); |
| #ifdef USE_MAPPED_LOCATION |
| input_location = saved_location; |
| #else |
| ctxp->filename = saved; |
| input_filename = saved_input_filename; |
| ctxp->lexer->token_start = save_lc; |
| #endif |
| force_error = 0; |
| } |
| |
| /* Issue an error message at a current source line CL. |
| FUTURE/FIXME: change cl to be a source_location. */ |
| |
| void |
| parse_error_context (tree cl, const char *gmsgid, ...) |
| { |
| va_list ap; |
| va_start (ap, gmsgid); |
| #ifdef USE_MAPPED_LOCATION |
| issue_warning_error_from_context (EXPR_LOCATION (cl), gmsgid, &ap); |
| #else |
| issue_warning_error_from_context (cl, gmsgid, &ap); |
| #endif |
| va_end (ap); |
| } |
| |
| /* Issue a warning at a current source line CL. |
| FUTURE/FIXME: change cl to be a source_location. */ |
| |
| static void |
| parse_warning_context (tree cl, const char *gmsgid, ...) |
| { |
| va_list ap; |
| va_start (ap, gmsgid); |
| |
| do_warning = 1; |
| #ifdef USE_MAPPED_LOCATION |
| issue_warning_error_from_context (EXPR_LOCATION (cl), gmsgid, &ap); |
| #else |
| issue_warning_error_from_context (cl, gmsgid, &ap); |
| #endif |
| do_warning = 0; |
| va_end (ap); |
| } |
| |
| static tree |
| find_expr_with_wfl (tree node) |
| { |
| while (node) |
| { |
| enum tree_code_class code; |
| tree to_return; |
| |
| switch (TREE_CODE (node)) |
| { |
| case BLOCK: |
| node = BLOCK_EXPR_BODY (node); |
| continue; |
| |
| case COMPOUND_EXPR: |
| to_return = find_expr_with_wfl (TREE_OPERAND (node, 0)); |
| if (to_return) |
| return to_return; |
| node = TREE_OPERAND (node, 1); |
| continue; |
| |
| case LOOP_EXPR: |
| node = TREE_OPERAND (node, 0); |
| continue; |
| |
| case LABELED_BLOCK_EXPR: |
| node = LABELED_BLOCK_BODY (node); |
| continue; |
| |
| default: |
| code = TREE_CODE_CLASS (TREE_CODE (node)); |
| if (((code == tcc_unary) || (code == tcc_binary) |
| || (code == tcc_expression)) |
| && EXPR_WFL_LINECOL (node)) |
| return node; |
| return NULL_TREE; |
| } |
| } |
| return NULL_TREE; |
| } |
| |
| /* Issue a missing return statement error. Uses METHOD to figure the |
| last line of the method the error occurs in. */ |
| |
| static void |
| missing_return_error (tree method) |
| { |
| #ifdef USE_MAPPED_LOCATION |
| SET_EXPR_LOCATION (wfl_operator, DECL_FUNCTION_LAST_LINE (method)); |
| #else |
| EXPR_WFL_SET_LINECOL (wfl_operator, DECL_FUNCTION_LAST_LINE (method), -2); |
| #endif |
| parse_error_context (wfl_operator, "Missing return statement"); |
| } |
| |
| /* Issue an unreachable statement error. From NODE, find the next |
| statement to report appropriately. */ |
| static void |
| unreachable_stmt_error (tree node) |
| { |
| /* Browse node to find the next expression node that has a WFL. Use |
| the location to report the error */ |
| if (TREE_CODE (node) == COMPOUND_EXPR) |
| node = find_expr_with_wfl (TREE_OPERAND (node, 1)); |
| else |
| node = find_expr_with_wfl (node); |
| |
| if (node) |
| { |
| #ifdef USE_MAPPED_LOCATION |
| SET_EXPR_LOCATION (wfl_operator, EXPR_LOCATION (node)); |
| #else |
| EXPR_WFL_SET_LINECOL (wfl_operator, EXPR_WFL_LINENO (node), -2); |
| #endif |
| parse_error_context (wfl_operator, "Unreachable statement"); |
| } |
| else |
| abort (); |
| } |
| |
| static int |
| not_accessible_field_error (tree wfl, tree decl) |
| { |
| parse_error_context |
| (wfl, "Can't access %s field %<%s.%s%> from %qs", |
| accessibility_string (get_access_flags_from_decl (decl)), |
| GET_TYPE_NAME (DECL_CONTEXT (decl)), |
| IDENTIFIER_POINTER (DECL_NAME (decl)), |
| IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); |
| return 1; |
| } |
| |
| int |
| java_report_errors (void) |
| { |
| if (java_error_count) |
| fprintf (stderr, "%d error%s", |
| java_error_count, (java_error_count == 1 ? "" : "s")); |
| if ( |