/* Parser grammar for quick source code scan of Java(TM) language programs.
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com)
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+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.
-GNU CC is distributed in the hope that it will be useful,
+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 GNU CC; see the file COPYING. If not, write to
+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.
#include "config.h"
#include "system.h"
-
+#include "coretypes.h"
+#include "tm.h"
#include "obstack.h"
#include "toplev.h"
-extern char *input_filename;
extern FILE *finput, *out;
+
+ const char *main_input_filename;
/* Obstack for the lexer. */
struct obstack temporary_obstack;
/* The current parser context. */
-static struct parser_ctxt *ctxp;
+struct parser_ctxt *ctxp;
-/* Error and warning counts, current line number, because they're used
- elsewhere */
+/* Error and warning counts, because they're used elsewhere */
int java_error_count;
int java_warning_count;
-int lineno;
/* Tweak default rules when necessary. */
static int absorber;
#define USE_ABSORBER absorber = 0
-/* Keep track of the current class name and package name. */
-static char *current_class;
+/* Keep track of the current package name. */
static const char *package_name;
-/* Keep track of the current inner class qualifier. */
-static int current_class_length;
-
/* Keep track of whether things have be listed before. */
static int previous_output;
/* Numbers anonymous classes */
static int anonymous_count;
+/* This is used to record the current class context. */
+struct class_context
+{
+ char *name;
+ struct class_context *next;
+};
+
+/* The global class context. */
+static struct class_context *current_class_context;
+
+/* A special constant used to represent an anonymous context. */
+static const char *anonymous_context = "ANONYMOUS";
+
+/* Count of method depth. */
+static int method_depth;
+
/* Record a method declaration */
struct method_declarator {
const char *method_name;
};
#define NEW_METHOD_DECLARATOR(D,N,A) \
{ \
- (D) = \
- (struct method_declarator *)xmalloc (sizeof (struct method_declarator)); \
+ (D) = xmalloc (sizeof (struct method_declarator)); \
(D)->method_name = (N); \
(D)->args = (A); \
}
/* Two actions for this grammar */
-static void report_class_declaration PARAMS ((const char *));
-static void report_main_declaration PARAMS ((struct method_declarator *));
-static void push_class_context PARAMS ((const char *));
-static void pop_class_context PARAMS ((void));
+static int make_class_name_recursive (struct obstack *stack,
+ struct class_context *ctx);
+static char *get_class_name (void);
+static void report_class_declaration (const char *);
+static void report_main_declaration (struct method_declarator *);
+static void push_class_context (const char *);
+static void pop_class_context (void);
-void report PARAMS ((void));
+void report (void);
#include "lex.h"
#include "parse.h"
}
%{
+extern int flag_assert;
+
#include "lex.c"
%}
%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
/* 19.8.3 Productions from 8.4: Method Declarations */
method_declaration:
- method_header method_body
+ method_header
+ { ++method_depth; }
+ method_body
+ { --method_depth; }
;
method_header:
if (bracket_count)
{
int i;
- char *n = xmalloc (bracket_count + 1 + strlen ($$));
+ char *n = xmalloc (bracket_count + 1 + strlen ($2));
for (i = 0; i < bracket_count; ++i)
n[i] = '[';
- strcpy (n + bracket_count, $$);
+ strcpy (n + bracket_count, $2);
$$ = n;
}
else
/* 19.8.5 Productions from 8.6: Constructor Declarations */
/* NOTE FOR FURTHER WORK ON CONSTRUCTORS:
- - If a forbidded modifier is found, the the error is either the use of
- a forbidded modifier for a constructor OR bogus attempt to declare a
+ - If a forbidden modifier is found, the error is either the use of
+ a forbidden modifier for a constructor OR bogus attempt to declare a
method without having specified the return type. FIXME */
constructor_declaration:
constructor_declarator throws constructor_body
/* extra SC_TK, FIXME */
| modifiers constructor_declarator throws constructor_body SC_TK
{ modifier_value = 0; }
-/* I'm not happy with the SC_TK addition. It isn't in the grammer and should
+/* I'm not happy with the SC_TK addition. It isn't in the grammar and should
probably be matched by and empty statement. But it doesn't work. FIXME */
;
| synchronized_statement
| throw_statement
| try_statement
+| assert_statement
;
empty_statement:
THROW_TK expression SC_TK { ++complexity; }
;
+assert_statement:
+ ASSERT_TK expression REL_CL_TK expression SC_TK
+| ASSERT_TK expression SC_TK
+| ASSERT_TK error
+ {yyerror ("Missing term"); RECOVER;}
+| ASSERT_TK expression error
+ {yyerror ("';' expected"); RECOVER;}
+;
synchronized_statement:
synchronized OP_TK expression CP_TK block
| synchronized OP_TK expression CP_TK error
| array_access
| type_literals
/* Added, JDK1.1 inner classes. Documentation is wrong
- refering to a 'ClassName' (class_name) rule that doesn't
+ referring to a 'ClassName' (class_name) rule that doesn't
exist. Used name instead. */
| name DOT_TK THIS_TK
{ USE_ABSORBER; }
anonymous_class_creation:
NEW_TK class_type OP_TK CP_TK
- { report_class_declaration (NULL); }
+ { report_class_declaration (anonymous_context); }
class_body
| NEW_TK class_type OP_TK argument_list CP_TK
- { report_class_declaration (NULL); }
+ { report_class_declaration (anonymous_context); }
class_body
;
/* Create a new parser context */
void
-java_push_parser_context ()
+java_push_parser_context (void)
{
- struct parser_ctxt *new =
- (struct parser_ctxt *) xcalloc (1, sizeof (struct parser_ctxt));
+ struct parser_ctxt *new = xcalloc (1, sizeof (struct parser_ctxt));
new->next = ctxp;
ctxp = new;
}
static void
-push_class_context (name)
- const char *name;
+push_class_context (const char *name)
{
- /* If we already have CURRENT_CLASS set, we're in an inter
- class. Mangle its name. */
- if (current_class)
- {
- const char *p;
- char anonymous [3];
- int additional_length;
-
- /* NAME set to NULL indicates an anonymous class, which are named by
- numbering them. */
- if (!name)
- {
- sprintf (anonymous, "%d", ++anonymous_count);
- p = anonymous;
- }
- else
- p = name;
-
- additional_length = strlen (p)+1; /* +1 for `$' */
- current_class = xrealloc (current_class,
- current_class_length + additional_length + 1);
- current_class [current_class_length] = '$';
- strcpy (¤t_class [current_class_length+1], p);
- current_class_length += additional_length;
- }
- else
+ struct class_context *ctx;
+
+ ctx = xmalloc (sizeof (struct class_context));
+ ctx->name = (char *) name;
+ ctx->next = current_class_context;
+ current_class_context = ctx;
+}
+
+static void
+pop_class_context (void)
+{
+ struct class_context *ctx;
+
+ if (current_class_context == NULL)
+ return;
+
+ ctx = current_class_context->next;
+ if (current_class_context->name != anonymous_context)
+ free (current_class_context->name);
+ free (current_class_context);
+
+ current_class_context = ctx;
+ if (current_class_context == NULL)
+ anonymous_count = 0;
+}
+
+/* Recursively construct the class name. This is just a helper
+ function for get_class_name(). */
+static int
+make_class_name_recursive (struct obstack *stack, struct class_context *ctx)
+{
+ if (! ctx)
+ return 0;
+
+ make_class_name_recursive (stack, ctx->next);
+
+ /* Replace an anonymous context with the appropriate counter value. */
+ if (ctx->name == anonymous_context)
{
- if (!name)
- return;
- current_class_length = strlen (name);
- current_class = xmalloc (current_class_length+1);
- strcpy (current_class, name);
+ char buf[50];
+ ++anonymous_count;
+ sprintf (buf, "%d", anonymous_count);
+ ctx->name = xstrdup (buf);
}
+
+ obstack_grow (stack, ctx->name, strlen (ctx->name));
+ obstack_1grow (stack, '$');
+
+ return ISDIGIT (ctx->name[0]);
}
-static void
-pop_class_context ()
+/* Return a newly allocated string holding the name of the class. */
+static char *
+get_class_name (void)
{
- /* Go back to the last `$' and cut. */
- while (--current_class_length > 0
- && current_class [current_class_length] != '$')
- ;
- if (current_class_length)
+ char *result;
+ int last_was_digit;
+ struct obstack name_stack;
+
+ obstack_init (&name_stack);
+
+ /* Duplicate the logic of parse.y:maybe_make_nested_class_name(). */
+ last_was_digit = make_class_name_recursive (&name_stack,
+ current_class_context->next);
+
+ if (! last_was_digit
+ && method_depth
+ && current_class_context->name != anonymous_context)
{
- current_class = xrealloc (current_class, current_class_length+1);
- current_class [current_class_length] = '\0';
+ char buf[50];
+ ++anonymous_count;
+ sprintf (buf, "%d", anonymous_count);
+ obstack_grow (&name_stack, buf, strlen (buf));
+ obstack_1grow (&name_stack, '$');
}
- else
+
+ if (current_class_context->name == anonymous_context)
{
- current_class = NULL;
- anonymous_count = 0;
+ char buf[50];
+ ++anonymous_count;
+ sprintf (buf, "%d", anonymous_count);
+ current_class_context->name = xstrdup (buf);
+ obstack_grow0 (&name_stack, buf, strlen (buf));
}
+ else
+ obstack_grow0 (&name_stack, current_class_context->name,
+ strlen (current_class_context->name));
+
+ result = xstrdup (obstack_finish (&name_stack));
+ obstack_free (&name_stack, NULL);
+
+ return result;
}
/* Actions defined here */
static void
-report_class_declaration (name)
- const char * name;
+report_class_declaration (const char * name)
{
extern int flag_dump_class, flag_list_filename;
push_class_context (name);
if (flag_dump_class)
{
+ char *name = get_class_name ();
+
if (!previous_output)
{
if (flag_list_filename)
- fprintf (out, "%s: ", input_filename);
+ fprintf (out, "%s: ", main_input_filename);
previous_output = 1;
}
-
+
if (package_name)
- fprintf (out, "%s.%s ", package_name, current_class);
+ fprintf (out, "%s.%s ", package_name, name);
else
- fprintf (out, "%s ", current_class);
+ fprintf (out, "%s ", name);
+
+ free (name);
}
}
static void
-report_main_declaration (declarator)
- struct method_declarator *declarator;
+report_main_declaration (struct method_declarator *declarator)
{
extern int flag_find_main;
&& declarator->args [0] == '['
&& (! strcmp (declarator->args+1, "String")
|| ! strcmp (declarator->args + 1, "java.lang.String"))
- && current_class)
+ && current_class_context)
{
if (!previous_output)
{
+ char *name = get_class_name ();
if (package_name)
- fprintf (out, "%s.%s ", package_name, current_class);
+ fprintf (out, "%s.%s ", package_name, name);
else
- fprintf (out, "%s", current_class);
+ fprintf (out, "%s", name);
+ free (name);
previous_output = 1;
}
}
}
void
-report ()
+report (void)
{
extern int flag_complexity;
if (flag_complexity)
- fprintf (out, "%s %d\n", input_filename, complexity);
+ fprintf (out, "%s %d\n", main_input_filename, complexity);
}
/* Reset global status used by the report functions. */
-void reset_report ()
+void
+reset_report (void)
{
previous_output = 0;
package_name = NULL;
- current_class = NULL;
+ current_class_context = NULL;
complexity = 0;
}
void
-yyerror (msg)
- const char *msg ATTRIBUTE_UNUSED;
+yyerror (const char *msg ATTRIBUTE_UNUSED)
{
- fprintf (stderr, "%s: %d: %s\n", input_filename, lineno, msg);
+ fprintf (stderr, "%s: %s\n", main_input_filename, msg);
exit (1);
}
+
+#ifdef __XGETTEXT__
+/* Depending on the version of Bison used to compile this grammar,
+ it may issue generic diagnostics spelled "syntax error" or
+ "parse error". To prevent this from changing the translation
+ template randomly, we list all the variants of this particular
+ diagnostic here. Translators: there is no fine distinction
+ between diagnostics with "syntax error" in them, and diagnostics
+ with "parse error" in them. It's okay to give them both the same
+ translation. */
+const char d1[] = N_("syntax error");
+const char d2[] = N_("parse error");
+const char d3[] = N_("syntax error; also virtual memory exhausted");
+const char d4[] = N_("parse error; also virtual memory exhausted");
+const char d5[] = N_("syntax error: cannot back up");
+const char d6[] = N_("parse error: cannot back up");
+#endif