blob: e0abe7e8dc323051d0c947737d954db92c49286a [file] [log] [blame]
/* 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 (